fix: Resolve symlinks when creating files for OsFs compatibility
This commit is contained in:
@@ -1472,94 +1472,93 @@ var readTests = []struct {
|
||||
false,
|
||||
false,
|
||||
},
|
||||
// FIXME: Handle linkname
|
||||
// {
|
||||
// "Can not read /brokensymlink into non-empty buffer",
|
||||
// "/brokensymlink",
|
||||
// true,
|
||||
// func(f afero.Fs) error {
|
||||
// symFs, ok := f.(symFs)
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
{
|
||||
"Can not read /brokensymlink into non-empty buffer",
|
||||
"/brokensymlink",
|
||||
true,
|
||||
func(f afero.Fs) error {
|
||||
symFs, ok := f.(symFs)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if err := symFs.SymlinkIfPossible("/mydir", "/brokensymlink"); err != nil {
|
||||
// return err
|
||||
// }
|
||||
if err := symFs.SymlinkIfPossible("/mydir", "/brokensymlink"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// return nil
|
||||
// },
|
||||
// func(f afero.File) error {
|
||||
// gotContent := make([]byte, 10)
|
||||
return nil
|
||||
},
|
||||
func(f afero.File) error {
|
||||
gotContent := make([]byte, 10)
|
||||
|
||||
// if _, err := f.Read(gotContent); err != io.EOF {
|
||||
// return err
|
||||
// }
|
||||
if _, err := f.Read(gotContent); err != io.EOF {
|
||||
return err
|
||||
}
|
||||
|
||||
// return nil
|
||||
// },
|
||||
// true,
|
||||
// true,
|
||||
// false,
|
||||
// false,
|
||||
// },
|
||||
// {
|
||||
// "Can read /existingsymlink into non-empty buffer without readlink",
|
||||
// "/existingsymlink",
|
||||
// false,
|
||||
// func(f afero.Fs) error {
|
||||
// symFs, ok := f.(symFs)
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
return nil
|
||||
},
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Can read /existingsymlink into non-empty buffer without readlink",
|
||||
"/existingsymlink",
|
||||
false,
|
||||
func(f afero.Fs) error {
|
||||
symFs, ok := f.(symFs)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// file, err := f.Create("/test.txt")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
file, err := f.Create("/test.txt")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// r := newDeterministicReader(1000)
|
||||
r := newDeterministicReader(1000)
|
||||
|
||||
// if _, err := io.Copy(file, r); err != nil {
|
||||
// return err
|
||||
// }
|
||||
if _, err := io.Copy(file, r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if err := file.Close(); err != nil {
|
||||
// return err
|
||||
// }
|
||||
if err := file.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if err := symFs.SymlinkIfPossible("/test.txt", "/existingsymlink"); err != nil {
|
||||
// return err
|
||||
// }
|
||||
if err := symFs.SymlinkIfPossible("/test.txt", "/existingsymlink"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// return nil
|
||||
// },
|
||||
// func(f afero.File) error {
|
||||
// wantHash := "HTUi7GuNreHASha4hhl1xwuYk03pyTJ0IJbFLv04UdccT9m_NA2oBFTrnMxJhEu3VMGxDYk_04Th9C0zOj5MyA=="
|
||||
// wantLength := int64(32800768)
|
||||
return nil
|
||||
},
|
||||
func(f afero.File) error {
|
||||
wantHash := "HTUi7GuNreHASha4hhl1xwuYk03pyTJ0IJbFLv04UdccT9m_NA2oBFTrnMxJhEu3VMGxDYk_04Th9C0zOj5MyA=="
|
||||
wantLength := int64(32800768)
|
||||
|
||||
// hasher := sha512.New()
|
||||
// gotLength, err := io.Copy(hasher, f)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// gotHash := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
|
||||
hasher := sha512.New()
|
||||
gotLength, err := io.Copy(hasher, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gotHash := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
|
||||
|
||||
// if gotLength != wantLength {
|
||||
// return fmt.Errorf("invalid read length, got %v, want %v", gotLength, wantLength)
|
||||
// }
|
||||
if gotLength != wantLength {
|
||||
return fmt.Errorf("invalid read length, got %v, want %v", gotLength, wantLength)
|
||||
}
|
||||
|
||||
// if gotHash != wantHash {
|
||||
// return fmt.Errorf("invalid read hash, got %v, want %v", gotHash, wantHash)
|
||||
// }
|
||||
if gotHash != wantHash {
|
||||
return fmt.Errorf("invalid read hash, got %v, want %v", gotHash, wantHash)
|
||||
}
|
||||
|
||||
// return nil
|
||||
// },
|
||||
// true,
|
||||
// false, // FIXME: This should not be required and BasePathFs fails if it is used
|
||||
// false, // FIXME: Allow resolving symlinks without using readlink`, which is what `BasePathFs` supports`
|
||||
// true,
|
||||
// },
|
||||
return nil
|
||||
},
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestFile_Read(t *testing.T) {
|
||||
|
||||
@@ -459,58 +459,97 @@ func (f *STFS) OpenFile(name string, flag int, perm os.FileMode) (afero.File, er
|
||||
|
||||
f.onHeader,
|
||||
)
|
||||
|
||||
createFile := func() error {
|
||||
if !f.readOnly && flag&os.O_CREATE != 0 && flag&os.O_EXCL == 0 {
|
||||
if _, err := inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
filepath.Dir(name),
|
||||
false,
|
||||
|
||||
f.onHeader,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if target, err := inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
name,
|
||||
true,
|
||||
|
||||
f.onHeader,
|
||||
); err == nil {
|
||||
if target.Typeflag == tar.TypeDir {
|
||||
return config.ErrIsDirectory
|
||||
}
|
||||
}
|
||||
|
||||
if err := f.mknodeWithoutLocking(false, name, perm, false, "", false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hdr, err = inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
name,
|
||||
false,
|
||||
|
||||
f.onHeader,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
if !f.readOnly && flag&os.O_CREATE != 0 && flag&os.O_EXCL == 0 {
|
||||
if _, err := inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
filepath.Dir(name),
|
||||
false,
|
||||
|
||||
f.onHeader,
|
||||
); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if target, err := inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
name,
|
||||
true,
|
||||
|
||||
f.onHeader,
|
||||
); err == nil {
|
||||
if target.Typeflag == tar.TypeDir {
|
||||
return nil, config.ErrIsDirectory
|
||||
}
|
||||
}
|
||||
|
||||
if err := f.mknodeWithoutLocking(false, name, perm, false, "", false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hdr, err = inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
name,
|
||||
false,
|
||||
|
||||
f.onHeader,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, os.ErrNotExist
|
||||
if err := createFile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
hdr, err = inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
hdr.Linkname,
|
||||
false,
|
||||
|
||||
f.onHeader,
|
||||
)
|
||||
|
||||
if err == nil && !f.readOnly && flag&os.O_CREATE != 0 && flag&os.O_EXCL == 0 {
|
||||
hdr, err = inventory.Stat(
|
||||
f.metadata,
|
||||
|
||||
hdr.Linkname,
|
||||
true,
|
||||
|
||||
f.onHeader,
|
||||
)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
if err := createFile(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
|
||||
@@ -1388,20 +1388,19 @@ var openTests = []struct {
|
||||
},
|
||||
func(f afero.File) error { return nil },
|
||||
},
|
||||
// FIXME: Since we can't differentiate between broken and non-broken symlinks, this does not work yet
|
||||
// {
|
||||
// "Can not broken symlink to /brokensymlink",
|
||||
// openArgs{"/brokensymlink"},
|
||||
// true,
|
||||
// func(sf symFs) error {
|
||||
// if err := sf.SymlinkIfPossible("/test.txt", "/brokensymlink"); err != nil {
|
||||
// return nil
|
||||
// }
|
||||
{
|
||||
"Can not open broken symlink to /test.txt",
|
||||
openArgs{"/brokensymlink"},
|
||||
true,
|
||||
func(sf symFs) error {
|
||||
if err := sf.SymlinkIfPossible("/test.txt", "/brokensymlink"); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// return nil
|
||||
// },
|
||||
// func(f afero.File) error { return nil },
|
||||
// },
|
||||
return nil
|
||||
},
|
||||
func(f afero.File) error { return nil },
|
||||
},
|
||||
{
|
||||
"Can open symlink /existingsymlink to directory",
|
||||
openArgs{"/existingsymlink"},
|
||||
|
||||
@@ -51,6 +51,12 @@ func Stat(
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent returning broken symlinks as headers
|
||||
if !symlink && dbhdr.Linkname != "" {
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
|
||||
if symlink {
|
||||
dbhdr.Name = linkname
|
||||
dbhdr.Linkname = name
|
||||
|
||||
Reference in New Issue
Block a user