Skip to content

Commit da80e90

Browse files
6543zeripathtechknowlogick
authored
Fix race in local storage (#14888) (#14901)
LocalStorage should only put completed files in position Signed-off-by: Andrew Thornton <[email protected]> Co-authored-by: zeripath <[email protected]> Co-authored-by: techknowlogick <[email protected]>
1 parent 74dc223 commit da80e90

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
@@ -45,9 +48,14 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
4548
return nil, err
4649
}
4750

51+
if config.TemporaryPath == "" {
52+
config.TemporaryPath = config.Path + "/tmp"
53+
}
54+
4855
return &LocalStorage{
49-
ctx: ctx,
50-
dir: config.Path,
56+
ctx: ctx,
57+
dir: config.Path,
58+
tmpdir: config.TemporaryPath,
5159
}, nil
5260
}
5361

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

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

71-
f, err := os.Create(p)
89+
n, err := io.Copy(tmp, r)
7290
if err != nil {
7391
return 0, err
7492
}
75-
defer f.Close()
76-
return io.Copy(f, r)
93+
94+
if err := tmp.Close(); err != nil {
95+
return 0, err
96+
}
97+
98+
if err := os.Rename(tmp.Name(), p); err != nil {
99+
return 0, err
100+
}
101+
102+
tmpRemoved = true
103+
104+
return n, nil
77105
}
78106

79107
// Stat returns the info of the file

0 commit comments

Comments
 (0)