@@ -179,26 +179,17 @@ func (fs *MemFS) ReadDir(path string) ([]os.FileInfo, error) {
179
179
}
180
180
181
181
func (fs * MemFS ) fileInfo (path string ) (parent * fileInfo , node * fileInfo , err error ) {
182
- path = filepath . Clean ( path )
183
- segments := vfs . SplitPath ( path , PathSeparator )
182
+ return fs . relativeFileInfo ( fs . wd , path )
183
+ }
184
184
185
- // Shortcut for working directory and root
186
- if len (segments ) == 1 {
187
- if segments [0 ] == "" {
188
- return nil , fs .root , nil
189
- } else if segments [0 ] == "." {
190
- return fs .wd .parent , fs .wd , nil
191
- }
192
- }
185
+ func (fs * MemFS ) relativeFileInfo (wd * fileInfo , path string ) (parent * fileInfo , node * fileInfo , err error ) {
186
+ parent , segments := fs .dirSegments (wd , path )
193
187
194
- // Determine root to traverse
195
- parent = fs .root
196
- if segments [0 ] == "." {
197
- parent = fs .wd
188
+ // Shortcut for working directory and root
189
+ if len (segments ) == 0 {
190
+ return parent .parent , parent , nil
198
191
}
199
- segments = segments [1 :]
200
192
201
- // Further directories
202
193
for _ , seg := range segments [:len (segments )- 1 ] {
203
194
204
195
if parent .childs == nil {
@@ -211,10 +202,16 @@ func (fs *MemFS) fileInfo(path string) (parent *fileInfo, node *fileInfo, err er
211
202
if entry .dir {
212
203
parent = entry
213
204
} else if entry .mode & os .ModeSymlink != 0 {
214
- _ , parent , err = fs .fileInfo (string (* entry .buf ))
205
+ // Look up interior symlink
206
+ _ , parent , err = fs .relativeFileInfo (parent , string (* entry .buf ))
215
207
if err != nil {
216
208
return nil , nil , err
217
209
}
210
+ // Symlink was not to a directory
211
+ if parent == nil {
212
+ return nil , nil , vfs .ErrNotDirectory
213
+ }
214
+
218
215
} else {
219
216
return nil , nil , os .ErrNotExist
220
217
}
@@ -223,6 +220,9 @@ func (fs *MemFS) fileInfo(path string) (parent *fileInfo, node *fileInfo, err er
223
220
lastSeg := segments [len (segments )- 1 ]
224
221
if parent .childs != nil {
225
222
if node , ok := parent .childs [lastSeg ]; ok {
223
+ if node .mode & os .ModeSymlink != 0 {
224
+ return fs .relativeFileInfo (parent , string (* node .buf ))
225
+ }
226
226
return parent , node , nil
227
227
}
228
228
} else {
@@ -232,6 +232,19 @@ func (fs *MemFS) fileInfo(path string) (parent *fileInfo, node *fileInfo, err er
232
232
return parent , nil , nil
233
233
}
234
234
235
+ func (fs * MemFS ) dirSegments (wd * fileInfo , path string ) (parent * fileInfo , segments []string ) {
236
+ path = filepath .Clean (path )
237
+ segments = vfs .SplitPath (path , PathSeparator )
238
+
239
+ // Determine root to traverse
240
+ parent = fs .root
241
+ if segments [0 ] == "." {
242
+ parent = wd
243
+ }
244
+ segments = segments [1 :]
245
+ return parent , segments
246
+ }
247
+
235
248
func hasFlag (flag int , flags int ) bool {
236
249
return flags & flag == flag
237
250
}
@@ -243,11 +256,6 @@ func (fs *MemFS) OpenFile(name string, flag int, perm os.FileMode) (vfs.File, er
243
256
fs .lock .Lock ()
244
257
defer fs .lock .Unlock ()
245
258
246
- return fs .openFile (name , flag , perm )
247
- }
248
-
249
- func (fs * MemFS ) openFile (name string , flag int , perm os.FileMode ) (vfs.File , error ) {
250
-
251
259
name = filepath .Clean (name )
252
260
base := filepath .Base (name )
253
261
fiParent , fiNode , err := fs .fileInfo (name )
@@ -275,9 +283,6 @@ func (fs *MemFS) openFile(name string, flag int, perm os.FileMode) (vfs.File, er
275
283
if fiNode .dir {
276
284
return nil , & os.PathError {"open" , name , ErrIsDirectory }
277
285
}
278
- if fiNode .mode & os .ModeSymlink != 0 {
279
- return fs .openFile (string (* fiNode .buf ), flag , perm )
280
- }
281
286
}
282
287
283
288
if ! hasFlag (os .O_RDONLY , flag ) {
0 commit comments