Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blob/fileblob: Allow customization of the FileMode #3426

Merged
merged 1 commit into from Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 23 additions & 3 deletions blob/fileblob/fileblob.go
Expand Up @@ -110,6 +110,9 @@ const Scheme = "file"
//
// - create_dir: (any non-empty value) the directory is created (using os.MkDirAll)
// if it does not already exist.
// - dir_file_mode: any directories that are created (the base directory when create_dir
// is true, or subdirectories for keys) are created using this os.FileMode, parsed
// using os.Parseuint. Defaults to 0777.
// - no_tmp_dir: (any non-empty value) temporary files are created next to the final
// path instead of in os.TempDir.
// - base_url: the base URL to use to construct signed URLs; see URLSignerHMAC
Expand Down Expand Up @@ -160,6 +163,7 @@ var recognizedParams = map[string]bool{
"secret_key_path": true,
"metadata": true,
"no_tmp_dir": true,
"dir_file_mode": true,
}

type metadataOption string // Not exported as subject to change.
Expand Down Expand Up @@ -198,13 +202,20 @@ func (o *URLOpener) forParams(ctx context.Context, q url.Values) (*Options, erro
if q.Get("create_dir") != "" {
opts.CreateDir = true
}
if fms := q.Get("dir_file_mode"); fms != "" {
fm, err := strconv.ParseUint(fms, 10, 32)
if err != nil {
return nil, fmt.Errorf("fileblob.OpenBucket: invalid dir_file_mode %q: %v", fms, err)
}
opts.DirFileMode = os.FileMode(fm)
}
if q.Get("no_tmp_dir") != "" {
opts.NoTempDir = true
}
baseURL := q.Get("base_url")
keyPath := q.Get("secret_key_path")
if (baseURL == "") != (keyPath == "") {
return nil, errors.New("must supply both base_url and secret_key_path query parameters")
return nil, errors.New("fileblob.OpenBucket: must supply both base_url and secret_key_path query parameters")
}
if baseURL != "" {
burl, err := url.Parse(baseURL)
Expand Down Expand Up @@ -232,6 +243,11 @@ type Options struct {
// (using os.MkdirAll).
CreateDir bool

// The FileMode to use when creating directories for the top-level directory
// backing the bucket (when CreateDir is true), and for subdirectories for keys.
// Defaults to 0777.
DirFileMode os.FileMode

// If true, don't use os.TempDir for temporary files, but instead place them
// next to the actual files. This may result in "stranded" temporary files
// (e.g., if the application is killed before the file cleanup runs).
Expand All @@ -257,6 +273,10 @@ func openBucket(dir string, opts *Options) (driver.Bucket, error) {
if opts == nil {
opts = &Options{}
}
if opts.DirFileMode == 0 {
opts.DirFileMode = os.FileMode(0777)
}

absdir, err := filepath.Abs(dir)
if err != nil {
return nil, fmt.Errorf("failed to convert %s into an absolute path: %v", dir, err)
Expand All @@ -265,7 +285,7 @@ func openBucket(dir string, opts *Options) (driver.Bucket, error) {

// Optionally, create the directory if it does not already exist.
if err != nil && opts.CreateDir && os.IsNotExist(err) {
err = os.MkdirAll(absdir, os.FileMode(0777))
err = os.MkdirAll(absdir, opts.DirFileMode)
if err != nil {
return nil, fmt.Errorf("tried to create directory but failed: %v", err)
}
Expand Down Expand Up @@ -699,7 +719,7 @@ func (b *bucket) NewTypedWriter(ctx context.Context, key string, contentType str
if err != nil {
return nil, err
}
if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0777)); err != nil {
if err := os.MkdirAll(filepath.Dir(path), b.opts.DirFileMode); err != nil {
return nil, err
}
f, err := createTemp(path, b.opts.NoTempDir)
Expand Down
6 changes: 6 additions & 0 deletions blob/fileblob/fileblob_test.go
Expand Up @@ -394,6 +394,12 @@ func TestOpenBucketFromURL(t *testing.T) {
{"file://" + dirpath + "subdir", "", true, false, ""},
// Subdir does not exist, but create_dir creates it. Error is at file read time.
{"file://" + dirpath + "subdir2?create_dir=true", "filenotfound.txt", false, true, ""},
// Invalid dir_file_mode.
{"file://" + dirpath + "subdir?dir_file_mode=x", "myfile.txt", true, false, ""},
// Another invalid dir_file_mode.
{"file://" + dirpath + "subdir?dir_file_mode=-1", "myfile.txt", true, false, ""},
// Valid dir_file_mode.
{"file://" + dirpath + "subdir3?dir_file_mode=666&create_dir=true", "filenotfound.txt", false, true, ""},
// Invalid query parameter.
{"file://" + dirpath + "?param=value", "myfile.txt", true, false, ""},
// Unrecognized value for parameter "metadata".
Expand Down