Skip to content

Commit

Permalink
feat: add option to configure mode permissions on new directories
Browse files Browse the repository at this point in the history
We had 0755 hard coded for newly created directories before. This
adds a user option to configure what the default mode permissions
should be for newly created directories.

Fixes #878
  • Loading branch information
benmcclelland committed Oct 16, 2024
1 parent a78c826 commit 2c713c5
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 25 deletions.
11 changes: 3 additions & 8 deletions backend/mkdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ import (
"github.com/versity/versitygw/s3err"
)

var (
// TODO: make this configurable
defaultDirPerm fs.FileMode = 0755
)

// MkdirAll is similar to os.MkdirAll but it will return
// ErrObjectParentIsFile when appropriate
// MkdirAll creates a directory named path,
Expand All @@ -32,7 +27,7 @@ var (
// and returns nil.
// Any directory created will be set to provided uid/gid ownership
// if doChown is true.
func MkdirAll(path string, uid, gid int, doChown bool) error {
func MkdirAll(path string, uid, gid int, doChown bool, dirPerm fs.FileMode) error {
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := os.Stat(path)
if err == nil {
Expand All @@ -55,14 +50,14 @@ func MkdirAll(path string, uid, gid int, doChown bool) error {

if j > 1 {
// Create parent.
err = MkdirAll(path[:j-1], uid, gid, doChown)
err = MkdirAll(path[:j-1], uid, gid, doChown, dirPerm)
if err != nil {
return err
}
}

// Parent now exists; invoke Mkdir and use its result.
err = os.Mkdir(path, defaultDirPerm)
err = os.Mkdir(path, dirPerm)
if err != nil {
// Handle arguments like "foo/." by
// double-checking that directory doesn't exist.
Expand Down
20 changes: 10 additions & 10 deletions backend/posix/posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ type Posix struct {

// bucket versioning directory path
versioningDir string

// newDirPerm is the permission to set on newly created directories
newDirPerm fs.FileMode
}

var _ backend.Backend = &Posix{}
Expand Down Expand Up @@ -103,6 +106,7 @@ type PosixOpts struct {
ChownGID bool
BucketLinks bool
VersioningDir string
NewDirPerm fs.FileMode
}

func New(rootdir string, meta meta.MetadataStorer, opts PosixOpts) (*Posix, error) {
Expand Down Expand Up @@ -167,6 +171,7 @@ func New(rootdir string, meta meta.MetadataStorer, opts PosixOpts) (*Posix, erro
chowngid: opts.ChownGID,
bucketlinks: opts.BucketLinks,
versioningDir: verioningdirAbs,
newDirPerm: opts.NewDirPerm,
}, nil
}

Expand Down Expand Up @@ -291,11 +296,6 @@ func (p *Posix) HeadBucket(_ context.Context, input *s3.HeadBucketInput) (*s3.He
return &s3.HeadBucketOutput{}, nil
}

var (
// TODO: make this configurable
defaultDirPerm fs.FileMode = 0755
)

func (p *Posix) CreateBucket(ctx context.Context, input *s3.CreateBucketInput, acl []byte) error {
if input.Bucket == nil {
return s3err.GetAPIError(s3err.ErrInvalidBucketName)
Expand All @@ -310,7 +310,7 @@ func (p *Posix) CreateBucket(ctx context.Context, input *s3.CreateBucketInput, a

bucket := *input.Bucket

err := os.Mkdir(bucket, defaultDirPerm)
err := os.Mkdir(bucket, p.newDirPerm)
if err != nil && os.IsExist(err) {
aclJSON, err := p.meta.RetrieveAttribute(nil, bucket, "", aclkey)
if err != nil {
Expand Down Expand Up @@ -642,7 +642,7 @@ func (p *Posix) createObjVersion(bucket, key string, size int64, acc auth.Accoun

versionPath = filepath.Join(versionBucketPath, versioningKey)

err = os.MkdirAll(filepath.Join(versionBucketPath, genObjVersionKey(key)), defaultDirPerm)
err = os.MkdirAll(filepath.Join(versionBucketPath, genObjVersionKey(key)), p.newDirPerm)
if err != nil {
return versionPath, err
}
Expand Down Expand Up @@ -1375,7 +1375,7 @@ func (p *Posix) CompleteMultipartUpload(ctx context.Context, input *s3.CompleteM
dir := filepath.Dir(objname)
if dir != "" {
uid, gid, doChown := p.getChownIDs(acct)
err = backend.MkdirAll(dir, uid, gid, doChown)
err = backend.MkdirAll(dir, uid, gid, doChown, p.newDirPerm)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -2158,7 +2158,7 @@ func (p *Posix) PutObject(ctx context.Context, po *s3.PutObjectInput) (s3respons
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrDirectoryObjectContainsData)
}

err = backend.MkdirAll(name, uid, gid, doChown)
err = backend.MkdirAll(name, uid, gid, doChown, p.newDirPerm)
if err != nil {
if errors.Is(err, syscall.EDQUOT) {
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrQuotaExceeded)
Expand Down Expand Up @@ -2248,7 +2248,7 @@ func (p *Posix) PutObject(ctx context.Context, po *s3.PutObjectInput) (s3respons

dir := filepath.Dir(name)
if dir != "" {
err = backend.MkdirAll(dir, uid, gid, doChown)
err = backend.MkdirAll(dir, uid, gid, doChown, p.newDirPerm)
if err != nil {
return s3response.PutObjectOutput{}, s3err.GetAPIError(s3err.ErrExistingObjectIsDirectory)
}
Expand Down
6 changes: 4 additions & 2 deletions backend/posix/with_otmpfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type tmpfile struct {
needsChown bool
uid int
gid int
newDirPerm fs.FileMode
}

var (
Expand All @@ -62,7 +63,7 @@ func (p *Posix) openTmpFile(dir, bucket, obj string, size int64, acct auth.Accou
fd, err := unix.Open(dir, unix.O_RDWR|unix.O_TMPFILE|unix.O_CLOEXEC, defaultFilePerm)
if err != nil {
// O_TMPFILE not supported, try fallback
err = backend.MkdirAll(dir, uid, gid, doChown)
err = backend.MkdirAll(dir, uid, gid, doChown, p.newDirPerm)
if err != nil {
return nil, fmt.Errorf("make temp dir: %w", err)
}
Expand Down Expand Up @@ -108,6 +109,7 @@ func (p *Posix) openTmpFile(dir, bucket, obj string, size int64, acct auth.Accou
needsChown: doChown,
uid: uid,
gid: gid,
newDirPerm: p.newDirPerm,
}

// falloc is best effort, its fine if this fails
Expand Down Expand Up @@ -151,7 +153,7 @@ func (tmp *tmpfile) link() error {

dir := filepath.Dir(objPath)

err = backend.MkdirAll(dir, tmp.uid, tmp.gid, tmp.needsChown)
err = backend.MkdirAll(dir, tmp.uid, tmp.gid, tmp.needsChown, tmp.newDirPerm)
if err != nil {
return fmt.Errorf("make parent dir: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion backend/posix/without_otmpfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (p *Posix) openTmpFile(dir, bucket, obj string, size int64, acct auth.Accou

// Create a temp file for upload while in progress (see link comments below).
var err error
err = backend.MkdirAll(dir, uid, gid, doChown)
err = backend.MkdirAll(dir, uid, gid, doChown, p.newDirPerm)
if err != nil {
return nil, fmt.Errorf("make temp dir: %w", err)
}
Expand Down
6 changes: 5 additions & 1 deletion backend/scoutfs/scoutfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type ScoutfsOpts struct {
ChownGID bool
GlacierMode bool
BucketLinks bool
NewDirPerm fs.FileMode
}

type ScoutFS struct {
Expand Down Expand Up @@ -74,6 +75,9 @@ type ScoutFS struct {
// used to determine if chowning is needed
euid int
egid int

// newDirPerm is the permissions to use when creating new directories
newDirPerm fs.FileMode
}

var _ backend.Backend = &ScoutFS{}
Expand Down Expand Up @@ -277,7 +281,7 @@ func (s *ScoutFS) CompleteMultipartUpload(ctx context.Context, input *s3.Complet
dir := filepath.Dir(objname)
if dir != "" {
uid, gid, doChown := s.getChownIDs(acct)
err = backend.MkdirAll(dir, uid, gid, doChown)
err = backend.MkdirAll(dir, uid, gid, doChown, s.newDirPerm)
if err != nil {
return nil, err
}
Expand Down
7 changes: 5 additions & 2 deletions backend/scoutfs/scoutfs_compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func New(rootdir string, opts ScoutfsOpts) (*ScoutFS, error) {
ChownUID: opts.ChownUID,
ChownGID: opts.ChownGID,
BucketLinks: opts.BucketLinks,
NewDirPerm: opts.NewDirPerm,
})
if err != nil {
return nil, err
Expand All @@ -58,6 +59,7 @@ func New(rootdir string, opts ScoutfsOpts) (*ScoutFS, error) {
chownuid: opts.ChownUID,
chowngid: opts.ChownGID,
glaciermode: opts.GlacierMode,
newDirPerm: opts.NewDirPerm,
}, nil
}

Expand All @@ -71,10 +73,10 @@ type tmpfile struct {
needsChown bool
uid int
gid int
newDirPerm fs.FileMode
}

var (
// TODO: make this configurable
defaultFilePerm uint32 = 0644
)

Expand Down Expand Up @@ -102,6 +104,7 @@ func (s *ScoutFS) openTmpFile(dir, bucket, obj string, size int64, acct auth.Acc
needsChown: doChown,
uid: uid,
gid: gid,
newDirPerm: s.newDirPerm,
}

if doChown {
Expand Down Expand Up @@ -129,7 +132,7 @@ func (tmp *tmpfile) link() error {

dir := filepath.Dir(objPath)

err = backend.MkdirAll(dir, tmp.uid, tmp.gid, tmp.needsChown)
err = backend.MkdirAll(dir, tmp.uid, tmp.gid, tmp.needsChown, tmp.newDirPerm)
if err != nil {
return fmt.Errorf("make parent dir: %w", err)
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/versitygw/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ func initPosix(ctx context.Context) {
log.Fatalf("make temp directory: %v", err)
}

be, err := posix.New(tempdir, meta.XattrMeta{}, posix.PosixOpts{})
be, err := posix.New(tempdir, meta.XattrMeta{}, posix.PosixOpts{
NewDirPerm: 0755,
})
if err != nil {
log.Fatalf("init posix: %v", err)
}
Expand Down
16 changes: 16 additions & 0 deletions cmd/versitygw/posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package main

import (
"fmt"
"io/fs"
"math"

"github.com/urfave/cli/v2"
"github.com/versity/versitygw/backend/meta"
Expand All @@ -26,6 +28,7 @@ var (
chownuid, chowngid bool
bucketlinks bool
versioningDir string
dirPerms uint
)

func posixCommand() *cli.Command {
Expand Down Expand Up @@ -68,6 +71,14 @@ will be translated into the file /mnt/fs/gwroot/mybucket/a/b/c/myobject`,
EnvVars: []string{"VGW_VERSIONING_DIR"},
Destination: &versioningDir,
},
&cli.UintFlag{
Name: "dir-perms",
Usage: "default directory permissions for new directories",
EnvVars: []string{"VGW_DIR_PERMS"},
Destination: &dirPerms,
DefaultText: "0755",
Value: 0755,
},
},
}
}
Expand All @@ -83,11 +94,16 @@ func runPosix(ctx *cli.Context) error {
return fmt.Errorf("posix xattr check: %v", err)
}

if dirPerms > math.MaxUint32 {
return fmt.Errorf("invalid directory permissions: %d", dirPerms)
}

be, err := posix.New(gwroot, meta.XattrMeta{}, posix.PosixOpts{
ChownUID: chownuid,
ChownGID: chowngid,
BucketLinks: bucketlinks,
VersioningDir: versioningDir,
NewDirPerm: fs.FileMode(dirPerms),
})
if err != nil {
return fmt.Errorf("init posix: %v", err)
Expand Down
15 changes: 15 additions & 0 deletions cmd/versitygw/scoutfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package main

import (
"fmt"
"io/fs"
"math"

"github.com/urfave/cli/v2"
"github.com/versity/versitygw/backend/scoutfs"
Expand Down Expand Up @@ -69,6 +71,14 @@ move interfaces as well as support for tiered filesystems.`,
EnvVars: []string{"VGW_BUCKET_LINKS"},
Destination: &bucketlinks,
},
&cli.UintFlag{
Name: "dir-perms",
Usage: "default directory permissions for new directories",
EnvVars: []string{"VGW_DIR_PERMS"},
Destination: &dirPerms,
DefaultText: "0755",
Value: 0755,
},
},
}
}
Expand All @@ -78,11 +88,16 @@ func runScoutfs(ctx *cli.Context) error {
return fmt.Errorf("no directory provided for operation")
}

if dirPerms > math.MaxUint32 {
return fmt.Errorf("invalid directory permissions: %d", dirPerms)
}

var opts scoutfs.ScoutfsOpts
opts.GlacierMode = glacier
opts.ChownUID = chownuid
opts.ChownGID = chowngid
opts.BucketLinks = bucketlinks
opts.NewDirPerm = fs.FileMode(dirPerms)

be, err := scoutfs.New(ctx.Args().Get(0), opts)
if err != nil {
Expand Down

0 comments on commit 2c713c5

Please sign in to comment.