static void test_rsetattr (void) { Npfcall *fc, *fc2; if (!(fc = np_create_rsetattr ())) msg_exit ("out of memory"); fc2 = _rcv_buf (fc, P9_RSETATTR, __FUNCTION__); free (fc); free (fc2); }
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->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if ((valid & P9_SETATTR_MODE)) { /* N.B. derefs symlinks */ if (chmod (f->path, mode) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_SETATTR_UID) || (valid & P9_SETATTR_GID)) { if (lchown (f->path, (valid & P9_SETATTR_UID) ? uid : -1, (valid & P9_SETATTR_GID) ? gid : -1) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_SETATTR_SIZE)) { if (truncate (f->path, size) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_SETATTR_ATIME) || (valid & P9_SETATTR_MTIME)) { #if HAVE_UTIMENSAT struct timespec ts[2]; if (!(valid & P9_SETATTR_ATIME)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_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_SETATTR_MTIME)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_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, 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_SETATTR_ATIME) && !(valid & P9_SETATTR_ATIME_SET) && (valid & P9_SETATTR_MTIME) && !(valid & P9_SETATTR_MTIME_SET)) { tvp = NULL; /* set both to now */ } else { if (lstat(f->path, &sb) < 0) { np_uerror (errno); goto error_quiet; } if (gettimeofday (&now, NULL) < 0) { np_uerror (errno); goto error_quiet; } if (!(valid & P9_SETATTR_ATIME)) { tv[0].tv_sec = sb.st_atim.tv_sec; tv[0].tv_usec = sb.st_atim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_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_SETATTR_MTIME)) { tv[1].tv_sec = sb.st_mtim.tv_sec; tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_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 (f->path, tvp) < 0) { np_uerror(errno); goto error_quiet; } #endif /* HAVE_UTIMENSAT */ ctime_updated = 1; } if ((valid & P9_SETATTR_CTIME) && !ctime_updated) { if (lchown (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), f->path, valid); error_quiet: 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 = NULL; Fid *f = fid->aux; int fidstat_updated = 0; int ctime_updated = 0; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if ((valid & P9_SETATTR_MODE) || (valid & P9_SETATTR_SIZE)) { if (_fidstat(f) < 0) goto error_quiet; fidstat_updated = 1; if (S_ISLNK(f->stat.st_mode)) { msg ("diod_setattr: unhandled mode/size update on symlink"); np_uerror(EINVAL); goto error; } } /* chmod (N.B. dereferences symlinks) */ if ((valid & P9_SETATTR_MODE)) { if (chmod (f->path, mode) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } /* chown */ if ((valid & P9_SETATTR_UID) || (valid & P9_SETATTR_GID)) { if (lchown (f->path, (valid & P9_SETATTR_UID) ? uid : -1, (valid & P9_SETATTR_GID) ? gid : -1) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } /* truncate (N.B. dereferences symlinks) */ if ((valid & P9_SETATTR_SIZE)) { if (truncate (f->path, size) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } /* utimes */ if ((valid & P9_SETATTR_ATIME) || (valid & P9_SETATTR_MTIME)) { #if HAVE_UTIMENSAT struct timespec ts[2]; if (!(valid & P9_SETATTR_ATIME)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_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_SETATTR_MTIME)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_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, f->path, ts, AT_SYMLINK_NOFOLLOW) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; #else /* HAVE_UTIMENSAT */ struct timeval tv[2], now, *tvp; /* N.B. this utimes () implementation loses atomicity and precision. */ if ((valid & P9_SETATTR_ATIME) && !(valid & P9_SETATTR_ATIME_SET) && (valid & P9_SETATTR_MTIME) && !(valid & P9_SETATTR_MTIME_SET)) { tvp = NULL; /* set both to now */ } else { if (!fidstat_updated && _fidstat(f) < 0) goto error_quiet; fidstat_updated = 1; if (gettimeofday (&now, NULL) < 0) { np_uerror (errno); goto error_quiet; } if (!(valid & P9_SETATTR_ATIME)) { tv[0].tv_sec = f->stat.st_atim.tv_sec; tv[0].tv_usec = f->stat.st_atim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_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_SETATTR_MTIME)) { tv[1].tv_sec = f->stat.st_mtim.tv_sec; tv[1].tv_usec = f->stat.st_mtim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_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 (f->path, tvp) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; #endif } if ((valid & P9_SETATTR_CTIME) && !ctime_updated) { if (lchown (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), f->path, valid); error_quiet: if (ret) free (ret); return NULL; }