diff --git a/go.mod b/go.mod index 409aa74535c7..63c0d5f4153a 100644 --- a/go.mod +++ b/go.mod @@ -249,7 +249,7 @@ require ( replace github.com/minio/minio v0.0.0-20210206053228-97fe57bba92c => github.com/juicedata/minio v0.0.0-20240912134328-6a47725331ab -replace github.com/hanwen/go-fuse/v2 v2.1.1-0.20210611132105-24a1dfe6b4f8 => github.com/juicedata/go-fuse/v2 v2.1.1-0.20240809072820-d78c97ed7b7a +replace github.com/hanwen/go-fuse/v2 v2.1.1-0.20210611132105-24a1dfe6b4f8 => github.com/juicedata/go-fuse/v2 v2.1.1-0.20241120081217-1d367e67855d replace github.com/dgrijalva/jwt-go v3.2.0+incompatible => github.com/golang-jwt/jwt v3.2.1+incompatible diff --git a/go.sum b/go.sum index be59fe1a0e2a..bd8a5877f030 100644 --- a/go.sum +++ b/go.sum @@ -501,8 +501,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juicedata/cli/v2 v2.19.4-0.20230605075551-9c9c5c0dce83 h1:RyHTka3jCnTaUqfRYjlwcQlr53aasmkvHEbYLXthqr8= github.com/juicedata/cli/v2 v2.19.4-0.20230605075551-9c9c5c0dce83/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= -github.com/juicedata/go-fuse/v2 v2.1.1-0.20240809072820-d78c97ed7b7a h1:Rzopfv1+KpROzMWd6NVAs1wTjr5bc5ZdzIhIs0u5XBc= -github.com/juicedata/go-fuse/v2 v2.1.1-0.20240809072820-d78c97ed7b7a/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= +github.com/juicedata/go-fuse/v2 v2.1.1-0.20241120081217-1d367e67855d h1:SLvbtmwPSdnIv2VtqjXswAaKKX3P3R+lj02oxMCuxN8= +github.com/juicedata/go-fuse/v2 v2.1.1-0.20241120081217-1d367e67855d/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= github.com/juicedata/go-nfs-client v0.0.0-20231018052507-dbca444fa7e8 h1:mVVipCbohnzKZPiHGzFncLKEJZpypqjpGr4End2PP48= github.com/juicedata/go-nfs-client v0.0.0-20231018052507-dbca444fa7e8/go.mod h1:xOMqi3lOrcGe9uZLnSzgaq94Vc3oz6VPCNDLJUnXpKs= github.com/juicedata/godaemon v0.0.0-20210629045518-3da5144a127d h1:kpQMvNZJKGY3PTt7OSoahYc4nM0HY67SvK0YyS0GLwA= diff --git a/pkg/meta/base.go b/pkg/meta/base.go index 8279efffc63d..97a8123b8ede 100644 --- a/pkg/meta/base.go +++ b/pkg/meta/base.go @@ -1180,6 +1180,9 @@ func (m *baseMeta) Link(ctx Context, inode, parent Ino, name string, attr *Attr) if attr.Typ == TypeDirectory { return syscall.EPERM } + if attr.Flags&FlagTmpFile != 0 { + return syscall.ENOENT + } if m.checkDirQuota(ctx, parent, align4K(attr.Length), 1) { return syscall.EDQUOT } diff --git a/pkg/meta/interface.go b/pkg/meta/interface.go index a601c6bc7eea..65b1d1345225 100644 --- a/pkg/meta/interface.go +++ b/pkg/meta/interface.go @@ -93,6 +93,7 @@ const ( const ( FlagImmutable = 1 << iota FlagAppend + FlagTmpFile ) const ( diff --git a/pkg/vfs/vfs.go b/pkg/vfs/vfs.go index c46c91aa1d4d..1b81b9f5509c 100644 --- a/pkg/vfs/vfs.go +++ b/pkg/vfs/vfs.go @@ -27,6 +27,7 @@ import ( "syscall" "time" + "github.com/google/uuid" "github.com/juicedata/juicefs/pkg/acl" "github.com/juicedata/juicefs/pkg/chunk" "github.com/juicedata/juicefs/pkg/meta" @@ -474,10 +475,17 @@ func (v *VFS) Releasedir(ctx Context, ino Ino, fh uint64) int { return 0 } +const O_TMPFILE = 020000000 + func (v *VFS) Create(ctx Context, parent Ino, name string, mode uint16, cumask uint16, flags uint32) (entry *meta.Entry, fh uint64, err syscall.Errno) { defer func() { logit(ctx, "create", err, "(%d,%s,%s:0%04o):%s [fh:%d]", parent, name, smode(mode), mode, (*Entry)(entry), fh) }() + // O_TMPFILE support + doUnlink := runtime.GOOS == "linux" && flags&O_TMPFILE != 0 + if doUnlink { + name = fmt.Sprintf("tmpfile_%s", uuid.New().String()) + } if parent == rootID && IsSpecialName(name) { err = syscall.EEXIST return @@ -498,6 +506,16 @@ func (v *VFS) Create(ctx Context, parent Ino, name string, mode uint16, cumask u fh = v.newFileHandle(inode, attr.Length, flags) entry = &meta.Entry{Inode: inode, Attr: attr} v.invalidateDirHandle(parent, name, inode, attr) + + if doUnlink { + if flags&syscall.O_EXCL != 0 { + attr.Flags |= meta.FlagTmpFile + if err = v.Meta.SetAttr(ctx, inode, uint16(meta.SetAttrFlag), 0, attr); err != 0 { + logger.Warnf("set flag for tmpfile %d failed: %s", inode, err) + } + } + err = v.Unlink(ctx, parent, name) + } } return }