Various bugfixes and code cleanups. Most notably, it fixes metadata handling in
mapped-file security mode (especially for the virtfs root). -----BEGIN PGP SIGNATURE----- iEYEABECAAYFAlktdVYACgkQAvw66wEB28LaTgCfS/bunOy4Wp+I+DO/Gx/5bfNp 7/IAn3qfJYBqRnpfz8KNKRZJ8QG/Bu5X =KTTf -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/gkurz/tags/for-upstream' into staging Various bugfixes and code cleanups. Most notably, it fixes metadata handling in mapped-file security mode (especially for the virtfs root). # gpg: Signature made Tue 30 May 2017 14:36:22 BST # gpg: using DSA key 0x02FC3AEB0101DBC2 # gpg: Good signature from "Greg Kurz <groug@kaod.org>" # gpg: aka "Greg Kurz <groug@free.fr>" # gpg: aka "Greg Kurz <gkurz@linux.vnet.ibm.com>" # gpg: aka "Gregory Kurz (Groug) <groug@free.fr>" # gpg: aka "[jpeg image of size 3330]" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 2BD4 3B44 535E C0A7 9894 DBA2 02FC 3AEB 0101 DBC2 * remotes/gkurz/tags/for-upstream: 9pfs: local: metadata file for the VirtFS root 9pfs: local: simplify file opening 9pfs: local: resolve special directories in paths 9pfs: check return value of v9fs_co_name_to_path() util: drop old utimensat() compat code 9pfs: assume utimensat() and futimens() are present fsdev: fix virtfs-proxy-helper cwd 9pfs: local: fix unlink of alien files in mapped-file mode 9pfs: drop pdu_push_and_notify() fsdev: don't allow unknown format in marshal/unmarshal virtio-9p/xen-9p: move 9p specific bits to core 9p code Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						066ae4f829
					
				
							
								
								
									
										22
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								configure
									
									
									
									
										vendored
									
									
								
							@ -3629,25 +3629,6 @@ if compile_prog "" "" ; then
 | 
				
			|||||||
  inotify1=yes
 | 
					  inotify1=yes
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# check if utimensat and futimens are supported
 | 
					 | 
				
			||||||
utimens=no
 | 
					 | 
				
			||||||
cat > $TMPC << EOF
 | 
					 | 
				
			||||||
#define _ATFILE_SOURCE
 | 
					 | 
				
			||||||
#include <stddef.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <sys/stat.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    utimensat(AT_FDCWD, "foo", NULL, 0);
 | 
					 | 
				
			||||||
    futimens(0, NULL);
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
EOF
 | 
					 | 
				
			||||||
if compile_prog "" "" ; then
 | 
					 | 
				
			||||||
  utimens=yes
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# check if pipe2 is there
 | 
					# check if pipe2 is there
 | 
				
			||||||
pipe2=no
 | 
					pipe2=no
 | 
				
			||||||
cat > $TMPC << EOF
 | 
					cat > $TMPC << EOF
 | 
				
			||||||
@ -5434,9 +5415,6 @@ fi
 | 
				
			|||||||
if test "$curses" = "yes" ; then
 | 
					if test "$curses" = "yes" ; then
 | 
				
			||||||
  echo "CONFIG_CURSES=y" >> $config_host_mak
 | 
					  echo "CONFIG_CURSES=y" >> $config_host_mak
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
if test "$utimens" = "yes" ; then
 | 
					 | 
				
			||||||
  echo "CONFIG_UTIMENSAT=y" >> $config_host_mak
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
if test "$pipe2" = "yes" ; then
 | 
					if test "$pipe2" = "yes" ; then
 | 
				
			||||||
  echo "CONFIG_PIPE2=y" >> $config_host_mak
 | 
					  echo "CONFIG_PIPE2=y" >> $config_host_mak
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
				
			|||||||
@ -168,7 +168,7 @@ ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            break;
 | 
					            g_assert_not_reached();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (copied < 0) {
 | 
					        if (copied < 0) {
 | 
				
			||||||
            return copied;
 | 
					            return copied;
 | 
				
			||||||
@ -281,7 +281,7 @@ ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset,
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            break;
 | 
					            g_assert_not_reached();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (copied < 0) {
 | 
					        if (copied < 0) {
 | 
				
			||||||
            return copied;
 | 
					            return copied;
 | 
				
			||||||
 | 
				
			|||||||
@ -945,7 +945,8 @@ static int process_requests(int sock)
 | 
				
			|||||||
                                     &spec[0].tv_sec, &spec[0].tv_nsec,
 | 
					                                     &spec[0].tv_sec, &spec[0].tv_nsec,
 | 
				
			||||||
                                     &spec[1].tv_sec, &spec[1].tv_nsec);
 | 
					                                     &spec[1].tv_sec, &spec[1].tv_nsec);
 | 
				
			||||||
            if (retval > 0) {
 | 
					            if (retval > 0) {
 | 
				
			||||||
                retval = qemu_utimens(path.data, spec);
 | 
					                retval = utimensat(AT_FDCWD, path.data, spec,
 | 
				
			||||||
 | 
					                                   AT_SYMLINK_NOFOLLOW);
 | 
				
			||||||
                if (retval < 0) {
 | 
					                if (retval < 0) {
 | 
				
			||||||
                    retval = -errno;
 | 
					                    retval = -errno;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -1129,14 +1130,14 @@ int main(int argc, char **argv)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chdir("/") < 0) {
 | 
					 | 
				
			||||||
        do_perror("chdir");
 | 
					 | 
				
			||||||
        goto error;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (chroot(rpath) < 0) {
 | 
					    if (chroot(rpath) < 0) {
 | 
				
			||||||
        do_perror("chroot");
 | 
					        do_perror("chroot");
 | 
				
			||||||
        goto error;
 | 
					        goto error;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (chdir("/") < 0) {
 | 
				
			||||||
 | 
					        do_perror("chdir");
 | 
				
			||||||
 | 
					        goto error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get_version = false;
 | 
					    get_version = false;
 | 
				
			||||||
#ifdef FS_IOC_GETVERSION
 | 
					#ifdef FS_IOC_GETVERSION
 | 
				
			||||||
 | 
				
			|||||||
@ -378,7 +378,6 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
 | 
				
			|||||||
                            const struct timespec *buf)
 | 
					                            const struct timespec *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
#ifdef CONFIG_UTIMENSAT
 | 
					 | 
				
			||||||
    int fd;
 | 
					    int fd;
 | 
				
			||||||
    struct handle_data *data = (struct handle_data *)ctx->private;
 | 
					    struct handle_data *data = (struct handle_data *)ctx->private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -388,10 +387,6 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    ret = futimens(fd, buf);
 | 
					    ret = futimens(fd, buf);
 | 
				
			||||||
    close(fd);
 | 
					    close(fd);
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    ret = -1;
 | 
					 | 
				
			||||||
    errno = ENOSYS;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -53,13 +53,37 @@ int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
 | 
				
			|||||||
                        mode_t mode)
 | 
					                        mode_t mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    LocalData *data = fs_ctx->private;
 | 
					    LocalData *data = fs_ctx->private;
 | 
				
			||||||
 | 
					    int fd = data->mountfd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* All paths are relative to the path data->mountfd points to */
 | 
					    while (*path && fd != -1) {
 | 
				
			||||||
    while (*path == '/') {
 | 
					        const char *c;
 | 
				
			||||||
        path++;
 | 
					        int next_fd;
 | 
				
			||||||
 | 
					        char *head;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Only relative paths without consecutive slashes */
 | 
				
			||||||
 | 
					        assert(*path != '/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        head = g_strdup(path);
 | 
				
			||||||
 | 
					        c = strchrnul(path, '/');
 | 
				
			||||||
 | 
					        if (*c) {
 | 
				
			||||||
 | 
					            /* Intermediate path element */
 | 
				
			||||||
 | 
					            head[c - path] = 0;
 | 
				
			||||||
 | 
					            path = c + 1;
 | 
				
			||||||
 | 
					            next_fd = openat_dir(fd, head);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            /* Rightmost path element */
 | 
				
			||||||
 | 
					            next_fd = openat_file(fd, head, flags, mode);
 | 
				
			||||||
 | 
					            path = c;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_free(head);
 | 
				
			||||||
 | 
					        if (fd != data->mountfd) {
 | 
				
			||||||
 | 
					            close_preserve_errno(fd);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        fd = next_fd;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return relative_openat_nofollow(data->mountfd, path, flags, mode);
 | 
					    assert(fd != data->mountfd);
 | 
				
			||||||
 | 
					    return fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int local_opendir_nofollow(FsContext *fs_ctx, const char *path)
 | 
					int local_opendir_nofollow(FsContext *fs_ctx, const char *path)
 | 
				
			||||||
@ -83,6 +107,7 @@ static void unlinkat_preserve_errno(int dirfd, const char *path, int flags)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VIRTFS_META_DIR ".virtfs_metadata"
 | 
					#define VIRTFS_META_DIR ".virtfs_metadata"
 | 
				
			||||||
 | 
					#define VIRTFS_META_ROOT_FILE VIRTFS_META_DIR "_root"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
 | 
					static FILE *local_fopenat(int dirfd, const char *name, const char *mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -119,6 +144,7 @@ static void local_mapped_file_attr(int dirfd, const char *name,
 | 
				
			|||||||
    char buf[ATTR_MAX];
 | 
					    char buf[ATTR_MAX];
 | 
				
			||||||
    int map_dirfd;
 | 
					    int map_dirfd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (strcmp(name, ".")) {
 | 
				
			||||||
        map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
 | 
					        map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
 | 
				
			||||||
        if (map_dirfd == -1) {
 | 
					        if (map_dirfd == -1) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -126,6 +152,9 @@ static void local_mapped_file_attr(int dirfd, const char *name,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        fp = local_fopenat(map_dirfd, name, "r");
 | 
					        fp = local_fopenat(map_dirfd, name, "r");
 | 
				
			||||||
        close_preserve_errno(map_dirfd);
 | 
					        close_preserve_errno(map_dirfd);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        fp = local_fopenat(dirfd, VIRTFS_META_ROOT_FILE, "r");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (!fp) {
 | 
					    if (!fp) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -203,8 +232,19 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
 | 
				
			|||||||
    int ret;
 | 
					    int ret;
 | 
				
			||||||
    char buf[ATTR_MAX];
 | 
					    char buf[ATTR_MAX];
 | 
				
			||||||
    int uid = -1, gid = -1, mode = -1, rdev = -1;
 | 
					    int uid = -1, gid = -1, mode = -1, rdev = -1;
 | 
				
			||||||
    int map_dirfd;
 | 
					    int map_dirfd = -1, map_fd;
 | 
				
			||||||
 | 
					    bool is_root = !strcmp(name, ".");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (is_root) {
 | 
				
			||||||
 | 
					        fp = local_fopenat(dirfd, VIRTFS_META_ROOT_FILE, "r");
 | 
				
			||||||
 | 
					        if (!fp) {
 | 
				
			||||||
 | 
					            if (errno == ENOENT) {
 | 
				
			||||||
 | 
					                goto update_map_file;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
        ret = mkdirat(dirfd, VIRTFS_META_DIR, 0700);
 | 
					        ret = mkdirat(dirfd, VIRTFS_META_DIR, 0700);
 | 
				
			||||||
        if (ret < 0 && errno != EEXIST) {
 | 
					        if (ret < 0 && errno != EEXIST) {
 | 
				
			||||||
            return -1;
 | 
					            return -1;
 | 
				
			||||||
@ -224,6 +264,7 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
 | 
				
			|||||||
                return -1;
 | 
					                return -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    memset(buf, 0, ATTR_MAX);
 | 
					    memset(buf, 0, ATTR_MAX);
 | 
				
			||||||
    while (fgets(buf, ATTR_MAX, fp)) {
 | 
					    while (fgets(buf, ATTR_MAX, fp)) {
 | 
				
			||||||
        if (!strncmp(buf, "virtfs.uid", 10)) {
 | 
					        if (!strncmp(buf, "virtfs.uid", 10)) {
 | 
				
			||||||
@ -240,12 +281,26 @@ static int local_set_mapped_file_attrat(int dirfd, const char *name,
 | 
				
			|||||||
    fclose(fp);
 | 
					    fclose(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
update_map_file:
 | 
					update_map_file:
 | 
				
			||||||
 | 
					    if (is_root) {
 | 
				
			||||||
 | 
					        fp = local_fopenat(dirfd, VIRTFS_META_ROOT_FILE, "w");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
        fp = local_fopenat(map_dirfd, name, "w");
 | 
					        fp = local_fopenat(map_dirfd, name, "w");
 | 
				
			||||||
 | 
					        /* We can't go this far with map_dirfd not being a valid file descriptor
 | 
				
			||||||
 | 
					         * but some versions of gcc aren't smart enough to see it.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (map_dirfd != -1) {
 | 
				
			||||||
            close_preserve_errno(map_dirfd);
 | 
					            close_preserve_errno(map_dirfd);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (!fp) {
 | 
					    if (!fp) {
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    map_fd = fileno(fp);
 | 
				
			||||||
 | 
					    assert(map_fd != -1);
 | 
				
			||||||
 | 
					    ret = fchmod(map_fd, 0600);
 | 
				
			||||||
 | 
					    assert(ret == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (credp->fc_uid != -1) {
 | 
					    if (credp->fc_uid != -1) {
 | 
				
			||||||
        uid = credp->fc_uid;
 | 
					        uid = credp->fc_uid;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -454,7 +509,8 @@ static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name)
 | 
					static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return !strcmp(name, VIRTFS_META_DIR);
 | 
					    return
 | 
				
			||||||
 | 
					        !strcmp(name, VIRTFS_META_DIR) || !strcmp(name, VIRTFS_META_ROOT_FILE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs)
 | 
					static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs)
 | 
				
			||||||
@ -471,7 +527,7 @@ again:
 | 
				
			|||||||
        entry->d_type = DT_UNKNOWN;
 | 
					        entry->d_type = DT_UNKNOWN;
 | 
				
			||||||
    } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 | 
					    } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 | 
				
			||||||
        if (local_is_mapped_file_metadata(ctx, entry->d_name)) {
 | 
					        if (local_is_mapped_file_metadata(ctx, entry->d_name)) {
 | 
				
			||||||
            /* skip the meta data directory */
 | 
					            /* skip the meta data */
 | 
				
			||||||
            goto again;
 | 
					            goto again;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        entry->d_type = DT_UNKNOWN;
 | 
					        entry->d_type = DT_UNKNOWN;
 | 
				
			||||||
@ -992,6 +1048,14 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
 | 
				
			|||||||
    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 | 
					    if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
 | 
				
			||||||
        int map_dirfd;
 | 
					        int map_dirfd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* We need to remove the metadata as well:
 | 
				
			||||||
 | 
					         * - the metadata directory if we're removing a directory
 | 
				
			||||||
 | 
					         * - the metadata file in the parent's metadata directory
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * If any of these are missing (ie, ENOENT) then we're probably
 | 
				
			||||||
 | 
					         * trying to remove something that wasn't created in mapped-file
 | 
				
			||||||
 | 
					         * mode. We just ignore the error.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
        if (flags == AT_REMOVEDIR) {
 | 
					        if (flags == AT_REMOVEDIR) {
 | 
				
			||||||
            int fd;
 | 
					            int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -999,32 +1063,20 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name,
 | 
				
			|||||||
            if (fd == -1) {
 | 
					            if (fd == -1) {
 | 
				
			||||||
                goto err_out;
 | 
					                goto err_out;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            /*
 | 
					 | 
				
			||||||
             * If directory remove .virtfs_metadata contained in the
 | 
					 | 
				
			||||||
             * directory
 | 
					 | 
				
			||||||
             */
 | 
					 | 
				
			||||||
            ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
 | 
					            ret = unlinkat(fd, VIRTFS_META_DIR, AT_REMOVEDIR);
 | 
				
			||||||
            close_preserve_errno(fd);
 | 
					            close_preserve_errno(fd);
 | 
				
			||||||
            if (ret < 0 && errno != ENOENT) {
 | 
					            if (ret < 0 && errno != ENOENT) {
 | 
				
			||||||
                /*
 | 
					 | 
				
			||||||
                 * We didn't had the .virtfs_metadata file. May be file created
 | 
					 | 
				
			||||||
                 * in non-mapped mode ?. Ignore ENOENT.
 | 
					 | 
				
			||||||
                 */
 | 
					 | 
				
			||||||
                goto err_out;
 | 
					                goto err_out;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        /*
 | 
					 | 
				
			||||||
         * Now remove the name from parent directory
 | 
					 | 
				
			||||||
         * .virtfs_metadata directory.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
 | 
					        map_dirfd = openat_dir(dirfd, VIRTFS_META_DIR);
 | 
				
			||||||
 | 
					        if (map_dirfd != -1) {
 | 
				
			||||||
            ret = unlinkat(map_dirfd, name, 0);
 | 
					            ret = unlinkat(map_dirfd, name, 0);
 | 
				
			||||||
            close_preserve_errno(map_dirfd);
 | 
					            close_preserve_errno(map_dirfd);
 | 
				
			||||||
            if (ret < 0 && errno != ENOENT) {
 | 
					            if (ret < 0 && errno != ENOENT) {
 | 
				
			||||||
            /*
 | 
					                goto err_out;
 | 
				
			||||||
             * We didn't had the .virtfs_metadata file. May be file created
 | 
					            }
 | 
				
			||||||
             * in non-mapped mode ?. Ignore ENOENT.
 | 
					        } else if (errno != ENOENT) {
 | 
				
			||||||
             */
 | 
					 | 
				
			||||||
            goto err_out;
 | 
					            goto err_out;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1138,14 +1190,32 @@ static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dir_path) {
 | 
					    if (dir_path) {
 | 
				
			||||||
        v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
 | 
					        if (!strcmp(name, ".")) {
 | 
				
			||||||
    } else if (strcmp(name, "/")) {
 | 
					            /* "." relative to "foo/bar" is "foo/bar" */
 | 
				
			||||||
        v9fs_path_sprintf(target, "%s", name);
 | 
					            v9fs_path_copy(target, dir_path);
 | 
				
			||||||
 | 
					        } else if (!strcmp(name, "..")) {
 | 
				
			||||||
 | 
					            if (!strcmp(dir_path->data, ".")) {
 | 
				
			||||||
 | 
					                /* ".." relative to the root is "." */
 | 
				
			||||||
 | 
					                v9fs_path_sprintf(target, ".");
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
        /* We want the path of the export root to be relative, otherwise
 | 
					                char *tmp = g_path_get_dirname(dir_path->data);
 | 
				
			||||||
         * "*at()" syscalls would treat it as "/" in the host.
 | 
					                /* Symbolic links are resolved by the client. We can assume
 | 
				
			||||||
 | 
					                 * that ".." relative to "foo/bar" is equivalent to "foo"
 | 
				
			||||||
                 */
 | 
					                 */
 | 
				
			||||||
        v9fs_path_sprintf(target, "%s", ".");
 | 
					                v9fs_path_sprintf(target, "%s", tmp);
 | 
				
			||||||
 | 
					                g_free(tmp);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            assert(!strchr(name, '/'));
 | 
				
			||||||
 | 
					            v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else if (!strcmp(name, "/") || !strcmp(name, ".") ||
 | 
				
			||||||
 | 
					               !strcmp(name, "..")) {
 | 
				
			||||||
 | 
					            /* This is the root fid */
 | 
				
			||||||
 | 
					        v9fs_path_sprintf(target, ".");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        assert(!strchr(name, '/'));
 | 
				
			||||||
 | 
					        v9fs_path_sprintf(target, "./%s", name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,49 +14,6 @@
 | 
				
			|||||||
#include "qemu/xattr.h"
 | 
					#include "qemu/xattr.h"
 | 
				
			||||||
#include "9p-util.h"
 | 
					#include "9p-util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int relative_openat_nofollow(int dirfd, const char *path, int flags,
 | 
					 | 
				
			||||||
                             mode_t mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fd = dup(dirfd);
 | 
					 | 
				
			||||||
    if (fd == -1) {
 | 
					 | 
				
			||||||
        return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (*path) {
 | 
					 | 
				
			||||||
        const char *c;
 | 
					 | 
				
			||||||
        int next_fd;
 | 
					 | 
				
			||||||
        char *head;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Only relative paths without consecutive slashes */
 | 
					 | 
				
			||||||
        assert(path[0] != '/');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        head = g_strdup(path);
 | 
					 | 
				
			||||||
        c = strchr(path, '/');
 | 
					 | 
				
			||||||
        if (c) {
 | 
					 | 
				
			||||||
            head[c - path] = 0;
 | 
					 | 
				
			||||||
            next_fd = openat_dir(fd, head);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            next_fd = openat_file(fd, head, flags, mode);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        g_free(head);
 | 
					 | 
				
			||||||
        if (next_fd == -1) {
 | 
					 | 
				
			||||||
            close_preserve_errno(fd);
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        close(fd);
 | 
					 | 
				
			||||||
        fd = next_fd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!c) {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        path = c + 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return fd;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
 | 
					ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
 | 
				
			||||||
                             void *value, size_t size)
 | 
					                             void *value, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
				
			|||||||
@ -50,8 +50,6 @@ static inline int openat_file(int dirfd, const char *name, int flags,
 | 
				
			|||||||
    return fd;
 | 
					    return fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int relative_openat_nofollow(int dirfd, const char *path, int flags,
 | 
					 | 
				
			||||||
                             mode_t mode);
 | 
					 | 
				
			||||||
ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
 | 
					ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
 | 
				
			||||||
                             void *value, size_t size);
 | 
					                             void *value, size_t size);
 | 
				
			||||||
int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
 | 
					int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										43
									
								
								hw/9pfs/9p.c
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								hw/9pfs/9p.c
									
									
									
									
									
								
							@ -65,11 +65,6 @@ ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pdu_push_and_notify(V9fsPDU *pdu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    pdu->s->transport->push_and_notify(pdu);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int omode_to_uflags(int8_t mode)
 | 
					static int omode_to_uflags(int8_t mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int ret = 0;
 | 
					    int ret = 0;
 | 
				
			||||||
@ -668,7 +663,7 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
 | 
				
			|||||||
    pdu->size = len;
 | 
					    pdu->size = len;
 | 
				
			||||||
    pdu->id = id;
 | 
					    pdu->id = id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pdu_push_and_notify(pdu);
 | 
					    pdu->s->transport->push_and_notify(pdu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Now wakeup anybody waiting in flush for this request */
 | 
					    /* Now wakeup anybody waiting in flush for this request */
 | 
				
			||||||
    if (!qemu_co_queue_next(&pdu->complete)) {
 | 
					    if (!qemu_co_queue_next(&pdu->complete)) {
 | 
				
			||||||
@ -2576,7 +2571,10 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
 | 
				
			|||||||
            err = -EINVAL;
 | 
					            err = -EINVAL;
 | 
				
			||||||
            goto out;
 | 
					            goto out;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
 | 
					        err = v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        old_name = fidp->path.data;
 | 
					        old_name = fidp->path.data;
 | 
				
			||||||
        end = strrchr(old_name, '/');
 | 
					        end = strrchr(old_name, '/');
 | 
				
			||||||
@ -2588,8 +2586,11 @@ static int coroutine_fn v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
 | 
				
			|||||||
        new_name = g_malloc0(end - old_name + name->size + 1);
 | 
					        new_name = g_malloc0(end - old_name + name->size + 1);
 | 
				
			||||||
        strncat(new_name, old_name, end - old_name);
 | 
					        strncat(new_name, old_name, end - old_name);
 | 
				
			||||||
        strncat(new_name + (end - old_name), name->data, name->size);
 | 
					        strncat(new_name + (end - old_name), name->data, name->size);
 | 
				
			||||||
        v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
 | 
					        err = v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
 | 
				
			||||||
        g_free(new_name);
 | 
					        g_free(new_name);
 | 
				
			||||||
 | 
					        if (err < 0) {
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    err = v9fs_co_rename(pdu, &fidp->path, &new_path);
 | 
					    err = v9fs_co_rename(pdu, &fidp->path, &new_path);
 | 
				
			||||||
    if (err < 0) {
 | 
					    if (err < 0) {
 | 
				
			||||||
@ -2669,7 +2670,7 @@ out_nofid:
 | 
				
			|||||||
    v9fs_string_free(&name);
 | 
					    v9fs_string_free(&name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
 | 
					static int coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
 | 
				
			||||||
                                           V9fsString *old_name,
 | 
					                                           V9fsString *old_name,
 | 
				
			||||||
                                           V9fsPath *newdir,
 | 
					                                           V9fsPath *newdir,
 | 
				
			||||||
                                           V9fsString *new_name)
 | 
					                                           V9fsString *new_name)
 | 
				
			||||||
@ -2677,12 +2678,18 @@ static void coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
 | 
				
			|||||||
    V9fsFidState *tfidp;
 | 
					    V9fsFidState *tfidp;
 | 
				
			||||||
    V9fsPath oldpath, newpath;
 | 
					    V9fsPath oldpath, newpath;
 | 
				
			||||||
    V9fsState *s = pdu->s;
 | 
					    V9fsState *s = pdu->s;
 | 
				
			||||||
 | 
					    int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    v9fs_path_init(&oldpath);
 | 
					    v9fs_path_init(&oldpath);
 | 
				
			||||||
    v9fs_path_init(&newpath);
 | 
					    v9fs_path_init(&newpath);
 | 
				
			||||||
    v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
 | 
					    err = v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
 | 
				
			||||||
    v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    err = v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
 | 
				
			||||||
 | 
					    if (err < 0) {
 | 
				
			||||||
 | 
					        goto out;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Fixup fid's pointing to the old name to
 | 
					     * Fixup fid's pointing to the old name to
 | 
				
			||||||
@ -2694,8 +2701,10 @@ static void coroutine_fn v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
 | 
				
			|||||||
            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
 | 
					            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
    v9fs_path_free(&oldpath);
 | 
					    v9fs_path_free(&oldpath);
 | 
				
			||||||
    v9fs_path_free(&newpath);
 | 
					    v9fs_path_free(&newpath);
 | 
				
			||||||
 | 
					    return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int coroutine_fn v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
 | 
					static int coroutine_fn v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
 | 
				
			||||||
@ -2729,7 +2738,7 @@ static int coroutine_fn v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
 | 
					    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
 | 
				
			||||||
        /* Only for path based fid  we need to do the below fixup */
 | 
					        /* Only for path based fid  we need to do the below fixup */
 | 
				
			||||||
        v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
 | 
					        err = v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
 | 
				
			||||||
                                 &newdirfidp->path, new_name);
 | 
					                                 &newdirfidp->path, new_name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
@ -3446,12 +3455,16 @@ static inline bool is_read_only_op(V9fsPDU *pdu)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pdu_submit(V9fsPDU *pdu)
 | 
					void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    Coroutine *co;
 | 
					    Coroutine *co;
 | 
				
			||||||
    CoroutineEntry *handler;
 | 
					    CoroutineEntry *handler;
 | 
				
			||||||
    V9fsState *s = pdu->s;
 | 
					    V9fsState *s = pdu->s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pdu->size = le32_to_cpu(hdr->size_le);
 | 
				
			||||||
 | 
					    pdu->id = hdr->id;
 | 
				
			||||||
 | 
					    pdu->tag = le16_to_cpu(hdr->tag_le);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
 | 
					    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
 | 
				
			||||||
        (pdu_co_handlers[pdu->id] == NULL)) {
 | 
					        (pdu_co_handlers[pdu->id] == NULL)) {
 | 
				
			||||||
        handler = v9fs_op_not_supp;
 | 
					        handler = v9fs_op_not_supp;
 | 
				
			||||||
@ -3462,6 +3475,8 @@ void pdu_submit(V9fsPDU *pdu)
 | 
				
			|||||||
    if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
 | 
					    if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
 | 
				
			||||||
        handler = v9fs_fs_ro;
 | 
					        handler = v9fs_fs_ro;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    qemu_co_queue_init(&pdu->complete);
 | 
				
			||||||
    co = qemu_coroutine_create(handler, pdu);
 | 
					    co = qemu_coroutine_create(handler, pdu);
 | 
				
			||||||
    qemu_coroutine_enter(co);
 | 
					    qemu_coroutine_enter(co);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -347,7 +347,7 @@ ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...);
 | 
				
			|||||||
ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...);
 | 
					ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...);
 | 
				
			||||||
V9fsPDU *pdu_alloc(V9fsState *s);
 | 
					V9fsPDU *pdu_alloc(V9fsState *s);
 | 
				
			||||||
void pdu_free(V9fsPDU *pdu);
 | 
					void pdu_free(V9fsPDU *pdu);
 | 
				
			||||||
void pdu_submit(V9fsPDU *pdu);
 | 
					void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr);
 | 
				
			||||||
void v9fs_reset(V9fsState *s);
 | 
					void v9fs_reset(V9fsState *s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct V9fsTransport {
 | 
					struct V9fsTransport {
 | 
				
			||||||
 | 
				
			|||||||
@ -70,13 +70,7 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
 | 
				
			|||||||
            goto out_free_req;
 | 
					            goto out_free_req;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pdu->size = le32_to_cpu(out.size_le);
 | 
					        pdu_submit(pdu, &out);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        pdu->id = out.id;
 | 
					 | 
				
			||||||
        pdu->tag = le16_to_cpu(out.tag_le);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        qemu_co_queue_init(&pdu->complete);
 | 
					 | 
				
			||||||
        pdu_submit(pdu);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
				
			|||||||
@ -243,14 +243,10 @@ static int xen_9pfs_receive(Xen9pfsRing *ring)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* cannot fail, because we only handle one request per ring at a time */
 | 
					    /* cannot fail, because we only handle one request per ring at a time */
 | 
				
			||||||
    pdu = pdu_alloc(&ring->priv->state);
 | 
					    pdu = pdu_alloc(&ring->priv->state);
 | 
				
			||||||
    pdu->size = le32_to_cpu(h.size_le);
 | 
					 | 
				
			||||||
    pdu->id = h.id;
 | 
					 | 
				
			||||||
    pdu->tag = le32_to_cpu(h.tag_le);
 | 
					 | 
				
			||||||
    ring->out_size = le32_to_cpu(h.size_le);
 | 
					    ring->out_size = le32_to_cpu(h.size_le);
 | 
				
			||||||
    ring->out_cons = cons + le32_to_cpu(h.size_le);
 | 
					    ring->out_cons = cons + le32_to_cpu(h.size_le);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_co_queue_init(&pdu->complete);
 | 
					    pdu_submit(pdu, &h);
 | 
				
			||||||
    pdu_submit(pdu);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -51,17 +51,6 @@ int os_mlock(void);
 | 
				
			|||||||
typedef struct timeval qemu_timeval;
 | 
					typedef struct timeval qemu_timeval;
 | 
				
			||||||
#define qemu_gettimeofday(tp) gettimeofday(tp, NULL)
 | 
					#define qemu_gettimeofday(tp) gettimeofday(tp, NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef CONFIG_UTIMENSAT
 | 
					 | 
				
			||||||
#ifndef UTIME_NOW
 | 
					 | 
				
			||||||
# define UTIME_NOW     ((1l << 30) - 1l)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifndef UTIME_OMIT
 | 
					 | 
				
			||||||
# define UTIME_OMIT    ((1l << 30) - 2l)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
typedef struct timespec qemu_timespec;
 | 
					 | 
				
			||||||
int qemu_utimens(const char *path, const qemu_timespec *times);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool is_daemonized(void);
 | 
					bool is_daemonized(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -207,53 +207,6 @@ int qemu_pipe(int pipefd[2])
 | 
				
			|||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int qemu_utimens(const char *path, const struct timespec *times)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    struct timeval tv[2], tv_now;
 | 
					 | 
				
			||||||
    struct stat st;
 | 
					 | 
				
			||||||
    int i;
 | 
					 | 
				
			||||||
#ifdef CONFIG_UTIMENSAT
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
 | 
					 | 
				
			||||||
    if (ret != -1 || errno != ENOSYS) {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    /* Fallback: use utimes() instead of utimensat() */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* happy if special cases */
 | 
					 | 
				
			||||||
    if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) {
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) {
 | 
					 | 
				
			||||||
        return utimes(path, NULL);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* prepare for hard cases */
 | 
					 | 
				
			||||||
    if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
 | 
					 | 
				
			||||||
        gettimeofday(&tv_now, NULL);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
 | 
					 | 
				
			||||||
        stat(path, &st);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (i = 0; i < 2; i++) {
 | 
					 | 
				
			||||||
        if (times[i].tv_nsec == UTIME_NOW) {
 | 
					 | 
				
			||||||
            tv[i].tv_sec = tv_now.tv_sec;
 | 
					 | 
				
			||||||
            tv[i].tv_usec = tv_now.tv_usec;
 | 
					 | 
				
			||||||
        } else if (times[i].tv_nsec == UTIME_OMIT) {
 | 
					 | 
				
			||||||
            tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime;
 | 
					 | 
				
			||||||
            tv[i].tv_usec = 0;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            tv[i].tv_sec = times[i].tv_sec;
 | 
					 | 
				
			||||||
            tv[i].tv_usec = times[i].tv_nsec / 1000;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return utimes(path, &tv[0]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
char *
 | 
					char *
 | 
				
			||||||
qemu_get_local_state_pathname(const char *relative_pathname)
 | 
					qemu_get_local_state_pathname(const char *relative_pathname)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user