Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 12, 04:30 UTC
log: Only chmod if permission bits differ; make log dir (#6761)
* log: Only chmod if permission bits differ Follow-up to #6314 and https://caddy.community/t/caddy-2-9-0-breaking-change/27576/11 * Fix test * Refactor FileWriter * Ooooh octal... right...
Matt Holt committed
Jan 7, 2025 at 21:51 UTC
1f927d6b07d52d7cf46f1f3020c1ea5993a3e5e8
2 files changed
+57
-38
modules/logging/filewriter.go
+54
-36
@@ -20,6 +20,7 @@ import (
20
"io"
21
"math"
22
"os"
23
+ "path/filepath"
24
"strconv"
25
26
"github.com/dustin/go-humanize"
@@ -146,51 +147,68 @@ func (fw FileWriter) WriterKey() string {
147
148
// OpenWriter opens a new file writer.
149
func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
149
- if fw.Mode == 0 {
150
- fw.Mode = 0o600
150
+ modeIfCreating := os.FileMode(fw.Mode)
151
+ if modeIfCreating == 0 {
152
+ modeIfCreating = 0o600
153
}
154
153
- // roll log files by default
154
- if fw.Roll == nil || *fw.Roll {
155
- if fw.RollSizeMB == 0 {
156
- fw.RollSizeMB = 100
157
- }
158
- if fw.RollCompress == nil {
159
- compress := true
160
- fw.RollCompress = &compress
161
- }
162
- if fw.RollKeep == 0 {
163
- fw.RollKeep = 10
164
- }
165
- if fw.RollKeepDays == 0 {
166
- fw.RollKeepDays = 90
167
- }
155
+ // roll log files as a sensible default to avoid disk space exhaustion
156
+ roll := fw.Roll == nil || *fw.Roll
157
169
- // create the file if it does not exist with the right mode.
170
- // lumberjack will reuse the file mode across log rotation.
171
- f_tmp, err := os.OpenFile(fw.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(fw.Mode))
158
+ // create the file if it does not exist; create with the configured mode, or default
159
+ // to restrictive if not set. (lumberjack will reuse the file mode across log rotation)
160
+ if err := os.MkdirAll(filepath.Dir(fw.Filename), 0o700); err != nil {
161
+ return nil, err
162
+ }
163
+ file, err := os.OpenFile(fw.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, modeIfCreating)
164
+ if err != nil {
165
+ return nil, err
166
+ }
167
+ info, err := file.Stat()
168
+ if roll {
169
+ file.Close() // lumberjack will reopen it on its own
170
+ }
171
+
172
+ // Ensure already existing files have the right mode, since OpenFile will not set the mode in such case.
173
+ if configuredMode := os.FileMode(fw.Mode); configuredMode != 0 {
174
if err != nil {
173
- return nil, err
175
+ return nil, fmt.Errorf("unable to stat log file to see if we need to set permissions: %v", err)
176
}
175
- f_tmp.Close()
176
- // ensure already existing files have the right mode,
177
- // since OpenFile will not set the mode in such case.
178
- if err = os.Chmod(fw.Filename, os.FileMode(fw.Mode)); err != nil {
179
- return nil, err
177
+ // only chmod if the configured mode is different
178
+ if info.Mode()&os.ModePerm != configuredMode&os.ModePerm {
179
+ if err = os.Chmod(fw.Filename, configuredMode); err != nil {
180
+ return nil, err
181
+ }
182
}
183
+ }
184
182
- return &lumberjack.Logger{
183
- Filename: fw.Filename,
184
- MaxSize: fw.RollSizeMB,
185
- MaxAge: fw.RollKeepDays,
186
- MaxBackups: fw.RollKeep,
187
- LocalTime: fw.RollLocalTime,
188
- Compress: *fw.RollCompress,
189
- }, nil
185
+ // if not rolling, then the plain file handle is all we need
186
+ if !roll {
187
+ return file, nil
188
}
189
192
- // otherwise just open a regular file
193
- return os.OpenFile(fw.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(fw.Mode))
190
+ // otherwise, return a rolling log
191
+ if fw.RollSizeMB == 0 {
192
+ fw.RollSizeMB = 100
193
+ }
194
+ if fw.RollCompress == nil {
195
+ compress := true
196
+ fw.RollCompress = &compress
197
+ }
198
+ if fw.RollKeep == 0 {
199
+ fw.RollKeep = 10
200
+ }
201
+ if fw.RollKeepDays == 0 {
202
+ fw.RollKeepDays = 90
203
+ }
204
+ return &lumberjack.Logger{
205
+ Filename: fw.Filename,
206
+ MaxSize: fw.RollSizeMB,
207
+ MaxAge: fw.RollKeepDays,
208
+ MaxBackups: fw.RollKeep,
209
+ LocalTime: fw.RollLocalTime,
210
+ Compress: *fw.RollCompress,
211
+ }, nil
212
}
213
214
// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
modules/logging/filewriter_test.go
+3
-2
@@ -20,6 +20,7 @@ import (
20
"encoding/json"
21
"os"
22
"path"
23
+ "path/filepath"
24
"syscall"
25
"testing"
26
@@ -77,7 +78,7 @@ func TestFileCreationMode(t *testing.T) {
78
t.Fatalf("failed to create tempdir: %v", err)
79
}
80
defer os.RemoveAll(dir)
80
- fpath := path.Join(dir, "test.log")
81
+ fpath := filepath.Join(dir, "test.log")
82
tt.fw.Filename = fpath
83
84
logger, err := tt.fw.OpenWriter()
@@ -92,7 +93,7 @@ func TestFileCreationMode(t *testing.T) {
93
}
94
95
if st.Mode() != tt.wantMode {
95
- t.Errorf("file mode is %v, want %v", st.Mode(), tt.wantMode)
96
+ t.Errorf("%s: file mode is %v, want %v", tt.name, st.Mode(), tt.wantMode)
97
}
98
})
99
}