Skip to content

Commit 963ab79

Browse files
committed
wip: local: implement the stat function
Signed-off-by: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com>
1 parent 91dd96a commit 963ab79

File tree

2 files changed

+132
-9
lines changed

2 files changed

+132
-9
lines changed

backend/local/local.go

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,8 +1126,103 @@ func (f *Fs) Command(ctx context.Context, name string, arg []string, opt map[str
11261126
// Stat returns the DirEntry for the given name
11271127
//
11281128
// It should return fs.ErrorNotImplemented if it can't return a DirEntry
1129-
func (f *Fs) Stat(ctx context.Context, dir string, leaf string) (fs.DirEntry, error) {
1130-
return nil, fs.ErrorNotImplemented
1129+
func (f *Fs) Stat(ctx context.Context, dir string, leaf string) (entry fs.DirEntry, err error) {
1130+
filter, useFilter := filter.GetConfig(ctx), filter.GetUseFilter(ctx)
1131+
1132+
fsDirPath := f.localPath(dir)
1133+
_, err = os.Stat(fsDirPath)
1134+
if err != nil {
1135+
return nil, fs.ErrorDirNotFound
1136+
}
1137+
1138+
fd, err := os.Open(fsDirPath)
1139+
if err != nil {
1140+
isPerm := os.IsPermission(err)
1141+
err = fmt.Errorf("failed to open directory %q: %w", dir, err)
1142+
fs.Errorf(dir, "%v", err)
1143+
if isPerm {
1144+
_ = accounting.Stats(ctx).Error(fserrors.NoRetryError(err))
1145+
err = nil // ignore error but fail sync
1146+
}
1147+
return nil, err
1148+
}
1149+
defer func() {
1150+
cerr := fd.Close()
1151+
if cerr != nil && err == nil {
1152+
err = fmt.Errorf("failed to close directory %q: %w", dir, cerr)
1153+
}
1154+
}()
1155+
1156+
leafPath := join.FilePathJoin(fsDirPath, leaf)
1157+
fi, fierr := os.Lstat(leafPath)
1158+
if fierr != nil {
1159+
// Don't report errors on any file names that are excluded
1160+
if useFilter {
1161+
newRemote := f.cleanRemote(dir, leaf)
1162+
if !filter.IncludeRemote(newRemote) {
1163+
return nil, fs.ErrorObjectNotFound
1164+
}
1165+
}
1166+
1167+
_ = accounting.Stats(ctx).Error(fserrors.NoRetryError(fierr)) // fail the sync
1168+
1169+
return nil, fmt.Errorf("%q: failed to get info about directory entry %q: %w", dir, leafPath, fierr)
1170+
}
1171+
1172+
name := fi.Name()
1173+
mode := fi.Mode()
1174+
newRemote := f.cleanRemote(dir, name)
1175+
1176+
// Follow symlinks if required
1177+
if f.opt.FollowSymlinks && (mode&os.ModeSymlink) != 0 {
1178+
fi, fierr = os.Stat(leafPath)
1179+
// Quietly skip errors on excluded files and directories
1180+
if fierr != nil && useFilter && !filter.IncludeRemote(newRemote) {
1181+
return nil, fs.ErrorObjectNotFound
1182+
}
1183+
1184+
if fierr != nil {
1185+
// Check for bad symlinks and circular symlinks
1186+
if os.IsNotExist(fierr) || isCircularSymlinkError(fierr) {
1187+
_ = accounting.Stats(ctx).Error(fserrors.NoRetryError(fierr)) // fail the sync
1188+
}
1189+
return nil, fmt.Errorf("%q: following symlink for %q: %w", dir, leafPath, fierr)
1190+
}
1191+
1192+
mode = fi.Mode()
1193+
}
1194+
1195+
if fi.IsDir() {
1196+
// Ignore directories which are symlinks. These are junction points under windows which
1197+
// are kind of a souped up symlink. Unix doesn't have directories which are symlinks.
1198+
if (mode&os.ModeSymlink) == 0 && f.dev == readDevice(fi, f.opt.OneFileSystem) {
1199+
d := f.newDirectory(newRemote, fi)
1200+
return d, nil
1201+
}
1202+
1203+
} else {
1204+
// Check whether this link should be translated
1205+
if f.opt.TranslateSymlinks && fi.Mode()&os.ModeSymlink != 0 {
1206+
newRemote += fs.LinkSuffix
1207+
}
1208+
1209+
// Don't include non directory if not included
1210+
// we leave directory filtering to the layer above
1211+
if useFilter && !filter.IncludeRemote(newRemote) {
1212+
return nil, fs.ErrorObjectNotFound
1213+
}
1214+
1215+
fso, err := f.newObjectWithInfo(newRemote, fi)
1216+
if err != nil {
1217+
return nil, err
1218+
}
1219+
1220+
if fso.Storable() {
1221+
return fso, nil
1222+
}
1223+
}
1224+
1225+
return nil, fs.ErrorObjectNotFound
11311226
}
11321227

11331228
// ------------------------------------------------------------

backend/union/union.go

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,41 @@ func (f *Fs) ListR(ctx context.Context, dir string, callback fs.ListRCallback) (
796796
return callback(entries)
797797
}
798798

799+
// Stat returns the DirEntry for the given name
800+
//
801+
// It should return fs.ErrorNotImplemented if it can't return a DirEntry
802+
func (f *Fs) Stat(ctx context.Context, dir string, leaf string) (fs.DirEntry, error) {
803+
//entriesList := make([][]upstream.Entry, len(f.upstreams))
804+
//errs := Errors(make([]error, len(f.upstreams)))
805+
//multithread(len(f.upstreams), func(i int) {
806+
// u := f.upstreams[i]
807+
// entries, err := u.List(ctx, dir)
808+
// if err != nil {
809+
// errs[i] = fmt.Errorf("%s: %w", u.Name(), err)
810+
// return
811+
// }
812+
// uEntries := make([]upstream.Entry, len(entries))
813+
// for j, e := range entries {
814+
// uEntries[j], _ = u.WrapEntry(e)
815+
// }
816+
// entriesList[i] = uEntries
817+
//})
818+
//if len(errs) == len(errs.FilterNil()) {
819+
// errs = errs.Map(func(e error) error {
820+
// if errors.Is(e, fs.ErrorDirNotFound) {
821+
// return nil
822+
// }
823+
// return e
824+
// })
825+
// if len(errs) == 0 {
826+
// return nil, fs.ErrorDirNotFound
827+
// }
828+
// return nil, errs.Err()
829+
//}
830+
//return f.mergeDirEntries(entriesList)
831+
return nil, fs.ErrorNotImplemented
832+
}
833+
799834
// NewObject creates a new remote union file object
800835
func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
801836
objs := make([]*upstream.Object, len(f.upstreams))
@@ -911,13 +946,6 @@ func (f *Fs) CleanUp(ctx context.Context) error {
911946
return errs.Err()
912947
}
913948

914-
// Stat returns the DirEntry for the given name
915-
//
916-
// It should return fs.ErrorNotImplemented if it can't return a DirEntry
917-
func (f *Fs) Stat(ctx context.Context, dir string, leaf string) (fs.DirEntry, error) {
918-
return nil, fs.ErrorNotImplemented
919-
}
920-
921949
// NewFs constructs an Fs from the path.
922950
//
923951
// The returned Fs is the actual Fs, referenced by remote in the config

0 commit comments

Comments
 (0)