Hard-link, rename, or copy an item to the backup name. Returns 0 for * failure, 1 if item was moved, 2 if item was duplicated or hard linked * into backup area, or 3 if item doesn't exist or isn't a regular file. */
| 224 | * failure, 1 if item was moved, 2 if item was duplicated or hard linked |
| 225 | * into backup area, or 3 if item doesn't exist or isn't a regular file. */ |
| 226 | int make_backup(const char *fname, BOOL prefer_rename) |
| 227 | { |
| 228 | stat_x sx; |
| 229 | struct file_struct *file; |
| 230 | int save_preserve_xattrs; |
| 231 | char *buf; |
| 232 | int ret = 0; |
| 233 | |
| 234 | init_stat_x(&sx); |
| 235 | /* Return success if no file to keep. */ |
| 236 | if (x_lstat(fname, &sx.st, NULL) < 0) |
| 237 | return 3; |
| 238 | |
| 239 | if (!(buf = get_backup_name(fname))) |
| 240 | return 0; |
| 241 | |
| 242 | /* Try a hard-link or a rename first. Using rename is not atomic, but |
| 243 | * is more efficient than forcing a copy for larger files when no hard- |
| 244 | * linking is possible. */ |
| 245 | if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0) |
| 246 | goto success; |
| 247 | if (errno == EEXIST || errno == EISDIR) { |
| 248 | STRUCT_STAT bakst; |
| 249 | if (do_lstat_at(buf, &bakst) == 0) { |
| 250 | int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE; |
| 251 | if (delete_item(buf, bakst.st_mode, flags) != 0) |
| 252 | return 0; |
| 253 | } |
| 254 | if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0) |
| 255 | goto success; |
| 256 | } |
| 257 | |
| 258 | /* Fall back to making a copy. */ |
| 259 | if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS))) |
| 260 | return 3; /* the file could have disappeared */ |
| 261 | |
| 262 | #ifdef SUPPORT_ACLS |
| 263 | if (preserve_acls && !S_ISLNK(file->mode)) { |
| 264 | get_acl(fname, &sx); |
| 265 | cache_tmp_acl(file, &sx); |
| 266 | free_acl(&sx); |
| 267 | } |
| 268 | #endif |
| 269 | #ifdef SUPPORT_XATTRS |
| 270 | if (preserve_xattrs) { |
| 271 | get_xattr(fname, &sx); |
| 272 | cache_tmp_xattr(file, &sx); |
| 273 | free_xattr(&sx); |
| 274 | } |
| 275 | #endif |
| 276 | |
| 277 | /* Check to see if this is a device file, or link */ |
| 278 | if ((am_root && preserve_devices && IS_DEVICE(file->mode)) |
| 279 | || (preserve_specials && IS_SPECIAL(file->mode))) { |
| 280 | if (do_mknod_at(buf, file->mode, sx.st.st_rdev) < 0) |
| 281 | rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf)); |
| 282 | else if (DEBUG_GTE(BACKUP, 1)) |
| 283 | rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname); |
no test coverage detected