Npfcall* diod_lcreate(Npfid *fid, Npstr *name, u32 flags, u32 mode, u32 gid) { Fid *f = fid->aux; Npfcall *ret = NULL; char *npath = NULL; Npqid qid; int fd = -1; struct stat sb; mode_t saved_umask; int created = 0; u32 iounit = 0; /* client will use msize-P9_IOHDRSZ */ if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(flags & O_CREAT)) /* can't happen? */ flags |= O_CREAT; if (!(npath = _mkpath(f->path, name))) { np_uerror (ENOMEM); goto error; } saved_umask = umask(0); if ((fd = open (npath, flags, mode)) < 0) { np_uerror (errno); goto error_quiet; } created = 1; umask(saved_umask); if (fstat (fd, &sb) < 0) { np_uerror (errno); goto error; /* shouldn't happen? */ } _ustat2qid (&sb, &qid); //iounit = sb.st_blksize; if (!((ret = np_create_rlcreate (&qid, iounit)))) { np_uerror (ENOMEM); goto error; } free (f->path); f->path = npath; f->fd = fd; return ret; error: errn (np_rerror (), "diod_lcreate %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, name->len, name->str); error_quiet: if (fd >= 0) { (void)close (fd); } if (created && npath) (void)unlink (npath); if (npath) free (npath); if (ret) free (ret); return NULL; }
Npfcall* diod_symlink(Npfid *fid, Npstr *name, Npstr *symtgt, u32 gid) { Fid *f = fid->aux; Npfcall *ret = NULL; char *target = NULL, *npath = NULL; Npqid qid; struct stat sb; mode_t saved_umask; int created = 0; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = _mkpath(f->path, name))) { np_uerror (ENOMEM); goto error; } if (!(target = np_strdup (symtgt))) { np_uerror (ENOMEM); goto error; } saved_umask = umask(0); if (symlink (target, npath) < 0) { np_uerror (errno); goto error_quiet; } created = 1; umask(saved_umask); if (lstat (npath, &sb) < 0) { np_uerror (errno); goto error; /* shouldn't happen? */ } _ustat2qid (&sb, &qid); if (!((ret = np_create_rsymlink (&qid)))) { np_uerror (ENOMEM); goto error; } free (npath); free (target); return ret; error: errn (np_rerror (), "diod_symlink %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, name->len, name->str); error_quiet: if (created && npath) (void)unlink (npath); if (npath) free (npath); if (target) free (target); if (ret) free (ret); return NULL; }
Npfcall* diod_lopen (Npfid *fid, u32 flags) { Fid *f = fid->aux; Npfcall *res = NULL; Npqid qid; u32 iounit = 0; /* client will use msize-P9_IOHDRSZ */ if ((f->xflags & XFLAGS_RO) && ((flags & O_WRONLY) || (flags & O_RDWR))) { np_uerror (EROFS); goto error_quiet; } if ((flags & O_CREAT)) /* can't happen? */ flags &= ~O_CREAT; /* clear and allow to fail with ENOENT */ if (_fidstat (f) < 0) goto error_quiet; if (S_ISDIR (f->stat.st_mode)) { f->dir = opendir (f->path); if (!f->dir) { np_uerror (errno); goto error_quiet; } } else { f->fd = open (f->path, flags); if (f->fd < 0) { np_uerror (errno); goto error_quiet; } } if (_fidstat (f) < 0) goto error; /* can't happen? */ _ustat2qid (&f->stat, &qid); //iounit = f->stat.st_blksize; if (!(res = np_create_rlopen (&qid, iounit))) { np_uerror (ENOMEM); goto error; } return res; error: errn (np_rerror (), "diod_lopen %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: if (f->dir) { (void)closedir (f->dir); f->dir = NULL; } if (f->fd != -1) { (void)close (f->fd); f->fd = -1; } if (res) free (res); return NULL; }
Npfcall* diod_lopen (Npfid *fid, u32 flags) { Fid *f = fid->aux; Npfcall *res; Npqid qid; u32 iounit = 0; /* if iounit is 0, v9fs will use msize-P9_IOHDRSZ */ struct stat sb; if ((f->xflags & XFLAGS_RO) && ((flags & O_WRONLY) || (flags & O_RDWR))) { np_uerror (EROFS); goto error_quiet; } if ((flags & O_CREAT)) /* can't happen? */ flags &= ~O_CREAT; /* clear and allow to fail with ENOENT */ f->fd = open (f->path, flags); if (f->fd < 0) { np_uerror (errno); goto error_quiet; } f->dir = fdopendir (f->fd); if (!f->dir && errno != ENOTDIR) { np_uerror (errno); goto error_quiet; } if (fstat (f->fd, &sb) < 0) { np_uerror (errno); goto error_quiet; } _ustat2qid (&sb, &qid); //iounit = sb.st_blksize; if (!(res = np_create_rlopen (&qid, iounit))) { np_uerror (ENOMEM); goto error; } return res; error: errn (np_rerror (), "diod_lopen %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: if (f->dir) (void)closedir (f->dir); else if (f->fd != -1) (void)close (f->fd); f->dir = NULL; f->fd = -1; return NULL; }
/* Tattach - attach a new user (fid->user) to aname. * diod_auth.c::diod_checkauth first authenticates/authorizes user */ Npfcall* diod_attach (Npfid *fid, Npfid *afid, Npstr *aname) { Npfcall* ret = NULL; Fid *f = NULL; Npqid qid; struct stat sb; if (aname->len == 0 || *aname->str != '/') { np_uerror (EPERM); goto error; } if (!(f = _fidalloc ()) || !(f->path = np_strdup (aname))) { np_uerror (ENOMEM); goto error; } if (diod_conf_opt_runasuid ()) { if (fid->user->uid != diod_conf_get_runasuid ()) { np_uerror (EPERM); goto error; } } if (!diod_match_exports (f->path, fid->conn, fid->user, &f->xflags)) goto error; if (stat (f->path, &sb) < 0) { /* OK to follow symbolic links */ np_uerror (errno); goto error; } if (!S_ISDIR (sb.st_mode)) { np_uerror (ENOTDIR); goto error; } _ustat2qid (&sb, &qid); if ((ret = np_create_rattach (&qid)) == NULL) { np_uerror (ENOMEM); goto error; } fid->aux = f; np_fid_incref (fid); return ret; error: errn (np_rerror (), "diod_attach %s@%s:%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), aname->len, aname->str); if (f) _fidfree (f); return NULL; }
Npfcall* diod_getattr(Npfid *fid, u64 request_mask) { Fid *f = fid->aux; Npfcall *ret; Npqid qid; struct stat sb; if (f->mountpt) { if (_statmnt (f->path, &sb) < 0) { np_uerror (errno); goto error_quiet; } } else { if (lstat (f->path, &sb) < 0) { np_uerror (errno); goto error_quiet; } } _ustat2qid (&sb, &qid); if (!(ret = np_create_rgetattr(request_mask, &qid, sb.st_mode, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_rdev, sb.st_size, sb.st_blksize, sb.st_blocks, sb.st_atim.tv_sec, sb.st_atim.tv_nsec, sb.st_mtim.tv_sec, sb.st_mtim.tv_nsec, sb.st_ctim.tv_sec, sb.st_ctim.tv_nsec, 0, 0, 0, 0))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_getattr %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: return NULL; }
/* Twalk - walk a file path * Called from fcall.c::np_walk () on each wname component in succession. * On error, call np_uerror () and return 0. */ int diod_walk (Npfid *fid, Npstr* wname, Npqid *wqid) { Fid *f = fid->aux; struct stat sb, sb2; char *npath = NULL; if (f->mountpt) { np_uerror (ENOENT); goto error_quiet; } if (!(npath = _mkpath (f->path, wname))) { np_uerror (ENOMEM); goto error; } if (lstat (npath, &sb) < 0) { np_uerror (errno); goto error_quiet; } if (lstat (f->path, &sb2) < 0) { np_uerror (errno); goto error; } if (sb.st_dev != sb2.st_dev) { if (_statmnt (npath, &sb) < 0) goto error; f->mountpt = 1; } free (f->path); f->path = npath; _ustat2qid (&sb, wqid); return 1; error: errn (np_rerror (), "diod_walk %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, wname->len, wname->str); error_quiet: if (npath) free (npath); return 0; }
/* Twalk - walk a file path * Called from fcall.c::np_walk () on each wname component in succession. * On error, call np_uerror () and return 0. */ int diod_walk (Npfid *fid, Npstr* wname, Npqid *wqid) { Fid *f = fid->aux; struct stat st; char *npath; if (!(npath = _mkpath (f->path, wname))) { np_uerror (ENOMEM); goto error; } if (lstat (npath, &st) < 0) { np_uerror (errno); goto error_quiet; } /* N.B. inodes would not be unique if we could cross over to another * file system. But with the code below, ls -l returns ??? for mount * point dirs, which would otherwise have a "foreign" inode number. * How does NFS make them appear as empty directories? That would be * prettier. */ if (_fidstat (f) < 0) goto error; if (st.st_dev != f->stat.st_dev) { np_uerror (EXDEV); goto error; } free (f->path); f->path = npath; _ustat2qid (&st, wqid); return 1; error: errn (np_rerror (), "diod_walk %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, wname->len, wname->str); error_quiet: if (npath) free (npath); return 0; }
Npfcall* diod_mknod(Npfid *fid, Npstr *name, u32 mode, u32 major, u32 minor, u32 gid) { Npfcall *ret; Fid *f = fid->aux; char *npath = NULL; Npqid qid; struct stat sb; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = _mkpath(f->path, name))) { np_uerror (ENOMEM); goto error; } if (mknod (npath, mode, makedev (major, minor)) < 0 || lstat (npath, &sb) < 0) { np_uerror (errno); goto error_quiet; } _ustat2qid (&sb, &qid); if (!((ret = np_create_rmknod (&qid)))) { (void)unlink (npath); np_uerror (ENOMEM); goto error; } free (npath); return ret; error: errn (np_rerror (), "diod_mknod %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, name->len, name->str); error_quiet: if (npath) free (npath); return NULL; }
Npfcall* diod_getattr(Npfid *fid, u64 request_mask) { Fid *f = fid->aux; Npfcall *ret = NULL; Npqid qid; if (_fidstat (f) < 0) goto error_quiet; _ustat2qid (&f->stat, &qid); if (!(ret = np_create_rgetattr(request_mask, &qid, f->stat.st_mode, f->stat.st_uid, f->stat.st_gid, f->stat.st_nlink, f->stat.st_rdev, f->stat.st_size, f->stat.st_blksize, f->stat.st_blocks, f->stat.st_atim.tv_sec, f->stat.st_atim.tv_nsec, f->stat.st_mtim.tv_sec, f->stat.st_mtim.tv_nsec, f->stat.st_ctim.tv_sec, f->stat.st_ctim.tv_nsec, 0, 0, 0, 0))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_getattr %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: if (ret) free (ret); return NULL; }
static u32 _copy_dirent_linux (Fid *f, u8 *buf, u32 buflen) { Npqid qid; u32 ret = 0; if (f->dirent->d_type == DT_UNKNOWN) { char path[PATH_MAX + 1]; struct stat sb; snprintf (path, sizeof(path), "%s/%s", f->path, f->dirent->d_name); if (lstat (path, &sb) < 0) { np_uerror (errno); goto done; } _ustat2qid (&sb, &qid); } else { _dirent2qid (f->dirent, &qid); } ret = np_serialize_p9dirent(&qid, f->dirent->d_off, f->dirent->d_type, f->dirent->d_name, buf, buflen); done: return ret; }