Skip to content

Commit 9cdce06

Browse files
committed
wip: local: implement the stat function
Signed-off-by: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com>
1 parent 25e5367 commit 9cdce06

File tree

2 files changed

+114
-9
lines changed

2 files changed

+114
-9
lines changed

backend/local/local.go

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,8 +1126,85 @@ 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+
leafPath := join.FilePathJoin(fsDirPath, leaf)
1139+
fi, fierr := os.Lstat(leafPath)
1140+
if fierr != nil {
1141+
// Don't report errors on any file names that are excluded
1142+
if useFilter {
1143+
newRemote := f.cleanRemote(dir, leaf)
1144+
if !filter.IncludeRemote(newRemote) {
1145+
return nil, fs.ErrorObjectNotFound
1146+
}
1147+
}
1148+
1149+
_ = accounting.Stats(ctx).Error(fserrors.NoRetryError(fierr)) // fail the sync
1150+
1151+
return nil, fmt.Errorf("%q: failed to get info about directory entry %q: %w", dir, leafPath, fierr)
1152+
}
1153+
1154+
name := fi.Name()
1155+
mode := fi.Mode()
1156+
newRemote := f.cleanRemote(dir, name)
1157+
1158+
// Follow symlinks if required
1159+
if f.opt.FollowSymlinks && (mode&os.ModeSymlink) != 0 {
1160+
fi, fierr = os.Stat(leafPath)
1161+
// Quietly skip errors on excluded files and directories
1162+
if fierr != nil && useFilter && !filter.IncludeRemote(newRemote) {
1163+
return nil, fs.ErrorObjectNotFound
1164+
}
1165+
1166+
if fierr != nil {
1167+
// Check for bad symlinks and circular symlinks
1168+
if os.IsNotExist(fierr) || isCircularSymlinkError(fierr) {
1169+
_ = accounting.Stats(ctx).Error(fserrors.NoRetryError(fierr)) // fail the sync
1170+
}
1171+
return nil, fmt.Errorf("%q: following symlink for %q: %w", dir, leafPath, fierr)
1172+
}
1173+
1174+
mode = fi.Mode()
1175+
}
1176+
1177+
if fi.IsDir() {
1178+
// Ignore directories which are symlinks. These are junction points under windows which
1179+
// are kind of a souped up symlink. Unix doesn't have directories which are symlinks.
1180+
if (mode&os.ModeSymlink) == 0 && f.dev == readDevice(fi, f.opt.OneFileSystem) {
1181+
d := f.newDirectory(newRemote, fi)
1182+
return d, nil
1183+
}
1184+
1185+
} else {
1186+
// Check whether this link should be translated
1187+
if f.opt.TranslateSymlinks && fi.Mode()&os.ModeSymlink != 0 {
1188+
newRemote += fs.LinkSuffix
1189+
}
1190+
1191+
// Don't include non directory if not included
1192+
// we leave directory filtering to the layer above
1193+
if useFilter && !filter.IncludeRemote(newRemote) {
1194+
return nil, fs.ErrorObjectNotFound
1195+
}
1196+
1197+
fso, err := f.newObjectWithInfo(newRemote, fi)
1198+
if err != nil {
1199+
return nil, err
1200+
}
1201+
1202+
if fso.Storable() {
1203+
return fso, nil
1204+
}
1205+
}
1206+
1207+
return nil, fs.ErrorObjectNotFound
11311208
}
11321209

11331210
// ------------------------------------------------------------

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)