| 39 | } |
| 40 | |
| 41 | func tusPostHandler(cache UploadCache) handleFunc { |
| 42 | return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { |
| 43 | if !d.user.Perm.Create || !d.Check(r.URL.Path) { |
| 44 | return http.StatusForbidden, nil |
| 45 | } |
| 46 | |
| 47 | file, err := files.NewFileInfo(&files.FileOptions{ |
| 48 | Fs: d.user.Fs, |
| 49 | Path: r.URL.Path, |
| 50 | Modify: d.user.Perm.Modify, |
| 51 | Expand: false, |
| 52 | ReadHeader: d.server.TypeDetectionByHeader, |
| 53 | Checker: d, |
| 54 | }) |
| 55 | switch { |
| 56 | case errors.Is(err, afero.ErrFileNotFound): |
| 57 | dirPath := filepath.Dir(r.URL.Path) |
| 58 | if _, statErr := d.user.Fs.Stat(dirPath); os.IsNotExist(statErr) { |
| 59 | if mkdirErr := d.user.Fs.MkdirAll(dirPath, d.settings.DirMode); mkdirErr != nil { |
| 60 | return http.StatusInternalServerError, err |
| 61 | } |
| 62 | } |
| 63 | case err != nil: |
| 64 | return errToStatus(err), err |
| 65 | } |
| 66 | |
| 67 | fileFlags := os.O_CREATE | os.O_WRONLY |
| 68 | |
| 69 | // if file exists |
| 70 | if file != nil { |
| 71 | if file.IsDir { |
| 72 | return http.StatusBadRequest, fmt.Errorf("cannot upload to a directory %s", file.RealPath()) |
| 73 | } |
| 74 | |
| 75 | // Existing files will remain untouched unless explicitly instructed to override |
| 76 | if r.URL.Query().Get("override") != "true" { |
| 77 | return http.StatusConflict, nil |
| 78 | } |
| 79 | |
| 80 | // Permission for overwriting the file |
| 81 | if !d.user.Perm.Modify { |
| 82 | return http.StatusForbidden, nil |
| 83 | } |
| 84 | |
| 85 | fileFlags |= os.O_TRUNC |
| 86 | } |
| 87 | |
| 88 | openFile, err := d.user.Fs.OpenFile(r.URL.Path, fileFlags, d.settings.FileMode) |
| 89 | if err != nil { |
| 90 | return errToStatus(err), err |
| 91 | } |
| 92 | defer openFile.Close() |
| 93 | |
| 94 | file, err = files.NewFileInfo(&files.FileOptions{ |
| 95 | Fs: d.user.Fs, |
| 96 | Path: r.URL.Path, |
| 97 | Modify: d.user.Perm.Modify, |
| 98 | Expand: false, |