|
ILIAS
trunk Revision v13.0_alpha-62-g3b72d83f2e5
|
Writes a file so that concurrent readers only see the complete old or new content: a temporary file in the SAME directory (rename() is only atomic within one filesystem) replaces the target via rename(). More...
Collaboration diagram for ILIAS\Language\ComponentTranslation\AtomicFileWriter:Static Public Member Functions | |
| static | write (string $file, string $content, ?string $confine_to_directory=null, bool $flush_to_disk=true) |
| static | grantsAtLeast (int $effective_mode, int $intended_mode) |
| Whether $effective_mode (permission bits 07777 only) grants every permission of $intended_mode. More... | |
Static Private Member Functions | |
| static | isAtOrBelow (string|false $resolved_path, string $resolved_root) |
| static | acceptUnchangeableMode (string $file, int $mode) |
| Some file systems do not support chmod(): that is only an error if the resulting mode lacks a permission $mode grants (e.g. More... | |
| static | writeContent (string $file, string $content, bool $flush_to_disk) |
| Writes $content to $file and with $flush_to_disk flushes it, so the rename() cannot publish content that is not persisted yet. More... | |
Writes a file so that concurrent readers only see the complete old or new content: a temporary file in the SAME directory (rename() is only atomic within one filesystem) replaces the target via rename().
The data is fsync()ed first unless the caller opts out; an existing target keeps its file mode.
Accepted residual risk (TOCTOU, CWE-367): PHP has no openat()/O_NOFOLLOW, so the confinement check and the later operations work on path names; whoever can replace a directory component of $file by a symbolic link in between (needs write access, i.e. the web server user) can redirect the write. After the rename() the directory is resolved again: outside $confine_to_directory the write throws and removes $file only if it is the file just written (same inode and device). Best effort. The same risk covers the overlay lock file created by MigratedLanguageFileSync::acquireLock().
Definition at line 37 of file AtomicFileWriter.php.
|
staticprivate |
Some file systems do not support chmod(): that is only an error if the resulting mode lacks a permission $mode grants (e.g.
the web server could no longer read a Setup-written file), else it is logged.
Definition at line 144 of file AtomicFileWriter.php.
|
static |
Whether $effective_mode (permission bits 07777 only) grants every permission of $intended_mode.
Decision of acceptUnchangeableMode(), public for tests only.
Definition at line 129 of file AtomicFileWriter.php.
Referenced by ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testGrantsAtLeast().
Here is the caller graph for this function:
|
staticprivate |
Definition at line 134 of file AtomicFileWriter.php.
|
static |
| string | null | $confine_to_directory | $file must resolve (its directory via realpath()) to this directory or below, so a symbolic link cannot redirect the write (CWE-59); checked before and after |
| bool | $flush_to_disk | false skips the fsync(): readers still see complete content, but after a crash the file may be lost. Only for reproducible files (e.g. build artifacts), as an fsync() per file is slow for thousands of them. |
| RuntimeException | if $file is a symbolic link, lies outside $confine_to_directory, or cannot be written |
Definition at line 48 of file AtomicFileWriter.php.
Referenced by ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testAnExistingTargetKeepsItsOwnModeInsteadOfANewFilesMode(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testConfineToDirectoryAllowsAWriteWhoseTargetResolvesInsideIt(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testConfineToDirectoryThrowsWhenTheTargetResolvesOutsideIt(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testFlushToDiskDisabledStillHonoursConfineToDirectory(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testReplacesAnExistingFile(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testTheWrittenFileDoesNotKeepTheRestrictiveTempnamPermissions(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testThrowsWhenAPathComponentIsARegularFile(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testThrowsWhenTheTargetCannotBeReplacedAndRemovesTheTemporaryFile(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testThrowsWhenTheTargetDirectoryDoesNotExist(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testWritesANewFileAndLeavesNoTemporaryFileBehind(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testWritesCompleteContentWithFlushToDiskDisabled(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testWritesEmptyContent(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testWritesIntoASymlinkedDirectory(), ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testWritesToARelativePath(), and ILIAS\Language\Tests\ComponentTranslation\AtomicFileWriterTest\testWritesWithADoubleSlashInThePath().
Here is the caller graph for this function:
|
staticprivate |
Writes $content to $file and with $flush_to_disk flushes it, so the rename() cannot publish content that is not persisted yet.
Definition at line 170 of file AtomicFileWriter.php.
References $written.