Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions src/main.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of rmw<https://theimpossibleastronaut.github.io/rmw-website/>

Copyright (C) 2012-2023 Andy Alt (arch_stanton5995@proton.me)
Copyright (C) 2012-2025 Andy Alt (arch_stanton5995@proton.me)
Other authors: https://github.com/theimpossibleastronaut/rmw/blob/master/AUTHORS.md

This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -262,7 +262,6 @@ list_waste_folders(st_waste *waste_head)
return;
}


static int
remove_to_waste(const int argc,
char *const argv[],
Expand Down Expand Up @@ -412,12 +411,26 @@ damage of 5000 hp. You feel satisfied.\n"));
int r_result = 0;
if (cli_user_options->want_dry_run == false)
{
if ((waste_curr->dev_num != st_target.dev_num) && !S_ISDIR(st_file_arg.st_mode))
int save_errno = errno;
const char *src = argv[file_arg];
const char *dst = st_target.waste_dest_name;

if (waste_curr->dev_num != st_target.dev_num)
{
int save_errno = errno;
r_result =
do_btrfs_clone(argv[file_arg], st_target.waste_dest_name,
&save_errno);
/* cross-device: different device numbers */
if (!S_ISDIR(st_file_arg.st_mode))
{
/* attempt btrfs clone if not a directory */
r_result = do_btrfs_clone(src, dst, &save_errno);
errno = save_errno;
}
else
{
/* directory on different device: call /bin/mv safely */
r_result = safe_mv_via_exec(src, dst, &save_errno);
errno = save_errno;
}

if (r_result != 0)
{
if (save_errno == EXDEV)
Expand All @@ -426,12 +439,16 @@ damage of 5000 hp. You feel satisfied.\n"));
continue;
}
else
{
exit(EXIT_FAILURE);
}
}
}
else
{
r_result = rename(argv[file_arg], st_target.waste_dest_name);
/* same device: simple rename */
r_result = rename(src, dst);
/* rename sets errno on failure */
}
}

Expand Down
77 changes: 66 additions & 11 deletions src/restore.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of rmw<https://theimpossibleastronaut.github.io/rmw-website/>

Copyright (C) 2012-2023 Andy Alt (arch_stanton5995@proton.me)
Copyright (C) 2012-2025 Andy Alt (arch_stanton5995@proton.me)
Other authors: https://github.com/theimpossibleastronaut/rmw/blob/master/AUTHORS.md

This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -63,6 +63,67 @@ get_waste_parent(char *waste_parent, const char *src)
return;
}

static int
move_back(const char *src, const char *dest, bool want_dry_run)
{
int rename_res = 0;
int save_errno = 0;
int clone_errno = 0;

if (want_dry_run)
return 0;

rename_res = rename(src, dest);
if (rename_res == 0)
return 0; /* success */

/* rename failed; preserve errno immediately */
save_errno = errno;

struct stat st_src;

/* rename already failed and save_errno == errno from rename() */
if (save_errno == EXDEV)
{
/* get file type without following symlinks */
if (lstat(src, &st_src) != 0)
{
/* cannot stat. restore rename's errno and fail */
errno = save_errno;
return -1;
}

if (S_ISDIR(st_src.st_mode))
{
/* directory on different device -> execv mv */
int mv_ret = safe_mv_via_exec(src, dest, &clone_errno);
if (mv_ret == 0)
{
errno = 0;
return 0;
}
errno = clone_errno ? clone_errno : save_errno;
return -1;
}
else
{
/* regular file on different device -> try btrfs clone */
int clone_res = do_btrfs_clone(src, dest, &clone_errno);
if (clone_res == 0)
{
errno = 0;
return 0;
}
errno = clone_errno ? clone_errno : save_errno;
return -1;
}
}

/* other rename error */
errno = save_errno;
return -1;
}


int
restore(const char *src, st_time *st_time_var,
Expand Down Expand Up @@ -171,16 +232,10 @@ Duplicate filename at destination - appending time string...\n"));
return p_state_parent;
}

int rename_res = 0;
int save_errno = errno;
if (cli_user_options->want_dry_run == false)
{
rename_res = rename(src, dest);
if (errno == EXDEV)
rename_res = do_btrfs_clone(src, dest, &save_errno);
}
int res = move_back(src, dest, cli_user_options->want_dry_run);


if (!rename_res)
if (!res)
{
printf("+'%s' -> '%s'\n", src, dest);

Expand All @@ -199,7 +254,7 @@ Duplicate filename at destination - appending time string...\n"));
else
{
msg_err_rename(src, dest);
return rename_res;
return res;
}
}
else
Expand Down
65 changes: 64 additions & 1 deletion src/utils.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of rmw<https://theimpossibleastronaut.github.io/rmw-website/>

Copyright (C) 2012-2023 Andy Alt (arch_stanton5995@proton.me)
Copyright (C) 2012-2025 Andy Alt (arch_stanton5995@proton.me)
Other authors: https://github.com/theimpossibleastronaut/rmw/blob/master/AUTHORS.md

This program is free software: you can redistribute it and/or modify
Expand All @@ -21,6 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef INC_GLOBALS_H
#define INC_GLOBALS_H

#include <sys/wait.h>

#include "globals.h"
#endif

Expand Down Expand Up @@ -495,6 +497,67 @@ count_chars(const char c, const char *str)
}


/* returns 0 on success, non-zero on failure.
On error sets *out_errno when out_errno != NULL. */
int
safe_mv_via_exec(const char *src, const char *dst, int *out_errno)
{
pid_t pid;
int status;
int saved_errno = 0;

pid = fork();
if (pid < 0)
{
saved_errno = errno;
if (out_errno)
*out_errno = saved_errno;
return -1;
}

if (pid == 0)
{
/* child: exec /bin/mv directly (argv[0] is "mv") */
char *const argv_mv[] = { "mv", (char *) src, (char *) dst, NULL };
execv("/bin/mv", argv_mv);
/* if execv fails, set errno and exit with a distinct code */
_exit(127);
}

/* parent: wait for child */
if (waitpid(pid, &status, 0) < 0)
{
saved_errno = errno;
if (out_errno)
*out_errno = saved_errno;
return -1;
}

if (WIFEXITED(status))
{
int code = WEXITSTATUS(status);
if (code == 0)
{
if (out_errno)
*out_errno = 0;
return 0;
}
/* child program returned nonzero. we cannot see its errno.
map common mv exit codes to errno conservatively. */
saved_errno = EIO;
if (out_errno)
*out_errno = saved_errno;
return code;
}

/* child was terminated by signal */
saved_errno = EINTR;
if (out_errno)
*out_errno = saved_errno;
return -1;
}


///////////////////////////////////////////////////////////////////////
#ifdef TEST_LIB

Expand Down
4 changes: 3 additions & 1 deletion src/utils.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This file is part of rmw<https://theimpossibleastronaut.github.io/rmw-website/>

Copyright (C) 2012-2024 Andy Alt (arch_stanton5995@proton.me)
Copyright (C) 2012-2025 Andy Alt (arch_stanton5995@proton.me)
Other authors: https://github.com/theimpossibleastronaut/rmw/blob/master/AUTHORS.md

This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -64,4 +64,6 @@ bool is_dir_f(const char *pathname);

int count_chars(const char c, const char *str);

int safe_mv_via_exec(const char *src, const char *dst, int *out_errno);

#endif
1 change: 0 additions & 1 deletion test/conf/btrfs_img.testrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#waste = /tmp/rmw-loop/.Trash-$UID
waste = /tmp/rmw-loop/three/Waste
waste = /tmp/rmw-loop/@two/Waste
waste = /tmp/rmw-loop/trashlink
WASTE = $HOME/.local/share/Waste
Expand Down
8 changes: 5 additions & 3 deletions test/test_btrfs_clone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,22 @@ fi
cd "$BTRFS_IMAGE_MOUNTPOINT"
RMW_TEST_CMD_STRING="$BIN_DIR/rmw -c ${MESON_SOURCE_ROOT}/test/conf/btrfs_img.testrc"

SUBVOLUME_USED="/tmp/rmw-loop/three"
SUBVOLUME_USED="/tmp/rmw-loop/@two"

WASTE_USED="$SUBVOLUME_USED/Waste"
if [ -d "$WASTE_USED" ]; then
rm -rf "$WASTE_USED"
fi

TEST_DIR="$SUBVOLUME_USED/test_dir"
TEST_DIR="$BTRFS_IMAGE_MOUNTPOINT/test_dir"
if [ -d "$TEST_DIR" ]; then
rm -rf "$TEST_DIR"
fi

mkdir "$TEST_DIR"
$RMW_TEST_CMD_STRING -v "$TEST_DIR"
$RMW_TEST_CMD_STRING "$TEST_DIR"

$RMW_TEST_CMD_STRING -u

touch foo
$RMW_TEST_CMD_STRING foo
Expand Down
Loading