description: "原子文件替换与跨进程写锁,供绝不允许在磁盘上留下不完整、被符号链接劫持或权限过宽内容的包使用。"
English | 中文
使用 dsh-atomic-write 替换文件时,不会暴露部分内容,也不会跟随指向临时路径的符号链接。它的写锁会跨进程串行化读-修改-写入循环,因此并发写入方不会用陈旧状态相互覆盖。每次替换都会在全新 inode 上使用调用方选择的权限位,从而安全地收窄现有文件的权限。这个零依赖库只接受字符串;它不提供 cordis.yml 插件,也不保证崩溃持久性,因为它不调用 fsync。
当文件型存储必须替换一份已渲染好的字符串、且绝不允许暴露部分写入、符号链接劫持或权限过宽状态时,使用 writeFileAtomic;当多个进程读写同一文件时,使用 withFileLock。最小路径是一次调用,传入最终内容与替换 inode 的权限位。
import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'
declare const text: string
await writeFileAtomic('/home/u/.dsh/settings.yaml', text, { mode: 0o600 })
父目录会按需创建,读取方只会观察到旧内容或完整的新内容。在 Windows 上,报告为 EACCES、EBUSY 或 EPERM 的瞬时替换干扰会在有界时间内重试;任何剩余失败都会移除临时文件,并保持目标文件不变。
对于单靠原子提交无法保证安全的读-渲染-提交循环,请在操作期间持有写锁:
import { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'
declare const render: (previous: string) => string
declare const readCurrent: () => Promise<string>
await withFileLock('/home/u/.dsh/settings.yaml', async () => {
const previous = await readCurrent()
await writeFileAtomic('/home/u/.dsh/settings.yaml', render(previous), { mode: 0o600 })
})
只有写入方会竞争——读取方从不取锁——竞争者按指数退避,超时即以错误失败,而不是无限阻塞。竞争者等待多久由每次调用经 waitMs 声明:默认值只按纯文件工作量级选定,因此持锁方循环若包含一次网络往返——例如刷新过期 token 的凭据变更——就应声明更长的值,否则该文件的其他写入方在这段时间内都会失败。退避节奏保持固定。竞争者绝不移除已有锁,因为文件存续时间无法证明其持有者已经停止。
锁的父目录必须已经存在,因此 withFileLock 会在运行操作之前拒绝无效的父目录层级。持锁进程退出时会把锁文件留在原地;后续写入方超时失败,操作者只有在确认没有写入方仍持有该锁后才会移除它。
当你需要了解消费它的存储或本原语所属的家族时,阅读以下页面。
无:本包是纯文件系统写入原语,不注册任何面向模型的内容。
此处没有任何内容进入请求前缀,因此提供方缓存复用不受影响。
这些限制说明本包何时不是合适的工具。它们是当前包约束,不是任务积压。
fsync,因此崩溃后可能观察到 rename 被回退。此处的文件型存储在启动时重新读取并重新发布,把持久性留作调用方的策略。Buffer 或流式形态。