Lines Matching +full:qemu +full:- +full:user +full:- +full:static
29 * Based on libixp code: �2007-2010 Kris Maglione <maglione.k at Gmail>
104 /* FF_NO_POSIX_ACL 0x02 -- not yet */
109 * - a reference count
110 * - a uid
111 * - a gid-set
113 * The "default" gid is the first gid in the git-set, provided the
114 * set size is at least 1. The set-size may be zero, though.
116 * Adjustments to the ref-count must be atomic, once it's shared.
123 * If this gid is (gid_t)-1 it is not used and only the remaining
126 * The uid may also be (uid_t)-1, meaning "no uid was available
145 * We have a global-static mutex for single-threading Tattach
149 static bool fs_attach_mutex_inited;
150 static pthread_mutex_t fs_attach_mutex;
155 static struct passwd *fs_getpwuid(struct fs_softc *, uid_t, struct r_pgdata *);
156 static struct group *fs_getgrgid(struct fs_softc *, gid_t, struct r_pgdata *);
157 static int fs_buildname(struct l9p_fid *, char *, char *, size_t);
158 static int fs_pdir(struct fs_softc *, struct l9p_fid *, char *, size_t,
160 static int fs_dpf(char *, char *, size_t);
161 static int fs_oflags_dotu(int, int *);
162 static int fs_oflags_dotl(uint32_t, int *, enum l9p_omode *);
163 static int fs_nde(struct fs_softc *, struct l9p_fid *, bool, gid_t,
165 static struct fs_fid *open_fid(int, const char *, struct fs_authinfo *, bool);
166 static void dostat(struct fs_softc *, struct l9p_stat *, char *,
168 static void dostatfs(struct l9p_statfs *, struct statfs *, long);
169 static void fillacl(struct fs_fid *ff);
170 static struct l9p_acl *getacl(struct fs_fid *ff, int fd, const char *path);
171 static void dropacl(struct fs_fid *ff);
172 static struct l9p_acl *look_for_nfsv4_acl(struct fs_fid *ff, int fd,
174 static int check_access(int32_t,
177 static void generate_qid(struct stat *, struct l9p_qid *);
179 static int fs_icreate(void *, struct l9p_fid *, char *, int,
181 static int fs_iopen(void *, struct l9p_fid *, int, enum l9p_omode,
183 static int fs_imkdir(void *, struct l9p_fid *, char *,
185 static int fs_imkfifo(void *, struct l9p_fid *, char *,
187 static int fs_imknod(void *, struct l9p_fid *, char *,
189 static int fs_imksocket(void *, struct l9p_fid *, char *,
191 static int fs_isymlink(void *, struct l9p_fid *, char *, char *,
197 static int fs_attach(void *, struct l9p_request *);
198 static int fs_clunk(void *, struct l9p_fid *);
199 static int fs_create(void *, struct l9p_request *);
200 static int fs_open(void *, struct l9p_request *);
201 static int fs_read(void *, struct l9p_request *);
202 static int fs_remove(void *, struct l9p_fid *);
203 static int fs_stat(void *, struct l9p_request *);
204 static int fs_walk(void *, struct l9p_request *);
205 static int fs_write(void *, struct l9p_request *);
206 static int fs_wstat(void *, struct l9p_request *);
207 static int fs_statfs(void *, struct l9p_request *);
208 static int fs_lopen(void *, struct l9p_request *);
209 static int fs_lcreate(void *, struct l9p_request *);
210 static int fs_symlink(void *, struct l9p_request *);
211 static int fs_mknod(void *, struct l9p_request *);
212 static int fs_rename(void *, struct l9p_request *);
213 static int fs_readlink(void *, struct l9p_request *);
214 static int fs_getattr(void *, struct l9p_request *);
215 static int fs_setattr(void *, struct l9p_request *);
216 static int fs_xattrwalk(void *, struct l9p_request *);
217 static int fs_xattrcreate(void *, struct l9p_request *);
218 static int fs_readdir(void *, struct l9p_request *);
219 static int fs_fsync(void *, struct l9p_request *);
220 static int fs_lock(void *, struct l9p_request *);
221 static int fs_getlock(void *, struct l9p_request *);
222 static int fs_link(void *, struct l9p_request *);
223 static int fs_renameat(void *, struct l9p_request *);
224 static int fs_unlinkat(void *, struct l9p_request *);
225 static void fs_freefid(void *, struct l9p_fid *);
228 * Convert from 9p2000 open/create mode to Unix-style O_* flags.
232 * The <mode> given here is the one-byte (uint8_t) "mode"
236 * http://plan9.bell-labs.com/magic/man2html/5/open
258 static int
299 * ORCLOSE - caller only in fs_oflags_dotu()
300 * OCEXEC - makes no sense in server in fs_oflags_dotu()
301 * ODIRECT - not applicable here in fs_oflags_dotu()
323 * Linux currently does not have open-for-exec, but there is a
328 static int
388 * per-mount basis.) in fs_oflags_dotl()
414 static struct passwd *
418 return (r_cap_getpwuid(sc->fs_cappwd, uid, pg)); in fs_getpwuid()
425 static struct group *
429 return (r_cap_getgrgid(sc->fs_capgrp, gid, pg)); in fs_getgrgid()
439 static int
442 struct fs_fid *dirf = dir->lo_aux; in fs_buildname()
446 dlen = strlen(dirf->ff_name); in fs_buildname()
450 memcpy(buf, dirf->ff_name, dlen); in fs_buildname()
461 static int
468 ff = fid->lo_aux; in fs_pdir()
470 path = ff->ff_name; in fs_pdir()
474 if (fstatat(ff->ff_dirfd, path, st, AT_SYMLINK_NOFOLLOW) != 0) in fs_pdir()
476 if (!S_ISDIR(st->st_mode)) in fs_pdir()
488 * (Think of the function name as "directory plus-equals file".)
490 static int
506 * mkdir, etc -- any operation that creates a new inode),
510 * The new entity should be owned by user/group <*nuid, *ngid>,
514 * (e.g., read-only file system or no permission to write in
519 static int
528 if (sc->fs_readonly) in fs_nde()
530 dirf = dir->lo_aux; in fs_nde()
532 if (fstatat(dirf->ff_dirfd, dirf->ff_name, st, in fs_nde()
535 if (!S_ISDIR(st->st_mode)) in fs_nde()
537 dirf = dir->lo_aux; in fs_nde()
538 ai = dirf->ff_ai; in fs_nde()
541 error = check_access(op, dirf->ff_acl, st, NULL, NULL, ai, egid); in fs_nde()
545 *nuid = ai->ai_uid != (uid_t)-1 ? ai->ai_uid : st->st_uid; in fs_nde()
546 *ngid = egid != (gid_t)-1 ? egid : in fs_nde()
547 ai->ai_ngids > 0 ? ai->ai_gids[0] : st->st_gid; in fs_nde()
552 * Allocate new open-file data structure to attach to a fid.
557 static struct fs_fid *
565 error = pthread_mutex_init(&ret->ff_mtx, NULL); in open_fid()
570 ret->ff_fd = -1; in open_fid()
571 ret->ff_dirfd = dirfd; in open_fid()
572 ret->ff_name = strdup(path); in open_fid()
573 if (ret->ff_name == NULL) { in open_fid()
574 pthread_mutex_destroy(&ret->ff_mtx); in open_fid()
578 pthread_mutex_lock(&ai->ai_mtx); in open_fid()
579 newcount = ++ai->ai_refcnt; in open_fid()
580 pthread_mutex_unlock(&ai->ai_mtx); in open_fid()
591 ret->ff_ai = ai; in open_fid()
595 static void
599 struct passwd *user; in dostat() local
604 generate_qid(buf, &s->qid); in dostat()
606 s->type = 0; in dostat()
607 s->dev = 0; in dostat()
608 s->mode = buf->st_mode & 0777; in dostat()
610 if (S_ISDIR(buf->st_mode)) in dostat()
611 s->mode |= L9P_DMDIR; in dostat()
613 if (S_ISLNK(buf->st_mode) && dotu) in dostat()
614 s->mode |= L9P_DMSYMLINK; in dostat()
616 if (S_ISCHR(buf->st_mode) || S_ISBLK(buf->st_mode)) in dostat()
617 s->mode |= L9P_DMDEVICE; in dostat()
619 if (S_ISSOCK(buf->st_mode)) in dostat()
620 s->mode |= L9P_DMSOCKET; in dostat()
622 if (S_ISFIFO(buf->st_mode)) in dostat()
623 s->mode |= L9P_DMNAMEDPIPE; in dostat()
625 s->atime = (uint32_t)buf->st_atime; in dostat()
626 s->mtime = (uint32_t)buf->st_mtime; in dostat()
627 s->length = (uint64_t)buf->st_size; in dostat()
629 s->name = r_basename(name, NULL, 0); in dostat()
634 user = fs_getpwuid(sc, buf->st_uid, &udata); in dostat()
635 group = fs_getgrgid(sc, buf->st_gid, &gdata); in dostat()
636 s->uid = user != NULL ? strdup(user->pw_name) : NULL; in dostat()
637 s->gid = group != NULL ? strdup(group->gr_name) : NULL; in dostat()
638 s->muid = user != NULL ? strdup(user->pw_name) : NULL; in dostat()
644 * providing user and group names in textual form. in dostat()
646 * NB: if the asprintf()s fail, s->extension should in dostat()
649 s->n_uid = buf->st_uid; in dostat()
650 s->n_gid = buf->st_gid; in dostat()
651 s->n_muid = buf->st_uid; in dostat()
653 if (S_ISLNK(buf->st_mode)) { in dostat()
658 s->extension = NULL; in dostat()
662 s->extension = strndup(target, (size_t)ret); in dostat()
665 if (S_ISBLK(buf->st_mode)) { in dostat()
666 asprintf(&s->extension, "b %d %d", major(buf->st_rdev), in dostat()
667 minor(buf->st_rdev)); in dostat()
670 if (S_ISCHR(buf->st_mode)) { in dostat()
671 asprintf(&s->extension, "c %d %d", major(buf->st_rdev), in dostat()
672 minor(buf->st_rdev)); in dostat()
677 static void dostatfs(struct l9p_statfs *out, struct statfs *in, long namelen) in dostatfs()
680 out->type = L9P_FSTYPE; in dostatfs()
681 out->bsize = in->f_bsize; in dostatfs()
682 out->blocks = in->f_blocks; in dostatfs()
683 out->bfree = in->f_bfree; in dostatfs()
684 out->bavail = in->f_bavail; in dostatfs()
685 out->files = in->f_files; in dostatfs()
686 out->ffree = in->f_ffree; in dostatfs()
687 out->namelen = (uint32_t)namelen; in dostatfs()
688 out->fsid = ((uint64_t)in->f_fsid.val[0] << 32) | in dostatfs()
689 (uint64_t)in->f_fsid.val[1]; in dostatfs()
692 static void
695 qid->path = buf->st_ino; in generate_qid()
696 qid->version = 0; in generate_qid()
698 if (S_ISREG(buf->st_mode)) in generate_qid()
699 qid->type |= L9P_QTFILE; in generate_qid()
701 if (S_ISDIR(buf->st_mode)) in generate_qid()
702 qid->type |= L9P_QTDIR; in generate_qid()
704 if (S_ISLNK(buf->st_mode)) in generate_qid()
705 qid->type |= L9P_QTSYMLINK; in generate_qid()
709 * Fill in ff->ff_acl if it's not set yet. Skip if the "don't use
713 static void
717 if (ff->ff_acl == NULL && (ff->ff_flags & FF_NO_NFSV4_ACL) == 0) { in fillacl()
718 ff->ff_acl = look_for_nfsv4_acl(ff, ff->ff_fd, ff->ff_name); in fillacl()
719 if (ff->ff_acl == NULL) in fillacl()
720 ff->ff_flags |= FF_NO_NFSV4_ACL; in fillacl()
732 static struct l9p_acl *
736 if (ff->ff_flags & FF_NO_NFSV4_ACL) in getacl()
742 * Drop cached ff->ff_acl, e.g., after moving from one directory to
745 static void
749 l9p_acl_free(ff->ff_acl); in dropacl()
750 ff->ff_acl = NULL; in dropacl()
751 ff->ff_flags = ff->ff_ai->ai_flags; in dropacl()
759 static struct l9p_acl *
767 fd = openat(ff->ff_dirfd, path, 0); in look_for_nfsv4_acl()
803 * Verify that the user whose authinfo is in <ai> and effective
804 * group ID is <egid> ((gid_t)-1 means no egid supplied) has
811 * be NULL but pst or cst must be non-NULL depending on the
814 static int
825 * bits, and allow super-user as well. in check_access()
827 args.aca_uid = ai->ai_uid; in check_access()
829 args.aca_groups = ai->ai_gids; in check_access()
830 args.aca_ngroups = (size_t)ai->ai_ngids; in check_access()
843 static int
858 assert(req->lr_fid != NULL); in fs_attach()
861 * Single-thread pwd/group related items. We have a reentrant in fs_attach()
863 * may use non-reentrant C library getgr* routines. in fs_attach()
867 n_uname = req->lr_req.tattach.n_uname; in fs_attach()
873 "Tattach: uid %ld: no such user", (long)uid); in fs_attach()
875 uid = (uid_t)-1; in fs_attach()
877 pwd = cap_getpwnam(sc->fs_cappwd, req->lr_req.tattach.uname); in fs_attach()
879 pwd = getpwnam(req->lr_req.tattach.uname); in fs_attach()
883 "Tattach: %s: no such user", in fs_attach()
884 req->lr_req.tattach.uname); in fs_attach()
893 * We do at least support ai->ai_ngids==0 properly now though. in fs_attach()
895 if (uid == (uid_t)-1 && pwd != NULL) in fs_attach()
896 uid = pwd->pw_uid; in fs_attach()
897 if (uid == (uid_t)-1) in fs_attach()
901 if (fstat(sc->fs_rootfd, &st) != 0) in fs_attach()
922 * returns non-NULL, or fails and sets ngroups to 0 in fs_attach()
925 gids = l9p_getgrlist(pwd->pw_name, pwd->pw_gid, &ngroups); in fs_attach()
933 * non-reentrant C library routines; allow other threads in. in fs_attach()
942 error = pthread_mutex_init(&ai->ai_mtx, NULL); in fs_attach()
948 ai->ai_refcnt = 0; in fs_attach()
949 ai->ai_uid = uid; in fs_attach()
950 ai->ai_flags = 0; /* XXX for now */ in fs_attach()
951 ai->ai_ngids = ngroups; in fs_attach()
952 memcpy(ai->ai_gids, gids, (size_t)ngroups * sizeof(gid_t)); in fs_attach()
955 file = open_fid(sc->fs_rootfd, ".", ai, true); in fs_attach()
957 pthread_mutex_destroy(&ai->ai_mtx); in fs_attach()
962 req->lr_fid->lo_aux = file; in fs_attach()
963 generate_qid(&st, &req->lr_resp.rattach.qid); in fs_attach()
967 static int
972 file = fid->lo_aux; in fs_clunk()
975 if (file->ff_dir) { in fs_clunk()
976 closedir(file->ff_dir); in fs_clunk()
977 file->ff_dir = NULL; in fs_clunk()
978 } else if (file->ff_fd != -1) { in fs_clunk()
979 close(file->ff_fd); in fs_clunk()
980 file->ff_fd = -1; in fs_clunk()
991 * existing path is due to a fid-based file (req->lr_fid).
993 * One op (create regular file) sets file->fd, the rest do not.
995 static int
1005 dir = req->lr_fid; in fs_create()
1006 name = req->lr_req.tcreate.name; in fs_create()
1007 dmperm = req->lr_req.tcreate.perm; in fs_create()
1012 perm, (gid_t)-1, &st); in fs_create()
1015 req->lr_req.tcreate.extension, (gid_t)-1, &st); in fs_create()
1018 perm, (gid_t)-1, &st); in fs_create()
1021 perm, (gid_t)-1, &st); in fs_create()
1032 if (sscanf(req->lr_req.tcreate.extension, "%c %u %u", in fs_create()
1049 (gid_t)-1, &st); in fs_create()
1054 p9 = req->lr_req.tcreate.mode; in fs_create()
1059 true, perm, (gid_t)-1, &st); in fs_create()
1060 req->lr_resp.rcreate.iounit = req->lr_conn->lc_max_io_size; in fs_create()
1064 generate_qid(&st, &req->lr_resp.rcreate.qid); in fs_create()
1071 * http://plan9.bell-labs.com/magic/man2html/5/open
1082 static inline mode_t
1106 * file, which is now open; its associated file-name changes too.
1111 static int
1121 file = dir->lo_aux; in fs_icreate()
1135 /* In case of success, we will need a new file->ff_name. */ in fs_icreate()
1147 /* Adjust new-file permissions for Plan9 protocol. */ in fs_icreate()
1149 perm = fs_p9perm(perm, st->st_mode, false); in fs_icreate()
1152 fd = openat(file->ff_dirfd, newname, flags | O_CREAT | O_EXCL, perm); in fs_icreate()
1171 free(file->ff_name); in fs_icreate()
1172 file->ff_name = name; in fs_icreate()
1173 file->ff_fd = fd; in fs_icreate()
1179 * argument), then open the file-or-directory, leaving the internal
1186 * so if some other race-winner substitutes in a symlink we won't
1193 * on substitution-detection via fstat(). To simplify the code we
1194 * just always re-check.
1202 static int
1215 /* Forbid write ops on read-only file system. */ in fs_iopen()
1216 if (sc->fs_readonly) { in fs_iopen()
1225 file = fid->lo_aux; in fs_iopen()
1227 name = file->ff_name; in fs_iopen()
1229 if (fstatat(file->ff_dirfd, name, &first, AT_SYMLINK_NOFOLLOW) != 0) in fs_iopen()
1249 error = check_access(op, NULL, NULL, file->ff_acl, &first, in fs_iopen()
1250 file->ff_ai, (gid_t)-1); in fs_iopen()
1258 fd = openat(file->ff_dirfd, name, O_DIRECTORY); in fs_iopen()
1265 fd = openat(file->ff_dirfd, name, flags); in fs_iopen()
1271 * We have a valid fd, and maybe non-null dirp. Re-check in fs_iopen()
1275 first.st_dev != st->st_dev || in fs_iopen()
1276 first.st_ino != st->st_ino) { in fs_iopen()
1284 file->ff_dir = dirp; in fs_iopen()
1286 file->ff_fd = fd; in fs_iopen()
1301 static int
1311 ff = dir->lo_aux; in fs_imkdir()
1321 perm = fs_p9perm(perm, st->st_mode, true); in fs_imkdir()
1323 if (mkdirat(ff->ff_dirfd, newname, perm) != 0) in fs_imkdir()
1326 fd = openat(ff->ff_dirfd, newname, in fs_imkdir()
1347 static int fs_ifchdir_thread_local(int fd) in fs_ifchdir_thread_local()
1350 #pragma clang diagnostic ignored "-Wdeprecated-declarations" in fs_ifchdir_thread_local()
1361 static int
1372 ff = dir->lo_aux; in fs_imknod()
1382 perm = fs_p9perm(mode & 0777, st->st_mode, false); in fs_imknod()
1389 if (fs_ifchdir_thread_local(ff->ff_dirfd) < 0) { in fs_imknod()
1390 return -1; in fs_imknod()
1394 /* Stop using the thread-local cwd */ in fs_imknod()
1395 fs_ifchdir_thread_local(-1); in fs_imknod()
1401 if (mknodat(ff->ff_dirfd, newname, mode, dev) != 0) in fs_imknod()
1406 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 || in fs_imknod()
1407 fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 || in fs_imknod()
1408 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0) in fs_imknod()
1410 else if ((st->st_mode & S_IFMT) != (mode & S_IFMT)) in fs_imknod()
1421 static int
1431 ff = dir->lo_aux; in fs_imkfifo()
1441 perm = fs_p9perm(perm, st->st_mode, false); in fs_imkfifo()
1447 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 || in fs_imkfifo()
1448 fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 || in fs_imkfifo()
1449 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0) in fs_imkfifo()
1451 else if (!S_ISFIFO(st->st_mode)) in fs_imkfifo()
1465 static int
1477 ff = dir->lo_aux; in fs_imksocket()
1487 perm = fs_p9perm(perm, st->st_mode, false); in fs_imksocket()
1494 fd = -1; in fs_imksocket()
1498 fd = openat(ff->ff_dirfd, ff->ff_name, in fs_imksocket()
1512 * Unix-like system, this was known to behave oddly, in fs_imksocket()
1537 * We believe we created the socket-inode. Fix in fs_imksocket()
1542 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 || in fs_imksocket()
1543 fchmodat(ff->ff_dirfd, newname, perm, AT_SYMLINK_NOFOLLOW) != 0 || in fs_imksocket()
1544 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0) in fs_imksocket()
1546 else if (!S_ISSOCK(st->st_mode)) in fs_imksocket()
1575 static int
1585 ff = dir->lo_aux; in fs_isymlink()
1594 if (symlinkat(symtgt, ff->ff_dirfd, newname) != 0) in fs_isymlink()
1598 if (fchownat(ff->ff_dirfd, newname, uid, gid, AT_SYMLINK_NOFOLLOW) != 0 || in fs_isymlink()
1599 fstatat(ff->ff_dirfd, newname, st, AT_SYMLINK_NOFOLLOW) != 0) in fs_isymlink()
1601 else if (!S_ISLNK(st->st_mode)) in fs_isymlink()
1609 static int
1612 struct l9p_fid *fid = req->lr_fid; in fs_open()
1617 p9 = req->lr_req.topen.mode; in fs_open()
1622 error = fs_iopen(softc, fid, flags, p9, (gid_t)-1, &st); in fs_open()
1626 generate_qid(&st, &req->lr_resp.ropen.qid); in fs_open()
1627 req->lr_resp.ropen.iounit = req->lr_conn->lc_max_io_size; in fs_open()
1635 * all systems do, so hide the ifdef-ed code in an inline function.
1637 static inline int
1641 return (fstatat(dirfd(file->ff_dir), name, st, AT_SYMLINK_NOFOLLOW)); in fs_lstatat()
1644 static int
1650 bool dotu = req->lr_conn->lc_version >= L9P_2000U; in fs_read()
1654 file = req->lr_fid->lo_aux; in fs_read()
1657 if (file->ff_dir != NULL) { in fs_read()
1663 pthread_mutex_lock(&file->ff_mtx); in fs_read()
1681 o = telldir(file->ff_dir); in fs_read()
1682 d = readdir(file->ff_dir); in fs_read()
1685 if (fs_lstatat(file, d->d_name, &st)) in fs_read()
1687 dostat(sc, &l9stat, d->d_name, &st, dotu); in fs_read()
1689 seekdir(file->ff_dir, o); in fs_read()
1693 seekdir(file->ff_dir, o); in fs_read()
1694 (void) readdir(file->ff_dir); in fs_read()
1698 pthread_mutex_unlock(&file->ff_mtx); in fs_read()
1700 size_t niov = l9p_truncate_iov(req->lr_data_iov, in fs_read()
1701 req->lr_data_niov, req->lr_req.io.count); in fs_read()
1704 ret = preadv(file->ff_fd, req->lr_data_iov, niov, in fs_read()
1705 req->lr_req.io.offset); in fs_read()
1708 if (lseek(file->ff_fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0) in fs_read()
1711 ret = (uint32_t)readv(file->ff_fd, req->lr_data_iov, (int)niov); in fs_read()
1717 req->lr_resp.io.count = (uint32_t)ret; in fs_read()
1723 static int
1733 if (sc->fs_readonly) in fs_remove()
1740 file = fid->lo_aux; in fs_remove()
1741 if (fstatat(file->ff_dirfd, file->ff_name, &cst, AT_SYMLINK_NOFOLLOW) != 0) in fs_remove()
1744 parent_acl = getacl(file, -1, dirname); in fs_remove()
1748 parent_acl, &pst, file->ff_acl, &cst, file->ff_ai, (gid_t)-1); in fs_remove()
1753 if (unlinkat(file->ff_dirfd, file->ff_name, in fs_remove()
1760 static int
1766 bool dotu = req->lr_conn->lc_version >= L9P_2000U; in fs_stat()
1769 file = req->lr_fid->lo_aux; in fs_stat()
1772 if (fstatat(file->ff_dirfd, file->ff_name, &st, in fs_stat()
1776 dostat(sc, &req->lr_resp.rstat.stat, file->ff_name, &st, dotu); in fs_stat()
1780 static int
1785 struct fs_fid *file = req->lr_fid->lo_aux; in fs_walk()
1828 namelen = strlcpy(succ, file->ff_name, MAXPATHLEN); in fs_walk()
1831 if (fstatat(file->ff_dirfd, succ, &st, AT_SYMLINK_NOFOLLOW) < 0) in fs_walk()
1833 ai = file->ff_ai; in fs_walk()
1836 acl = file->ff_acl; in fs_walk()
1838 nwname = (int)req->lr_req.twalk.nwname; in fs_walk()
1843 * Then, look up each component in its directory-so-far. in fs_walk()
1853 NULL, NULL, acl, &st, ai, (gid_t)-1); in fs_walk()
1856 "Twalk: denying dir-walk on \"%s\" for uid %u", in fs_walk()
1857 succ, (unsigned)ai->ai_uid); in fs_walk()
1861 comp = req->lr_req.twalk.wname[i]; in fs_walk()
1921 if (fstatat(file->ff_dirfd, next, &st, AT_SYMLINK_NOFOLLOW) < 0) { in fs_walk()
1930 generate_qid(&st, &req->lr_resp.rwalk.wqid[i]); in fs_walk()
1934 if (acl != NULL && acl != file->ff_acl) in fs_walk()
1936 acl = getacl(file, -1, next); in fs_walk()
1950 newfile = open_fid(file->ff_dirfd, succ, ai, false); in fs_walk()
1955 if (req->lr_newfid == req->lr_fid) { in fs_walk()
1957 * Before overwriting fid->lo_aux, free the old value. in fs_walk()
1961 if (acl == file->ff_acl) in fs_walk()
1963 fs_freefid(softc, req->lr_fid); in fs_walk()
1966 req->lr_newfid->lo_aux = newfile; in fs_walk()
1967 if (file != NULL && acl != file->ff_acl) { in fs_walk()
1968 newfile->ff_acl = acl; in fs_walk()
1971 req->lr_resp.rwalk.nwqid = (uint16_t)i; in fs_walk()
1973 if (file != NULL && acl != file->ff_acl) in fs_walk()
1978 static int
1985 file = req->lr_fid->lo_aux; in fs_write()
1988 if (sc->fs_readonly) in fs_write()
1991 size_t niov = l9p_truncate_iov(req->lr_data_iov, in fs_write()
1992 req->lr_data_niov, req->lr_req.io.count); in fs_write()
1995 ret = pwritev(file->ff_fd, req->lr_data_iov, niov, in fs_write()
1996 req->lr_req.io.offset); in fs_write()
1999 if (lseek(file->ff_fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0) in fs_write()
2002 ret = writev(file->ff_fd, req->lr_data_iov, in fs_write()
2009 req->lr_resp.io.count = (uint32_t)ret; in fs_write()
2013 static int
2017 struct l9p_stat *l9stat = &req->lr_req.twstat.stat; in fs_wstat()
2022 fid = req->lr_fid; in fs_wstat()
2023 file = fid->lo_aux; in fs_wstat()
2038 if (sc->fs_readonly) in fs_wstat()
2041 if (l9stat->atime != (uint32_t)~0) { in fs_wstat()
2045 if (l9stat->mtime != (uint32_t)~0) { in fs_wstat()
2049 if (l9stat->dev != (uint32_t)~0) { in fs_wstat()
2054 if (l9stat->length != (uint64_t)~0) { in fs_wstat()
2055 if (file->ff_dir != NULL) { in fs_wstat()
2060 if (truncate(file->ff_name, (off_t)l9stat->length) != 0) { in fs_wstat()
2066 if (req->lr_conn->lc_version >= L9P_2000U) { in fs_wstat()
2067 if (fchownat(file->ff_dirfd, file->ff_name, l9stat->n_uid, in fs_wstat()
2068 l9stat->n_gid, AT_SYMLINK_NOFOLLOW) != 0) { in fs_wstat()
2074 if (l9stat->mode != (uint32_t)~0) { in fs_wstat()
2075 if (fchmodat(file->ff_dirfd, file->ff_name, in fs_wstat()
2076 l9stat->mode & 0777, 0) != 0) { in fs_wstat()
2082 if (strlen(l9stat->name) > 0) { in fs_wstat()
2089 * Rename-within-directory: it's not deleting anything, in fs_wstat()
2096 parent_acl = getacl(file, -1, newname); in fs_wstat()
2098 parent_acl, &st, NULL, NULL, file->ff_ai, (gid_t)-1); in fs_wstat()
2102 error = fs_dpf(newname, l9stat->name, sizeof(newname)); in fs_wstat()
2110 if (renameat(file->ff_dirfd, file->ff_name, file->ff_dirfd, in fs_wstat()
2116 /* Successful rename, update file->ff_name. ACL can stay. */ in fs_wstat()
2117 free(file->ff_name); in fs_wstat()
2118 file->ff_name = tmp; in fs_wstat()
2124 static int
2134 file = req->lr_fid->lo_aux; in fs_statfs()
2137 if (fstatat(file->ff_dirfd, file->ff_name, &st, in fs_statfs()
2147 file->ff_acl, &st, file->ff_ai, (gid_t)-1); in fs_statfs()
2151 fd = openat(file->ff_dirfd, file->ff_name, 0); in fs_statfs()
2162 if (name_max == -1) in fs_statfs()
2165 dostatfs(&req->lr_resp.rstatfs.statfs, &f, name_max); in fs_statfs()
2170 static int
2173 struct l9p_fid *fid = req->lr_fid; in fs_lopen()
2179 error = fs_oflags_dotl(req->lr_req.tlopen.flags, &flags, &p9); in fs_lopen()
2183 gid = req->lr_req.tlopen.gid; in fs_lopen()
2188 generate_qid(&st, &req->lr_resp.rlopen.qid); in fs_lopen()
2189 req->lr_resp.rlopen.iounit = req->lr_conn->lc_max_io_size; in fs_lopen()
2193 static int
2204 dir = req->lr_fid; in fs_lcreate()
2205 name = req->lr_req.tlcreate.name; in fs_lcreate()
2207 error = fs_oflags_dotl(req->lr_req.tlcreate.flags, &flags, &p9); in fs_lcreate()
2211 perm = (mode_t)req->lr_req.tlcreate.mode & 0777; /* ? set-id bits? */ in fs_lcreate()
2212 gid = req->lr_req.tlcreate.gid; in fs_lcreate()
2215 generate_qid(&st, &req->lr_resp.rlcreate.qid); in fs_lcreate()
2216 req->lr_resp.rlcreate.iounit = req->lr_conn->lc_max_io_size; in fs_lcreate()
2220 static int
2229 dir = req->lr_fid; in fs_symlink()
2230 name = req->lr_req.tsymlink.name; in fs_symlink()
2231 symtgt = req->lr_req.tsymlink.symtgt; in fs_symlink()
2232 gid = req->lr_req.tsymlink.gid; in fs_symlink()
2235 generate_qid(&st, &req->lr_resp.rsymlink.qid); in fs_symlink()
2239 static int
2250 dir = req->lr_fid; in fs_mknod()
2251 name = req->lr_req.tmknod.name; in fs_mknod()
2252 mode = req->lr_req.tmknod.mode; in fs_mknod()
2253 gid = req->lr_req.tmknod.gid; in fs_mknod()
2259 major = req->lr_req.tmknod.major; in fs_mknod()
2260 minor = req->lr_req.tmknod.major; in fs_mknod()
2281 generate_qid(&st, &req->lr_resp.rmknod.qid); in fs_mknod()
2285 static int
2300 if (sc->fs_readonly) in fs_rename()
2310 fid = req->lr_fid; in fs_rename()
2311 file = fid->lo_aux; in fs_rename()
2313 ai = file->ff_ai; in fs_rename()
2319 f2 = req->lr_fid2; in fs_rename()
2320 f2ff = f2->lo_aux; in fs_rename()
2323 reparenting = strcmp(olddir, f2ff->ff_name) != 0; in fs_rename()
2328 if (fstatat(file->ff_dirfd, file->ff_name, &cst, in fs_rename()
2337 oparent_acl = getacl(file, -1, olddir); in fs_rename()
2339 oparent_acl, &opst, file->ff_acl, &cst, ai, (gid_t)-1); in fs_rename()
2348 * for dir write permission if not reparenting -- but that's just in fs_rename()
2349 * add-file/add-subdir, which means doing this always.) in fs_rename()
2351 if (fstatat(f2ff->ff_dirfd, f2ff->ff_name, &npst, in fs_rename()
2356 error = check_access(op, f2ff->ff_acl, &npst, NULL, NULL, in fs_rename()
2357 ai, (gid_t)-1); in fs_rename()
2363 * f2ff->ff_name cannot exceed MAXPATHLEN, but out of general in fs_rename()
2366 if (strlcpy(newname, f2ff->ff_name, sizeof(newname)) >= sizeof(newname)) in fs_rename()
2368 error = fs_dpf(newname, req->lr_req.trename.name, sizeof(newname)); in fs_rename()
2375 if (renameat(file->ff_dirfd, file->ff_name, file->ff_dirfd, tmp) != 0) { in fs_rename()
2382 free(file->ff_name); in fs_rename()
2383 file->ff_name = tmp; in fs_rename()
2389 static int
2397 file = req->lr_fid->lo_aux; in fs_readlink()
2400 linklen = readlinkat(file->ff_dirfd, file->ff_name, buf, sizeof(buf)); in fs_readlink()
2405 else if ((req->lr_resp.rreadlink.target = strndup(buf, in fs_readlink()
2411 static int
2419 file = req->lr_fid->lo_aux; in fs_getattr()
2423 if (fstatat(file->ff_dirfd, file->ff_name, &st, AT_SYMLINK_NOFOLLOW)) { in fs_getattr()
2427 /* ?? Can we provide items not-requested? If so, can skip tests. */ in fs_getattr()
2428 mask = req->lr_req.tgetattr.request_mask; in fs_getattr()
2431 req->lr_resp.rgetattr.mode = st.st_mode; in fs_getattr()
2435 req->lr_resp.rgetattr.nlink = st.st_nlink; in fs_getattr()
2439 /* provide st_uid, or file->ff_uid? */ in fs_getattr()
2440 req->lr_resp.rgetattr.uid = st.st_uid; in fs_getattr()
2444 /* provide st_gid, or file->ff_gid? */ in fs_getattr()
2445 req->lr_resp.rgetattr.gid = st.st_gid; in fs_getattr()
2450 req->lr_resp.rgetattr.rdev = (uint64_t)st.st_rdev; in fs_getattr()
2454 req->lr_resp.rgetattr.atime_sec = in fs_getattr()
2456 req->lr_resp.rgetattr.atime_nsec = in fs_getattr()
2461 req->lr_resp.rgetattr.mtime_sec = in fs_getattr()
2463 req->lr_resp.rgetattr.mtime_nsec = in fs_getattr()
2468 req->lr_resp.rgetattr.ctime_sec = in fs_getattr()
2470 req->lr_resp.rgetattr.ctime_nsec = in fs_getattr()
2476 req->lr_resp.rgetattr.btime_sec = in fs_getattr()
2478 req->lr_resp.rgetattr.btime_nsec = in fs_getattr()
2481 req->lr_resp.rgetattr.btime_sec = 0; in fs_getattr()
2482 req->lr_resp.rgetattr.btime_nsec = 0; in fs_getattr()
2489 req->lr_resp.rgetattr.size = (uint64_t)st.st_size; in fs_getattr()
2493 req->lr_resp.rgetattr.blksize = (uint64_t)st.st_blksize; in fs_getattr()
2494 req->lr_resp.rgetattr.blocks = (uint64_t)st.st_blocks; in fs_getattr()
2498 req->lr_resp.rgetattr.gen = st.st_gen; in fs_getattr()
2503 generate_qid(&st, &req->lr_resp.rgetattr.qid); in fs_getattr()
2505 req->lr_resp.rgetattr.valid = valid; in fs_getattr()
2512 static int
2523 file = req->lr_fid->lo_aux; in fs_setattr()
2526 if (sc->fs_readonly) in fs_setattr()
2532 mask = req->lr_req.tsetattr.valid; in fs_setattr()
2534 if (fstatat(file->ff_dirfd, file->ff_name, &st, AT_SYMLINK_NOFOLLOW)) { in fs_setattr()
2545 if (fchmodat(file->ff_dirfd, file->ff_name, in fs_setattr()
2546 req->lr_req.tsetattr.mode & 0777, in fs_setattr()
2555 ? req->lr_req.tsetattr.uid in fs_setattr()
2556 : (uid_t)-1; in fs_setattr()
2559 ? req->lr_req.tsetattr.gid in fs_setattr()
2560 : (gid_t)-1; in fs_setattr()
2562 if (fchownat(file->ff_dirfd, file->ff_name, uid, gid, in fs_setattr()
2571 int fd = openat(file->ff_dirfd, file->ff_name, O_RDWR); in fs_setattr()
2572 if (ftruncate(fd, (off_t)req->lr_req.tsetattr.size)) { in fs_setattr()
2588 ts[0].tv_sec = req->lr_req.tsetattr.atime_sec; in fs_setattr()
2589 ts[0].tv_nsec = req->lr_req.tsetattr.atime_nsec; in fs_setattr()
2600 ts[1].tv_sec = req->lr_req.tsetattr.mtime_sec; in fs_setattr()
2601 ts[1].tv_nsec = req->lr_req.tsetattr.mtime_nsec; in fs_setattr()
2610 if (utimensat(file->ff_dirfd, file->ff_name, ts, in fs_setattr()
2620 static int
2626 static int
2632 static int
2643 file = req->lr_fid->lo_aux; in fs_readdir()
2646 if (file->ff_dir == NULL) in fs_readdir()
2649 pthread_mutex_lock(&file->ff_mtx); in fs_readdir()
2655 * client(s) use the zero-offset thing to rescan without in fs_readdir()
2662 if (req->lr_req.io.offset == 0) in fs_readdir()
2663 rewinddir(file->ff_dir); in fs_readdir()
2665 seekdir(file->ff_dir, (long)req->lr_req.io.offset); in fs_readdir()
2669 while ((dp = readdir(file->ff_dir)) != NULL) { in fs_readdir()
2679 * TODO: we do a full lstat here; could use dp->d_* in fs_readdir()
2681 * as dp->d_type != DT_UNKNOWN. in fs_readdir()
2683 if (fs_lstatat(file, dp->d_name, &st)) in fs_readdir()
2688 de.offset = (uint64_t)telldir(file->ff_dir); in fs_readdir()
2689 de.type = dp->d_type; in fs_readdir()
2690 de.name = dp->d_name; in fs_readdir()
2698 pthread_mutex_unlock(&file->ff_mtx); in fs_readdir()
2699 req->lr_resp.io.count = count; in fs_readdir()
2703 static int
2709 file = req->lr_fid->lo_aux; in fs_fsync()
2711 if (fsync(file->ff_dir != NULL ? dirfd(file->ff_dir) : file->ff_fd)) in fs_fsync()
2716 static int
2720 switch (req->lr_req.tlock.type) { in fs_lock()
2729 req->lr_resp.rlock.status = L9PL_LOCK_SUCCESS; in fs_lock()
2733 static int
2740 * op is useless. QEMU simply says "unlocked!", so we do in fs_getlock()
2743 switch (req->lr_req.getlock.type) { in fs_getlock()
2752 req->lr_resp.getlock = req->lr_req.getlock; in fs_getlock()
2753 req->lr_resp.getlock.type = L9PL_LOCK_TYPE_UNLOCK; in fs_getlock()
2754 req->lr_resp.getlock.client_id = strdup(""); /* XXX what should go here? */ in fs_getlock()
2758 static int
2771 dir = req->lr_fid2; in fs_link()
2772 dirf = dir->lo_aux; in fs_link()
2775 name = req->lr_req.tlink.name; in fs_link()
2780 file = req->lr_fid->lo_aux; in fs_link()
2783 if (fstatat(dirf->ff_dirfd, dirf->ff_name, &tdst, AT_SYMLINK_NOFOLLOW) != 0 || in fs_link()
2784 fstatat(file->ff_dirfd, file->ff_name, &fst, AT_SYMLINK_NOFOLLOW) != 0) in fs_link()
2791 dirf->ff_acl, &tdst, NULL, NULL, file->ff_ai, (gid_t)-1); in fs_link()
2795 if (linkat(file->ff_dirfd, file->ff_name, file->ff_dirfd, in fs_link()
2804 static int
2814 dir = req->lr_fid; in fs_mkdir()
2815 name = req->lr_req.tmkdir.name; in fs_mkdir()
2816 perm = (mode_t)req->lr_req.tmkdir.mode; in fs_mkdir()
2817 gid = req->lr_req.tmkdir.gid; in fs_mkdir()
2821 generate_qid(&st, &req->lr_resp.rmkdir.qid); in fs_mkdir()
2825 static int
2839 if (sc->fs_readonly) in fs_renameat()
2842 olddir = req->lr_fid; in fs_renameat()
2843 newdir = req->lr_fid2; in fs_renameat()
2845 off = olddir->lo_aux; in fs_renameat()
2846 nff = newdir->lo_aux; in fs_renameat()
2849 onp = req->lr_req.trenameat.oldname; in fs_renameat()
2850 nnp = req->lr_req.trenameat.newname; in fs_renameat()
2857 if (fstatat(off->ff_dirfd, onb, &fst, AT_SYMLINK_NOFOLLOW) != 0) in fs_renameat()
2861 strcmp(off->ff_name, nff->ff_name) != 0; in fs_renameat()
2863 if (fstatat(off->ff_dirfd, off->ff_name, &odst, AT_SYMLINK_NOFOLLOW) != 0) in fs_renameat()
2870 if (fstatat(nff->ff_dirfd, nff->ff_name, &ndst, AT_SYMLINK_NOFOLLOW) != 0) in fs_renameat()
2874 facl = getacl(off, -1, onb); in fs_renameat()
2878 off->ff_acl, &odst, facl, &fst, off->ff_ai, (gid_t)-1); in fs_renameat()
2885 nff->ff_acl, &ndst, NULL, NULL, nff->ff_ai, (gid_t)-1); in fs_renameat()
2890 if (renameat(off->ff_dirfd, onb, nff->ff_dirfd, nnb)) in fs_renameat()
2900 static int
2912 if (sc->fs_readonly) in fs_unlinkat()
2915 dir = req->lr_fid; in fs_unlinkat()
2916 dirff = dir->lo_aux; in fs_unlinkat()
2918 name = req->lr_req.tunlinkat.name; in fs_unlinkat()
2922 if (fstatat(dirff->ff_dirfd, newname, &fst, AT_SYMLINK_NOFOLLOW) != 0 || in fs_unlinkat()
2923 fstatat(dirff->ff_dirfd, dirff->ff_name, &dirst, AT_SYMLINK_NOFOLLOW) != 0) in fs_unlinkat()
2926 facl = getacl(dirff, -1, newname); in fs_unlinkat()
2928 dirff->ff_acl, &dirst, facl, &fst, dirff->ff_ai, (gid_t)-1); in fs_unlinkat()
2933 if (req->lr_req.tunlinkat.flags & L9PL_AT_REMOVEDIR) { in fs_unlinkat()
2934 if (unlinkat(dirff->ff_dirfd, newname, AT_REMOVEDIR) != 0) in fs_unlinkat()
2937 if (unlinkat(dirff->ff_dirfd, newname, 0) != 0) in fs_unlinkat()
2943 static void
2946 struct fs_fid *f = fid->lo_aux; in fs_freefid()
2955 if (f->ff_fd != -1) in fs_freefid()
2956 close(f->ff_fd); in fs_freefid()
2958 if (f->ff_dir) in fs_freefid()
2959 closedir(f->ff_dir); in fs_freefid()
2961 pthread_mutex_destroy(&f->ff_mtx); in fs_freefid()
2962 free(f->ff_name); in fs_freefid()
2963 ai = f->ff_ai; in fs_freefid()
2964 l9p_acl_free(f->ff_acl); in fs_freefid()
2966 pthread_mutex_lock(&ai->ai_mtx); in fs_freefid()
2967 newcount = --ai->ai_refcnt; in fs_freefid()
2968 pthread_mutex_unlock(&ai->ai_mtx); in fs_freefid()
2975 pthread_mutex_destroy(&ai->ai_mtx); in fs_freefid()
2997 return (-1); in l9p_backend_fs_init()
3003 backend->attach = fs_attach; in l9p_backend_fs_init()
3004 backend->clunk = fs_clunk; in l9p_backend_fs_init()
3005 backend->create = fs_create; in l9p_backend_fs_init()
3006 backend->open = fs_open; in l9p_backend_fs_init()
3007 backend->read = fs_read; in l9p_backend_fs_init()
3008 backend->remove = fs_remove; in l9p_backend_fs_init()
3009 backend->stat = fs_stat; in l9p_backend_fs_init()
3010 backend->walk = fs_walk; in l9p_backend_fs_init()
3011 backend->write = fs_write; in l9p_backend_fs_init()
3012 backend->wstat = fs_wstat; in l9p_backend_fs_init()
3013 backend->statfs = fs_statfs; in l9p_backend_fs_init()
3014 backend->lopen = fs_lopen; in l9p_backend_fs_init()
3015 backend->lcreate = fs_lcreate; in l9p_backend_fs_init()
3016 backend->symlink = fs_symlink; in l9p_backend_fs_init()
3017 backend->mknod = fs_mknod; in l9p_backend_fs_init()
3018 backend->rename = fs_rename; in l9p_backend_fs_init()
3019 backend->readlink = fs_readlink; in l9p_backend_fs_init()
3020 backend->getattr = fs_getattr; in l9p_backend_fs_init()
3021 backend->setattr = fs_setattr; in l9p_backend_fs_init()
3022 backend->xattrwalk = fs_xattrwalk; in l9p_backend_fs_init()
3023 backend->xattrcreate = fs_xattrcreate; in l9p_backend_fs_init()
3024 backend->readdir = fs_readdir; in l9p_backend_fs_init()
3025 backend->fsync = fs_fsync; in l9p_backend_fs_init()
3026 backend->lock = fs_lock; in l9p_backend_fs_init()
3027 backend->getlock = fs_getlock; in l9p_backend_fs_init()
3028 backend->link = fs_link; in l9p_backend_fs_init()
3029 backend->mkdir = fs_mkdir; in l9p_backend_fs_init()
3030 backend->renameat = fs_renameat; in l9p_backend_fs_init()
3031 backend->unlinkat = fs_unlinkat; in l9p_backend_fs_init()
3032 backend->freefid = fs_freefid; in l9p_backend_fs_init()
3035 sc->fs_rootfd = rootfd; in l9p_backend_fs_init()
3036 sc->fs_readonly = ro; in l9p_backend_fs_init()
3037 backend->softc = sc; in l9p_backend_fs_init()
3042 return (-1); in l9p_backend_fs_init()
3044 sc->fs_cappwd = cap_service_open(capcas, "system.pwd"); in l9p_backend_fs_init()
3045 if (sc->fs_cappwd == NULL) in l9p_backend_fs_init()
3046 return (-1); in l9p_backend_fs_init()
3048 sc->fs_capgrp = cap_service_open(capcas, "system.grp"); in l9p_backend_fs_init()
3049 if (sc->fs_capgrp == NULL) in l9p_backend_fs_init()
3050 return (-1); in l9p_backend_fs_init()
3052 cap_setpassent(sc->fs_cappwd, 1); in l9p_backend_fs_init()
3053 cap_setgroupent(sc->fs_capgrp, 1); in l9p_backend_fs_init()