Npfcall* diod_readlink(Npfid *fid) { Fid *f = fid->aux; Npfcall *ret; char target[PATH_MAX + 1]; int n; if ((n = readlink (path_s (f->path), target, sizeof(target) - 1)) < 0) { np_uerror (errno); goto error_quiet; } target[n] = '\0'; if (!(ret = np_create_rreadlink(target))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_readlink %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: return NULL; }
int xattr_close (Npfid *fid) { Fid *f = fid->aux; int rc = 0; if (f->xattr) { if ((f->xattr->flags & XATTR_FLAGS_SET)) { if (f->xattr->len > 0) { if (lsetxattr (path_s (f->path), f->xattr->name, f->xattr->buf, f->xattr->len, f->xattr->setflags) < 0) { np_uerror (errno); rc = -1; } } else if (f->xattr->len == 0) { if (lremovexattr (path_s (f->path), f->xattr->name) < 0) { np_uerror (errno); rc = -1; } } } _xattr_destroy (&f->xattr); } return rc; }
/* Tremove - remove a file or directory. */ Npfcall* diod_remove (Npfid *fid) { Fid *f = fid->aux; Npfcall *ret; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (remove (path_s (f->path)) < 0) { np_uerror (errno); goto error_quiet; } if (!(ret = np_create_rremove ())) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_remove %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: return NULL; }
/* Tstatfs - read file system information. */ Npfcall* diod_statfs (Npfid *fid) { Fid *f = fid->aux; struct statfs sb; Npfcall *ret; u64 fsid; u32 type = V9FS_MAGIC; if (statfs (path_s (f->path), &sb) < 0) { np_uerror (errno); goto error; } fsid = (u64)sb.f_fsid.__val[0] | ((u64)sb.f_fsid.__val[1] << 32); if (diod_conf_get_statfs_passthru ()) type = sb.f_type; if (!(ret = np_create_rstatfs(type, sb.f_bsize, sb.f_blocks, sb.f_bfree, sb.f_bavail, sb.f_files, sb.f_ffree, fsid, sb.f_namelen))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_statfs %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); return NULL; }
Npfcall* diod_lcreate(Npfid *fid, Npstr *name, u32 flags, u32 mode, u32 gid) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; Npfcall *ret; Path opath = NULL; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } flags = _remap_oflags (flags); if (flags & O_DIRECT) { np_uerror (EINVAL); /* O_DIRECT not allowed - see issue 110 */ goto error_quiet; } if (!(flags & O_CREAT)) /* can't happen? */ flags |= O_CREAT; if (f->ioctx != NULL) { msg ("diod_lcreate: fid is already open"); np_uerror (EINVAL); goto error; } opath = f->path; if (!(f->path = path_append (srv, opath, name))) { np_uerror (ENOMEM); goto error; } if (ioctx_open (fid, flags, mode) < 0) { if (np_rerror () == ENOMEM) goto error; goto error_quiet; } if (!((ret = np_create_rlcreate (ioctx_qid (f->ioctx), ioctx_iounit (f->ioctx))))) { (void)ioctx_close (fid, 0); (void)unlink (path_s (f->path)); np_uerror (ENOMEM); goto error; } path_decref (srv, opath); return ret; error: errn (np_rerror (), "diod_lcreate %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), opath ? path_s (opath) : path_s (f->path), name->len, name->str); error_quiet: if (opath) { if (f->path) path_decref (srv, f->path); f->path = opath; } 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; int xflags; if (aname->len == 0 || *aname->str != '/') { np_uerror (EPERM); goto error; } if (!(f = diod_fidalloc (fid, 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 (path_s (f->path), fid->conn, fid->user, &xflags)) goto error; if ((xflags & XFLAGS_RO)) f->flags |= DIOD_FID_FLAGS_ROFS; if ((xflags & XFLAGS_SHAREFD)) f->flags |= DIOD_FID_FLAGS_SHAREFD; if (stat (path_s (f->path), &sb) < 0) { /* OK to follow symbolic links */ np_uerror (errno); goto error; } /* N.B. removed S_ISDIR (sb.st_mode) || return ENOTDIR check. * Allow a regular file or a blcok device to be exported. */ diod_ustat2qid (&sb, &qid); if ((ret = np_create_rattach (&qid)) == NULL) { np_uerror (ENOMEM); goto error; } 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); diod_fiddestroy (fid); return NULL; }
Npfcall* diod_symlink(Npfid *fid, Npstr *name, Npstr *symtgt, u32 gid) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; Npfcall *ret; char *target = NULL; Path npath = NULL; Npqid qid; struct stat sb; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, f->path, name))) { np_uerror (ENOMEM); goto error; } if (!(target = np_strdup (symtgt))) { np_uerror (ENOMEM); goto error; } if (symlink (target, path_s (npath)) < 0 || lstat (path_s (npath), &sb) < 0) { np_uerror (errno); goto error_quiet; } diod_ustat2qid (&sb, &qid); if (!((ret = np_create_rsymlink (&qid)))) { (void)unlink (path_s (npath)); np_uerror (ENOMEM); goto error; } path_decref (srv, 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), path_s (f->path), name->len, name->str); error_quiet: if (npath) path_decref (srv, npath); if (target) free (target); return NULL; }
char * diod_get_path (Npfid *fid) { Fid *f = fid->aux; return f ? path_s (f->path) : NULL; }
/* Twrite - write to a file. */ Npfcall* diod_write (Npfid *fid, u64 offset, u32 count, u8 *data, Npreq *req) { Fid *f = fid->aux; Npfcall *ret; ssize_t n; if (!f->ioctx) { msg ("diod_write: fid is not open"); np_uerror (EBADF); goto error; } if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if ((n = ioctx_pwrite (f->ioctx, data, count, offset)) < 0) { np_uerror (errno); goto error_quiet; } if (!(ret = np_create_rwrite (n))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_write %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: return NULL; }
/* Tread - read from a file or directory. */ Npfcall* diod_read (Npfid *fid, u64 offset, u32 count, Npreq *req) { Fid *f = fid->aux; Npfcall *ret = NULL; ssize_t n; if (!f->ioctx) { msg ("diod_read: fid is not open"); np_uerror (EBADF); goto error; } if (!(ret = np_alloc_rread (count))) { np_uerror (ENOMEM); goto error; } n = ioctx_pread (f->ioctx, ret->u.rread.data, count, offset); if (n < 0) { np_uerror (errno); goto error_quiet; } np_set_rread_count (ret, n); return ret; error: errn (np_rerror (), "diod_read %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: if (ret) free (ret); return NULL; }
Npfcall* diod_readdir(Npfid *fid, u64 offset, u32 count, Npreq *req) { int n; Fid *f = fid->aux; Npfcall *ret; if (!f->ioctx) { msg ("diod_readdir: fid is not open"); np_uerror (EBADF); goto error; } if (!(ret = np_create_rreaddir (count))) { np_uerror (ENOMEM); goto error; } n = _read_dir_linux (f, ret->u.rreaddir.data, offset, count); if (np_rerror ()) { free (ret); ret = NULL; } else np_finalize_rreaddir (ret, n); return ret; error: errn (np_rerror (), "diod_readdir %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); return NULL; }
Npfcall* diod_fsync (Npfid *fid) { Fid *f = fid->aux; Npfcall *ret; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!f->ioctx) { msg ("diod_fsync: fid is not open"); np_uerror (EBADF); goto error; } if (ioctx_fsync (f->ioctx) < 0) { np_uerror (errno); goto error_quiet; } if (!((ret = np_create_rfsync ()))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_fsync %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: return NULL; }
Npfcall* diod_getattr(Npfid *fid, u64 request_mask) { Fid *f = fid->aux; Npfcall *ret; Npqid qid; struct stat sb; if ((f->flags & DIOD_FID_FLAGS_MOUNTPT)) { if (_statmnt (path_s (f->path), &sb) < 0) { np_uerror (errno); goto error_quiet; } } else { if (lstat (path_s (f->path), &sb) < 0) { np_uerror (errno); goto error_quiet; } } diod_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), path_s (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) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; struct stat sb, sb2; Path npath = NULL; if ((f->flags & DIOD_FID_FLAGS_MOUNTPT)) { np_uerror (ENOENT); goto error_quiet; } if (!(npath = path_append (srv, f->path, wname))) { np_uerror (ENOMEM); goto error; } if (lstat (path_s (npath), &sb) < 0) { np_uerror (errno); goto error_quiet; } if (lstat (path_s (f->path), &sb2) < 0) { np_uerror (errno); goto error; } if (sb.st_dev != sb2.st_dev) { if (_statmnt (path_s (npath), &sb) < 0) goto error; f->flags |= DIOD_FID_FLAGS_MOUNTPT; } path_decref (srv, f->path); f->path = npath; diod_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), path_s (f->path), wname->len, wname->str); error_quiet: if (npath) path_decref (srv, npath); return 0; }
/* Locking note: * Implement POSIX locks in terms of BSD flock locks. * This at least gets distributed whole-file locking to work. * Strategies for distributed record locking will deadlock. */ Npfcall* diod_lock (Npfid *fid, u8 type, u32 flags, u64 start, u64 length, u32 proc_id, Npstr *client_id) { Fid *f = fid->aux; Npfcall *ret; u8 status = P9_LOCK_ERROR; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (flags & ~P9_LOCK_FLAGS_BLOCK) { /* only one valid flag for now */ np_uerror (EINVAL); /* (which we ignore) */ goto error; } if (!f->ioctx) { msg ("diod_lock: fid is not open"); np_uerror (EBADF); goto error; } switch (type) { case P9_LOCK_TYPE_UNLCK: if (ioctx_flock (f->ioctx, LOCK_UN) == 0) status = P9_LOCK_SUCCESS; break; case P9_LOCK_TYPE_RDLCK: if (ioctx_flock (f->ioctx, LOCK_SH | LOCK_NB) == 0) status = P9_LOCK_SUCCESS; else if (errno == EWOULDBLOCK) status = P9_LOCK_BLOCKED; break; case P9_LOCK_TYPE_WRLCK: if (ioctx_flock (f->ioctx, LOCK_EX | LOCK_NB) == 0) status = P9_LOCK_SUCCESS; else if (errno == EWOULDBLOCK) status = P9_LOCK_BLOCKED; break; default: np_uerror (EINVAL); goto error; } if (!((ret = np_create_rlock (status)))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_lock %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: return NULL; }
Npfcall* diod_mknod(Npfid *fid, Npstr *name, u32 mode, u32 major, u32 minor, u32 gid) { Npsrv *srv = fid->conn->srv; Npfcall *ret; Fid *f = fid->aux; Path npath = NULL; Npqid qid; struct stat sb; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, f->path, name))) { np_uerror (ENOMEM); goto error; } if (mknod (path_s (npath), mode, makedev (major, minor)) < 0 || lstat (path_s (npath), &sb) < 0) { np_uerror (errno); goto error_quiet; } diod_ustat2qid (&sb, &qid); if (!((ret = np_create_rmknod (&qid)))) { (void)unlink (path_s (npath)); np_uerror (ENOMEM); goto error; } path_decref (srv, npath); return ret; error: errn (np_rerror (), "diod_mknod %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), name->len, name->str); error_quiet: if (npath) path_decref (srv, npath); return NULL; }
Npfcall* diod_link (Npfid *dfid, Npfid *fid, Npstr *name) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; Npfcall *ret; Fid *df = dfid->aux; Path npath = NULL; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, df->path, name))) { np_uerror (ENOMEM); goto error; } if (link (path_s (f->path), path_s (npath)) < 0) { np_uerror (errno); goto error_quiet; } if (!((ret = np_create_rlink ()))) { (void)unlink (path_s (npath)); np_uerror (ENOMEM); goto error; } path_decref (srv, npath); return ret; error: errn (np_rerror (), "diod_link %s@%s:%s %s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), path_s (df->path), name->len, name->str); error_quiet: if (npath) path_decref (srv, npath); return NULL; }
int xattr_open (Npfid *fid, Npstr *name, u64 *sizep) { Fid *f = fid->aux; assert (f->xattr == NULL); f->xattr = _xattr_create (name, 0, XATTR_FLAGS_GET, 0); if (_lgetxattr (f->xattr, path_s (f->path)) < 0) goto error; *sizep = (u64)f->xattr->len; return 0; error: _xattr_destroy (&f->xattr); return -1; }
/* Twalk - walk a file path * Called from fcall.c::np_walk () to clone the fid. * On error, call np_uerror () and return 0. */ int diod_clone (Npfid *fid, Npfid *newfid) { Fid *f = fid->aux; if (!(diod_fidclone (newfid, fid))) { np_uerror (ENOMEM); goto error; } return 1; error: errn (np_rerror (), "diod_clone %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); return 0; }
Npfcall* diod_lopen (Npfid *fid, u32 flags) { Fid *f = fid->aux; Npfcall *res; if ((f->flags & DIOD_FID_FLAGS_ROFS) && ((flags & O_WRONLY) || (flags & O_RDWR))) { np_uerror (EROFS); goto error_quiet; } flags = _remap_oflags (flags); if (flags & O_DIRECT) { np_uerror (EINVAL); /* O_DIRECT not allowed - see issue 110 */ goto error_quiet; } if ((flags & O_CREAT)) /* can't happen? */ flags &= ~O_CREAT; /* clear and allow to fail with ENOENT */ if (f->ioctx != NULL) { msg ("diod_lopen: fid is already open"); np_uerror (EINVAL); goto error; } if (ioctx_open (fid, flags, 0) < 0) { if (np_rerror () == ENOMEM) goto error; goto error_quiet; } if (!(res = np_create_rlopen (ioctx_qid (f->ioctx), ioctx_iounit (f->ioctx)))) { (void)ioctx_close (fid, 0); 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), path_s (f->path)); error_quiet: return NULL; }
Npfcall* diod_getlock (Npfid *fid, u8 type, u64 start, u64 length, u32 proc_id, Npstr *client_id) { Fid *f = fid->aux; Npfcall *ret; char *cid = NULL; int ftype; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!f->ioctx) { msg ("diod_getlock: fid is not open"); np_uerror (EBADF); goto error; } if (!(cid = np_strdup (client_id))) { np_uerror (ENOMEM); goto error; } if (type != P9_LOCK_TYPE_RDLCK && type != P9_LOCK_TYPE_WRLCK) { np_uerror (EINVAL); goto error; } ftype = (type == P9_LOCK_TYPE_RDLCK) ? LOCK_SH : LOCK_EX; ftype = ioctx_testlock (f->ioctx, ftype); type = (ftype == LOCK_EX) ? P9_LOCK_TYPE_WRLCK : P9_LOCK_TYPE_UNLCK; if (!((ret = np_create_rgetlock(type, start, length, proc_id, cid)))) { np_uerror (ENOMEM); goto error; } free (cid); return ret; error: errn (np_rerror (), "diod_getlock %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: if (cid) free (cid); return NULL; }
/* Tclunk - close a file. */ Npfcall* diod_clunk (Npfid *fid) { Fid *f = fid->aux; Npfcall *ret; if (f->ioctx) { if (ioctx_close (fid, 1) < 0) goto error_quiet; } if (!(ret = np_create_rclunk ())) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_clunk %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: return NULL; }
static u32 _copy_dirent_linux (Fid *f, struct dirent *dp, u8 *buf, u32 buflen) { Npqid qid; u32 ret = 0; if (dp->d_type == DT_UNKNOWN) { char path[PATH_MAX + 1]; struct stat sb; snprintf (path, sizeof(path), "%s/%s", path_s (f->path), dp->d_name); if (lstat (path, &sb) < 0) { np_uerror (errno); goto done; } diod_ustat2qid (&sb, &qid); } else { _dirent2qid (dp, &qid); } ret = np_serialize_p9dirent(&qid, dp->d_off, dp->d_type, dp->d_name, buf, buflen); done: return ret; }
/* Trename - rename a file, potentially to another directory */ Npfcall* diod_rename (Npfid *fid, Npfid *dfid, Npstr *name) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; Fid *d = dfid->aux; Npfcall *ret; Path npath = NULL; int renamed = 0; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, d->path, name))) { np_uerror (ENOMEM); goto error; } if (rename (path_s (f->path), path_s (npath)) < 0) { np_uerror (errno); goto error_quiet; } renamed = 1; if (!(ret = np_create_rrename ())) { np_uerror (ENOMEM); goto error; } path_decref (srv, f->path); f->path = npath; return ret; error: errn (np_rerror (), "diod_rename %s@%s:%s to %s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), path_s (d->path), name->len, name->str); error_quiet: if (renamed && npath) (void)rename (path_s (npath), path_s (f->path)); if (npath) path_decref (srv, npath); return NULL; }
Npfcall* diod_setattr (Npfid *fid, u32 valid, u32 mode, u32 uid, u32 gid, u64 size, u64 atime_sec, u64 atime_nsec, u64 mtime_sec, u64 mtime_nsec) { Npfcall *ret; Fid *f = fid->aux; int ctime_updated = 0; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if ((valid & P9_ATTR_MODE)) { /* N.B. derefs symlinks */ if (chmod (path_s (f->path), mode) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_ATTR_UID) || (valid & P9_ATTR_GID)) { if (lchown (path_s (f->path), (valid & P9_ATTR_UID) ? uid : -1, (valid & P9_ATTR_GID) ? gid : -1) < 0){ np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_ATTR_SIZE)) { if (truncate (path_s (f->path), size) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_ATTR_ATIME) || (valid & P9_ATTR_MTIME)) { #if HAVE_UTIMENSAT struct timespec ts[2]; if (!(valid & P9_ATTR_ATIME)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_ATTR_ATIME_SET)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_NOW; } else { ts[0].tv_sec = atime_sec; ts[0].tv_nsec = atime_nsec; } if (!(valid & P9_ATTR_MTIME)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_ATTR_MTIME_SET)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_NOW; } else { ts[1].tv_sec = mtime_sec; ts[1].tv_nsec = mtime_nsec; } if (utimensat(-1, path_s (f->path), ts, AT_SYMLINK_NOFOLLOW) < 0) { np_uerror(errno); goto error_quiet; } #else /* HAVE_UTIMENSAT */ struct timeval tv[2], now, *tvp; struct stat sb; if ((valid & P9_ATTR_ATIME) && !(valid & P9_ATTR_ATIME_SET) && (valid & P9_ATTR_MTIME) && !(valid & P9_ATTR_MTIME_SET)) { tvp = NULL; /* set both to now */ } else { if (lstat(path_s (f->path), &sb) < 0) { np_uerror (errno); goto error_quiet; } if (gettimeofday (&now, NULL) < 0) { np_uerror (errno); goto error_quiet; } if (!(valid & P9_ATTR_ATIME)) { tv[0].tv_sec = sb.st_atim.tv_sec; tv[0].tv_usec = sb.st_atim.tv_nsec / 1000; } else if (!(valid & P9_ATTR_ATIME_SET)) { tv[0].tv_sec = now.tv_sec; tv[0].tv_usec = now.tv_usec; } else { tv[0].tv_sec = atime_sec; tv[0].tv_usec = atime_nsec / 1000; } if (!(valid & P9_ATTR_MTIME)) { tv[1].tv_sec = sb.st_mtim.tv_sec; tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000; } else if (!(valid & P9_ATTR_MTIME_SET)) { tv[1].tv_sec = now.tv_sec; tv[1].tv_usec = now.tv_usec; } else { tv[1].tv_sec = mtime_sec; tv[1].tv_usec = mtime_nsec / 1000; } tvp = tv; } if (utimes (path_s (f->path), tvp) < 0) { np_uerror(errno); goto error_quiet; } #endif /* HAVE_UTIMENSAT */ ctime_updated = 1; } if ((valid & P9_ATTR_CTIME) && !ctime_updated) { if (lchown (path_s (f->path), -1, -1) < 0) { np_uerror (errno); goto error_quiet; } } if (!(ret = np_create_rsetattr())) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_setattr %s@%s:%s (valid=0x%x)", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), valid); error_quiet: return NULL; }