aboutsummaryrefslogtreecommitdiffstats
path: root/ports
diff options
context:
space:
mode:
Diffstat (limited to 'ports')
-rw-r--r--ports/unix/guts/closedir.c20
-rw-r--r--ports/unix/guts/opendir.c17
-rw-r--r--ports/unix/guts/renameat.c100
-rw-r--r--ports/unix/wrapfuncs.in1
4 files changed, 136 insertions, 2 deletions
diff --git a/ports/unix/guts/closedir.c b/ports/unix/guts/closedir.c
new file mode 100644
index 0000000..1085361
--- /dev/null
+++ b/ports/unix/guts/closedir.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012 Wind River Systems; see
+ * guts/COPYRIGHT for information.
+ *
+ * static int
+ * wrap_closedir(DIR *dirp) {
+ * int rc = -1;
+ */
+ if (!dirp) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ int fd = dirfd(dirp);
+ pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0);
+ rc = real_closedir(dirp);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/unix/guts/opendir.c b/ports/unix/guts/opendir.c
index 8eaa71f..e69717e 100644
--- a/ports/unix/guts/opendir.c
+++ b/ports/unix/guts/opendir.c
@@ -6,8 +6,25 @@
* wrap_opendir(const char *path) {
* DIR * rc = NULL;
*/
+ struct stat buf;
+ int save_errno;
rc = real_opendir(path);
+ if (rc) {
+ int fd;
+ save_errno = errno;
+ fd = dirfd(rc);
+ if (real_fstat(fd, &buf) == -1) {
+ pseudo_debug(1, "diropen (fd %d) succeeded, but fstat failed (%s).\n",
+ fd, strerror(errno));
+ pseudo_client_op_plain(OP_OPEN, PSA_READ, fd, -1, path, 0);
+ } else {
+ pseudo_client_op_plain(OP_OPEN, PSA_READ, fd, -1, path, &buf);
+ }
+
+
+ errno = save_errno;
+ }
/* return rc;
* }
diff --git a/ports/unix/guts/renameat.c b/ports/unix/guts/renameat.c
index c8203b7..f13cd1e 100644
--- a/ports/unix/guts/renameat.c
+++ b/ports/unix/guts/renameat.c
@@ -1,15 +1,111 @@
/*
- * Copyright (c) 2008-2010 Wind River Systems; see
+ * Copyright (c) 2008-2012 Wind River Systems; see
* guts/COPYRIGHT for information.
*
* static int
* wrap_renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
* int rc = -1;
*/
+ pseudo_msg_t *msg;
+ struct stat oldbuf, newbuf;
+ int oldrc, newrc;
+ int save_errno;
+ int old_db_entry = 0;
- pseudo_diag("help! unimplemented renameat [%s -> %s].\n", oldpath, newpath);
+ pseudo_debug(2, "renameat: %d,%s->%d,%s\n",
+ olddirfd, oldpath ? oldpath : "<nil>",
+ newdirfd, newpath ? newpath : "<nil>");
+
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+ if (olddirfd != AT_FDCWD || newdirfd != AT_FDCWD) {
+ errno = ENOSYS;
+ return -1;
+ }
+#endif
+
+ if (!oldpath || !newpath) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ save_errno = errno;
+
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+ newrc = real_lstat(newpath, &newbuf);
+ oldrc = real_lstat(oldpath, &oldbuf);
+#else
+ oldrc = real___fxstatat(_STAT_VER, olddirfd, oldpath, &oldbuf, AT_SYMLINK_NOFOLLOW);
+ newrc = real___fxstatat(_STAT_VER, newdirfd, newpath, &newbuf, AT_SYMLINK_NOFOLLOW);
+#endif
+
+ errno = save_errno;
+
+ /* newpath must be removed. */
+ /* as with unlink, we have to mark that the file may get deleted */
+ msg = pseudo_client_op_plain(OP_MAY_UNLINK, 0, -1, newdirfd, newpath, newrc ? NULL : &newbuf);
+ if (msg && msg->result == RESULT_SUCCEED)
+ old_db_entry = 1;
rc = real_renameat(olddirfd, oldpath, newdirfd, newpath);
+ save_errno = errno;
+ if (old_db_entry) {
+ if (rc == -1) {
+ /* since we failed, that wasn't really unlinked -- put
+ * it back.
+ */
+ pseudo_client_op_plain(OP_CANCEL_UNLINK, 0, -1, newdirfd, newpath, &newbuf);
+ } else {
+ /* confirm that the file was removed */
+ pseudo_client_op_plain(OP_DID_UNLINK, 0, -1, newdirfd, newpath, &newbuf);
+ }
+ }
+ if (rc == -1) {
+ /* and we're done. */
+ errno = save_errno;
+ return rc;
+ }
+ save_errno = errno;
+ /* nothing to do for a "rename" of a link to itself */
+ if (newrc != -1 && oldrc != -1 &&
+ newbuf.st_dev == oldbuf.st_dev &&
+ newbuf.st_ino == oldbuf.st_ino) {
+ return rc;
+ }
+
+ /* rename(3) is not mv(1). rename(file, dir) fails; you must provide
+ * the corrected path yourself. You can rename over a directory only
+ * if the source is a directory. Symlinks are simply removed.
+ *
+ * If we got here, the real rename call succeeded. That means newpath
+ * has been unlinked and oldpath has been linked to it.
+ *
+ * There are a ton of special cases to error check. I don't check
+ * for any of them, because in every such case, the underlying rename
+ * failed, and there is nothing to do.
+ * The only tricky part is that, because we used to ignore symlinks,
+ * we may have to rename or remove directory trees even though in
+ * theory rename can never destroy a directory tree.
+ */
+ 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.
+ */
+ 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, "creating new '%s' [%llu] to rename\n",
+ oldpath, (unsigned long long) oldbuf.st_ino);
+ pseudo_client_op_plain(OP_LINK, 0, -1, olddirfd, oldpath, &oldbuf);
+ }
+ /* special case: use 'fd' for olddirfd, because
+ * we know it has no other meaning for RENAME
+ */
+ pseudo_client_op_plain(OP_RENAME, 0, olddirfd, newdirfd, newpath, &oldbuf, oldpath);
+ errno = save_errno;
/* return rc;
* }
*/
diff --git a/ports/unix/wrapfuncs.in b/ports/unix/wrapfuncs.in
index e06e404..32250c4 100644
--- a/ports/unix/wrapfuncs.in
+++ b/ports/unix/wrapfuncs.in
@@ -21,6 +21,7 @@ long pathconf(const char *path, int name);
char *realpath(const char *name, char *resolved_name); /* version="GLIBC_2.3" */
int remove(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */
DIR *opendir(const char *path);
+int closedir(DIR *dirp);
char *tempnam(const char *template, const char *pfx);
char *tmpnam(char *s);
int truncate(const char *path, off_t length);