aboutsummaryrefslogtreecommitdiffstats
path: root/guts
diff options
context:
space:
mode:
Diffstat (limited to 'guts')
-rw-r--r--guts/rename.c41
-rw-r--r--guts/rmdir.c27
-rw-r--r--guts/unlinkat.c28
3 files changed, 41 insertions, 55 deletions
diff --git a/guts/rename.c b/guts/rename.c
index 973b164..8d4106b 100644
--- a/guts/rename.c
+++ b/guts/rename.c
@@ -10,6 +10,7 @@
struct stat64 oldbuf, newbuf;
int oldrc, newrc;
int save_errno;
+ int old_db_entry = 0;
pseudo_debug(2, "rename: %s->%s\n",
oldpath ? oldpath : "<nil>",
@@ -28,24 +29,24 @@
errno = save_errno;
/* newpath must be removed. */
- /* as with unlink, we have to do the remove before the operation
- */
- msg = pseudo_client_op(OP_UNLINK, 0, -1, -1, newpath, newrc ? NULL : &newbuf);
- /* stash the server's old data */
+ /* as with unlink, we have to mark that the file may get deleted */
+ msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, -1, newpath, newrc ? NULL : &newbuf);
+ if (msg && msg->result == RESULT_SUCCEED)
+ old_db_entry = 1;
rc = real_rename(oldpath, newpath);
save_errno = errno;
- if (rc == -1) {
- if (msg && msg->result == RESULT_SUCCEED) {
- newbuf.st_uid = msg->uid;
- newbuf.st_gid = msg->uid;
- newbuf.st_mode = msg->mode;
- newbuf.st_dev = msg->dev;
- newbuf.st_ino = msg->ino;
+ if (old_db_entry) {
+ if (rc == -1) {
/* since we failed, that wasn't really unlinked -- put
* it back.
*/
- pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &newbuf);
+ pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, newpath, &newbuf);
+ } else {
+ /* confirm that the file was removed */
+ pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, newpath, &newbuf);
}
+ }
+ if (rc == -1) {
/* and we're done. */
errno = save_errno;
return rc;
@@ -72,21 +73,7 @@
* we may have to rename or remove directory trees even though in
* theory rename can never destroy a directory tree.
*/
-
- /* re-stat the new file. Why? Because if something got moved
- * across device boundaries, its dev/ino changed!
- */
- newrc = real___lxstat64(_STAT_VER, newpath, &newbuf);
- if (msg && msg->result == RESULT_SUCCEED) {
- pseudo_stat_msg(&oldbuf, msg);
- if (newrc == 0) {
- if (newbuf.st_dev != oldbuf.st_dev) {
- oldbuf.st_dev = newbuf.st_dev;
- oldbuf.st_ino = newbuf.st_ino;
- }
- }
- pseudo_debug(1, "renaming %s, got old mode of 0%o\n", oldpath, (int) msg->mode);
- } else {
+ if (!old_db_entry) {
/* create an entry under the old name, which will then be
* renamed; this way, children would get renamed too, if there
* were any.
diff --git a/guts/rmdir.c b/guts/rmdir.c
index f3cd9e4..af7fb7e 100644
--- a/guts/rmdir.c
+++ b/guts/rmdir.c
@@ -6,30 +6,29 @@
* wrap_rmdir(const char *path) {
* int rc = -1;
*/
- pseudo_msg_t *old_file;
+ pseudo_msg_t *msg;
struct stat64 buf;
int save_errno;
+ int old_db_entry = 0;
rc = real___lxstat64(_STAT_VER, path, &buf);
if (rc == -1) {
return rc;
}
- old_file = pseudo_client_op(OP_UNLINK, 0, -1, -1, path, &buf);
+ msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, -1, path, &buf);
+ if (msg && msg->result == RESULT_SUCCEED)
+ old_db_entry = 1;
rc = real_rmdir(path);
- if (rc == -1) {
- save_errno = errno;
- if (old_file && old_file->result == RESULT_SUCCEED) {
- pseudo_debug(1, "rmdir failed, trying to relink...\n");
- buf.st_uid = old_file->uid;
- buf.st_gid = old_file->uid;
- buf.st_mode = old_file->mode;
- buf.st_dev = old_file->dev;
- buf.st_ino = old_file->ino;
- pseudo_client_op(OP_LINK, 0, -1, -1, path, &buf);
+ if (old_db_entry) {
+ if (rc == -1) {
+ save_errno = errno;
+ pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, path, &buf);
+ errno = save_errno;
} else {
- pseudo_debug(1, "rmdir failed, but found no database entry, ignoring.\n");
+ pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, path, &buf);
}
- errno = save_errno;
+ } else {
+ pseudo_debug(1, "rmdir on <%s>, not in database, no effect.\n", path);
}
/* return rc;
diff --git a/guts/unlinkat.c b/guts/unlinkat.c
index 13fdc82..3bfda81 100644
--- a/guts/unlinkat.c
+++ b/guts/unlinkat.c
@@ -6,9 +6,10 @@
* wrap_unlinkat(int dirfd, const char *path, int rflags) {
* int rc = -1;
*/
- pseudo_msg_t *old_file;
+ pseudo_msg_t *msg;
int save_errno;
struct stat64 buf;
+ int old_db_entry;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
if (dirfd != AT_FDCWD) {
@@ -35,27 +36,26 @@
if (rc == -1) {
return rc;
}
- old_file = pseudo_client_op(OP_UNLINK, 0, -1, dirfd, path, &buf);
+ msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, dirfd, path, &buf);
+ if (msg && msg->result == RESULT_SUCCEED)
+ old_db_entry = 1;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
rc = real_unlink(path);
#else
rc = real_unlinkat(dirfd, path, rflags);
#endif
- if (rc == -1) {
- save_errno = errno;
- if (old_file && old_file->result == RESULT_SUCCEED) {
- pseudo_debug(1, "unlink failed, trying to relink...\n");
- buf.st_uid = old_file->uid;
- buf.st_gid = old_file->uid;
- buf.st_mode = old_file->mode;
- buf.st_dev = old_file->dev;
- buf.st_ino = old_file->ino;
- pseudo_client_op(OP_LINK, 0, -1, dirfd, path, &buf);
+ if (old_db_entry) {
+ if (rc == -1) {
+ save_errno = errno;
+ pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, path, &buf);
+ errno = save_errno;
} else {
- pseudo_debug(1, "unlink failed, but found no database entry, ignoring.\n");
+ pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, path, &buf);
}
- errno = save_errno;
+ } else {
+ pseudo_debug(1, "unlink on <%s>, not in database, no effect.\n", path);
}
+
/* return rc;
* }
*/