@@ -55,7 +55,7 @@ typedef struct FileOperations
int (*mksock)(FsContext *, const char *);
int (*utime)(FsContext *, const char *, const struct utimbuf *);
int (*remove)(FsContext *, const char *);
- int (*symlink)(FsContext *, const char *, const char *);
+ int (*symlink)(FsContext *, const char *, const char *, FsCred *);
int (*link)(FsContext *, const char *, const char *);
int (*setuid)(FsContext *, uid_t);
int (*close)(FsContext *, int);
@@ -107,10 +107,25 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
return 0;
}
-static ssize_t local_readlink(FsContext *ctx, const char *path,
- char *buf, size_t bufsz)
+static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
+ char *buf, size_t bufsz)
{
- return readlink(rpath(ctx, path), buf, bufsz);
+ ssize_t tsize = -1;
+ if (fs_ctx->fs_sm == SM_MAPPED) {
+ int fd;
+ fd = open(rpath(fs_ctx, path), O_RDONLY);
+ if (fd == -1) {
+ return -1;
+ }
+ do {
+ tsize = read(fd, (void *)buf, bufsz);
+ } while (tsize == -1 && errno == EINTR);
+ close(fd);
+ return tsize;
+ } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
+ }
+ return tsize;
}
static int local_close(FsContext *ctx, int fd)
@@ -314,10 +329,58 @@ err_end:
}
-static int local_symlink(FsContext *ctx, const char *oldpath,
- const char *newpath)
+static int local_symlink(FsContext *fs_ctx, const char *oldpath,
+ const char *newpath, FsCred *credp)
{
- return symlink(oldpath, rpath(ctx, newpath));
+ int err = -1;
+ int serrno = 0;
+
+ /* Determine the security model */
+ if (fs_ctx->fs_sm == SM_MAPPED) {
+ int fd;
+ ssize_t oldpath_size, write_size;
+ fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
+ SM_LOCAL_MODE_BITS);
+ if (fd == -1) {
+ return fd;
+ }
+ /* Write the oldpath (target) to the file. */
+ oldpath_size = strlen(oldpath) + 1;
+ do {
+ write_size = write(fd, (void *)oldpath, oldpath_size);
+ } while (write_size == -1 && errno == EINTR);
+
+ if (write_size != oldpath_size) {
+ serrno = errno;
+ close(fd);
+ err = -1;
+ goto err_end;
+ }
+ close(fd);
+ /* Set cleint credentials in symlink's xattr */
+ credp->fc_mode = credp->fc_mode|S_IFLNK;
+ err = local_set_xattr(rpath(fs_ctx, newpath), credp);
+ if (err == -1) {
+ serrno = errno;
+ goto err_end;
+ }
+ } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
+ err = symlink(oldpath, rpath(fs_ctx, newpath));
+ if (err) {
+ return err;
+ }
+ err = local_post_create_passthrough(fs_ctx, newpath, credp);
+ if (err == -1) {
+ serrno = errno;
+ goto err_end;
+ }
+ }
+ return err;
+
+err_end:
+ remove(rpath(fs_ctx, newpath));
+ errno = serrno;
+ return err;
}
static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
@@ -199,10 +199,15 @@ static int v9fs_do_open2(V9fsState *s, V9fsCreateState *vs)
return s->ops->open2(&s->ctx, vs->fullname.data, flags, &cred);
}
-static int v9fs_do_symlink(V9fsState *s, V9fsString *oldpath,
- V9fsString *newpath)
+static int v9fs_do_symlink(V9fsState *s, V9fsCreateState *vs)
{
- return s->ops->symlink(&s->ctx, oldpath->data, newpath->data);
+ FsCred cred;
+ cred_init(&cred);
+ cred.fc_uid = vs->fidp->uid;
+ cred.fc_mode = vs->perm | 0777;
+
+ return s->ops->symlink(&s->ctx, vs->extension.data, vs->fullname.data,
+ &cred);
}
static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
@@ -1785,7 +1790,7 @@ static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
err = v9fs_do_mkdir(s, vs);
v9fs_create_post_mkdir(s, vs, err);
} else if (vs->perm & P9_STAT_MODE_SYMLINK) {
- err = v9fs_do_symlink(s, &vs->extension, &vs->fullname);
+ err = v9fs_do_symlink(s, vs);
v9fs_create_post_perms(s, vs, err);
} else if (vs->perm & P9_STAT_MODE_LINK) {
int32_t nfid = atoi(vs->extension.data);