Skip to content

Commit

Permalink
Loop on EINTR on Linux (#50)
Browse files Browse the repository at this point in the history
Co-authored-by: greatroar <@>
  • Loading branch information
greatroar committed Nov 7, 2020
1 parent c081af6 commit 9943167
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 12 deletions.
82 changes: 70 additions & 12 deletions xattr_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package xattr

import (
"errors"
"os"
"syscall"

Expand All @@ -22,52 +23,109 @@ const (
ENOATTR = syscall.ENODATA
)

// On Linux, FUSE and CIFS filesystems can return EINTR for interrupted system
// calls. This function works around this by retrying system calls until they
// stop returning EINTR.
//
// See https://github.com/golang/go/commit/6b420169d798c7ebe733487b56ea5c3fa4aab5ce.
func ignoringEINTR(fn func() error) (err error) {
for {
err = fn()
if !errors.Is(err, unix.EINTR) {

This comment has been minimized.

Copy link
@rfjakob

rfjakob Nov 15, 2020

Contributor

The breaks Go 1.10: https://travis-ci.org/github/rfjakob/cshatag/builds/743651578#L216

../../../gopath/src/github.com/pkg/xattr/xattr_linux.go:34:7: undefined: errors.Is

This comment has been minimized.

Copy link
@kuba--

kuba-- Nov 15, 2020

Member

yes (because of updates in errors package), but do we still want to support go 1.10.X ?

it's pretty old...

This comment has been minimized.

Copy link
@rfjakob

rfjakob Nov 15, 2020

Contributor

Hmm, looking at https://pkgs.org/download/golang , Debian 10 is on Go 1.11. And, looking at this ( https://travis-ci.org/github/rfjakob/cshatag/builds/743731111 ), everything below Go 1.13 fails to compile.

The upstream commit ( golang/go@6b42016#diff-4961c1d8cb230e376e3523064c5d7a73ce498eefc8bf8e14c691d1cc0395a2bdR86 ) just uses "==", is there a reason that's not good enough?

This comment has been minimized.

Copy link
@kuba--

kuba-- Nov 15, 2020

Member

Ok, makes sense. It's not extremely important feature to break compatibility.
I'll fix it, soon.

break
}
}
return err
}

func getxattr(path string, name string, data []byte) (int, error) {
return unix.Getxattr(path, name, data)
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Getxattr(path, name, data)
return err
})
return r, err
}

func lgetxattr(path string, name string, data []byte) (int, error) {
return unix.Lgetxattr(path, name, data)
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Lgetxattr(path, name, data)
return err
})
return r, err
}

func fgetxattr(f *os.File, name string, data []byte) (int, error) {
return unix.Fgetxattr(int(f.Fd()), name, data)
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Fgetxattr(int(f.Fd()), name, data)
return err
})
return r, err
}

func setxattr(path string, name string, data []byte, flags int) error {
return unix.Setxattr(path, name, data, flags)
return ignoringEINTR(func() (err error) {
return unix.Setxattr(path, name, data, flags)
})
}

func lsetxattr(path string, name string, data []byte, flags int) error {
return unix.Lsetxattr(path, name, data, flags)
return ignoringEINTR(func() (err error) {
return unix.Lsetxattr(path, name, data, flags)
})
}

func fsetxattr(f *os.File, name string, data []byte, flags int) error {
return unix.Fsetxattr(int(f.Fd()), name, data, flags)
return ignoringEINTR(func() (err error) {
return unix.Fsetxattr(int(f.Fd()), name, data, flags)
})
}

func removexattr(path string, name string) error {
return unix.Removexattr(path, name)
return ignoringEINTR(func() (err error) {
return unix.Removexattr(path, name)
})
}

func lremovexattr(path string, name string) error {
return unix.Lremovexattr(path, name)
return ignoringEINTR(func() (err error) {
return unix.Lremovexattr(path, name)
})
}

func fremovexattr(f *os.File, name string) error {
return unix.Fremovexattr(int(f.Fd()), name)
return ignoringEINTR(func() (err error) {
return unix.Fremovexattr(int(f.Fd()), name)
})
}

func listxattr(path string, data []byte) (int, error) {
return unix.Listxattr(path, data)
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Listxattr(path, data)
return err
})
return r, err
}

func llistxattr(path string, data []byte) (int, error) {
return unix.Llistxattr(path, data)
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Llistxattr(path, data)
return err
})
return r, err
}

func flistxattr(f *os.File, data []byte) (int, error) {
return unix.Flistxattr(int(f.Fd()), data)
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Flistxattr(int(f.Fd()), data)
return err
})
return r, err
}

// stringsFromByteSlice converts a sequence of attributes to a []string.
Expand Down
21 changes: 21 additions & 0 deletions xattr_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package xattr

import (
"syscall"
"testing"
)

func TestIgnoringEINTR(t *testing.T) {
eintrs := 100
err := ignoringEINTR(func() error {
if eintrs == 0 {
return nil
}
eintrs--
return syscall.EINTR
})

if err != nil {
t.Fatal(err)
}
}

0 comments on commit 9943167

Please sign in to comment.