X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;f=remote%2Fsync%2Ffiles.go;h=9803e936093d1c3edf59c3881ac2966a041ab3c2;hb=ba1a93368ed95d7160062f60fb8b579bc178d3aa;hp=edf81bd2cc795a2630f4b775eca25786ad838c61;hpb=2804606f9f8dc5078c38580bac363b47eb638620;p=safcm%2Fsafcm.git diff --git a/remote/sync/files.go b/remote/sync/files.go index edf81bd..9803e93 100644 --- a/remote/sync/files.go +++ b/remote/sync/files.go @@ -15,6 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//go:build !windows // +build !windows package sync @@ -249,7 +250,7 @@ reopen: } // Compare file content (if possible) - switch change.Old.Mode.Type() { + switch change.Old.Mode.Type() { //nolint:exhaustive case 0: // regular file x, err := io.ReadAll(oldFh) if err != nil { @@ -324,7 +325,7 @@ reopen: err := unix.Unlinkat(parentFd, baseName, 0) if err != nil && !os.IsNotExist(err) { err2 := unix.Unlinkat(parentFd, baseName, - AT_REMOVEDIR) + unix.AT_REMOVEDIR) if err2 != nil && !os.IsNotExist(err2) { // See src/os/file_unix.go in Go's sources if err2 == unix.ENOTDIR { @@ -383,6 +384,10 @@ reopen: // the error when the user tries to access this // directory (access for the group will fail though). mode := change.Old.Mode & fs.ModePerm & 0700 + // Retain setgid/sticky so that the behavior does not + // change when creating and removing files. + mode |= change.Old.Mode & fs.ModeSetgid + mode |= change.Old.Mode & fs.ModeSticky debugf("chmodding %#o (temporary)", mode) err := oldFh.Chmod(mode) if err != nil { @@ -441,7 +446,7 @@ reopen: err = unix.Fchownat(parentFd, tmpBase, file.Uid, file.Gid, unix.AT_SYMLINK_NOFOLLOW) if err != nil { - unix.Unlinkat(parentFd, tmpBase, 0) + unix.Unlinkat(parentFd, tmpBase, 0) //nolint:errcheck return err } // Permissions are irrelevant for symlinks (on most systems) @@ -453,9 +458,17 @@ reopen: debugf("renaming %q", slashpath.Join(dir, tmpBase)) err = unix.Renameat(parentFd, tmpBase, parentFd, baseName) if err != nil { - unix.Unlinkat(parentFd, tmpBase, 0) + unix.Unlinkat(parentFd, tmpBase, 0) //nolint:errcheck return err } + // To guarantee durability fsync must be called on a parent directory + // after adding, renaming or removing files therein. + // + // Calling sync on the files itself is not enough according to POSIX; + // man 2 fsync: "Calling fsync() does not necessarily ensure that the + // entry in the directory containing the file has also reached disk. + // For that an explicit fsync() on a file descriptor for the directory + // is also needed." err = unix.Fsync(parentFd) if err != nil { return err @@ -540,9 +553,12 @@ func OpenParentDirectoryNoSymlinks(path string) (int, string, error) { } dir = ".." parts = []string{filepath.Base(wd)} - } else if parts[0] != "." { + } else { // Relative path: start at the current directory dir = "." + if parts[0] == "." { + parts = parts[1:] + } } dirFd, err := unix.Openat(unix.AT_FDCWD, dir, openReadonlyFlags, 0) @@ -643,31 +659,31 @@ func WriteTempAt(dirFd int, base string, data []byte, uid, gid int, _, err = fh.Write(data) if err != nil { fh.Close() - unix.Unlinkat(dirFd, tmpBase, 0) + unix.Unlinkat(dirFd, tmpBase, 0) //nolint:errcheck return "", err } // createTempAt() creates the file with 0600 err = fh.Chown(uid, gid) if err != nil { fh.Close() - unix.Unlinkat(dirFd, tmpBase, 0) + unix.Unlinkat(dirFd, tmpBase, 0) //nolint:errcheck return "", err } err = fh.Chmod(mode) if err != nil { fh.Close() - unix.Unlinkat(dirFd, tmpBase, 0) + unix.Unlinkat(dirFd, tmpBase, 0) //nolint:errcheck return "", err } err = fh.Sync() if err != nil { fh.Close() - unix.Unlinkat(dirFd, tmpBase, 0) + unix.Unlinkat(dirFd, tmpBase, 0) //nolint:errcheck return "", err } err = fh.Close() if err != nil { - unix.Unlinkat(dirFd, tmpBase, 0) + unix.Unlinkat(dirFd, tmpBase, 0) //nolint:errcheck return "", err } @@ -695,24 +711,3 @@ retry: return os.NewFile(uintptr(fd), ""), tmpBase, nil } - -// SyncPath syncs path, which should be a directory. To guarantee durability -// it must be called on a parent directory after adding, renaming or removing -// files therein. -// -// Calling sync on the files itself is not enough according to POSIX; man 2 -// fsync: "Calling fsync() does not necessarily ensure that the entry in the -// directory containing the file has also reached disk. For that an explicit -// fsync() on a file descriptor for the directory is also needed." -func SyncPath(path string) error { - x, err := os.Open(path) - if err != nil { - return err - } - err = x.Sync() - closeErr := x.Close() - if err != nil { - return err - } - return closeErr -}