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