Skip to content

Commit

Permalink
updated Options to use string for file permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
funkyshu committed Sep 16, 2024
1 parent 5c3ef8c commit d43bb65
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 19 deletions.
11 changes: 6 additions & 5 deletions backend/sftp/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,22 @@ Example:
},
)
# DefaultPermissions
# FilePermissions
The `DefaultPermissions` option allows you to specify the default file permissions for files created or modified using the SFTP backend.
Permissions should be specified using an octal literal (e.g., `0777` for full read, write, and execute permissions for all users).
The `FilePermissions` option allows you to specify the file permissions for files created or modified using the SFTP backend.
These permissions will override the sftp server or underlying filesystem's umask (default permissions). Permissions should
be specified using an octal literal (e.g., `0777` for full read, write, and execute permissions for all users).
Example:
fs = fs.WithOptions(
sftp.Options{
DefaultPermissions: &os.FileMode(0777), // Correctly specify permissions as octal
FilePermissions: &os.FileMode(0777), // Correctly specify permissions as octal
// other settings
},
)
When a file is opened for Write() or Touch()'d, the specified `DefaultPermissions` will be applied to the file.
When a file is opened for Write() or Touch()'d, the specified `FilePermissions` will be applied to the file.
# AutoDisconnect
Expand Down
31 changes: 25 additions & 6 deletions backend/sftp/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,13 +504,32 @@ func (f *File) _open(flags int) (ReadWriteSeekCloser, error) {
return rwsc, nil
}

// setPermissions sets the file permissions if the default permissions are set in the options
// setPermissions sets the file permissions if they are set in the options
func (f *File) setPermissions(client Client, opts vfs.Options) error {
if opts != nil && opts.(Options).DefaultPermissions != nil {
err := client.Chmod(f.Path(), *f.fileSystem.options.(Options).DefaultPermissions)
if err != nil {
return fmt.Errorf("chmod err: %w", err)
}
if opts == nil {
return nil
}

// ensure we're dealing with pointer to Options
ptrOpts, ok := opts.(*Options)
if !ok {
p := opts.(Options)
ptrOpts = &p
}

// if file permissions are not set, return early
if ptrOpts.FilePermissions == nil {
return nil
}

// get file mode
perms, err := ptrOpts.GetFileMode()
if err != nil {
return fmt.Errorf("get file mode err: %w", err)
}

if err := client.Chmod(f.Path(), *perms); err != nil {
return fmt.Errorf("chmod err: %w", err)
}

return nil
Expand Down
11 changes: 5 additions & 6 deletions backend/sftp/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (ts *fileTestSuite) Test_openFile() {
Authority: authority,
fileSystem: &FileSystem{
sftpclient: client,
options: Options{DefaultPermissions: utils.Ptr(os.FileMode(0644))},
options: Options{FilePermissions: utils.Ptr("0644")},
},
}

Expand Down Expand Up @@ -831,10 +831,9 @@ func (ts *fileTestSuite) TestTouch() {
fileSystem: &FileSystem{
sftpclient: client,
options: Options{
DefaultPermissions: func() *os.FileMode {
FilePermissions: func() *string {
if tc.setPermissions {
mode := os.FileMode(0666)
return &mode
return utils.Ptr("0666")
}
return nil
}(),
Expand Down Expand Up @@ -974,7 +973,7 @@ func (ts *fileTestSuite) TestSetDefaultPermissions() {
return client
}(),
options: func() vfs.Options {
opts := Options{DefaultPermissions: utils.Ptr(os.FileMode(0644))}
opts := Options{FilePermissions: utils.Ptr("0644")}
return opts
}(),
expectedError: false,
Expand All @@ -987,7 +986,7 @@ func (ts *fileTestSuite) TestSetDefaultPermissions() {
return client
}(),
options: func() vfs.Options {
opts := Options{DefaultPermissions: utils.Ptr(os.FileMode(0644))}
opts := Options{FilePermissions: utils.Ptr("0644")}
return opts
}(),
expectedError: true,
Expand Down
20 changes: 18 additions & 2 deletions backend/sftp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path"
"runtime"
"strconv"

"github.com/mitchellh/go-homedir"
_sftp "github.com/pkg/sftp"
Expand All @@ -31,8 +32,23 @@ type Options struct {
HostKeyAlgorithms []string `json:"hostKeyAlgorithms,omitempty"`
AutoDisconnect int `json:"autoDisconnect,omitempty"` // seconds before disconnecting. default: 10
KnownHostsCallback ssh.HostKeyCallback // env var VFS_SFTP_INSECURE_KNOWN_HOSTS
FileBufferSize int // Buffer Size In Bytes Used with utils.TouchCopyBuffered
DefaultPermissions *os.FileMode // Default Permissions for new files
FileBufferSize int `json:"fileBufferSize,omitempty"` // Buffer Size In Bytes Used with utils.TouchCopyBuffered
FilePermissions *string `json:"filePermissions,omitempty"` // Default File Permissions for new files
}

// GetFileMode converts the FilePermissions string to os.FileMode.
func (o *Options) GetFileMode() (*os.FileMode, error) {
if o.FilePermissions == nil {
return nil, nil
}

// Convert the string to an unsigned integer, interpreting it as an octal value
parsed, err := strconv.ParseUint(*o.FilePermissions, 0, 32)
if err != nil {
return nil, fmt.Errorf("invalid file mode: %v", err)
}
mode := os.FileMode(parsed)
return &mode, nil
}

var defaultSSHConfig = &ssh.ClientConfig{
Expand Down
63 changes: 63 additions & 0 deletions backend/sftp/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,69 @@ func (o *optionsSuite) TestGetSSHConfig() {
}
}

func (o *optionsSuite) TestGetFileMode() {
tests := []struct {
name string
filePermissions *string
expectedMode *os.FileMode
expectError bool
}{
{
name: "NilFilePermissions",
filePermissions: nil,
expectedMode: nil,
expectError: false,
},
{
name: "ValidOctalString",
filePermissions: utils.Ptr("0755"),
expectedMode: utils.Ptr(os.FileMode(0755)),
expectError: false,
},
{
name: "InvalidString",
filePermissions: utils.Ptr("invalid"),
expectedMode: nil,
expectError: true,
},
{
name: "EmptyString",
filePermissions: utils.Ptr(""),
expectedMode: nil,
expectError: true,
},
{
name: "ValidDecimalString",
filePermissions: utils.Ptr("493"), // 0755 in decimal
expectedMode: utils.Ptr(os.FileMode(0755)),
expectError: false,
},
}

for _, tt := range tests {
o.Run(tt.name, func() {
opts := &Options{
FilePermissions: tt.filePermissions,
}
mode, err := opts.GetFileMode()
if tt.expectError {
o.Error(err)
} else {
o.NoError(err)
o.Equal(tt.expectedMode, mode)
}
})
}
}

func strPtr(s string) *string {

Check failure on line 611 in backend/sftp/options_test.go

View workflow job for this annotation

GitHub Actions / lint

func `strPtr` is unused (unused)
return &s
}

func modePtr(m os.FileMode) *os.FileMode {

Check failure on line 615 in backend/sftp/options_test.go

View workflow job for this annotation

GitHub Actions / lint

func `modePtr` is unused (unused)
return &m
}

func TestUtils(t *testing.T) {
suite.Run(t, new(optionsSuite))
}
Expand Down

0 comments on commit d43bb65

Please sign in to comment.