diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2024-09-27 22:36:31 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-27 16:36:31 +0200 |
commit | 4f5c0efaf24e863b26b16d7998eac3bdd830e7be (patch) | |
tree | 4eca358c7eec2f84b7ff2a151276c1184c081a33 | |
parent | 821d0806feb3648ced5809a78b07581ea3bd7880 (diff) | |
download | Nim-4f5c0efaf24e863b26b16d7998eac3bdd830e7be.tar.gz |
fixes #24174; allow copyDir and copyDirWithPermissions skipping special files (#24190)
fixes #24174
-rw-r--r-- | changelog.md | 1 | ||||
-rw-r--r-- | lib/std/private/osdirs.nim | 21 | ||||
-rw-r--r-- | lib/std/private/osfiles.nim | 2 | ||||
-rw-r--r-- | tests/stdlib/tos.nim | 15 |
4 files changed, 30 insertions, 9 deletions
diff --git a/changelog.md b/changelog.md index 6fcf750b6..dfbddeaa6 100644 --- a/changelog.md +++ b/changelog.md @@ -70,6 +70,7 @@ - Changed `std/osfiles.copyFile` to allow specifying `bufferSize` instead of a hard-coded one. - Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads. - `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it. +- Changed `std/os.copyDir` and `copyDirWithPermissions` to allow skipping special "file" objects like FIFOs, device files, etc on Unix by specifying a `skipSpecial` parameter. [//]: # "Additions:" diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim index b89a59c8d..a44cad7d9 100644 --- a/lib/std/private/osdirs.nim +++ b/lib/std/private/osdirs.nim @@ -446,13 +446,17 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", else: discard existsOrCreateDir(p) -proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", +proc copyDir*(source, dest: string, skipSpecial = false) {.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} = ## Copies a directory from `source` to `dest`. ## ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks ## are skipped. ## + ## If `skipSpecial` is true, then (besides all directories) only *regular* + ## files (**without** special "file" objects like FIFOs, device files, + ## etc) will be copied on Unix. + ## ## If this fails, `OSError` is raised. ## ## On the Windows platform this proc will copy the attributes from @@ -472,16 +476,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", ## * `createDir proc`_ ## * `moveDir proc`_ createDir(dest) - for kind, path in walkDir(source): + for kind, path in walkDir(source, skipSpecial = skipSpecial): var noSource = splitPath(path).tail if kind == pcDir: - copyDir(path, dest / noSource) + copyDir(path, dest / noSource, skipSpecial = skipSpecial) else: copyFile(path, dest / noSource, {cfSymlinkAsIs}) proc copyDirWithPermissions*(source, dest: string, - ignorePermissionErrors = true) + ignorePermissionErrors = true, + skipSpecial = false) {.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} = ## Copies a directory from `source` to `dest` preserving file permissions. @@ -489,6 +494,10 @@ proc copyDirWithPermissions*(source, dest: string, ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks ## are skipped. ## + ## If `skipSpecial` is true, then (besides all directories) only *regular* + ## files (**without** special "file" objects like FIFOs, device files, + ## etc) will be copied on Unix. + ## ## If this fails, `OSError` is raised. This is a wrapper proc around ## `copyDir`_ and `copyFileWithPermissions`_ procs ## on non-Windows platforms. @@ -518,10 +527,10 @@ proc copyDirWithPermissions*(source, dest: string, except: if not ignorePermissionErrors: raise - for kind, path in walkDir(source): + for kind, path in walkDir(source, skipSpecial = skipSpecial): var noSource = splitPath(path).tail if kind == pcDir: - copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors) + copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors, skipSpecial = skipSpecial) else: copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs}) diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim index a1d7079c5..37d8eabca 100644 --- a/lib/std/private/osfiles.nim +++ b/lib/std/private/osfiles.nim @@ -240,7 +240,7 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}; bufferSize = 1 else: # generic version of copyFile which works for any platform: var d, s: File - if not open(s, source):raiseOSError(osLastError(), source) + if not open(s, source): raiseOSError(osLastError(), source) if not open(d, dest, fmWrite): close(s) raiseOSError(osLastError(), dest) diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index ad34e479a..611659fdb 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -27,9 +27,8 @@ Raises """ # test os path creation, iteration, and deletion -import os, strutils, pathnorm from stdtest/specialpaths import buildDir -import std/[syncio, assertions] +import std/[syncio, assertions, osproc, os, strutils, pathnorm] block fileOperations: let files = @["these.txt", "are.x", "testing.r", "files.q"] @@ -161,6 +160,18 @@ block fileOperations: # createDir should not fail if `dir` is empty createDir("") + + when defined(linux): # bug #24174 + createDir("a/b") + open("a/file.txt", fmWrite).close + + if not fileExists("a/fifoFile"): + doAssert execCmd("mkfifo -m 600 a/fifoFile") == 0 + + copyDir("a/", "../dest/a/", skipSpecial = true) + copyDirWithPermissions("a/", "../dest2/a/", skipSpecial = true) + removeDir("a") + # Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`, # `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`. block: |