@marcel91200 / caddy Mirror · read-only / commits / 1f927d6b
Fork 0

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 }