mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
tools/xen-9pfsd: add 9pfs create request support
Add the create request of the 9pfs protocol. Signed-off-by: Juergen Gross <jgross@suse.com> Acked-by: Anthony PERARD <anthony.perard@citrix.com> Reviewed-by: Jason Andryuk <jandryuk@gmail.com>
This commit is contained in:
1 parent
052a3a7fd9
commit
34449f8cf0
1 file changed
+151
@@ -32,6 +32,7 @@
|
||||
#define P9_CMD_ERROR 107
|
||||
#define P9_CMD_WALK 110
|
||||
#define P9_CMD_OPEN 112
|
||||
#define P9_CMD_CREATE 114
|
||||
#define P9_CMD_CLUNK 120
|
||||
|
||||
/* P9 protocol open flags. */
|
||||
@@ -42,6 +43,12 @@
|
||||
#define P9_OTRUNC 0x10 /* or'ed in, truncate file first */
|
||||
#define P9_OREMOVE 0x40 /* or'ed in, remove file after clunk */
|
||||
|
||||
/* P9 protocol create permission masks. */
|
||||
#define P9_CREATE_PERM_DIR 0x80000000
|
||||
#define P9_CREATE_PERM_NOTSUPP 0x03b00000 /* link, symlink, ... */
|
||||
#define P9_CREATE_PERM_DIR_MASK 0777
|
||||
#define P9_CREATE_PERM_FILE_MASK 0666
|
||||
|
||||
#define P9_MIN_MSIZE 2048
|
||||
#define P9_VERSION "9P2000.u"
|
||||
#define P9_WALK_MAXELEM 16
|
||||
@@ -961,6 +968,146 @@ static void p9_open(struct ring *ring, struct p9_header *hdr)
|
||||
p9_error(ring, hdr->tag, errno);
|
||||
}
|
||||
|
||||
static void p9_create(struct ring *ring, struct p9_header *hdr)
|
||||
{
|
||||
device *device = ring->device;
|
||||
uint32_t fid;
|
||||
unsigned int name_off;
|
||||
uint32_t perm;
|
||||
uint8_t mode;
|
||||
unsigned int ext_off;
|
||||
struct p9_fid *fidp;
|
||||
struct p9_fid *new_fidp;
|
||||
char *path;
|
||||
struct stat st;
|
||||
struct p9_qid qid;
|
||||
uint32_t iounit;
|
||||
int flags;
|
||||
int ret;
|
||||
|
||||
ret = fill_data(ring, "USUbS", &fid, &name_off, &perm, &mode, &ext_off);
|
||||
if ( ret != 5 )
|
||||
{
|
||||
p9_error(ring, hdr->tag, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !name_ok(ring->str + name_off) )
|
||||
{
|
||||
p9_error(ring, hdr->tag, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( perm & P9_CREATE_PERM_NOTSUPP )
|
||||
{
|
||||
p9_error(ring, hdr->tag, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
fidp = get_fid_ref(device, fid);
|
||||
if ( !fidp || fidp->opened )
|
||||
{
|
||||
free_fid(device, fidp);
|
||||
p9_error(ring, hdr->tag, EINVAL);
|
||||
return;
|
||||
}
|
||||
if ( fstatat(device->root_fd, fidp->path, &st, 0) < 0 )
|
||||
{
|
||||
free_fid(device, fidp);
|
||||
p9_error(ring, hdr->tag, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
path = malloc(strlen(fidp->path) + strlen(ring->str + name_off) + 2);
|
||||
if ( !path )
|
||||
{
|
||||
free_fid(device, fidp);
|
||||
p9_error(ring, hdr->tag, ENOMEM);
|
||||
return;
|
||||
}
|
||||
sprintf(path, "%s/%s", fidp->path, ring->str + name_off);
|
||||
new_fidp = alloc_fid_mem(device, fid, path);
|
||||
free(path);
|
||||
if ( !new_fidp )
|
||||
{
|
||||
free_fid(device, fidp);
|
||||
p9_error(ring, hdr->tag, ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&device->fid_mutex);
|
||||
|
||||
new_fidp->ref = fidp->ref;
|
||||
|
||||
if ( perm & P9_CREATE_PERM_DIR )
|
||||
{
|
||||
perm &= P9_CREATE_PERM_DIR_MASK & st.st_mode;
|
||||
if ( mode != P9_OREAD )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if ( mkdirat(device->root_fd, new_fidp->path, perm) < 0 )
|
||||
goto err;
|
||||
|
||||
XEN_TAILQ_REMOVE(&device->fids, fidp, list);
|
||||
XEN_TAILQ_INSERT_HEAD(&device->fids, new_fidp, list);
|
||||
free(fidp);
|
||||
fidp = new_fidp;
|
||||
new_fidp = NULL;
|
||||
|
||||
fidp->fd = openat(device->root_fd, fidp->path, O_RDONLY);
|
||||
if ( fidp->fd < 0 )
|
||||
goto err;
|
||||
fidp->data = fdopendir(fidp->fd);
|
||||
if ( !fidp->data )
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags = open_flags_from_mode(mode);
|
||||
if ( flags < 0 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
goto err;
|
||||
}
|
||||
perm &= P9_CREATE_PERM_FILE_MASK & st.st_mode;
|
||||
|
||||
XEN_TAILQ_REMOVE(&device->fids, fidp, list);
|
||||
XEN_TAILQ_INSERT_HEAD(&device->fids, new_fidp, list);
|
||||
free(fidp);
|
||||
fidp = new_fidp;
|
||||
new_fidp = NULL;
|
||||
|
||||
fidp->fd = openat(device->root_fd, fidp->path, flags | O_CREAT | O_EXCL,
|
||||
perm);
|
||||
if ( fidp->fd < 0 )
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ( fstatat(device->root_fd, fidp->path, &st, 0) < 0 )
|
||||
goto err;
|
||||
|
||||
fill_qid(device, fidp->path, &qid, &st);
|
||||
iounit = get_iounit(ring, &st);
|
||||
fidp->opened = true;
|
||||
fidp->mode = mode;
|
||||
|
||||
pthread_mutex_unlock(&device->fid_mutex);
|
||||
|
||||
fill_buffer(ring, hdr->cmd + 1, hdr->tag, "QU", &qid, &iounit);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
p9_error(ring, hdr->tag, errno);
|
||||
|
||||
pthread_mutex_unlock(&device->fid_mutex);
|
||||
|
||||
free(new_fidp);
|
||||
free_fid(device, fidp);
|
||||
}
|
||||
|
||||
static void p9_clunk(struct ring *ring, struct p9_header *hdr)
|
||||
{
|
||||
device *device = ring->device;
|
||||
@@ -1070,6 +1217,10 @@ void *io_thread(void *arg)
|
||||
p9_open(ring, &hdr);
|
||||
break;
|
||||
|
||||
case P9_CMD_CREATE:
|
||||
p9_create(ring, &hdr);
|
||||
break;
|
||||
|
||||
case P9_CMD_CLUNK:
|
||||
p9_clunk(ring, &hdr);
|
||||
break;
|
||||
|
||||