@@ -1126,8 +1126,122 @@ 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+ names , err := fd .Readdirnames (- 1 )
1157+ if err != nil {
1158+ return nil , fmt .Errorf ("failed to read directory entry: %w" , err )
1159+ }
1160+
1161+ foundLeaf := false
1162+ // Find the leaf in the directory
1163+ for _ , name := range names {
1164+ if name == leaf {
1165+ foundLeaf = true
1166+ break
1167+ }
1168+ }
1169+ if ! foundLeaf {
1170+ return nil , fs .ErrorObjectNotFound
1171+ }
1172+
1173+ leafPath := join .FilePathJoin (fsDirPath , leaf )
1174+ // Just a stat won't work without checking the entries from readdir first because of differences in unicode handling
1175+ fi , fierr := os .Lstat (leafPath )
1176+ if fierr != nil {
1177+ // Don't report errors on any file names that are excluded
1178+ if useFilter {
1179+ newRemote := f .cleanRemote (dir , leaf )
1180+ if ! filter .IncludeRemote (newRemote ) {
1181+ return nil , fs .ErrorObjectNotFound
1182+ }
1183+ }
1184+
1185+ _ = accounting .Stats (ctx ).Error (fserrors .NoRetryError (fierr )) // fail the sync
1186+
1187+ return nil , fmt .Errorf ("%q: failed to get info about directory entry %q: %w" , dir , leafPath , fierr )
1188+ }
1189+
1190+ name := fi .Name ()
1191+ mode := fi .Mode ()
1192+ newRemote := f .cleanRemote (dir , name )
1193+
1194+ // Follow symlinks if required
1195+ if f .opt .FollowSymlinks && (mode & os .ModeSymlink ) != 0 {
1196+ localPath := join .FilePathJoin (fsDirPath , name )
1197+ fi , fierr = os .Stat (localPath )
1198+ // Quietly skip errors on excluded files and directories
1199+ if fierr != nil && useFilter && ! filter .IncludeRemote (newRemote ) {
1200+ return nil , fs .ErrorObjectNotFound
1201+ }
1202+
1203+ if fierr != nil {
1204+ // Check for bad symlinks and circular symlinks
1205+ if os .IsNotExist (fierr ) || isCircularSymlinkError (fierr ) {
1206+ _ = accounting .Stats (ctx ).Error (fserrors .NoRetryError (fierr )) // fail the sync
1207+ }
1208+ return nil , fmt .Errorf ("%q: following symlink for %q: %w" , dir , leafPath , fierr )
1209+ }
1210+
1211+ mode = fi .Mode ()
1212+ }
1213+
1214+ if fi .IsDir () {
1215+ // Ignore directories which are symlinks. These are junction points under windows which
1216+ // are kind of a souped up symlink. Unix doesn't have directories which are symlinks.
1217+ if (mode & os .ModeSymlink ) == 0 && f .dev == readDevice (fi , f .opt .OneFileSystem ) {
1218+ d := f .newDirectory (newRemote , fi )
1219+ return d , nil
1220+ }
1221+
1222+ } else {
1223+ // Check whether this link should be translated
1224+ if f .opt .TranslateSymlinks && fi .Mode ()& os .ModeSymlink != 0 {
1225+ newRemote += fs .LinkSuffix
1226+ }
1227+
1228+ // Don't include non directory if not included
1229+ // we leave directory filtering to the layer above
1230+ if useFilter && ! filter .IncludeRemote (newRemote ) {
1231+ return nil , fs .ErrorObjectNotFound
1232+ }
1233+
1234+ fso , err := f .newObjectWithInfo (newRemote , fi )
1235+ if err != nil {
1236+ return nil , err
1237+ }
1238+
1239+ if fso .Storable () {
1240+ return fso , nil
1241+ }
1242+ }
1243+
1244+ return nil , fs .ErrorObjectNotFound
11311245}
11321246
11331247// ------------------------------------------------------------
0 commit comments