func touch(filename string, nacc, nmod int64) (errcnt int) { var st syscall.Stat_t var ut syscall.Utimbuf if e := syscall.Stat(filename, &st); e != 0 { if e == syscall.ENOENT { if *cflag { errcnt++ return } var fd int defer syscall.Close(fd) if fd, e = syscall.Creat(filename, 0666); e != 0 { fmt.Fprintf(os.Stderr, "touch: can not create %s\n", filename) errcnt += 1 return } if e = syscall.Fstat(fd, &st); e != 0 { fmt.Fprintf(os.Stderr, "touch: can't stat %s\n", filename) errcnt += 1 return } } else { fmt.Fprintf(os.Stderr, "touch: can't stat %s\n", filename) errcnt += 1 return } } if *aflag { ut.Actime = nacc } else { ut.Actime = st.Atim.Sec } if *mflag { ut.Modtime = nmod } else { ut.Modtime = st.Mtim.Sec } if nulltime { if e := syscall.Utime(filename, nil); e != 0 { fmt.Fprintf(os.Stderr, "touch: unable to touch %s", filename) errcnt += 1 } } else { if e := syscall.Utime(filename, &ut); e != 0 { fmt.Fprintf(os.Stderr, "touch: unable to touch %s", filename) errcnt += 1 } } return }
func (constor *Constor) setdeleted(pathl string) error { stat := syscall.Stat_t{} err := syscall.Stat(pathl, &stat) if err != nil { fd, err := syscall.Creat(pathl, 0) if err != nil { return err } syscall.Close(fd) } return syscall.Setxattr(pathl, DELXATTR, []byte{49}, 0) }
func (constor *Constor) Rmdir(header *fuse.InHeader, name string) (code fuse.Status) { constor.log("%d %s", header.NodeId, name) var stat syscall.Stat_t parentino := header.NodeId dirpath, err := constor.dentrymap.getPath(parentino) if err != nil { return fuse.ToStatus(err) } path := Path.Join(dirpath, name) if err := constor.Lstat(path, &stat); err != nil { return fuse.ToStatus(err) } li := constor.getLayer(path) if li == -1 { return fuse.EIO } pathlayer0 := Path.Join(constor.layers[0], path) if li == 0 { // FIXME: make sure the dir is not empty // err = os.RemoveAll(pathlayer0) err = syscall.Rmdir(pathlayer0) if err != nil { return fuse.ToStatus(err) } li = constor.getLayer(path) } if li > 0 { err := constor.createPath(dirpath) if err != nil { return fuse.ToStatus(err) } fd, err := syscall.Creat(pathlayer0, 0) if err != nil { return fuse.ToStatus(err) } syscall.Close(fd) err = constor.setdeleted(pathlayer0) if err != nil { return fuse.ToStatus(err) } } dentry, err := constor.dentrymap.findDentry(parentino, stat.Ino) if err != nil { return fuse.ToStatus(err) } constor.dentrymap.unhashDentry(dentry) return fuse.OK }
func (constor *Constor) Link(input *fuse.LinkIn, name string, out *fuse.EntryOut) (code fuse.Status) { inodeold := constor.inodemap.findInodePtr(input.Oldnodeid) if inodeold == nil { constor.error("inodeold == nil") return fuse.ENOENT } parent := constor.inodemap.findInodePtr(input.NodeId) if parent == nil { constor.error("parent == nil") return fuse.ENOENT } constor.log("%s <- %s/%s", inodeold.id, parent.id, name) if err := constor.copyup(inodeold); err != nil { constor.error("copyup failed for %s - %s", inodeold.id, err) return fuse.ToStatus(err) } if err := constor.copyup(parent); err != nil { constor.error("copyup failed for %s - %s", parent.id, err) return fuse.ToStatus(err) } path := constor.getPath(0, parent.id) entrypath := Path.Join(path, name) if constor.isdeleted(entrypath, nil) { if err := syscall.Unlink(entrypath); err != nil { constor.error("Unlink %s : %s", entrypath, err) return fuse.ToStatus(err) } } if fd, err := syscall.Creat(entrypath, 0); err != nil { constor.error("Creat %s : %s", entrypath, err) return fuse.ToStatus(err) } else { syscall.Close(fd) } id := constor.setid(entrypath, inodeold.id) if id == "" { constor.error("setid %s : %s", entrypath) return fuse.EIO } if err := constor.inclinkscnt(inodeold.id); err != nil { constor.error("inclinkscnt %s : %s", inodeold.id, err) return fuse.ToStatus(err) } return constor.Lookup((*fuse.InHeader)(unsafe.Pointer(input)), name, out) }
func (constor *Constor) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) { sendEntryNotify := false var inodedel *Inode oldParent := constor.inodemap.findInodePtr(input.NodeId) if oldParent == nil { constor.error("oldParent == nil") return fuse.ENOENT } newParent := constor.inodemap.findInodePtr(input.Newdir) if newParent == nil { constor.error("newParent == nil") return fuse.ENOENT } if err := constor.copyup(newParent); err != nil { constor.error("copyup failed for %s - %s", newParent.id, err) return fuse.EIO } newParentPath := constor.getPath(0, newParent.id) newentrypath := Path.Join(newParentPath, newName) constor.log("%s %s %s %s", oldParent.id, oldName, newParent.id, newName) // remove any entry that existed in the newName's place if iddel, err := constor.getid(-1, newParent.id, newName); err == nil { if inodedel = constor.inodemap.findInodeId(iddel); inodedel != nil { if inodedel.layer == 0 { linkcnt, err := constor.declinkscnt(inodedel.id) if err != nil { constor.error("declinkscnt %s : %s", inodedel.id, err) return fuse.ToStatus(err) } if linkcnt == 0 { path := constor.getPath(0, iddel) fi, err := os.Lstat(path) if err != nil { constor.error("Lstat failed on %s", path) return fuse.ToStatus(err) } if fi.IsDir() { // FIXME: take care of this situation constor.error("path is a directory") return fuse.Status(syscall.EEXIST) } if err := syscall.Unlink(path); err != nil { constor.error("Unable to remove %s", path) return fuse.ToStatus(err) } inodedel.layer = -1 } } stat := syscall.Stat_t{} // FIXME do copyup and declinkscnt if err := syscall.Lstat(newentrypath, &stat); err == nil { fi, err := os.Lstat(newentrypath) if err != nil { constor.error("Lstat failed on %s", newentrypath) return fuse.ToStatus(err) } if fi.IsDir() { // FIXME: take care of this situation constor.error("path is a directory") return fuse.Status(syscall.EEXIST) } if err := syscall.Unlink(newentrypath); err != nil { constor.error("Unable to remove %s", newentrypath) return fuse.ToStatus(err) } } // inodedel.parentPtr = input.Newdir // inodedel.name = newName sendEntryNotify = true // constor.ms.DeleteNotify(input.Newdir, uint64(uintptr(unsafe.Pointer(inodedel))), newName) // constor.ms.EntryNotify(input.Newdir, newName) } else { constor.error("inodedel == nil for %s %s", newParent.id, newName) return fuse.EIO } } // remove any deleted placeholder if constor.isdeleted(newentrypath, nil) { if err := syscall.Unlink(newentrypath); err != nil { constor.error("Unlink %s : %s", newentrypath, err) return fuse.ToStatus(err) } } oldid, err := constor.getid(-1, oldParent.id, oldName) if err != nil { constor.error("getid error %s %s", oldParent.id, oldName) return fuse.ToStatus(err) } oldinode := constor.inodemap.findInodeId(oldid) if oldinode == nil { constor.error("oldinode == nil for %s", oldid) return fuse.ENOENT } path := constor.getPath(oldinode.layer, oldid) fi, err := os.Lstat(path) if err != nil { constor.error("Lstat %s", path) return fuse.ToStatus(err) } oldParentPath := constor.getPath(0, oldParent.id) oldentrypath := Path.Join(oldParentPath, oldName) oldstat := syscall.Stat_t{} if err := syscall.Lstat(oldentrypath, &oldstat); err == nil { if fi.IsDir() { if err := syscall.Rmdir(oldentrypath); err != nil { constor.error("Rmdir %s : %s", oldentrypath, err) return fuse.ToStatus(err) } } else { if err := syscall.Unlink(oldentrypath); err != nil { constor.error("Unlink %s : %s", oldentrypath, err) return fuse.ToStatus(err) } } } if _, err := constor.getid(-1, oldParent.id, oldName); err == nil { constor.setdeleted(oldentrypath) } if fi.Mode()&os.ModeSymlink == os.ModeSymlink { err = os.Symlink("placeholder", newentrypath) if err != nil { constor.error("Symlink %s : %s", newentrypath, err) return fuse.ToStatus(err) } } else if fi.Mode()&os.ModeDir == os.ModeDir { err := os.Mkdir(newentrypath, fi.Mode()) if err != nil { constor.error("Mkdir %s : %s", newentrypath, err) return fuse.ToStatus(err) } } else { fd, err := syscall.Creat(newentrypath, uint32(fi.Mode())) if err != nil { constor.error("create %s : %s", newentrypath, err) return fuse.ToStatus(err) } syscall.Close(fd) } id := constor.setid(newentrypath, oldid) if id == "" { constor.error("setid %s : %s", newentrypath, err) return fuse.EIO } if sendEntryNotify { go func() { // FIXME: is this needed? constor.ms.DeleteNotify(input.Newdir, uint64(uintptr(unsafe.Pointer(inodedel))), newName) constor.ms.DeleteNotify(input.NodeId, uint64(uintptr(unsafe.Pointer(oldinode))), oldName) }() } return fuse.OK }
func (constor *Constor) Create(input *fuse.CreateIn, name string, out *fuse.CreateOut) (code fuse.Status) { flags := 0 inode := constor.inodemap.findInodePtr(input.NodeId) if inode == nil { constor.error("inode == nil") return fuse.ENOENT } err := constor.copyup(inode) if err != nil { constor.error("copyup failed for %s - %s", inode.id, err) return fuse.ToStatus(err) } dirpath := constor.getPath(0, inode.id) entrypath := Path.Join(dirpath, name) if constor.isdeleted(entrypath, nil) { if err := syscall.Unlink(entrypath); err != nil { constor.error("Unlink %s : %s", entrypath, err) return fuse.ToStatus(err) } } fd, err := syscall.Creat(entrypath, input.Mode) if err != nil { constor.error("Creat %s : %s", entrypath, err) return fuse.ToStatus(err) } syscall.Close(fd) id := constor.setid(entrypath, "") if id == "" { constor.error("setid %s : %s", entrypath, err) return fuse.EIO } constor.log("%s : %s", entrypath, id) if err := constor.createPath(id); err != nil { constor.error("createPath %s : %s", id, err) return fuse.ToStatus(err) } path := constor.getPath(0, id) if input.Flags != 0 { flags = int(input.Flags) | syscall.O_CREAT } else { flags = syscall.O_CREAT | syscall.O_RDWR | syscall.O_EXCL } fd, err = syscall.Open(path, flags, input.Mode) // fd, err = syscall.Open(path, int(input.Flags), input.Mode) if err != nil { constor.error("open %s : %s", path, err) return fuse.ToStatus(err) } err = syscall.Chown(path, int(input.Uid), int(input.Gid)) if err != nil { constor.error("Chown %s : %s", path, err) return fuse.ToStatus(err) } F := new(FD) F.fd = fd F.layer = 0 F.id = id F.pid = input.Pid constor.putfd(F) if flags&syscall.O_DIRECT != 0 { out.OpenFlags = fuse.FOPEN_DIRECT_IO } else { out.OpenFlags = fuse.FOPEN_KEEP_CACHE } out.Fh = uint64(uintptr(unsafe.Pointer(F))) constor.log("%d", out.Fh) return constor.Lookup((*fuse.InHeader)(unsafe.Pointer(input)), name, &out.EntryOut) }