func setStat(user string, e trees.File, parent trees.Dir, nstat qp.Stat) error { ostat, err := e.Stat() if err != nil { return err } length := false name := false mode := false owner := false if nstat.Type != ^uint16(0) && nstat.Type != ostat.Type { return errors.New("it is illegal to modify type") } if nstat.Dev != ^uint32(0) && nstat.Dev != ostat.Dev { return errors.New("it is illegal to modify dev") } if nstat.MUID != "" && nstat.MUID != ostat.MUID { return errors.New("it is illegal to modify muid") } if nstat.Atime != ^uint32(0) && nstat.Atime != ostat.Atime { return errors.New("it is illegal to modify atime") } if parent == nil && nstat.Name != "" && nstat.Name != ostat.Name { return errors.New("it is illegal to rename root") } if nstat.Length != ^uint64(0) && nstat.Length != ostat.Length { if ostat.Mode&qp.DMDIR != 0 { return errors.New("cannot set length of directory") } if nstat.Length > ostat.Length { return errors.New("cannot extend length") } length = true } if nstat.Name != "" && nstat.Name != ostat.Name { name = true } if (nstat.UID != "" && nstat.UID != ostat.UID) || (nstat.GID != "" && nstat.GID != ostat.GID) { owner = true } if nstat.Mode != ^qp.FileMode(0) && nstat.Mode != ostat.Mode { mode = true } if nstat.Mtime != ^uint32(0) && nstat.Mtime != ostat.Mtime { // We ignore mtime changes ATM. Only owner can change mtime. } if mode { if err := e.SetMode(user, ostat.Mode&qp.DMDIR | nstat.Mode & ^qp.DMDIR); err != nil { return err } } if owner { if err := e.SetOwner(user, nstat.UID, nstat.GID); err != nil { e.SetMode(user, ostat.Mode) return err } } if name { if err := parent.Rename(user, ostat.Name, nstat.Name); err != nil { e.SetMode(user, ostat.Mode) e.SetOwner(user, ostat.UID, ostat.GID) return err } } if length { if err := e.SetLength(user, nstat.Length); err != nil { e.SetMode(user, ostat.Mode) e.SetOwner(user, ostat.UID, ostat.GID) parent.Rename(user, nstat.Name, ostat.Name) return err } } return nil }