@@ -140,6 +140,7 @@ struct FileOperations
int (*renameat)(FsContext *ctx, V9fsPath *olddir, const char *old_name,
V9fsPath *newdir, const char *new_name);
int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
+ int (*ftruncate)(FsContext *, int, V9fsFidOpenState *, off_t);
void *opaque;
};
@@ -349,6 +349,20 @@ static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
return ret;
}
+static int handle_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ int fd;
+
+ if (fid_type == P9_FID_DIR) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = v9fs_get_fd_fid(fid_type, fs);
+ return ftruncate(fd, size);
+}
+
static int handle_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
@@ -696,4 +710,5 @@ FileOperations handle_ops = {
.name_to_path = handle_name_to_path,
.renameat = handle_renameat,
.unlinkat = handle_unlinkat,
+ .ftruncate = handle_ftruncate,
};
@@ -874,6 +874,20 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
return ret;
}
+static int local_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ int fd;
+
+ if (fid_type == P9_FID_DIR) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = v9fs_get_fd_fid(fid_type, fs);
+ return ftruncate(fd, size);
+}
+
static int local_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
@@ -1275,4 +1289,5 @@ FileOperations local_ops = {
.name_to_path = local_name_to_path,
.renameat = local_renameat,
.unlinkat = local_unlinkat,
+ .ftruncate = local_ftruncate,
};
@@ -864,6 +864,19 @@ static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
return 0;
}
+static int proxy_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ int fd;
+
+ if (fid_type == P9_FID_DIR) {
+ return -EINVAL;
+ }
+
+ fd = v9fs_get_fd_fid(fid_type, fs);
+ return ftruncate(fd, size);
+}
+
static int proxy_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
@@ -1207,4 +1220,5 @@ FileOperations proxy_ops = {
.name_to_path = proxy_name_to_path,
.renameat = proxy_renameat,
.unlinkat = proxy_unlinkat,
+ .ftruncate = proxy_ftruncate,
};
@@ -344,6 +344,13 @@ static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
return -1;
}
+static int synth_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
{
errno = EPERM;
@@ -566,4 +573,5 @@ FileOperations synth_ops = {
.name_to_path = synth_name_to_path,
.renameat = synth_renameat,
.unlinkat = synth_unlinkat,
+ .ftruncate = synth_ftruncate,
};
@@ -1181,6 +1181,19 @@ out_nofid:
pdu_complete(pdu, retval);
}
+static int v9fs_do_truncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size)
+{
+ int err;
+
+ if (fid_has_file(fidp)) {
+ err = v9fs_co_ftruncate(pdu, fidp, size);
+ } else {
+ err = v9fs_co_truncate(pdu, &fidp->path, size);
+ }
+
+ return err;
+}
+
/* Attribute flags */
#define P9_ATTR_MODE (1 << 0)
#define P9_ATTR_UID (1 << 1)
@@ -1266,7 +1279,7 @@ static void v9fs_setattr(void *opaque)
}
}
if (v9iattr.valid & (P9_ATTR_SIZE)) {
- err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+ err = v9fs_do_truncate(pdu, fidp, v9iattr.size);
if (err < 0) {
goto out;
}
@@ -2754,7 +2767,7 @@ static void v9fs_wstat(void *opaque)
}
}
if (v9stat.length != -1) {
- err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
+ err = v9fs_do_truncate(pdu, fidp, v9stat.length);
if (err < 0) {
goto out;
}
@@ -177,6 +177,24 @@ int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
return err;
}
+int v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size)
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->ftruncate(&s->ctx, fidp->fid_type, &fidp->fs, size);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ return err;
+}
+
int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid,
gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf)
{
@@ -94,5 +94,6 @@ extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
const char *, V9fsPath *);
extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t,
V9fsStatDotl *v9stat);
+extern int v9fs_co_ftruncate(V9fsPDU *, V9fsFidState *, off_t);
#endif
This patch adds a ftruncate operation to the fsdev API. It is then used if we have an open fd, so that ftruncate() in the guest is functional even if the file was unlinked or its file permissions would cause truncate() to fail. Signed-off-by: Greg Kurz <groug@kaod.org> --- fsdev/file-op-9p.h | 1 + hw/9pfs/9p-handle.c | 15 +++++++++++++++ hw/9pfs/9p-local.c | 15 +++++++++++++++ hw/9pfs/9p-proxy.c | 14 ++++++++++++++ hw/9pfs/9p-synth.c | 8 ++++++++ hw/9pfs/9p.c | 17 +++++++++++++++-- hw/9pfs/cofs.c | 18 ++++++++++++++++++ hw/9pfs/coth.h | 1 + 8 files changed, 87 insertions(+), 2 deletions(-)