hw/9pfs: add 9P2000.L renameat operation
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Mon, 23 May 2011 17:54:41 +0000 (23:24 +0530)
committerAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Fri, 9 Sep 2011 09:16:03 +0000 (14:46 +0530)
rename - change name of file or directory

size[4] Trenameat tag[2] olddirfid[4] oldname[s] newdirfid[4] newname[s]
size[4] Rrenameat tag[2]

older Trename have the below request format

size[4] Trename tag[2] fid[4] newdirfid[4] name[s]

The rename message is used to change the name of a file, possibly moving it
to a new directory. The rename opreation is actually a directory opertation
and should ideally have olddirfid, if not we cannot represent the fid on server
with anything other than name. We will have to derive the old directory name
from fid in the Trename request.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
hw/9pfs/virtio-9p.c
hw/9pfs/virtio-9p.h

index 1f186a25fb8c8e8241be6299cc46bbde27a05ef3..0293fe42b106526e71f4a301b0d64f31b8bb5ba3 100644 (file)
@@ -2440,6 +2440,87 @@ out_nofid:
     v9fs_string_free(&name);
 }
 
+static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
+                                  V9fsString *old_name, int32_t newdirfid,
+                                  V9fsString *new_name)
+{
+    int err = 0;
+    V9fsString old_full_name, new_full_name;
+    V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
+
+    olddirfidp = get_fid(s, olddirfid);
+    if (olddirfidp == NULL) {
+        err = -ENOENT;
+        goto out;
+    }
+    v9fs_string_init(&old_full_name);
+    v9fs_string_init(&new_full_name);
+
+    v9fs_string_sprintf(&old_full_name, "%s/%s",
+                        olddirfidp->path.data, old_name->data);
+    if (newdirfid != -1) {
+        newdirfidp = get_fid(s, newdirfid);
+        if (newdirfidp == NULL) {
+            err = -ENOENT;
+            goto out;
+        }
+        v9fs_string_sprintf(&new_full_name, "%s/%s",
+                            newdirfidp->path.data, new_name->data);
+    } else {
+        v9fs_string_sprintf(&new_full_name, "%s/%s",
+                            olddirfidp->path.data, new_name->data);
+    }
+
+    if (strcmp(old_full_name.data, new_full_name.data) != 0) {
+        V9fsFidState *tfidp;
+        err = v9fs_co_rename(s, &old_full_name, &new_full_name);
+        if (err < 0) {
+            goto out;
+        }
+        /*
+         * Fixup fid's pointing to the old name to
+         * start pointing to the new name
+         */
+        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
+            if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) {
+                /* replace the name */
+                v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size);
+            }
+        }
+    }
+out:
+    if (olddirfidp) {
+        put_fid(s, olddirfidp);
+    }
+    if (newdirfidp) {
+        put_fid(s, newdirfidp);
+    }
+    v9fs_string_free(&old_full_name);
+    v9fs_string_free(&new_full_name);
+    return err;
+}
+
+static void v9fs_renameat(void *opaque)
+{
+    ssize_t err = 0;
+    size_t offset = 7;
+    V9fsPDU *pdu = opaque;
+    V9fsState *s = pdu->s;
+    int32_t olddirfid, newdirfid;
+    V9fsString old_name, new_name;
+
+    pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
+                  &old_name, &newdirfid, &new_name);
+
+    err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
+    if (!err) {
+        err = offset;
+    }
+    complete_pdu(s, pdu, err);
+    v9fs_string_free(&old_name);
+    v9fs_string_free(&new_name);
+}
+
 static void v9fs_wstat(void *opaque)
 {
     int32_t fid;
@@ -2957,6 +3038,7 @@ static CoroutineEntry *pdu_co_handlers[] = {
     [P9_TRENAME] = v9fs_rename,
     [P9_TLOCK] = v9fs_lock,
     [P9_TGETLOCK] = v9fs_getlock,
+    [P9_TRENAMEAT] = v9fs_renameat,
     [P9_TREADLINK] = v9fs_readlink,
     [P9_TMKDIR] = v9fs_mkdir,
     [P9_TVERSION] = v9fs_version,
index 9d1b508e1642896133b8d2fef6583470d6a5bf08..49507825b668c6376a2b3cff9ec53c07d9e0bfcb 100644 (file)
@@ -50,6 +50,8 @@ enum {
     P9_RLINK,
     P9_TMKDIR = 72,
     P9_RMKDIR,
+    P9_TRENAMEAT = 74,
+    P9_RRENAMEAT,
     P9_TVERSION = 100,
     P9_RVERSION,
     P9_TAUTH = 102,