diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md index 1f34b5c6d00a4..ac3502efb9219 100644 --- a/docs/docs/install/environment-variables.md +++ b/docs/docs/install/environment-variables.md @@ -43,6 +43,7 @@ These environment variables are used by the `docker-compose.yml` file and do **N | `IMMICH_PROCESS_INVALID_IMAGES` | When `true`, generate thumbnails for invalid images | | server | microservices | | `IMMICH_TRUSTED_PROXIES` | List of comma separated IPs set as trusted proxies | | server | api | | `IMMICH_IGNORE_MOUNT_CHECK_ERRORS` | See [System Integrity](/docs/administration/system-integrity) | | server | api, microservices | +| `IMMICH_SKIP_UTIMES` | Does not call [`utimes`](https://linux.die.net/man/2/utimes) on files after processing. This can be useful for certain filesystems such as [geesefs](https://github.com/yandex-cloud/geesefs) that do not support it | `false` | server | | \*1: `TZ` should be set to a `TZ identifier` from [this list][tz-list]. For example, `TZ="Etc/UTC"`. `TZ` is used by `exiftool` as a fallback in case the timezone cannot be determined from the image metadata. It is also used for logfile timestamps and cron job execution. diff --git a/server/src/dtos/env.dto.ts b/server/src/dtos/env.dto.ts index 6c238252a633a..6d70ef23cc711 100644 --- a/server/src/dtos/env.dto.ts +++ b/server/src/dtos/env.dto.ts @@ -66,6 +66,9 @@ export class EnvDto { @Optional() IMMICH_REPOSITORY_URL?: string; + @ValidateBoolean({ optional: true }) + IMMICH_SKIP_UTIMES?: boolean; + @IsString() @Optional() IMMICH_SOURCE_REF?: string; diff --git a/server/src/interfaces/config.interface.ts b/server/src/interfaces/config.interface.ts index 300b55f27b6fd..c8a88e80723e2 100644 --- a/server/src/interfaces/config.interface.ts +++ b/server/src/interfaces/config.interface.ts @@ -83,6 +83,7 @@ export interface EnvData { storage: { ignoreMountCheckErrors: boolean; + skipUtimes: boolean; }; workers: ImmichWorker[]; diff --git a/server/src/repositories/config.repository.ts b/server/src/repositories/config.repository.ts index a8a1c9972b3d5..423f619e261d2 100644 --- a/server/src/repositories/config.repository.ts +++ b/server/src/repositories/config.repository.ts @@ -209,6 +209,7 @@ const getEnv = (): EnvData => { storage: { ignoreMountCheckErrors: !!dto.IMMICH_IGNORE_MOUNT_CHECK_ERRORS, + skipUtimes: !!dto.IMMICH_SKIP_UTIMES, }, telemetry: { diff --git a/server/src/repositories/storage.repository.ts b/server/src/repositories/storage.repository.ts index e4c0c68451477..c386e8ec1b8f6 100644 --- a/server/src/repositories/storage.repository.ts +++ b/server/src/repositories/storage.repository.ts @@ -8,6 +8,7 @@ import path from 'node:path'; import { Writable } from 'node:stream'; import { CrawlOptionsDto, WalkOptionsDto } from 'src/dtos/library.dto'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { IConfigRepository } from "src/interfaces/config.interface"; import { DiskUsage, IStorageRepository, @@ -19,7 +20,10 @@ import { mimeTypes } from 'src/utils/mime-types'; @Injectable() export class StorageRepository implements IStorageRepository { - constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { + constructor( + @Inject(ILoggerRepository) private logger: ILoggerRepository, + @Inject(IConfigRepository) private configRepository: IConfigRepository, + ) { this.logger.setContext(StorageRepository.name); } @@ -60,6 +64,9 @@ export class StorageRepository implements IStorageRepository { } utimes(filepath: string, atime: Date, mtime: Date) { + if (this.configRepository.getEnv().storage.skipUtimes){ + return Promise.resolve(); + } return fs.utimes(filepath, atime, mtime); }