diff options
Diffstat (limited to 'guts')
-rw-r--r-- | guts/rename.c | 41 | ||||
-rw-r--r-- | guts/rmdir.c | 27 | ||||
-rw-r--r-- | guts/unlinkat.c | 28 |
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; * } */ |