Preliminary symlink/readlink support.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 28 Dec 2009 04:49:53 +0000 (20:49 -0800)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 28 Dec 2009 04:49:53 +0000 (20:49 -0800)
Attributes on symlinks are not yet properly set.

bluesky/bluesky.h
bluesky/serialize.c
nfs3/nfs3.c

index 1d9f55c..f147088 100644 (file)
@@ -163,6 +163,9 @@ typedef struct {
     GHashTable *dirhash;        /* Hash table by name for LOOKUP */
     GHashTable *dirhash_folded; /* As above, but case-folded */
     uint64_t parent_inum;       /* inode for ".."; 0 if the root directory */
+
+    /* Symlink-specific fields */
+    gchar *symlink_contents;
 } BlueSkyInode;
 
 /* A directory entry.  The name is UTF-8 and is a freshly-allocated string.
index e243bd2..6f31dcb 100644 (file)
@@ -124,6 +124,13 @@ void bluesky_serialize_inode(GString *out, BlueSkyInode *inode)
 
         break;
     }
+
+    case BLUESKY_SYMLINK:
+    {
+        g_string_append(out, inode->symlink_contents);
+        g_string_append_c(out, '\0');
+    }
+
     default:
         g_warning("Serialization for inode type %d not implemented!\n",
                   inode->type);
@@ -200,6 +207,12 @@ BlueSkyInode *bluesky_deserialize_inode(BlueSkyFS *fs, const gchar *buf)
         }
         break;
     }
+
+    case BLUESKY_SYMLINK:
+    {
+        inode->symlink_contents = g_strdup(buf);
+    }
+
     default:
         g_warning("Deserialization for inode type %d not implemented!\n",
                   inode->type);
index 3f8a8d2..2aa4299 100644 (file)
@@ -258,8 +258,23 @@ readlink3res *
 nfsproc3_readlink_3_svc(nfs_fh3 *argp, struct svc_req *rqstp)
 {
     static readlink3res result;
+    memset(&result, 0, sizeof(result));
 
-    result.status = NFS3ERR_NOTSUPP;
+    BlueSkyInode *inode = lookup_fh(argp);
+    if (inode != NULL) {
+        if (inode->type == BLUESKY_SYMLINK) {
+            result.status = NFS3_OK;
+            result.readlink3res_u.resok.symlink_attributes.present = TRUE;
+            encode_fattr3(&result.readlink3res_u.resok.symlink_attributes.post_op_attr_u.attributes, inode);
+            result.readlink3res_u.resok.data = inode->symlink_contents;
+        } else {
+            result.status = NFS3ERR_INVAL;
+            result.readlink3res_u.resfail.present = TRUE;
+            encode_fattr3(&result.readlink3res_u.resfail.post_op_attr_u.attributes, inode);
+        }
+    } else {
+        result.status = NFS3ERR_STALE;
+    }
 
     return &result;
 }
@@ -468,8 +483,59 @@ diropres3 *
 nfsproc3_symlink_3_svc(symlink3args *argp, struct svc_req *rqstp)
 {
     static diropres3 result;
+    struct wcc_data wcc;
+    memset(&wcc, 0, sizeof(wcc));
 
-    result.status = NFS3ERR_NOTSUPP;
+    BlueSkyInode *dir = lookup_fh(&argp->where.dir);
+    if (dir == NULL) {
+        result.status = NFS3ERR_STALE;
+        result.diropres3_u.resfail = wcc;
+        return &result;
+    }
+
+    encode_pre_wcc(&wcc, dir);
+    if (dir->type != BLUESKY_DIRECTORY) {
+        result.status = NFS3ERR_NOTDIR;
+        result.diropres3_u.resfail = wcc;
+        return &result;
+    }
+
+    if (!validate_filename(argp->where.name)
+        || strcmp(argp->where.name, ".") == 0
+        || strcmp(argp->where.name, "..") == 0)
+    {
+        result.status = NFS3ERR_EXIST;
+        result.diropres3_u.resfail = wcc;
+        return &result;
+    }
+
+    BlueSkyInode *file;
+    file = bluesky_new_inode(bluesky_fs_alloc_inode(fs), fs, BLUESKY_SYMLINK);
+    file->nlink = 1;
+    file->mode = 0755;
+    int64_t time = bluesky_get_current_time();
+    file->mtime = time;
+    file->ctime = time;
+    file->atime = time;
+    file->ntime = time;
+    file->symlink_contents = g_strdup(argp->symlink.symlink_data);
+    bluesky_insert_inode(fs, file);
+    bluesky_directory_insert(dir, argp->where.name, file->inum);
+
+    dir->mtime = dir->ctime = bluesky_get_current_time();
+    dir->change_count++;
+
+    wcc.after.present = TRUE;
+    encode_fattr3(&wcc.after.post_op_attr_u.attributes, dir);
+    result.diropres3_u.resok.obj_attributes.present = TRUE;
+    encode_fattr3(&result.diropres3_u.resok.obj_attributes.post_op_attr_u.attributes, file);
+    result.diropres3_u.resok.dir_wcc = wcc;
+
+    static uint64_t fh_bytes;
+    fh_bytes = GUINT64_TO_BE(file->inum);
+    result.diropres3_u.resok.obj.present = TRUE;
+    result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_len = 8;
+    result.diropres3_u.resok.obj.post_op_fh3_u.handle.data.data_val = (char *)&fh_bytes;
 
     return &result;
 }
@@ -508,6 +574,8 @@ nfsproc3_remove_3_svc(diropargs3 *argp, struct svc_req *rqstp)
         return &result;
     }
 
+    /* TODO: Decrement link count, deallocate inode if needed. */
+
     bluesky_directory_remove(dir, argp->name);
 
     result.status = NFS3_OK;