- if (!initialised) {
- if (backup_dir_len && backup_dir[backup_dir_len - 1] == '/')
- backup_dir[--backup_dir_len] = '\0';
- if (verbose > 0)
- rprintf(FINFO, "backup_dir is %s\n", backup_dir);
- initialised = 1;
+ init_stat_x(&sx);
+ /* Return success if no file to keep. */
+ if (x_lstat(fname, &sx.st, NULL) < 0)
+ return 1;
+
+ /* Try a hard-link or a rename first. Using rename is not atomic, but
+ * is more efficient than forcing a copy for larger files when no hard-
+ * linking is possible. */
+ if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
+ goto success;
+ if (errno == EEXIST) {
+ STRUCT_STAT bakst;
+ if (do_lstat(buf, &bakst) == 0) {
+ int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE;
+ if (delete_item(buf, bakst.st_mode, flags) != 0)
+ return 0;
+ }
+ if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
+ goto success;
+ } else if (backup_dir && errno == ENOENT) {
+ /* If the backup dir is missing, try again after making it. */
+ if (make_bak_dir(buf) != 0)
+ return 0;
+ if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0)
+ goto success;