]> Git Repo - qemu.git/blob - hw/9pfs/9p-handle.c
target/arm: Split contiguous loads for endianness
[qemu.git] / hw / 9pfs / 9p-handle.c
1 /*
2  * 9p handle callback
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *    Aneesh Kumar K.V <[email protected]>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  *
12  */
13
14 #include "qemu/osdep.h"
15 #include "9p.h"
16 #include "9p-xattr.h"
17 #include <arpa/inet.h>
18 #include <pwd.h>
19 #include <grp.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include "qemu/xattr.h"
23 #include "qemu/cutils.h"
24 #include "qemu/error-report.h"
25 #include "qemu/option.h"
26 #include <linux/fs.h>
27 #ifdef CONFIG_LINUX_MAGIC_H
28 #include <linux/magic.h>
29 #endif
30 #include <sys/ioctl.h>
31
32 #ifndef XFS_SUPER_MAGIC
33 #define XFS_SUPER_MAGIC  0x58465342
34 #endif
35 #ifndef EXT2_SUPER_MAGIC
36 #define EXT2_SUPER_MAGIC 0xEF53
37 #endif
38 #ifndef REISERFS_SUPER_MAGIC
39 #define REISERFS_SUPER_MAGIC 0x52654973
40 #endif
41 #ifndef BTRFS_SUPER_MAGIC
42 #define BTRFS_SUPER_MAGIC 0x9123683E
43 #endif
44
45 typedef struct HandleData {
46     int mountfd;
47     int handle_bytes;
48 } HandleData;
49
50 static inline int name_to_handle(int dirfd, const char *name,
51                                  struct file_handle *fh, int *mnt_id, int flags)
52 {
53     return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
54 }
55
56 static inline int open_by_handle(int mountfd, const char *fh, int flags)
57 {
58     return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
59 }
60
61 static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
62 {
63     int fd, ret;
64     fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);
65     if (fd < 0) {
66         return fd;
67     }
68     ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
69     if (ret < 0) {
70         goto err_out;
71     }
72     ret = fchmod(fd, credp->fc_mode & 07777);
73 err_out:
74     close(fd);
75     return ret;
76 }
77
78
79 static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
80                         struct stat *stbuf)
81 {
82     int fd, ret;
83     HandleData *data = (HandleData *) fs_ctx->private;
84
85     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
86     if (fd < 0) {
87         return fd;
88     }
89     ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
90     close(fd);
91     return ret;
92 }
93
94 static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
95                                char *buf, size_t bufsz)
96 {
97     int fd, ret;
98     HandleData *data = (HandleData *) fs_ctx->private;
99
100     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
101     if (fd < 0) {
102         return fd;
103     }
104     ret = readlinkat(fd, "", buf, bufsz);
105     close(fd);
106     return ret;
107 }
108
109 static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
110 {
111     return close(fs->fd);
112 }
113
114 static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
115 {
116     return closedir(fs->dir.stream);
117 }
118
119 static int handle_open(FsContext *ctx, V9fsPath *fs_path,
120                        int flags, V9fsFidOpenState *fs)
121 {
122     HandleData *data = (HandleData *) ctx->private;
123
124     fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
125     return fs->fd;
126 }
127
128 static int handle_opendir(FsContext *ctx,
129                           V9fsPath *fs_path, V9fsFidOpenState *fs)
130 {
131     int ret;
132     ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
133     if (ret < 0) {
134         return -1;
135     }
136     fs->dir.stream = fdopendir(ret);
137     if (!fs->dir.stream) {
138         return -1;
139     }
140     return 0;
141 }
142
143 static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
144 {
145     rewinddir(fs->dir.stream);
146 }
147
148 static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
149 {
150     return telldir(fs->dir.stream);
151 }
152
153 static struct dirent *handle_readdir(FsContext *ctx, V9fsFidOpenState *fs)
154 {
155     return readdir(fs->dir.stream);
156 }
157
158 static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
159 {
160     seekdir(fs->dir.stream, off);
161 }
162
163 static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
164                              const struct iovec *iov,
165                              int iovcnt, off_t offset)
166 {
167 #ifdef CONFIG_PREADV
168     return preadv(fs->fd, iov, iovcnt, offset);
169 #else
170     int err = lseek(fs->fd, offset, SEEK_SET);
171     if (err == -1) {
172         return err;
173     } else {
174         return readv(fs->fd, iov, iovcnt);
175     }
176 #endif
177 }
178
179 static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
180                               const struct iovec *iov,
181                               int iovcnt, off_t offset)
182 {
183     ssize_t ret;
184 #ifdef CONFIG_PREADV
185     ret = pwritev(fs->fd, iov, iovcnt, offset);
186 #else
187     int err = lseek(fs->fd, offset, SEEK_SET);
188     if (err == -1) {
189         return err;
190     } else {
191         ret = writev(fs->fd, iov, iovcnt);
192     }
193 #endif
194 #ifdef CONFIG_SYNC_FILE_RANGE
195     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
196         /*
197          * Initiate a writeback. This is not a data integrity sync.
198          * We want to ensure that we don't leave dirty pages in the cache
199          * after write when writeout=immediate is sepcified.
200          */
201         sync_file_range(fs->fd, offset, ret,
202                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
203     }
204 #endif
205     return ret;
206 }
207
208 static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
209 {
210     int fd, ret;
211     HandleData *data = (HandleData *) fs_ctx->private;
212
213     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
214     if (fd < 0) {
215         return fd;
216     }
217     ret = fchmod(fd, credp->fc_mode);
218     close(fd);
219     return ret;
220 }
221
222 static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
223                        const char *name, FsCred *credp)
224 {
225     int dirfd, ret;
226     HandleData *data = (HandleData *) fs_ctx->private;
227
228     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
229     if (dirfd < 0) {
230         return dirfd;
231     }
232     ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
233     if (!ret) {
234         ret = handle_update_file_cred(dirfd, name, credp);
235     }
236     close(dirfd);
237     return ret;
238 }
239
240 static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
241                        const char *name, FsCred *credp)
242 {
243     int dirfd, ret;
244     HandleData *data = (HandleData *) fs_ctx->private;
245
246     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
247     if (dirfd < 0) {
248         return dirfd;
249     }
250     ret = mkdirat(dirfd, name, credp->fc_mode);
251     if (!ret) {
252         ret = handle_update_file_cred(dirfd, name, credp);
253     }
254     close(dirfd);
255     return ret;
256 }
257
258 static int handle_fstat(FsContext *fs_ctx, int fid_type,
259                         V9fsFidOpenState *fs, struct stat *stbuf)
260 {
261     int fd;
262
263     if (fid_type == P9_FID_DIR) {
264         fd = dirfd(fs->dir.stream);
265     } else {
266         fd = fs->fd;
267     }
268     return fstat(fd, stbuf);
269 }
270
271 static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
272                         int flags, FsCred *credp, V9fsFidOpenState *fs)
273 {
274     int ret;
275     int dirfd, fd;
276     HandleData *data = (HandleData *) fs_ctx->private;
277
278     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
279     if (dirfd < 0) {
280         return dirfd;
281     }
282     fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
283     if (fd >= 0) {
284         ret = handle_update_file_cred(dirfd, name, credp);
285         if (ret < 0) {
286             close(fd);
287             fd = ret;
288         } else {
289             fs->fd = fd;
290         }
291     }
292     close(dirfd);
293     return fd;
294 }
295
296
297 static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
298                           V9fsPath *dir_path, const char *name, FsCred *credp)
299 {
300     int fd, dirfd, ret;
301     HandleData *data = (HandleData *) fs_ctx->private;
302
303     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
304     if (dirfd < 0) {
305         return dirfd;
306     }
307     ret = symlinkat(oldpath, dirfd, name);
308     if (!ret) {
309         fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
310         if (fd < 0) {
311             ret = fd;
312             goto err_out;
313         }
314         ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
315         close(fd);
316     }
317 err_out:
318     close(dirfd);
319     return ret;
320 }
321
322 static int handle_link(FsContext *ctx, V9fsPath *oldpath,
323                        V9fsPath *dirpath, const char *name)
324 {
325     int oldfd, newdirfd, ret;
326     HandleData *data = (HandleData *) ctx->private;
327
328     oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
329     if (oldfd < 0) {
330         return oldfd;
331     }
332     newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
333     if (newdirfd < 0) {
334         close(oldfd);
335         return newdirfd;
336     }
337     ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
338     close(newdirfd);
339     close(oldfd);
340     return ret;
341 }
342
343 static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
344 {
345     int fd, ret;
346     HandleData *data = (HandleData *) ctx->private;
347
348     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
349     if (fd < 0) {
350         return fd;
351     }
352     ret = ftruncate(fd, size);
353     close(fd);
354     return ret;
355 }
356
357 static int handle_rename(FsContext *ctx, const char *oldpath,
358                          const char *newpath)
359 {
360     errno = EOPNOTSUPP;
361     return -1;
362 }
363
364 static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
365 {
366     int fd, ret;
367     HandleData *data = (HandleData *) fs_ctx->private;
368
369     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
370     if (fd < 0) {
371         return fd;
372     }
373     ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
374     close(fd);
375     return ret;
376 }
377
378 static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
379                             const struct timespec *buf)
380 {
381     int ret;
382     int fd;
383     HandleData *data = (HandleData *) ctx->private;
384
385     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
386     if (fd < 0) {
387         return fd;
388     }
389     ret = futimens(fd, buf);
390     close(fd);
391     return ret;
392 }
393
394 static int handle_remove(FsContext *ctx, const char *path)
395 {
396     errno = EOPNOTSUPP;
397     return -1;
398 }
399
400 static int handle_fsync(FsContext *ctx, int fid_type,
401                         V9fsFidOpenState *fs, int datasync)
402 {
403     int fd;
404
405     if (fid_type == P9_FID_DIR) {
406         fd = dirfd(fs->dir.stream);
407     } else {
408         fd = fs->fd;
409     }
410
411     if (datasync) {
412         return qemu_fdatasync(fd);
413     } else {
414         return fsync(fd);
415     }
416 }
417
418 static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
419                          struct statfs *stbuf)
420 {
421     int fd, ret;
422     HandleData *data = (HandleData *) ctx->private;
423
424     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
425     if (fd < 0) {
426         return fd;
427     }
428     ret = fstatfs(fd, stbuf);
429     close(fd);
430     return ret;
431 }
432
433 static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
434                                 const char *name, void *value, size_t size)
435 {
436     int fd, ret;
437     HandleData *data = (HandleData *) ctx->private;
438
439     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
440     if (fd < 0) {
441         return fd;
442     }
443     ret = fgetxattr(fd, name, value, size);
444     close(fd);
445     return ret;
446 }
447
448 static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
449                                  void *value, size_t size)
450 {
451     int fd, ret;
452     HandleData *data = (HandleData *) ctx->private;
453
454     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
455     if (fd < 0) {
456         return fd;
457     }
458     ret = flistxattr(fd, value, size);
459     close(fd);
460     return ret;
461 }
462
463 static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
464                             void *value, size_t size, int flags)
465 {
466     int fd, ret;
467     HandleData *data = (HandleData *) ctx->private;
468
469     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
470     if (fd < 0) {
471         return fd;
472     }
473     ret = fsetxattr(fd, name, value, size, flags);
474     close(fd);
475     return ret;
476 }
477
478 static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
479                                const char *name)
480 {
481     int fd, ret;
482     HandleData *data = (HandleData *) ctx->private;
483
484     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
485     if (fd < 0) {
486         return fd;
487     }
488     ret = fremovexattr(fd, name);
489     close(fd);
490     return ret;
491 }
492
493 static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
494                               const char *name, V9fsPath *target)
495 {
496     char *buffer;
497     struct file_handle *fh;
498     int dirfd, ret, mnt_id;
499     HandleData *data = (HandleData *) ctx->private;
500
501     /* "." and ".." are not allowed */
502     if (!strcmp(name, ".") || !strcmp(name, "..")) {
503         errno = EINVAL;
504         return -1;
505
506     }
507     if (dir_path) {
508         dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
509     } else {
510         /* relative to export root */
511         buffer = rpath(ctx, ".");
512         dirfd = open(buffer, O_DIRECTORY);
513         g_free(buffer);
514     }
515     if (dirfd < 0) {
516         return dirfd;
517     }
518     fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
519     fh->handle_bytes = data->handle_bytes;
520     /* add a "./" at the beginning of the path */
521     buffer = g_strdup_printf("./%s", name);
522     /* flag = 0 imply don't follow symlink */
523     ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
524     if (!ret) {
525         target->data = (char *)fh;
526         target->size = sizeof(struct file_handle) + data->handle_bytes;
527     } else {
528         g_free(fh);
529     }
530     close(dirfd);
531     g_free(buffer);
532     return ret;
533 }
534
535 static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
536                            const char *old_name, V9fsPath *newdir,
537                            const char *new_name)
538 {
539     int olddirfd, newdirfd, ret;
540     HandleData *data = (HandleData *) ctx->private;
541
542     olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
543     if (olddirfd < 0) {
544         return olddirfd;
545     }
546     newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
547     if (newdirfd < 0) {
548         close(olddirfd);
549         return newdirfd;
550     }
551     ret = renameat(olddirfd, old_name, newdirfd, new_name);
552     close(newdirfd);
553     close(olddirfd);
554     return ret;
555 }
556
557 static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
558                            const char *name, int flags)
559 {
560     int dirfd, ret;
561     HandleData *data = (HandleData *) ctx->private;
562
563     dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
564     if (dirfd < 0) {
565         return dirfd;
566     }
567
568     ret = unlinkat(dirfd, name, flags);
569
570     close(dirfd);
571     return ret;
572 }
573
574 static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
575                                  mode_t st_mode, uint64_t *st_gen)
576 {
577 #ifdef FS_IOC_GETVERSION
578     int err;
579     V9fsFidOpenState fid_open;
580
581     /*
582      * Do not try to open special files like device nodes, fifos etc
583      * We can get fd for regular files and directories only
584      */
585     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
586         errno = ENOTTY;
587         return -1;
588     }
589     err = handle_open(ctx, path, O_RDONLY, &fid_open);
590     if (err < 0) {
591         return err;
592     }
593     err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
594     handle_close(ctx, &fid_open);
595     return err;
596 #else
597     errno = ENOTTY;
598     return -1;
599 #endif
600 }
601
602 static int handle_init(FsContext *ctx, Error **errp)
603 {
604     int ret, mnt_id;
605     struct statfs stbuf;
606     struct file_handle fh;
607     HandleData *data = g_malloc(sizeof(HandleData));
608
609     data->mountfd = open(ctx->fs_root, O_DIRECTORY);
610     if (data->mountfd < 0) {
611         ret = data->mountfd;
612         goto err_out;
613     }
614     ret = statfs(ctx->fs_root, &stbuf);
615     if (!ret) {
616         switch (stbuf.f_type) {
617         case EXT2_SUPER_MAGIC:
618         case BTRFS_SUPER_MAGIC:
619         case REISERFS_SUPER_MAGIC:
620         case XFS_SUPER_MAGIC:
621             ctx->exops.get_st_gen = handle_ioc_getversion;
622             break;
623         }
624     }
625     memset(&fh, 0, sizeof(struct file_handle));
626     ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
627     if (ret && errno == EOVERFLOW) {
628         data->handle_bytes = fh.handle_bytes;
629         ctx->private = data;
630         ret = 0;
631         goto out;
632     }
633     /* we got 0 byte handle ? */
634     ret = -1;
635     close(data->mountfd);
636 err_out:
637     g_free(data);
638 out:
639     return ret;
640 }
641
642 static void handle_cleanup(FsContext *ctx)
643 {
644     HandleData *data = ctx->private;
645
646     close(data->mountfd);
647     g_free(data);
648 }
649
650 static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
651 {
652     const char *sec_model = qemu_opt_get(opts, "security_model");
653     const char *path = qemu_opt_get(opts, "path");
654
655     warn_report("handle backend is deprecated");
656
657     if (sec_model) {
658         error_report("Invalid argument security_model specified with handle fsdriver");
659         return -1;
660     }
661
662     if (!path) {
663         error_report("fsdev: No path specified");
664         return -1;
665     }
666     fse->path = g_strdup(path);
667     return 0;
668
669 }
670
671 FileOperations handle_ops = {
672     .parse_opts   = handle_parse_opts,
673     .init         = handle_init,
674     .cleanup      = handle_cleanup,
675     .lstat        = handle_lstat,
676     .readlink     = handle_readlink,
677     .close        = handle_close,
678     .closedir     = handle_closedir,
679     .open         = handle_open,
680     .opendir      = handle_opendir,
681     .rewinddir    = handle_rewinddir,
682     .telldir      = handle_telldir,
683     .readdir      = handle_readdir,
684     .seekdir      = handle_seekdir,
685     .preadv       = handle_preadv,
686     .pwritev      = handle_pwritev,
687     .chmod        = handle_chmod,
688     .mknod        = handle_mknod,
689     .mkdir        = handle_mkdir,
690     .fstat        = handle_fstat,
691     .open2        = handle_open2,
692     .symlink      = handle_symlink,
693     .link         = handle_link,
694     .truncate     = handle_truncate,
695     .rename       = handle_rename,
696     .chown        = handle_chown,
697     .utimensat    = handle_utimensat,
698     .remove       = handle_remove,
699     .fsync        = handle_fsync,
700     .statfs       = handle_statfs,
701     .lgetxattr    = handle_lgetxattr,
702     .llistxattr   = handle_llistxattr,
703     .lsetxattr    = handle_lsetxattr,
704     .lremovexattr = handle_lremovexattr,
705     .name_to_path = handle_name_to_path,
706     .renameat     = handle_renameat,
707     .unlinkat     = handle_unlinkat,
708 };
This page took 0.062769 seconds and 4 git commands to generate.