diff options
author | Andrey Makarov <ph.makarov@gmail.com> | 2022-10-25 08:42:47 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-25 07:42:47 +0200 |
commit | 8ed2431db0d95bb30d69c563a137e348cd299621 (patch) | |
tree | 8ec35a56161b3c84b15c8ca1a84db8875e479c71 /lib/std | |
parent | c1343739e15eb2b225d8a523d577c0bc84148ad9 (diff) | |
download | Nim-8ed2431db0d95bb30d69c563a137e348cd299621.tar.gz |
Implement Unix file regularity check (#20448) (#20628)
* Implement Unix file regularity check * update std/dirs also
Diffstat (limited to 'lib/std')
-rw-r--r-- | lib/std/dirs.nim | 32 | ||||
-rw-r--r-- | lib/std/private/oscommon.nim | 13 | ||||
-rw-r--r-- | lib/std/private/osdirs.nim | 46 |
3 files changed, 54 insertions, 37 deletions
diff --git a/lib/std/dirs.nim b/lib/std/dirs.nim index e89bfc668..304075a6f 100644 --- a/lib/std/dirs.nim +++ b/lib/std/dirs.nim @@ -121,30 +121,33 @@ iterator walkDirs*(pattern: Path): Path {.tags: [ReadDirEffect].} = for p in walkDirs(pattern.string): yield Path(p) -iterator walkDir*(dir: Path; relative = false, checkDir = false): +iterator walkDir*(dir: Path; relative = false, checkDir = false, + onlyRegular = false): tuple[kind: PathComponent, path: Path] {.tags: [ReadDirEffect].} = ## Walks over the directory `dir` and yields for each directory or file in ## `dir`. The component type and full path for each item are returned. ## - ## Walking is not recursive. If ``relative`` is true (default: false) - ## the resulting path is shortened to be relative to ``dir``. - ## - ## If `checkDir` is true, `OSError` is raised when `dir` - ## doesn't exist. - for (k, p) in walkDir(dir.string, relative, checkDir): + ## Walking is not recursive. + ## * If `relative` is true (default: false) + ## the resulting path is shortened to be relative to ``dir``, + ## otherwise the full path is returned. + ## * If `checkDir` is true, `OSError` is raised when `dir` + ## doesn't exist. + ## * If `onlyRegular` is true, then (besides all directories) only *regular* + ## files (**without** special "file" objects like FIFOs, device files, + ## etc) will be yielded on Unix. + for (k, p) in walkDir(dir.string, relative, checkDir, onlyRegular): yield (k, Path(p)) iterator walkDirRec*(dir: Path, yieldFilter = {pcFile}, followFilter = {pcDir}, - relative = false, checkDir = false): Path {.tags: [ReadDirEffect].} = + relative = false, checkDir = false, onlyRegular = false): + Path {.tags: [ReadDirEffect].} = ## Recursively walks over the directory `dir` and yields for each file ## or directory in `dir`. ## - ## If ``relative`` is true (default: false) the resulting path is - ## shortened to be relative to ``dir``, otherwise the full path is returned. - ## - ## If `checkDir` is true, `OSError` is raised when `dir` - ## doesn't exist. + ## Options `relative`, `checkdir`, `onlyRegular` are explained in + ## [walkDir iterator] description. ## ## .. warning:: Modifying the directory structure while the iterator ## is traversing may result in undefined behavior! @@ -173,5 +176,6 @@ iterator walkDirRec*(dir: Path, ## * `walkFiles iterator`_ ## * `walkDirs iterator`_ ## * `walkDir iterator`_ - for p in walkDirRec(dir.string, yieldFilter, followFilter, relative, checkDir): + for p in walkDirRec(dir.string, yieldFilter, followFilter, relative, + checkDir, onlyRegular): yield Path(p) diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim index dd66d137e..dbed1ba96 100644 --- a/lib/std/private/oscommon.nim +++ b/lib/std/private/oscommon.nim @@ -77,14 +77,17 @@ type when defined(posix) and not weirdTarget: - proc getSymlinkFileKind*(path: string): PathComponent = + proc getSymlinkFileKind*(path: string): + tuple[pc: PathComponent, isRegular: bool] = # Helper function. var s: Stat assert(path != "") - if stat(path, s) == 0'i32 and S_ISDIR(s.st_mode): - result = pcLinkToDir - else: - result = pcLinkToFile + result = (pcLinkToFile, true) + if stat(path, s) == 0'i32: + if S_ISDIR(s.st_mode): + result = (pcLinkToDir, true) + elif not S_ISREG(s.st_mode): + result = (pcLinkToFile, false) proc tryMoveFSObject*(source, dest: string, isDir: bool): bool {.noWeirdTarget.} = ## Moves a file (or directory if `isDir` is true) from `source` to `dest`. diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim index 486b1445b..2f98257e2 100644 --- a/lib/std/private/osdirs.nim +++ b/lib/std/private/osdirs.nim @@ -154,16 +154,21 @@ proc staticWalkDir(dir: string; relative: bool): seq[ tuple[kind: PathComponent, path: string]] = discard -iterator walkDir*(dir: string; relative = false, checkDir = false): +iterator walkDir*(dir: string; relative = false, checkDir = false, + onlyRegular = false): tuple[kind: PathComponent, path: string] {.tags: [ReadDirEffect].} = ## Walks over the directory `dir` and yields for each directory or file in ## `dir`. The component type and full path for each item are returned. ## - ## Walking is not recursive. If ``relative`` is true (default: false) - ## the resulting path is shortened to be relative to ``dir``. - ## - ## If `checkDir` is true, `OSError` is raised when `dir` - ## doesn't exist. + ## Walking is not recursive. + ## * If `relative` is true (default: false) + ## the resulting path is shortened to be relative to ``dir``, + ## otherwise the full path is returned. + ## * If `checkDir` is true, `OSError` is raised when `dir` + ## doesn't exist. + ## * If `onlyRegular` is true, then (besides all directories) only *regular* + ## files (**without** special "file" objects like FIFOs, device files, + ## etc) will be yielded on Unix. ## ## **Example:** ## @@ -234,24 +239,30 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): y = path var k = pcFile + template resolveSymlink() = + var isRegular: bool + (k, isRegular) = getSymlinkFileKind(path) + if onlyRegular and not isRegular: continue + template kSetGeneric() = # pure Posix component `k` resolution if lstat(path.cstring, s) < 0'i32: continue # don't yield elif S_ISDIR(s.st_mode): k = pcDir elif S_ISLNK(s.st_mode): - k = getSymlinkFileKind(path) + resolveSymlink() + elif onlyRegular and not S_ISREG(s.st_mode): continue when defined(linux) or defined(macosx) or defined(bsd) or defined(genode) or defined(nintendoswitch): case x.d_type of DT_DIR: k = pcDir of DT_LNK: - if dirExists(path): k = pcLinkToDir - else: k = pcLinkToFile + resolveSymlink() of DT_UNKNOWN: kSetGeneric() - else: # e.g. DT_REG etc - discard # leave it as pcFile + else: # DT_REG or special "files" like FIFOs + if onlyRegular and x.d_type != DT_REG: continue + else: discard # leave it as pcFile else: # assuming that field `d_type` is not present kSetGeneric() @@ -259,15 +270,13 @@ iterator walkDir*(dir: string; relative = false, checkDir = false): iterator walkDirRec*(dir: string, yieldFilter = {pcFile}, followFilter = {pcDir}, - relative = false, checkDir = false): string {.tags: [ReadDirEffect].} = + relative = false, checkDir = false, onlyRegular = false): + string {.tags: [ReadDirEffect].} = ## Recursively walks over the directory `dir` and yields for each file ## or directory in `dir`. ## - ## If ``relative`` is true (default: false) the resulting path is - ## shortened to be relative to ``dir``, otherwise the full path is returned. - ## - ## If `checkDir` is true, `OSError` is raised when `dir` - ## doesn't exist. + ## Options `relative`, `checkdir`, `onlyRegular` are explained in + ## [walkDir iterator] description. ## ## .. warning:: Modifying the directory structure while the iterator ## is traversing may result in undefined behavior! @@ -301,7 +310,8 @@ iterator walkDirRec*(dir: string, var checkDir = checkDir while stack.len > 0: let d = stack.pop() - for k, p in walkDir(dir / d, relative = true, checkDir = checkDir): + for k, p in walkDir(dir / d, relative = true, checkDir = checkDir, + onlyRegular = onlyRegular): let rel = d / p if k in {pcDir, pcLinkToDir} and k in followFilter: stack.add rel |