@@ -438,14 +438,24 @@ func (f ArchiveFS) Open(name string) (fs.File, error) {
438
438
// paths in archives can't necessarily be trusted; also clean up any "./" prefix
439
439
file .NameInArchive = path .Clean (file .NameInArchive )
440
440
441
- if ! strings .HasPrefix (file .NameInArchive , name ) {
441
+ // ignore this entry if it's neither the file we're looking for, nor
442
+ // one of its descendents; we can't just check that the filename is
443
+ // a prefix of the requested file, because that could wrongly match
444
+ // "a/b/c.jpg.json" if the requested filename is "a/b/c.jpg", and
445
+ // this could result in loading the wrong file (!!) so we append a
446
+ // path separator to ensure that can't happen: "a/b/c.jpg.json/"
447
+ // is not prefixed by "a/b/c.jpg/", but it will still match as we
448
+ // expect: "a/b/c/d/" is is prefixed by "a/b/c/", allowing us to
449
+ // match descenedent files, and "a/b/c.jpg/" is prefixed by
450
+ // "a/b/c.jpg/", allowing us to match exact filenames.
451
+ if ! strings .HasPrefix (file .NameInArchive + "/" , name + "/" ) {
442
452
return nil
443
453
}
444
454
445
455
// if this is the requested file, and it's a directory, set up the dirFile,
446
- // which will include a listing of all its contents as we continue the walk
456
+ // which will include a listing of all its contents as we continue iterating
447
457
if file .NameInArchive == name && file .IsDir () {
448
- fsFile = & dirFile {info : file } // will fill entries slice as we continue the walk
458
+ fsFile = & dirFile {info : file } // will fill entries slice as we continue iterating
449
459
return nil
450
460
}
451
461
@@ -738,7 +748,8 @@ func (f *ArchiveFS) Sub(dir string) (fs.FS, error) {
738
748
// The exported fields may be changed during the lifetime of a DeepFS value
739
749
// (but not concurrently). It is safe to use this type as an FS concurrently.
740
750
type DeepFS struct {
741
- // The root filepath on disk.
751
+ // The root filepath using OS separator, even if it
752
+ // traverses into an archive.
742
753
Root string
743
754
744
755
// An optional context, mainly for cancellation.
@@ -859,7 +870,6 @@ func (*DeepFS) splitPath(path string) (realPath, innerPath string) {
859
870
860
871
for {
861
872
part := strings .TrimRight (strings .ToLower (path [start :end ]), " " )
862
-
863
873
for _ , ext := range archiveExtensions {
864
874
if strings .HasSuffix (part , ext ) {
865
875
// we've found an archive extension, so the path until the end of this segment is
0 commit comments