Skip to content

Commit 144cfe5

Browse files
authored
Fix race in local storage (#14888)
LocalStorage should only put completed files in position Signed-off-by: Andrew Thornton <[email protected]>
1 parent 7525450 commit 144cfe5

File tree

1 file changed

+38
-10
lines changed

1 file changed

+38
-10
lines changed

modules/storage/local.go

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package storage
77
import (
88
"context"
99
"io"
10+
"io/ioutil"
1011
"net/url"
1112
"os"
1213
"path/filepath"
@@ -24,13 +25,15 @@ const LocalStorageType Type = "local"
2425

2526
// LocalStorageConfig represents the configuration for a local storage
2627
type LocalStorageConfig struct {
27-
Path string `ini:"PATH"`
28+
Path string `ini:"PATH"`
29+
TemporaryPath string `ini:"TEMPORARY_PATH"`
2830
}
2931

3032
// LocalStorage represents a local files storage
3133
type LocalStorage struct {
32-
ctx context.Context
33-
dir string
34+
ctx context.Context
35+
dir string
36+
tmpdir string
3437
}
3538

3639
// NewLocalStorage returns a local files
@@ -46,9 +49,14 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
4649
return nil, err
4750
}
4851

52+
if config.TemporaryPath == "" {
53+
config.TemporaryPath = config.Path + "/tmp"
54+
}
55+
4956
return &LocalStorage{
50-
ctx: ctx,
51-
dir: config.Path,
57+
ctx: ctx,
58+
dir: config.Path,
59+
tmpdir: config.TemporaryPath,
5260
}, nil
5361
}
5462

@@ -64,17 +72,37 @@ func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) {
6472
return 0, err
6573
}
6674

67-
// always override
68-
if err := util.Remove(p); err != nil {
75+
// Create a temporary file to save to
76+
if err := os.MkdirAll(l.tmpdir, os.ModePerm); err != nil {
6977
return 0, err
7078
}
79+
tmp, err := ioutil.TempFile(l.tmpdir, "upload-*")
80+
if err != nil {
81+
return 0, err
82+
}
83+
tmpRemoved := false
84+
defer func() {
85+
if !tmpRemoved {
86+
_ = util.Remove(tmp.Name())
87+
}
88+
}()
7189

72-
f, err := os.Create(p)
90+
n, err := io.Copy(tmp, r)
7391
if err != nil {
7492
return 0, err
7593
}
76-
defer f.Close()
77-
return io.Copy(f, r)
94+
95+
if err := tmp.Close(); err != nil {
96+
return 0, err
97+
}
98+
99+
if err := os.Rename(tmp.Name(), p); err != nil {
100+
return 0, err
101+
}
102+
103+
tmpRemoved = true
104+
105+
return n, nil
78106
}
79107

80108
// Stat returns the info of the file

0 commit comments

Comments
 (0)