@@ -179,26 +179,17 @@ func (fs *MemFS) ReadDir(path string) ([]os.FileInfo, error) {
179179}
180180
181181func (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+ }
184184
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 )
193187
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
198191 }
199- segments = segments [1 :]
200192
201- // Further directories
202193 for _ , seg := range segments [:len (segments )- 1 ] {
203194
204195 if parent .childs == nil {
@@ -211,10 +202,16 @@ func (fs *MemFS) fileInfo(path string) (parent *fileInfo, node *fileInfo, err er
211202 if entry .dir {
212203 parent = entry
213204 } 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 ))
215207 if err != nil {
216208 return nil , nil , err
217209 }
210+ // Symlink was not to a directory
211+ if parent == nil {
212+ return nil , nil , vfs .ErrNotDirectory
213+ }
214+
218215 } else {
219216 return nil , nil , os .ErrNotExist
220217 }
@@ -223,6 +220,9 @@ func (fs *MemFS) fileInfo(path string) (parent *fileInfo, node *fileInfo, err er
223220 lastSeg := segments [len (segments )- 1 ]
224221 if parent .childs != nil {
225222 if node , ok := parent .childs [lastSeg ]; ok {
223+ if node .mode & os .ModeSymlink != 0 {
224+ return fs .relativeFileInfo (parent , string (* node .buf ))
225+ }
226226 return parent , node , nil
227227 }
228228 } else {
@@ -232,6 +232,19 @@ func (fs *MemFS) fileInfo(path string) (parent *fileInfo, node *fileInfo, err er
232232 return parent , nil , nil
233233}
234234
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+
235248func hasFlag (flag int , flags int ) bool {
236249 return flags & flag == flag
237250}
@@ -243,11 +256,6 @@ func (fs *MemFS) OpenFile(name string, flag int, perm os.FileMode) (vfs.File, er
243256 fs .lock .Lock ()
244257 defer fs .lock .Unlock ()
245258
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-
251259 name = filepath .Clean (name )
252260 base := filepath .Base (name )
253261 fiParent , fiNode , err := fs .fileInfo (name )
@@ -275,9 +283,6 @@ func (fs *MemFS) openFile(name string, flag int, perm os.FileMode) (vfs.File, er
275283 if fiNode .dir {
276284 return nil , & os.PathError {"open" , name , ErrIsDirectory }
277285 }
278- if fiNode .mode & os .ModeSymlink != 0 {
279- return fs .openFile (string (* fiNode .buf ), flag , perm )
280- }
281286 }
282287
283288 if ! hasFlag (os .O_RDONLY , flag ) {
0 commit comments