| 66 | } |
| 67 | |
| 68 | func appendToFile(fileName string, data []byte) error { |
| 69 | f, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) |
| 70 | if err != nil { |
| 71 | // Some filesystems (e.g. FUSE-mounted cloud storage) reject O_APPEND |
| 72 | // at open time. Fall back to read + rewrite. |
| 73 | return appendToFileFallback(fileName, data) |
| 74 | } |
| 75 | n, writeErr := f.Write(data) |
| 76 | closeErr := f.Close() |
| 77 | if writeErr != nil { |
| 78 | if n > 0 { |
| 79 | // Partial write: some bytes were already persisted, so falling back |
| 80 | // to read + rewrite would duplicate them. Treat as non-recoverable. |
| 81 | return fmt.Errorf("partial write to %s (%d/%d bytes): %w", fileName, n, len(data), writeErr) |
| 82 | } |
| 83 | // Zero bytes written — safe to retry via read + rewrite. |
| 84 | return appendToFileFallback(fileName, data) |
| 85 | } |
| 86 | return closeErr |
| 87 | } |
| 88 | |
| 89 | // appendToFileFallback appends data by reading the existing file, then rewriting |
| 90 | // with the new data added. This is used as a fallback when O_APPEND is not |