100KB
(expandedPath string, verb string, mustExist bool)
| 18 | const MaxEditFileSize = 100 * 1024 // 100KB |
| 19 | |
| 20 | func validateTextFile(expandedPath string, verb string, mustExist bool) (os.FileInfo, error) { |
| 21 | if blocked, reason := isBlockedFile(expandedPath); blocked { |
| 22 | return nil, fmt.Errorf("access denied: potentially sensitive file: %s", reason) |
| 23 | } |
| 24 | |
| 25 | fileInfo, err := os.Lstat(expandedPath) |
| 26 | if err != nil { |
| 27 | if os.IsNotExist(err) { |
| 28 | if mustExist { |
| 29 | return nil, fmt.Errorf("file does not exist: %s", expandedPath) |
| 30 | } |
| 31 | return nil, nil |
| 32 | } |
| 33 | return nil, fmt.Errorf("failed to stat file: %w", err) |
| 34 | } |
| 35 | |
| 36 | if fileInfo.Mode()&os.ModeSymlink != 0 { |
| 37 | target, _ := os.Readlink(expandedPath) |
| 38 | if target == "" { |
| 39 | target = "(unknown)" |
| 40 | } |
| 41 | return nil, fmt.Errorf("cannot %s symlinks (target: %s). %s the target file directly if needed", verb, utilfn.MarshalJSONString(target), verb) |
| 42 | } |
| 43 | |
| 44 | if fileInfo.IsDir() { |
| 45 | return nil, fmt.Errorf("path is a directory, cannot %s it", verb) |
| 46 | } |
| 47 | |
| 48 | if !fileInfo.Mode().IsRegular() { |
| 49 | return nil, fmt.Errorf("path is not a regular file (devices, pipes, sockets not supported)") |
| 50 | } |
| 51 | |
| 52 | if fileInfo.Size() > MaxEditFileSize { |
| 53 | return nil, fmt.Errorf("file is too large (%d bytes, max %d bytes)", fileInfo.Size(), MaxEditFileSize) |
| 54 | } |
| 55 | |
| 56 | fileData, err := os.ReadFile(expandedPath) |
| 57 | if err != nil { |
| 58 | return nil, fmt.Errorf("failed to read file: %w", err) |
| 59 | } |
| 60 | |
| 61 | if utilfn.HasBinaryData(fileData) { |
| 62 | return nil, fmt.Errorf("file appears to contain binary data") |
| 63 | } |
| 64 | |
| 65 | dirPath := filepath.Dir(expandedPath) |
| 66 | dirInfo, err := os.Stat(dirPath) |
| 67 | if err != nil && !os.IsNotExist(err) { |
| 68 | return nil, fmt.Errorf("failed to stat directory: %w", err) |
| 69 | } |
| 70 | if err == nil && dirInfo.Mode().Perm()&0222 == 0 { |
| 71 | return nil, fmt.Errorf("directory is not writable (no write permission)") |
| 72 | } |
| 73 | |
| 74 | return fileInfo, nil |
| 75 | } |
| 76 | |
| 77 | type writeTextFileParams struct { |
no test coverage detected