@@ -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// ------------------------------------------------------------
0 commit comments