@@ -2006,7 +2006,7 @@ type OpenDirStatus* = enum
2006
2006
type WalkStepKind * = enum
2007
2007
wsOpenDir, # # attempt to open directory
2008
2008
wsEntryOk, # # the entry is OK
2009
- wsEntryBad # # usually a dangling symlink on posix, when it's unclear if it
2009
+ wsEntryBad # # a broken symlink on posix, where it's unclear if it
2010
2010
# # points to a file or directory
2011
2011
wsInterrupted # # the directory handle got invalidated during reading
2012
2012
@@ -2024,7 +2024,7 @@ type WalkStep = ref object
2024
2024
iterator tryWalkDir * (dir: string ; relative= false ): WalkStep {.
2025
2025
tags : [ReadDirEffect ], raises : [].} =
2026
2026
# # A version of `walkDir iterator <#walkDir.i,string>`_ with more
2027
- # # thorough error checking.
2027
+ # # thorough error checking. It never raises an exception.
2028
2028
# # Yields *steps* of walking through `dir`, each step contains
2029
2029
# # its path ``path``, OS error code ``code`` and additional tag ``kind``.
2030
2030
# # At first step it yields info ``openStatus`` of opening
@@ -2122,89 +2122,75 @@ iterator tryWalkDir*(dir: string; relative=false): WalkStep {.
2122
2122
defer :
2123
2123
if d != nil :
2124
2124
discard closedir (d)
2125
- while not lastIter:
2126
- yieldAllowed = true
2127
- if not init:
2128
- init = true
2129
- d = opendir (dir)
2130
- if d == nil :
2131
- lastIter = true
2132
- res =
2133
- if errno == ENOENT : sOpenDir (odNotFound, dir)
2134
- elif errno == ENOTDIR : sOpenDir (odNotDir, dir)
2135
- elif errno == EACCES : sOpenDir (odAccessDenied, dir)
2136
- else : sOpenDir (odUnknownError, dir)
2137
- else :
2138
- res = sOpenDir (odOpenOk, dir)
2139
- else :
2140
- errno = 0
2141
- var x = readdir (d)
2142
- if x == nil :
2143
- if errno == 0 :
2144
- break # normal end, yielding nothing
2145
- else :
2146
- lastIter = true
2147
- res = sGetError (wsInterrupted, dir)
2148
- else :
2125
+ block loop:
2126
+ while not lastIter:
2127
+ block beforeYield:
2128
+ if not init:
2129
+ init = true
2130
+ d = opendir (dir)
2131
+ if d == nil :
2132
+ lastIter = true
2133
+ res =
2134
+ if errno == ENOENT : sOpenDir (odNotFound, dir)
2135
+ elif errno == ENOTDIR : sOpenDir (odNotDir, dir)
2136
+ elif errno == EACCES : sOpenDir (odAccessDenied, dir)
2137
+ else : sOpenDir (odUnknownError, dir)
2138
+ else :
2139
+ res = sOpenDir (odOpenOk, dir)
2140
+ break beforeYield
2141
+ errno = 0
2142
+ var x = readdir (d)
2143
+ if x == nil :
2144
+ if errno == 0 :
2145
+ break loop # normal end, yielding nothing
2146
+ else :
2147
+ lastIter = true
2148
+ res = sGetError (wsInterrupted, dir)
2149
+ break beforeYield
2149
2150
when defined (nimNoArrayToCstringConversion):
2150
2151
var y = $ cstring (addr x.d_name)
2151
2152
else :
2152
2153
var y = $ x.d_name.cstring
2153
2154
if y == " ." or y == " .." :
2154
- yieldAllowed = false
2155
- else :
2156
- var s: Stat
2157
- let path = dir / y
2158
- if not relative:
2159
- y = path
2160
- var k = pcFile
2161
-
2162
- var useLstat = false
2163
- when defined (linux) or defined (macosx) or
2164
- defined (bsd) or defined (genode) or defined (nintendoswitch):
2165
- if x.d_type != DT_UNKNOWN :
2166
- if x.d_type == DT_DIR :
2167
- k = pcDir
2168
- res = sNoErrors (k, y)
2169
- elif x.d_type == DT_LNK :
2170
- errno = 0
2171
- if dirExists (path): k = pcLinkToDir
2172
- else : k = pcLinkToFile
2173
- if errno == 0 : # check error in dirExists
2174
- res = sNoErrors (k, y)
2175
- else :
2176
- res = sGetError (wsEntryBad, y)
2177
- else :
2178
- res = sNoErrors (k, y)
2179
- useLstat = false
2180
- else :
2181
- useLstat = true
2182
- else :
2183
- useLstat = true
2184
- if useLstat:
2185
- # special case of DT_UNKNOWN: some filesystems can't detect that
2186
- # entry is a directory and keep its d_type as 0=DT_UNKNOWN
2187
- if lstat (path, s) < 0 'i32 :
2188
- res = sGetError (wsEntryBad, y)
2189
- else :
2155
+ continue
2156
+ var s: Stat
2157
+ let path = dir / y
2158
+ if not relative:
2159
+ y = path
2160
+ var k = pcFile
2161
+
2162
+ when defined (linux) or defined (macosx) or
2163
+ defined (bsd) or defined (genode) or defined (nintendoswitch):
2164
+ if x.d_type != DT_UNKNOWN :
2165
+ if x.d_type == DT_DIR :
2166
+ k = pcDir
2167
+ res = sNoErrors (k, y)
2168
+ elif x.d_type == DT_LNK :
2190
2169
errno = 0
2191
- if S_ISDIR (s.st_mode):
2192
- k = pcDir
2193
- elif S_ISLNK (s.st_mode):
2194
- k = getSymlinkFileKind (path)
2195
- if errno == 0 : # check error in getSymlinkFileKind
2170
+ if dirExists (path): k = pcLinkToDir
2171
+ else : k = pcLinkToFile
2172
+ if errno == 0 : # check error in dirExists
2196
2173
res = sNoErrors (k, y)
2197
2174
else :
2198
2175
res = sGetError (wsEntryBad, y)
2199
- if yieldAllowed: yield res
2200
-
2201
- proc tryOpenDir * (dir: string ): OpenDirStatus {.
2202
- tags : [ReadDirEffect ], raises : [], since :(1 ,1 ).} =
2203
- # TODO
2204
- for step in tryWalkDir (dir):
2205
- case step.kind
2206
- of wsOpenDir: return step.openStatus
2207
- else : break # can not happen
2176
+ else :
2177
+ res = sNoErrors (k, y)
2178
+ break beforeYield
2179
+ # case of d_type==DT_UNKNOWN: some filesystems don't report
2180
+ # the entry type; one should fallback to lstat
2181
+ if lstat (path, s) < 0 'i32 :
2182
+ res = sGetError (wsEntryBad, y)
2183
+ else :
2184
+ errno = 0
2185
+ if S_ISDIR (s.st_mode):
2186
+ k = pcDir
2187
+ elif S_ISLNK (s.st_mode):
2188
+ k = getSymlinkFileKind (path)
2189
+ if errno == 0 : # check error in getSymlinkFileKind
2190
+ res = sNoErrors (k, y)
2191
+ else :
2192
+ res = sGetError (wsEntryBad, y)
2193
+ yield res
2208
2194
2209
2195
iterator walkDir * (dir: string ; relative= false ): tuple [kind: PathComponent , path: string ] {.
2210
2196
tags : [ReadDirEffect ].} =
0 commit comments