photoprism/pkg/fs
2025-12-01 17:16:33 +10:00
..
duf CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
fastwalk CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
testdata Config: Support YAML filenames with alternative extensions #5304 2025-11-02 11:33:40 +01:00
buffer_pool.go Pkg: Add fs/README.md to document performance & security improvements 2025-11-25 13:09:48 +01:00
bytes.go FS: Add /pkg/fs/duf to determine mount points and disk usage #4266 2025-03-03 11:24:30 +01:00
cache.go Config: Show error if originals and storage path seem identical #1642 2024-01-21 14:22:16 +01:00
cache_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
canonical.go Import: Allow configuration of the destination file path #4666 2024-12-15 17:26:00 +01:00
canonical_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
case.go Security: Create new files without execution permission #2809 2022-10-31 15:01:48 +01:00
case_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
codec.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
config.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
config_test.go Config: Enhance tests for configuration and database file names #5304 2025-11-02 11:49:00 +01:00
const.go Security: Improve credential handling across the cluster tooling #98 2025-10-20 00:06:17 +02:00
copy_move.go Pkg: Add fs/README.md to document performance & security improvements 2025-11-25 13:09:48 +01:00
copy_move_test.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
directories.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
directories_test.go Config: Support YAML filenames with alternative extensions #5304 2025-11-02 11:33:40 +01:00
done.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
done_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
errors.go Media: Log underlying error when MIME type detection fails #5149 2025-08-06 09:59:38 +02:00
ext_list.go Go: Replace strings.Split() with strings.SplitSeq() #5337 2025-11-25 14:26:29 +01:00
ext_list_test.go Upload: Delete invalid files, improve type checks and import logs #4895 2025-03-25 11:58:59 +01:00
file_ext.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
file_ext_test.go Media: Associate ".mp.jpg" and ".mp.jpeg" files with ImageJpeg #5289 2025-10-23 18:23:24 +02:00
file_exts.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
file_exts_test.go Media: Associate ".mp.jpg" and ".mp.jpeg" files with ImageJpeg #5289 2025-10-23 18:23:24 +02:00
file_info.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
file_type.go Live Photos: Only flag actual Live and Motion Photos as "Live" #5089 2025-07-06 11:07:25 +02:00
file_type_animated.go Pkg: Move /service/http/... to /http/... and add package /http/dns 2025-10-19 21:08:48 +02:00
file_type_test.go Media: Associate ".mp.jpg" and ".mp.jpeg" files with ImageJpeg #5289 2025-10-23 18:23:24 +02:00
file_types.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
file_types_ext.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
fileinfo.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
fileinfo_test.go Tests: Reorder imports in fileinfo_test.go 2023-06-27 20:25:50 +02:00
filepath.go Library: Stack sidecar files with vendor specific naming schemes #2983 2023-10-21 15:02:16 +02:00
filepath_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
fs.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
fs_test.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
hash.go Pkg: Add fs/README.md to document performance & security improvements 2025-11-25 13:09:48 +01:00
hash_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
id.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
id_test.go Auth: Add CLI command to create access tokens for apps #782 #808 #3943 2024-01-05 16:31:07 +01:00
ignore.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
ignore_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
mime.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
mime_test.go Pkg: Move /service/http/... to /http/... and add package /http/dns 2025-10-19 21:08:48 +02:00
mode.go Auth: Refactor cluster configuration and provisioning API endpoints #98 2025-09-24 08:28:38 +02:00
mode_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
modtime.go Metadata: Use file mod time instead of birth time as fallback #4157 2024-04-08 20:44:57 +02:00
modtime_test.go Metadata: Use file mod time instead of birth time as fallback #4157 2024-04-08 20:44:57 +02:00
name.go Backups: Improved saving of photo and album YAML files #4243 2024-05-14 08:45:18 +02:00
name_test.go Test: Use PascalCase names for all Go subtests in /pkg 2025-10-02 15:03:47 +02:00
purge.go Auth: Refactor cluster configuration and provisioning API endpoints #98 2025-09-24 08:28:38 +02:00
purge_test.go Auth: Refactor cluster configuration and provisioning API endpoints #98 2025-09-24 08:28:38 +02:00
readlines.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
README.md Pkg: Add fs/README.md to document performance & security improvements 2025-11-25 13:09:48 +01:00
resolve.go Index: Skip redundant thumbs and support symbolic file links #1049 #1874 2022-07-06 23:01:54 +02:00
resolve_test.go Auth: Refactor cluster configuration and provisioning API endpoints #98 2025-09-24 08:28:38 +02:00
stat_test.go Backend: Improve Copy()/Move() and increase pkg/internal test coverage 2025-09-22 03:07:51 +02:00
symlink.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
symlink_test.go Index: Skip redundant thumbs and support symbolic file links #1049 #1874 2022-07-06 23:01:54 +02:00
walk.go CI: Apply Go linter recommendations to remaining "pkg/..." code #5330 2025-11-22 16:14:43 +01:00
walk_test.go Config: Support YAML filenames with alternative extensions #5304 2025-11-02 11:33:40 +01:00
write.go Pkg: Add fs/README.md to document performance & security improvements 2025-11-25 13:09:48 +01:00
write_test.go Merge tag '251130-b3068414c' into PostgreSQL 2025-12-01 17:16:33 +10:00
zip.go Pkg: Add fs/README.md to document performance & security improvements 2025-11-25 13:09:48 +01:00
zip_test.go Merge tag '251130-b3068414c' into PostgreSQL 2025-12-01 17:16:33 +10:00

PhotoPrism — pkg/fs

Last Updated: November 25, 2025

Overview

pkg/fs provides safe, cross-platform filesystem helpers used across PhotoPrism. It supplies permission constants, copy/move utilities with force-aware semantics, safe path joins, archive extraction with size limits, MIME and extension lookups, hashing, canonical path casing, and fast directory walking with ignore lists.

Goals

  • Offer reusable, side-effect-safe filesystem helpers that other packages can call without importing internal/*.
  • Enforce shared permission defaults (ModeDir, ModeFile, ModeConfigFile, ModeSecretFile, ModeBackupFile).
  • Protect against common filesystem attacks (path traversal, overwrite of non-empty files without force, unsafe zip extraction).
  • Provide consistent file-type detection (extensions/MIME), hashing, and fast walkers with skip logic for caches and .ppstorage markers.

Non-Goals

  • Database migrations or metadata parsing (handled elsewhere).
  • Edition-specific behavior; all helpers are edition-agnostic.

Package Layout (Code Map)

  • Permissions & paths: mode.go, filepath.go, canonical.go, case.go.
  • Copy/Move & write helpers: copy_move.go, write.go, cache.go, purge.go.
  • Archive extraction: zip.go (size limits, safe join), tests in zip_test.go.
  • File info & types: file_type*.go, mime.go, file_ext*.go, name.go.
  • Hashing & IDs: hash.go, id.go.
  • Walkers & ignore rules: walk.go, ignore.go, done.go.
  • Utilities: bytes.go, resolve.go, symlink.go, modtime.go, readlines.go.

Usage & Test Guidelines

  • Overwrite semantics: pass force=true only when the caller explicitly confirmed replacement; empty files may be replaced without force.
  • Permissions: use provided mode constants; do not mix with stdlib io/fs bits.
  • Zip extraction: always set fileSizeLimit / totalSizeLimit in Unzip for untrusted inputs; ensure tests cover path traversal and size caps (see zip_test.go).
  • Focused tests: go test ./pkg/fs -run 'Copy|Move|Unzip|Write' -count=1 keeps feedback quick; full package: go test ./pkg/fs -count=1.

Recent Changes & Improvements

  • Hardened safeJoin: normalize \\//, use filepath.Rel to reject paths escaping baseDir, and keep volume/absolute checks.
  • Added optional max-entries guard in Unzip and treat totalSizeLimit=0 as “no limit” while documenting -1 as unlimited.
  • Added pool copy buffers (128256 KiB) that use io.CopyBuffer in Copy, Hash, Checksum, WriteFileFromReader to cut allocations/GC.

Pool Copy Buffers

  • Read/write iterations per 4GiB file:
    • Before: ~131,072 iterations (4GiB / 32KiB).
    • After: 16,384 iterations (4GiB / 256KiB).
    • ~8× fewer syscalls and loop bookkeeping.
  • Latency saved (order-of-magnitude):
    • If each read+write pair costs ~2µs of syscall/loop overhead, skipping ~115k iterations saves ≈0.23s on a 4GiB stream.
    • On SSD/NVMe where disk I/O dominates, expect ~510% throughput gain; on spinning disks or network mounts with higher syscall cost, closer to 1020% is realistic.
    • CPU-bound hashing (SHA-1) sees mostly overhead reduction; the hash itself stays the dominant cost, but you still avoid ~8× buffer boundary checks and syscalls, so a few percent improvement is typical.
  • Allocation/GC savings:
    • Before: each call allocated a fresh 32KiB buffer; hashing and copy both did this per invocation.
    • After: pooled 256KiB buffer reused; effectively zero steady-state allocations for these paths, which is most noticeable when hashing or copying many files in a batch (less GC pressure, fewer pauses).
  • Net effect on large video files (several GB):
    • Wall-clock improvement: modest but measurable (subsecond on SSDs; up to a couple of seconds on slower media per 4GiB).
    • CPU usage: a few percentage points lower due to fewer syscalls and eliminated buffer allocations.
    • GC: reduced minor-GC churn during bulk imports/hashes.