From 58521190ba24f68bfa17c2f7fefb0616c7c84a17 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Tue, 19 Jul 2022 20:41:36 +0200 Subject: [PATCH] Zip: Fix potential filesystem permission and timing issues #2532 Signed-off-by: Michael Mayer --- docker/develop/armv7/Dockerfile | 9 ++-- docker/develop/bookworm-slim/Dockerfile | 6 +-- docker/develop/bookworm/Dockerfile | 9 ++-- docker/develop/bullseye-slim/Dockerfile | 6 +-- docker/develop/bullseye/Dockerfile | 9 ++-- docker/develop/buster/Dockerfile | 9 ++-- docker/develop/impish/Dockerfile | 9 ++-- docker/develop/jammy/Dockerfile | 9 ++-- docker/examples/cloud/docker-compose.yml | 1 - docker/photoprism/armv7/Dockerfile | 7 +-- docker/photoprism/buster/Dockerfile | 6 +-- docker/photoprism/impish/Dockerfile | 6 +-- docker/photoprism/jammy/Dockerfile | 6 +-- internal/api/{download_zip.go => zip.go} | 13 ++--- .../api/{download_zip_test.go => zip_test.go} | 0 internal/config/config_filepaths.go | 51 +++++++++++++++---- internal/config/config_filepaths_test.go | 41 +++++++++++++-- pkg/fs/dirs.go | 6 +++ pkg/fs/fs.go | 4 +- scripts/dist/cleanup.sh | 2 - 20 files changed, 129 insertions(+), 80 deletions(-) rename internal/api/{download_zip.go => zip.go} (95%) rename internal/api/{download_zip_test.go => zip_test.go} (100%) diff --git a/docker/develop/armv7/Dockerfile b/docker/develop/armv7/Dockerfile index fe80304bd..def0acda6 100644 --- a/docker/develop/armv7/Dockerfile +++ b/docker/develop/armv7/Dockerfile @@ -99,11 +99,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -111,10 +108,12 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # download models and testdata -RUN wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ +RUN mkdir /tmp/photoprism && \ + wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ wget "https://dl.photoprism.app/tensorflow/nasnet.zip?${BUILD_TAG}" -O /tmp/photoprism/nasnet.zip && \ wget "https://dl.photoprism.app/tensorflow/facenet.zip?${BUILD_TAG}" -O /tmp/photoprism/facenet.zip && \ wget "https://dl.photoprism.app/qa/testdata.zip?${BUILD_TAG}" -O /tmp/photoprism/testdata.zip diff --git a/docker/develop/bookworm-slim/Dockerfile b/docker/develop/bookworm-slim/Dockerfile index 4a73e1c78..1318ae88b 100644 --- a/docker/develop/bookworm-slim/Dockerfile +++ b/docker/develop/bookworm-slim/Dockerfile @@ -51,11 +51,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -63,7 +60,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # define default directory and user WORKDIR /photoprism diff --git a/docker/develop/bookworm/Dockerfile b/docker/develop/bookworm/Dockerfile index db36d706b..acba1f332 100644 --- a/docker/develop/bookworm/Dockerfile +++ b/docker/develop/bookworm/Dockerfile @@ -69,11 +69,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -81,10 +78,12 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # download models and testdata -RUN wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ +RUN mkdir /tmp/photoprism && \ + wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ wget "https://dl.photoprism.app/tensorflow/nasnet.zip?${BUILD_TAG}" -O /tmp/photoprism/nasnet.zip && \ wget "https://dl.photoprism.app/tensorflow/facenet.zip?${BUILD_TAG}" -O /tmp/photoprism/facenet.zip && \ wget "https://dl.photoprism.app/qa/testdata.zip?${BUILD_TAG}" -O /tmp/photoprism/testdata.zip diff --git a/docker/develop/bullseye-slim/Dockerfile b/docker/develop/bullseye-slim/Dockerfile index 4e4441a5b..fab52bab4 100644 --- a/docker/develop/bullseye-slim/Dockerfile +++ b/docker/develop/bullseye-slim/Dockerfile @@ -71,11 +71,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -83,7 +80,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # define default directory and user WORKDIR /photoprism diff --git a/docker/develop/bullseye/Dockerfile b/docker/develop/bullseye/Dockerfile index ad23ccc1c..0c2a57dcb 100644 --- a/docker/develop/bullseye/Dockerfile +++ b/docker/develop/bullseye/Dockerfile @@ -110,11 +110,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -122,10 +119,12 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # download models and testdata -RUN wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ +RUN mkdir /tmp/photoprism && \ + wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ wget "https://dl.photoprism.app/tensorflow/nasnet.zip?${BUILD_TAG}" -O /tmp/photoprism/nasnet.zip && \ wget "https://dl.photoprism.app/tensorflow/facenet.zip?${BUILD_TAG}" -O /tmp/photoprism/facenet.zip && \ wget "https://dl.photoprism.app/qa/testdata.zip?${BUILD_TAG}" -O /tmp/photoprism/testdata.zip diff --git a/docker/develop/buster/Dockerfile b/docker/develop/buster/Dockerfile index 783c5d0d8..774c1f8c4 100644 --- a/docker/develop/buster/Dockerfile +++ b/docker/develop/buster/Dockerfile @@ -106,11 +106,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -118,10 +115,12 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # download models and testdata -RUN wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ +RUN mkdir /tmp/photoprism && \ + wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ wget "https://dl.photoprism.app/tensorflow/nasnet.zip?${BUILD_TAG}" -O /tmp/photoprism/nasnet.zip && \ wget "https://dl.photoprism.app/tensorflow/facenet.zip?${BUILD_TAG}" -O /tmp/photoprism/facenet.zip && \ wget "https://dl.photoprism.app/qa/testdata.zip?${BUILD_TAG}" -O /tmp/photoprism/testdata.zip diff --git a/docker/develop/impish/Dockerfile b/docker/develop/impish/Dockerfile index b800eb8c9..c7e4938f4 100644 --- a/docker/develop/impish/Dockerfile +++ b/docker/develop/impish/Dockerfile @@ -106,11 +106,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -118,10 +115,12 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # download models and testdata -RUN wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ +RUN mkdir /tmp/photoprism && \ + wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ wget "https://dl.photoprism.app/tensorflow/nasnet.zip?${BUILD_TAG}" -O /tmp/photoprism/nasnet.zip && \ wget "https://dl.photoprism.app/tensorflow/facenet.zip?${BUILD_TAG}" -O /tmp/photoprism/facenet.zip && \ wget "https://dl.photoprism.app/qa/testdata.zip?${BUILD_TAG}" -O /tmp/photoprism/testdata.zip diff --git a/docker/develop/jammy/Dockerfile b/docker/develop/jammy/Dockerfile index d65651c20..5b8158767 100644 --- a/docker/develop/jammy/Dockerfile +++ b/docker/develop/jammy/Dockerfile @@ -108,11 +108,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -120,10 +117,12 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # download models and testdata -RUN wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ +RUN mkdir /tmp/photoprism && \ + wget "https://dl.photoprism.app/tensorflow/nsfw.zip?${BUILD_TAG}" -O /tmp/photoprism/nsfw.zip && \ wget "https://dl.photoprism.app/tensorflow/nasnet.zip?${BUILD_TAG}" -O /tmp/photoprism/nasnet.zip && \ wget "https://dl.photoprism.app/tensorflow/facenet.zip?${BUILD_TAG}" -O /tmp/photoprism/facenet.zip && \ wget "https://dl.photoprism.app/qa/testdata.zip?${BUILD_TAG}" -O /tmp/photoprism/testdata.zip diff --git a/docker/examples/cloud/docker-compose.yml b/docker/examples/cloud/docker-compose.yml index 4e08c990b..2dfab7d05 100644 --- a/docker/examples/cloud/docker-compose.yml +++ b/docker/examples/cloud/docker-compose.yml @@ -164,7 +164,6 @@ services: - "./originals:/photoprism/originals" # original media files (photos and videos) - "./import:/photoprism/import" # *optional* base folder from which files can be imported to originals - "./storage:/photoprism/storage" # *writable* storage folder for cache, database, and sidecar files (never remove) - - "./backup:/var/lib/photoprism" # *optional* storage folder for database backups ## Traefik Reverse Proxy (required) ## see https://docs.photoprism.app/getting-started/proxies/traefik/ diff --git a/docker/photoprism/armv7/Dockerfile b/docker/photoprism/armv7/Dockerfile index 57c2cfc3d..2472bc919 100644 --- a/docker/photoprism/armv7/Dockerfile +++ b/docker/photoprism/armv7/Dockerfile @@ -104,11 +104,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -116,8 +113,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache - + /photoprism/storage/cache && \ + /scripts/cleanup.sh # define default directory and user WORKDIR /photoprism diff --git a/docker/photoprism/buster/Dockerfile b/docker/photoprism/buster/Dockerfile index c81c01e32..4e542bc18 100644 --- a/docker/photoprism/buster/Dockerfile +++ b/docker/photoprism/buster/Dockerfile @@ -120,11 +120,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -132,7 +129,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # define default directory and user WORKDIR /photoprism diff --git a/docker/photoprism/impish/Dockerfile b/docker/photoprism/impish/Dockerfile index 55e3839cc..91a8eb5b2 100644 --- a/docker/photoprism/impish/Dockerfile +++ b/docker/photoprism/impish/Dockerfile @@ -118,11 +118,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -130,7 +127,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # define default directory and user WORKDIR /photoprism diff --git a/docker/photoprism/jammy/Dockerfile b/docker/photoprism/jammy/Dockerfile index d78fb1262..733f36a26 100644 --- a/docker/photoprism/jammy/Dockerfile +++ b/docker/photoprism/jammy/Dockerfile @@ -119,11 +119,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \ cp /etc/skel/.bashrc /root/.bashrc && \ /scripts/create-users.sh && \ - /scripts/cleanup.sh && \ cp /scripts/heif-convert.sh /usr/local/bin/heif-convert && \ install -d -m 0777 -o 1000 -g 1000 \ - /var/lib/photoprism \ - /tmp/photoprism \ /photoprism/originals \ /photoprism/import \ /photoprism/storage \ @@ -131,7 +128,8 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \ /photoprism/storage/albums \ /photoprism/storage/backups \ /photoprism/storage/config \ - /photoprism/storage/cache + /photoprism/storage/cache && \ + /scripts/cleanup.sh # define default directory and user WORKDIR /photoprism diff --git a/internal/api/download_zip.go b/internal/api/zip.go similarity index 95% rename from internal/api/download_zip.go rename to internal/api/zip.go index 29faf4109..3e3c1ead7 100644 --- a/internal/api/download_zip.go +++ b/internal/api/zip.go @@ -19,7 +19,6 @@ import ( "github.com/photoprism/photoprism/internal/photoprism" "github.com/photoprism/photoprism/internal/query" "github.com/photoprism/photoprism/internal/service" - "github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/fs" "github.com/photoprism/photoprism/pkg/rnd" @@ -85,7 +84,7 @@ func CreateZip(router *gin.RouterGroup) { zipFileName := path.Join(zipPath, zipBaseName) // Create temp directory. - if err := os.MkdirAll(zipPath, 0700); err != nil { + if err = os.MkdirAll(zipPath, 0700); err != nil { Error(c, http.StatusInternalServerError, err, i18n.ErrZipFailed) return } @@ -101,7 +100,9 @@ func CreateZip(router *gin.RouterGroup) { // Create zip writer. zipWriter := zip.NewWriter(newZipFile) - defer zipWriter.Close() + defer func(w *zip.Writer) { + logError("zip", w.Close()) + }(zipWriter) var aliases = make(map[string]int) @@ -162,9 +163,9 @@ func DownloadZip(router *gin.RouterGroup) { c.FileAttachment(zipFileName, zipBaseName) - if err := os.Remove(zipFileName); err != nil { - log.Errorf("download: failed removing %s (%s)", clean.Log(zipFileName), err.Error()) - } + defer func(n string) { + logError("zip", os.Remove(n)) + }(zipFileName) }) } diff --git a/internal/api/download_zip_test.go b/internal/api/zip_test.go similarity index 100% rename from internal/api/download_zip_test.go rename to internal/api/zip_test.go diff --git a/internal/config/config_filepaths.go b/internal/config/config_filepaths.go index 37bafee40..f6daed10d 100644 --- a/internal/config/config_filepaths.go +++ b/internal/config/config_filepaths.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "io/ioutil" "os" "os/exec" "os/user" @@ -13,6 +14,7 @@ import ( // binPaths stores known executable paths. var binPaths = make(map[string]string, 8) +var tempPath = "" // findExecutable searches binaries by their name. func findExecutable(configBin, defaultBin string) (binPath string) { @@ -267,19 +269,48 @@ func (c *Config) SidecarWritable() bool { return !c.ReadOnly() || c.SidecarPathIsAbs() } -// TempPath returns a temporary directory name for uploads and downloads. +// TempPath returns the cached temporary directory name for uploads and downloads. func (c *Config) TempPath() string { - if c.options.TempPath != "" { - if c.options.TempPath[0] != '/' { - c.options.TempPath = fs.Abs(c.options.TempPath) - } - } else if dir, err := os.MkdirTemp(os.TempDir(), "photoprism"); err == nil { - c.options.TempPath = dir - } else { - c.options.TempPath = filepath.Join(os.TempDir(), "photoprism") + // Return cached value? + if tempPath == "" { + tempPath = c.tempPath() } - return c.options.TempPath + return tempPath +} + +// tempPath returns the uncached temporary directory name for uploads and downloads. +func (c *Config) tempPath() string { + // Check configured temp path first. + if c.options.TempPath != "" { + if dir := fs.Abs(c.options.TempPath); dir == "" { + // Ignore. + } else if err := os.MkdirAll(dir, os.ModePerm); err != nil { + // Ignore. + } else if fs.PathWritable(dir) { + return dir + } + } + + // Find alternative temp path based on storage serial checksum. + if dir := filepath.Join(os.TempDir(), "photoprism_"+c.SerialChecksum()); dir == "" { + // Ignore. + } else if err := os.MkdirAll(dir, os.ModePerm); err != nil { + // Ignore. + } else if fs.PathWritable(dir) { + return dir + } + + // Find alternative temp path based on built-in TempDir() function. + if dir, err := ioutil.TempDir(os.TempDir(), "photoprism_"); err != nil || dir == "" { + // Ignore. + } else if err = os.MkdirAll(dir, os.ModePerm); err != nil { + // Ignore. + } else if fs.PathWritable(dir) { + return dir + } + + return os.TempDir() } // CachePath returns the path for cache files. diff --git a/internal/config/config_filepaths_test.go b/internal/config/config_filepaths_test.go index 829ee25a8..a0c259f55 100644 --- a/internal/config/config_filepaths_test.go +++ b/internal/config/config_filepaths_test.go @@ -43,13 +43,46 @@ func TestConfig_FFmpegBin(t *testing.T) { func TestConfig_TempPath(t *testing.T) { c := NewConfig(CliTestContext()) - assert.Equal(t, "/go/src/github.com/photoprism/photoprism/storage/testdata/temp", c.TempPath()) + + d0 := c.tempPath() + + t.Logf("c.options.TempPath: '%s'", c.options.TempPath) + t.Logf("c.tempPath(): '%s'", d0) + + assert.Equal(t, "/go/src/github.com/photoprism/photoprism/storage/testdata/temp", c.tempPath()) + c.options.TempPath = "" - if dir := c.TempPath(); dir == "" { + d1 := c.tempPath() + + if d1 == "" { t.Fatal("temp path is empty") - } else if !strings.HasPrefix(dir, "/tmp/photoprism") { - t.Fatalf("unexpected temp path: %s", dir) + } + + if !strings.HasPrefix(d1, "/tmp/photoprism_") { + t.Fatalf("unexpected temp path: %s", d1) + } + + d2 := c.tempPath() + + if d2 == "" { + t.Fatal("temp path is empty") + } + + if !strings.HasPrefix(d2, "/tmp/photoprism_") { + t.Fatalf("unexpected temp path: %s", d2) + } + + if d1 != d2 { + t.Fatalf("temp paths should match: '%s' <=> '%s'", d1, d2) + } else { + t.Logf("temp paths match: '%s' == '%s'", d1, d2) + } + + if d4 := c.TempPath(); d4 != d0 { + t.Fatalf("temp paths should match: '%s' <=> '%s'", d4, d0) + } else { + t.Logf("temp paths match: '%s' == '%s'", d4, d0) } } diff --git a/pkg/fs/dirs.go b/pkg/fs/dirs.go index 73ad98526..e75a37ebd 100644 --- a/pkg/fs/dirs.go +++ b/pkg/fs/dirs.go @@ -14,6 +14,9 @@ var OriginalPaths = []string{ "/photoprism/storage/media/originals", "/photoprism/media/originals", "/photoprism/originals", + "/srv/photoprism/storage/media/originals", + "/srv/photoprism/media/originals", + "/srv/photoprism/originals", "/opt/photoprism/storage/media/originals", "/opt/photoprism/media/originals", "/opt/photoprism/originals", @@ -77,6 +80,9 @@ var ImportPaths = []string{ "/photoprism/storage/media/import", "/photoprism/media/import", "/photoprism/import", + "/srv/photoprism/storage/media/import", + "/srv/photoprism/media/import", + "/srv/photoprism/import", "/opt/photoprism/storage/media/import", "/opt/photoprism/media/import", "/opt/photoprism/import", diff --git a/pkg/fs/fs.go b/pkg/fs/fs.go index 53837fade..573e8295b 100644 --- a/pkg/fs/fs.go +++ b/pkg/fs/fs.go @@ -96,9 +96,9 @@ func PathWritable(path string) bool { if f, err := os.Create(tmpName); err != nil { return false - } else if err := f.Close(); err != nil { + } else if err = f.Close(); err != nil { return false - } else if err := os.Remove(tmpName); err != nil { + } else if err = os.Remove(tmpName); err != nil { return false } diff --git a/scripts/dist/cleanup.sh b/scripts/dist/cleanup.sh index a37e5da55..eec3e9a3a 100755 --- a/scripts/dist/cleanup.sh +++ b/scripts/dist/cleanup.sh @@ -1,7 +1,5 @@ #!/bin/bash -PATH="/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/scripts" - # abort if not executed as root if [[ $(id -u) != "0" ]]; then echo "Usage: run ${0##*/} as root" 1>&2