func (u *Ufs) Wstat(req *srv.Req) { var changed bool fid := req.Fid.Aux.(*Fid) err := fid.stat() if err != nil { req.RespondError(err) return } dir := &req.Tc.Dir if dir.Mode != 0xFFFFFFFF { changed = true mode := dir.Mode & 0777 if req.Conn.Dotu { if dir.Mode&ninep.DMSETUID > 0 { mode |= syscall.S_ISUID } if dir.Mode&ninep.DMSETGID > 0 { mode |= syscall.S_ISGID } } e := os.Chmod(fid.path, os.FileMode(mode)) if e != nil { req.RespondError(toError(e)) return } } uid, gid := ninep.NOUID, ninep.NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum } // Try to find local uid, gid by name. if (dir.Uid != "" || dir.Gid != "") && !req.Conn.Dotu { changed = true uid, err = lookup(dir.Uid, false) if err != nil { req.RespondError(err) return } // BUG(akumar): Lookup will never find gids // corresponding to group names, because // it only operates on user names. gid, err = lookup(dir.Gid, true) if err != nil { req.RespondError(err) return } } if uid != ninep.NOUID || gid != ninep.NOUID { changed = true e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) return } } if dir.Name != "" { changed = true // If we path.Join dir.Name to / before adding it to // the fid path, that ensures nobody gets to walk out of the // root of this server. newname := path.Join(path.Dir(fid.path), path.Join("/", dir.Name)) // absolute renaming. Ufs can do this, so let's support it. // We'll allow an absolute path in the Name and, if it is, // we will make it relative to root. This is a gigantic performance // improvement in systems that allow it. if filepath.IsAbs(dir.Name) { newname = path.Join(u.Root, dir.Name) } err := syscall.Rename(fid.path, newname) if err != nil { req.RespondError(toError(err)) return } fid.path = newname } if dir.Length != 0xFFFFFFFFFFFFFFFF { changed = true e := os.Truncate(fid.path, int64(dir.Length)) if e != nil { req.RespondError(toError(e)) return } } // If either mtime or atime need to be changed, then // we must change both. if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) { changed = true mt, at := time.Unix(int64(dir.Mtime), 0), time.Unix(int64(dir.Atime), 0) if cmt, cat := (dir.Mtime == ^uint32(0)), (dir.Atime == ^uint32(0)); cmt || cat { st, e := os.Stat(fid.path) if e != nil { req.RespondError(toError(e)) return } switch cmt { case true: mt = st.ModTime() default: at = atime(st.Sys().(*syscall.Stat_t)) } } e := os.Chtimes(fid.path, at, mt) if e != nil { req.RespondError(toError(e)) return } } if !changed && fid.file != nil { fid.file.Sync() } req.RespondRwstat() }