diff mbox

[V4,6/8] Support for creating special files

Message ID 1296538061-16790-1-git-send-email-mohan@in.ibm.com
State New
Headers show

Commit Message

Mohan Kumar M Feb. 1, 2011, 5:27 a.m. UTC
Add both server and client side interfaces to create special files
(directory, device nodes, links and symbolic links)

Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
---
 hw/9pfs/virtio-9p-chroot.c |   84 ++++++++++++++++++++++++++
 hw/9pfs/virtio-9p-chroot.h |    2 +
 hw/9pfs/virtio-9p-local.c  |  141 ++++++++++++++++++++++++++++++++++----------
 3 files changed, 196 insertions(+), 31 deletions(-)

Comments

Stefan Hajnoczi Feb. 1, 2011, 2:29 p.m. UTC | #1
On Tue, Feb 1, 2011 at 5:27 AM, M. Mohan Kumar <mohan@in.ibm.com> wrote:
> +static int passthrough_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
> +{
> +    V9fsFileObjectRequest request;
> +    int retval, error = 0;
> +
> +    fill_request(&request, path, credp);
> +    request.data.type = T_MKNOD;
> +
> +    retval = v9fs_create_special(fs_ctx, &request, &error);
> +    if (retval < 0) {
> +        errno = error;
> +    }
> +    return retval;
> +}

It would be nice to avoid duplicating all these wrappers.  Would it be
possible to write one generic function which takes the request type
and some optional arguments and runs the request?

Stefan
diff mbox

Patch

diff --git a/hw/9pfs/virtio-9p-chroot.c b/hw/9pfs/virtio-9p-chroot.c
index 890dd78..85a42e6 100644
--- a/hw/9pfs/virtio-9p-chroot.c
+++ b/hw/9pfs/virtio-9p-chroot.c
@@ -227,6 +227,31 @@  static void chroot_do_open(V9fsFileObjectRequest *request, FdInfo *fd_info)
     }
 }
 
+int v9fs_create_special(FsContext *fs_ctx,
+                V9fsFileObjectRequest *request, int *error)
+{
+    int fd;
+    pthread_mutex_lock(&fs_ctx->chroot_mutex);
+
+    if (fs_ctx->chroot_ioerror) {
+        *error = EIO;
+        goto unlock;
+    }
+    *error = 0;
+    v9fs_write_request(fs_ctx->chroot_socket, request);
+    fd = v9fs_receivefd(fs_ctx->chroot_socket, error);
+    if (fd == -EIO) {
+        fs_ctx->chroot_ioerror = 1;
+    }
+unlock:
+    pthread_mutex_unlock(&fs_ctx->chroot_mutex);
+    if (*error) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
 /*
  * Helper routine to create a file and return the file descriptor and
  * error status in FdInfo structure.
@@ -265,6 +290,59 @@  unset_uid:
     setfsuid(cur_uid);
 }
 
+/*
+ * Create directory, symbolic link, link, device node and regular files
+ * Similar to create, but it does not return the fd of created object
+ * Returns 0 on success, returns errno on failure
+ */
+static void chroot_do_create_special(V9fsFileObjectRequest *request,
+                FdInfo *fd_info)
+{
+    int cur_uid, cur_gid;
+
+    cur_uid = geteuid();
+    cur_gid = getegid();
+
+    fd_info->fi_fd = -1;
+    fd_info->fi_error = 0;
+
+    if (setfsuid(request->data.uid) < 0) {
+        fd_info->fi_error = errno;
+        return;
+    }
+    if (setfsgid(request->data.gid) < 0) {
+        fd_info->fi_error = errno;
+        goto unset_uid;
+    }
+
+    switch (request->data.type) {
+    case T_MKDIR:
+        fd_info->fi_fd = mkdir(request->path.path, request->data.mode);
+        break;
+    case T_SYMLINK:
+        fd_info->fi_fd = symlink(request->path.old_path, request->path.path);
+        break;
+    case T_LINK:
+        fd_info->fi_fd = link(request->path.old_path, request->path.path);
+        break;
+    default:
+        fd_info->fi_fd = mknod(request->path.path, request->data.mode,
+                        request->data.dev);
+        break;
+    }
+
+    if (fd_info->fi_fd < 0) {
+        fd_info->fi_error = errno;
+    } else {
+        fd_info->fi_error = 0;
+        fd_info->fi_fd = -1;
+    }
+
+    setfsgid(cur_gid);
+unset_uid:
+    setfsuid(cur_uid);
+}
+
 static int chroot_daemonize(int chroot_sock)
 {
     sigset_t sigset;
@@ -365,6 +443,12 @@  int v9fs_chroot(FsContext *fs_ctx)
         case T_CREATE:
             chroot_do_create(&request, &fd_info);
             break;
+        case T_MKDIR:
+        case T_SYMLINK:
+        case T_LINK:
+        case T_MKNOD:
+            chroot_do_create_special(&request, &fd_info);
+            break;
         default:
             fd_info.fi_fd = 0;
             fd_info.fi_error = EIO;
diff --git a/hw/9pfs/virtio-9p-chroot.h b/hw/9pfs/virtio-9p-chroot.h
index ffeeddc..c7ebb47 100644
--- a/hw/9pfs/virtio-9p-chroot.h
+++ b/hw/9pfs/virtio-9p-chroot.h
@@ -38,5 +38,7 @@  typedef struct V9fsFileObjectRequest
 
 int v9fs_chroot(FsContext *fs_ctx);
 int v9fs_request(FsContext *fs_ctx, V9fsFileObjectRequest *or, int *error);
+int v9fs_create_special(FsContext *fs_ctx,
+                V9fsFileObjectRequest *request, int *error);
 
 #endif /* _QEMU_VIRTIO_9P_CHROOT_H */
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index afb088a..c9ece6b 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -69,6 +69,78 @@  static int passthrough_create(FsContext *fs_ctx, const char *path, int flags,
     return fd;
 }
 
+static int passthrough_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    V9fsFileObjectRequest request;
+    int retval, error = 0;
+
+    fill_request(&request, path, credp);
+    request.data.type = T_MKNOD;
+
+    retval = v9fs_create_special(fs_ctx, &request, &error);
+    if (retval < 0) {
+        errno = error;
+    }
+    return retval;
+}
+
+static int passthrough_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
+{
+    V9fsFileObjectRequest request;
+    int retval, error = 0;
+
+    fill_request(&request, path, credp);
+    request.data.type = T_MKDIR;
+
+    retval = v9fs_create_special(fs_ctx, &request, &error);
+    if (retval < 0) {
+        errno = error;
+    }
+    qemu_free((void *)request.path.path);
+    return retval;
+}
+
+static int passthrough_symlink(FsContext *fs_ctx, const char *oldpath,
+                const char *newpath, FsCred *credp)
+{
+    V9fsFileObjectRequest request;
+    int retval, error = 0;
+
+    fill_request(&request, newpath, credp);
+    request.data.type = T_SYMLINK;
+    request.data.oldpath_len = strlen(oldpath);
+    request.path.old_path = qemu_strdup(oldpath);
+
+    retval = v9fs_create_special(fs_ctx, &request, &error);
+    if (retval > 0) {
+        errno = error;
+        return 0;
+    }
+    qemu_free((void *)request.path.old_path);
+    qemu_free((void *)request.path.path);
+    return retval;
+}
+
+static int passthrough_link(FsContext *fs_ctx, const char *oldpath,
+                const char *newpath)
+{
+    V9fsFileObjectRequest request;
+    int retval, error = 0;
+
+    fill_request(&request, newpath, NULL);
+    request.data.type = T_LINK;
+    request.data.oldpath_len = strlen(oldpath);
+    request.path.old_path = qemu_strdup(oldpath);
+    retval = v9fs_create_special(fs_ctx, &request, &error);
+    if (retval > 0) {
+        errno = error;
+        return 0;
+    }
+    qemu_free((void *)request.path.old_path);
+    qemu_free((void *)request.path.path);
+    return retval;
+}
+
 static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
 {
     int err;
@@ -286,8 +358,7 @@  static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
             serrno = errno;
             goto err_end;
         }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if (fs_ctx->fs_sm == SM_NONE) {
         err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
         if (err == -1) {
             return err;
@@ -297,6 +368,12 @@  static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
             serrno = errno;
             goto err_end;
         }
+    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+        err = passthrough_mknod(fs_ctx, path, credp);
+        if (err < 0) {
+            serrno = errno;
+            goto err_end;
+        }
     }
     return err;
 
@@ -323,8 +400,7 @@  static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
             serrno = errno;
             goto err_end;
         }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if (fs_ctx->fs_sm == SM_NONE) {
         err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
         if (err == -1) {
             return err;
@@ -334,6 +410,12 @@  static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
             serrno = errno;
             goto err_end;
         }
+    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+        err = passthrough_mkdir(fs_ctx, path, credp);
+        if (err < 0) {
+            serrno = errno;
+            goto err_end;
+        }
     }
     return err;
 
@@ -451,23 +533,18 @@  static int local_symlink(FsContext *fs_ctx, const char *oldpath,
             serrno = errno;
             goto err_end;
         }
-    } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
-               (fs_ctx->fs_sm == SM_NONE)) {
+    } else if (fs_ctx->fs_sm == SM_NONE) {
         err = symlink(oldpath, rpath(fs_ctx, newpath));
         if (err) {
             return err;
         }
         err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
-        if (err == -1) {
-            /*
-             * If we fail to change ownership and if we are
-             * using security model none. Ignore the error
-             */
-            if (fs_ctx->fs_sm != SM_NONE) {
-                serrno = errno;
-                goto err_end;
-            } else
-                err = 0;
+        err = 0;
+    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+        err = passthrough_symlink(fs_ctx, oldpath, newpath, credp);
+        if (err < 0) {
+            serrno = errno;
+            goto err_end;
         }
     }
     return err;
@@ -478,24 +555,26 @@  err_end:
     return err;
 }
 
-static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
+static int local_link(FsContext *fs_ctx, const char *oldpath,
+                const char *newpath)
 {
-    char *tmp = qemu_strdup(rpath(ctx, oldpath));
     int err, serrno = 0;
 
-    if (tmp == NULL) {
-        return -ENOMEM;
-    }
-
-    err = link(tmp, rpath(ctx, newpath));
-    if (err == -1) {
-        serrno = errno;
-    }
-
-    qemu_free(tmp);
-
-    if (err == -1) {
-        errno = serrno;
+    if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+        err = passthrough_link(fs_ctx, oldpath, newpath);
+        if (err < 0) {
+            serrno = errno;
+        }
+    } else {
+        char *tmp = qemu_strdup(rpath(fs_ctx, oldpath));
+        if (tmp == NULL) {
+            return -ENOMEM;
+        }
+        err = link(tmp, rpath(fs_ctx, newpath));
+        if (err == -1) {
+            serrno = errno;
+        }
+        qemu_free(tmp);
     }
 
     return err;