// OSX does not have the utimensat syscall neded to implement this properly. // We do our best to emulate it using futimes. func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status { tv := make([]syscall.Timeval, 2) if a == nil { tv[0].Usec = _UTIME_OMIT } else { tv[0] = timeToTimeval(a) } if m == nil { tv[1].Usec = _UTIME_OMIT } else { tv[1] = timeToTimeval(m) } f.lock.Lock() err := syscall.Futimes(int(f.File.Fd()), tv) f.lock.Unlock() return fuse.ToStatus(err) }
func (f *AzukiFile) Utimens(a *time.Time, m *time.Time) fuse.Status { tv := make([]syscall.Timeval, 2) if a == nil { tv[0].Usec = _UTIME_OMIT } else { n := a.UnixNano() tv[0] = syscall.NsecToTimeval(n) } if m == nil { tv[1].Usec = _UTIME_OMIT } else { n := a.UnixNano() tv[1] = syscall.NsecToTimeval(n) } err := syscall.Futimes(int(f.File.Fd()), tv) return fuse.ToStatus(err) }
func (f *loopbackFile) Utimens(a *time.Time, m *time.Time) fuse.Status { var ts = make([]syscall.Timeval, 2) if a == nil { ts[0].Sec = _UTIME_OMIT } else { ts[0].Sec = a.Unix() } if m == nil { ts[1].Sec = _UTIME_OMIT } else { ts[1].Sec = m.Unix() } f.lock.Lock() err := syscall.Futimes(int(f.File.Fd()), ts) f.lock.Unlock() return fuse.ToStatus(err) }
func (fs *Fs) wstatPost(fid *Fid, cur *Dir, next *Dir) error { defer fid.file.unlock() // Rename the file. if next.Name != "" && next.Name != cur.Name { new_path := path.Join(path.Dir(fid.Path), next.Name) err := fid.file.rename(fs, fid.Path, new_path) if err != nil { return err } } // Update our access times. atime := cur.Atime mtime := cur.Atime if next.Atime != math.MaxUint32 { atime = next.Atime } if next.Mtime != math.MaxUint32 { mtime = next.Mtime } if atime != cur.Atime || mtime != cur.Mtime { err := syscall.Futimes( fid.file.write_fd, []syscall.Timeval{ syscall.Timeval{int64(atime), 0}, syscall.Timeval{int64(mtime), 0}, }) if err != nil { return err } } // Truncate the file. if next.Length != math.MaxUint64 && next.Length != cur.Length { err := syscall.Ftruncate(fid.file.write_fd, int64(next.Length)) if err != nil { return err } } // Change the owner. uid := cur.Uidnum gid := cur.Gidnum if next.Uidnum != math.MaxUint32 && next.Uidnum != cur.Uidnum { uid = next.Uidnum } if next.Gidnum != math.MaxUint32 && next.Gidnum != cur.Gidnum { gid = next.Gidnum } if uid != cur.Uidnum || gid != cur.Gidnum { err := syscall.Fchown(fid.file.write_fd, int(uid), int(gid)) if err != nil { return err } } return nil }
func (constor *Constor) SetAttr(input *fuse.SetAttrIn, out *fuse.AttrOut) fuse.Status { var err error uid := -1 gid := -1 inode := constor.inodemap.findInodePtr(input.NodeId) if inode == nil { constor.error("inode nil") return fuse.EIO } constor.log("%s %d", inode.id, input.Valid) // if ((input.Valid & fuse.FATTR_FH) !=0) && ((input.Valid & (fuse.FATTR_ATIME | fuse.FATTR_MTIME)) == 0) { if ((input.Valid & fuse.FATTR_FH) != 0) && ((input.Valid & fuse.FATTR_SIZE) != 0) { ptr := uintptr(input.Fh) F := constor.getfd(ptr) if F == nil { constor.error("F == nil for %s", inode.id) return fuse.EIO } if F.layer != 0 && inode.layer == -1 { /* FIXME handle this valid case */ // file is in lower layer, opened, deleted, setattr-called constor.error("FSetAttr F.layer=%d inode.layer=%d", F.layer, inode.layer) return fuse.EIO } if F.layer != 0 && inode.layer != 0 { err := constor.copyup(inode) if err != nil { constor.error("copyup failed for %s - %s", inode.id, err) return fuse.ToStatus(err) } path := constor.getPath(0, inode.id) syscall.Close(F.fd) fd, err := syscall.Open(path, F.flags, 0) if err != nil { constor.error("open failed on %s - %s", path, err) return fuse.ToStatus(err) } F.fd = fd F.layer = 0 constor.log("reset fd for %s", path) } else if F.layer != 0 && inode.layer == 0 { // when some other process already has done a copyup syscall.Close(F.fd) path := constor.getPath(0, inode.id) fd, err := syscall.Open(path, F.flags, 0) if err != nil { constor.error("open failed on %s - %s", path, err) return fuse.ToStatus(err) } F.fd = fd F.layer = 0 constor.log("reset fd for %s", path) } if F.layer != 0 { constor.error("layer not 0") return fuse.EIO } if input.Valid&fuse.FATTR_MODE != 0 { permissions := uint32(07777) & input.Mode err = syscall.Fchmod(F.fd, permissions) if err != nil { constor.error("Fchmod failed on %s - %d : %s", F.id, permissions, err) return fuse.ToStatus(err) } } if input.Valid&(fuse.FATTR_UID) != 0 { uid = int(input.Uid) } if input.Valid&(fuse.FATTR_GID) != 0 { gid = int(input.Gid) } if input.Valid&(fuse.FATTR_UID|fuse.FATTR_GID) != 0 { err = syscall.Fchown(F.fd, uid, gid) if err != nil { constor.error("Fchown failed on %s - %d %d : %s", F.id, uid, gid, err) return fuse.ToStatus(err) } } if input.Valid&fuse.FATTR_SIZE != 0 { err := syscall.Ftruncate(F.fd, int64(input.Size)) if err != nil { constor.error("Ftruncate failed on %s - %d : %s", F.id, input.Size, err) return fuse.ToStatus(err) } } if input.Valid&(fuse.FATTR_ATIME|fuse.FATTR_MTIME|fuse.FATTR_ATIME_NOW|fuse.FATTR_MTIME_NOW) != 0 { now := time.Now() var tv []syscall.Timeval tv = make([]syscall.Timeval, 2) if input.Valid&fuse.FATTR_ATIME_NOW != 0 { tv[0].Sec = now.Unix() tv[0].Usec = now.UnixNano() / 1000 } else { tv[0].Sec = int64(input.Atime) tv[0].Usec = int64(input.Atimensec / 1000) } if input.Valid&fuse.FATTR_MTIME_NOW != 0 { tv[1].Sec = now.Unix() tv[1].Usec = now.UnixNano() / 1000 } else { tv[1].Sec = int64(input.Atime) tv[1].Usec = int64(input.Atimensec / 1000) } err := syscall.Futimes(F.fd, tv) if err != nil { constor.error("Futimes failed on %s : %s", F.id, err) return fuse.ToStatus(err) } } stat := syscall.Stat_t{} err = syscall.Fstat(F.fd, &stat) if err != nil { constor.error("Fstat failed on %s : %s", F.id, err) return fuse.ToStatus(err) } attr := (*fuse.Attr)(&out.Attr) attr.FromStat(&stat) attr.Ino = idtoino(inode.id) return fuse.OK } if inode.layer == -1 { return fuse.ENOENT } if inode.layer != 0 { err = constor.copyup(inode) if err != nil { constor.error("copyup failed for %s - %s", inode.id, err) return fuse.ToStatus(err) } } stat := syscall.Stat_t{} path := constor.getPath(0, inode.id) // just to satisfy PJD tests if input.Valid == 0 { err = syscall.Lchown(path, uid, gid) if err != nil { return fuse.ToStatus(err) } } if input.Valid&fuse.FATTR_MODE != 0 { permissions := uint32(07777) & input.Mode err = syscall.Chmod(path, permissions) if err != nil { constor.error("Lchmod failed on %s - %d : %s", path, permissions, err) return fuse.ToStatus(err) } } if input.Valid&(fuse.FATTR_UID) != 0 { uid = int(input.Uid) } if input.Valid&(fuse.FATTR_GID) != 0 { gid = int(input.Gid) } if input.Valid&(fuse.FATTR_UID|fuse.FATTR_GID) != 0 { constor.log("%s %d %d", path, uid, gid) err = syscall.Lchown(path, uid, gid) if err != nil { constor.error("Lchown failed on %s - %d %d : %s", path, uid, gid, err) return fuse.ToStatus(err) } } if input.Valid&fuse.FATTR_SIZE != 0 { err = syscall.Truncate(path, int64(input.Size)) if err != nil { constor.error("Truncate failed on %s - %d : %s", path, input.Size, err) return fuse.ToStatus(err) } } if input.Valid&(fuse.FATTR_ATIME|fuse.FATTR_MTIME|fuse.FATTR_ATIME_NOW|fuse.FATTR_MTIME_NOW) != 0 { now := time.Now() var atime *time.Time var mtime *time.Time if input.Valid&fuse.FATTR_ATIME_NOW != 0 { atime = &now } else { t := time.Unix(int64(input.Atime), int64(input.Atimensec)) atime = &t } if input.Valid&fuse.FATTR_MTIME_NOW != 0 { mtime = &now } else { t := time.Unix(int64(input.Mtime), int64(input.Mtimensec)) mtime = &t } fi, err := os.Lstat(path) if err != nil { return fuse.ToStatus(err) } if fi.Mode()&os.ModeSymlink != os.ModeSymlink { // FIXME: there is no Lchtimes err = os.Chtimes(path, *atime, *mtime) if err != nil { constor.error("Chtimes failed on %s : %s", path, err) return fuse.ToStatus(err) } } else { constor.error("Chtimes on Symlink not supported") } } attr := (*fuse.Attr)(&out.Attr) err = constor.Lstat(inode.layer, inode.id, &stat) if err != nil { constor.error("Lstat failed on %s : %s", inode.id, err) return fuse.ToStatus(err) } attr.FromStat(&stat) attr.Ino = stat.Ino return fuse.ToStatus(err) }