Class OwnerOnlyAtomicFile
<server root>/.ultikits/:
CredentialStore's credentials.json and CloudStateStore's cloud-outbox.json. It was
extracted from CredentialStore.writeLocked (plan 22-03, S-15) so the durability rule lives in one place;
both callers delegate here and neither keeps a copy.
One write, in order: create the parent directories; create the temporary file in the target's own directory
(owner-only, rw-------, at creation on a POSIX file system, and narrowed again after opening in case an
interrupted earlier write left the same name with another mode, D19-060); write the body through a UTF-8 encoder;
flush and force the bytes to disk; optionally run a hook; replace the target with
StandardCopyOption.ATOMIC_MOVE and StandardCopyOption.REPLACE_EXISTING; force the directory
(best-effort). A crash therefore leaves either the previous complete file or the new complete file, never a torn
one, and a power loss cannot leave the target naming bytes that never reached the disk (#573). When the move did
not happen, the temporary file is removed.
This class decides nothing about what is written or whether a write is allowed: it never reads the target, so it cannot judge operator content. Each caller states in its own javadoc why its write path cannot overwrite operator-written configuration (the configuration-layer rule, D-31).
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescription(package private) static interfaceWrites the complete content of the file toout; the writer is flushed and closed by the caller. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final Logger(package private) static final Set<PosixFilePermission> Owner read and write only: the mode of every file this class writes on POSIX (D19-060). -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate static voidforceDirectory(Path directory) Forces a directory's entries to disk after the rename, so the rename itself survives a power loss.(package private) static voidwrite(Path target, String tempFileName, OwnerOnlyAtomicFile.WriterBody body) Replacestargetatomically with the contentbodywrites.(package private) static voidwrite(Path target, String tempFileName, OwnerOnlyAtomicFile.WriterBody body, Runnable beforeMove) Aswrite(Path, String, WriterBody), runningbeforeMoveafter the temporary file is complete and forced to disk and before the atomic move.
-
Field Details
-
OWNER_ONLY
Owner read and write only: the mode of every file this class writes on POSIX (D19-060). -
LOGGER
-
-
Constructor Details
-
OwnerOnlyAtomicFile
private OwnerOnlyAtomicFile()
-
-
Method Details
-
write
static void write(Path target, String tempFileName, OwnerOnlyAtomicFile.WriterBody body) throws IOException Replacestargetatomically with the contentbodywrites.- Parameters:
target- the file to replace (or create)tempFileName- the bare name of the temporary file, created intarget's directorybody- writes the complete new content- Throws:
AtomicMoveNotSupportedException- if the file system cannot replace the target atomically; thrown unchanged so a caller can report it with its own message, never silently replaced by a non-atomic copyIOException- if any other step fails; the target is then left unchanged
-
write
static void write(Path target, String tempFileName, OwnerOnlyAtomicFile.WriterBody body, Runnable beforeMove) throws IOException Aswrite(Path, String, WriterBody), runningbeforeMoveafter the temporary file is complete and forced to disk and before the atomic move. OnlyCloudStateStore's test seam passes a hook.- Parameters:
beforeMove- run between the forced temporary file and the move, ornull- Throws:
IOException
-
forceDirectory
Forces a directory's entries to disk after the rename, so the rename itself survives a power loss. Best-effort: Windows cannot open a directory as a channel, and a failure here cannot undo a rename that already happened, so it is logged atLevel.FINEand not reported as a failed write.
-