renameFile attempts to rename an existing file to a destination and set the right attributes on it.
(cur, source, target protocol.FileInfo, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string)
| 951 | // renameFile attempts to rename an existing file to a destination |
| 952 | // and set the right attributes on it. |
| 953 | func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, dbUpdateChan chan<- dbUpdateJob, scanChan chan<- string) error { |
| 954 | // Used in the defer closure below, updated by the function body. Take |
| 955 | // care not declare another err. |
| 956 | var err error |
| 957 | |
| 958 | f.evLogger.Log(events.ItemStarted, map[string]string{ |
| 959 | "folder": f.folderID, |
| 960 | "item": source.Name, |
| 961 | "type": "file", |
| 962 | "action": "delete", |
| 963 | }) |
| 964 | f.evLogger.Log(events.ItemStarted, map[string]string{ |
| 965 | "folder": f.folderID, |
| 966 | "item": target.Name, |
| 967 | "type": "file", |
| 968 | "action": "update", |
| 969 | }) |
| 970 | |
| 971 | defer func() { |
| 972 | if err != nil { |
| 973 | slog.Info("Failed to rename file", f.LogAttr(), target.LogAttr(), slog.String("from", source.Name), slogutil.Error(err)) |
| 974 | } else { |
| 975 | slog.Info("Renamed file", f.LogAttr(), target.LogAttr(), slog.String("from", source.Name)) |
| 976 | } |
| 977 | f.evLogger.Log(events.ItemFinished, map[string]interface{}{ |
| 978 | "folder": f.folderID, |
| 979 | "item": source.Name, |
| 980 | "error": events.Error(err), |
| 981 | "type": "file", |
| 982 | "action": "delete", |
| 983 | }) |
| 984 | f.evLogger.Log(events.ItemFinished, map[string]interface{}{ |
| 985 | "folder": f.folderID, |
| 986 | "item": target.Name, |
| 987 | "error": events.Error(err), |
| 988 | "type": "file", |
| 989 | "action": "update", |
| 990 | }) |
| 991 | }() |
| 992 | |
| 993 | f.sl.Debug("Taking rename shortcut", "from", source.Name, "to", target.Name) |
| 994 | |
| 995 | // Check that source is compatible with what we have in the DB |
| 996 | if err = f.checkToBeDeleted(source, cur, true, scanChan); err != nil { |
| 997 | return err |
| 998 | } |
| 999 | // Check that the target corresponds to what we have in the DB |
| 1000 | curTarget, ok, err := f.model.sdb.GetDeviceFile(f.folderID, protocol.LocalDeviceID, target.Name) |
| 1001 | if err != nil { |
| 1002 | return err |
| 1003 | } |
| 1004 | switch stat, serr := f.mtimefs.Lstat(target.Name); { |
| 1005 | case serr != nil: |
| 1006 | var caseErr *fs.CaseConflictError |
| 1007 | switch { |
| 1008 | case errors.As(serr, &caseErr): |
| 1009 | if caseErr.Real != source.Name { |
| 1010 | err = serr |