newAsset validates one attached file.
(path, alt string)
| 119 | |
| 120 | // newAsset validates one attached file. |
| 121 | func newAsset(path, alt string) (UserAsset, error) { |
| 122 | fi, err := os.Stat(path) |
| 123 | if err != nil { |
| 124 | // Drop the syscall name so the message names the file, not the |
| 125 | // operation gh performed on it. |
| 126 | if pathErr, ok := errors.AsType[*fs.PathError](err); ok { |
| 127 | return nil, fmt.Errorf("%s: %w", path, pathErr.Err) |
| 128 | } |
| 129 | return nil, err |
| 130 | } |
| 131 | |
| 132 | if fi.IsDir() { |
| 133 | return nil, fmt.Errorf("%s is a directory", path) |
| 134 | } |
| 135 | |
| 136 | // Stat succeeds on a named pipe and Read then blocks forever. |
| 137 | if !fi.Mode().IsRegular() { |
| 138 | return nil, fmt.Errorf("%s is not a regular file", path) |
| 139 | } |
| 140 | |
| 141 | // Nothing downstream objects to zero bytes, so an empty file uploads and |
| 142 | // renders broken. |
| 143 | if fi.Size() == 0 { |
| 144 | return nil, fmt.Errorf("%s is empty", path) |
| 145 | } |
| 146 | |
| 147 | contentType, err := supportedContentType(path) |
| 148 | if err != nil { |
| 149 | return nil, err |
| 150 | } |
| 151 | |
| 152 | f := asset{path: path, info: fi, contentType: contentType} |
| 153 | |
| 154 | if strings.HasPrefix(contentType, "video/") { |
| 155 | return newVideoAsset(f, alt) |
| 156 | } |
| 157 | return newImageAsset(f, alt) |
| 158 | } |
| 159 | |
| 160 | // checkMaxSize rejects a file over the limit for its kind. The limit is |
| 161 | // inclusive, so the message says at most rather than under. |