| 154 | } |
| 155 | |
| 156 | func tusPatchHandler(cache UploadCache) handleFunc { |
| 157 | return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { |
| 158 | if !d.user.Perm.Create || !d.Check(r.URL.Path) { |
| 159 | return http.StatusForbidden, nil |
| 160 | } |
| 161 | if r.Header.Get("Content-Type") != "application/offset+octet-stream" { |
| 162 | return http.StatusUnsupportedMediaType, nil |
| 163 | } |
| 164 | |
| 165 | uploadOffset, err := getUploadOffset(r) |
| 166 | if err != nil { |
| 167 | return http.StatusBadRequest, fmt.Errorf("invalid upload offset") |
| 168 | } |
| 169 | |
| 170 | file, err := files.NewFileInfo(&files.FileOptions{ |
| 171 | Fs: d.user.Fs, |
| 172 | Path: r.URL.Path, |
| 173 | Modify: d.user.Perm.Modify, |
| 174 | Expand: false, |
| 175 | ReadHeader: d.server.TypeDetectionByHeader, |
| 176 | Checker: d, |
| 177 | }) |
| 178 | |
| 179 | switch { |
| 180 | case errors.Is(err, afero.ErrFileNotFound): |
| 181 | return http.StatusNotFound, nil |
| 182 | case err != nil: |
| 183 | return errToStatus(err), err |
| 184 | } |
| 185 | |
| 186 | uploadLength, err := cache.GetLength(file.RealPath()) |
| 187 | if err != nil { |
| 188 | return http.StatusNotFound, err |
| 189 | } |
| 190 | |
| 191 | // Prevent the upload from being evicted during the transfer |
| 192 | stop := keepUploadActive(cache, file.RealPath()) |
| 193 | defer stop() |
| 194 | |
| 195 | switch { |
| 196 | case file.IsDir: |
| 197 | return http.StatusBadRequest, fmt.Errorf("cannot upload to a directory %s", file.RealPath()) |
| 198 | case file.Size != uploadOffset: |
| 199 | return http.StatusConflict, fmt.Errorf( |
| 200 | "%s file size doesn't match the provided offset: %d", |
| 201 | file.RealPath(), |
| 202 | uploadOffset, |
| 203 | ) |
| 204 | } |
| 205 | |
| 206 | openFile, err := d.user.Fs.OpenFile(r.URL.Path, os.O_WRONLY|os.O_APPEND, d.settings.FileMode) |
| 207 | if err != nil { |
| 208 | return http.StatusInternalServerError, fmt.Errorf("could not open file: %w", err) |
| 209 | } |
| 210 | defer openFile.Close() |
| 211 | |
| 212 | _, err = openFile.Seek(uploadOffset, 0) |
| 213 | if err != nil { |