getfileattributes的file_attribute_readonly仅表示只读属性位被设置,不等于文件不可写,更不能推断“只写”;windows无原生“只写”属性,写权限由ntfs acl决定,与dos属性无关。

Windows下用GetFileAttributes判断WRITE_ONLY是否可靠
直接看结论:GetFileAttributes 返回的 FILE_ATTRIBUTE_READONLY 标志**只表示“只读属性位被设”,不等于“文件不可写”**,更不能反推“只写”——Windows 没有原生的“只写”文件属性概念。所谓“只写”,实际是 NTFS 权限(ACL)控制的结果,和 DOS 属性无关。
常见误解是:如果 GetFileAttributes 没返回 FILE_ATTRIBUTE_READONLY,就认为可写;但即使它返回了该标志,只要用户拥有 WRITE_DATA 权限,照样能写。反过来,哪怕没设只读属性,若 ACL 明确拒绝写入,fopen("file.txt", "w") 仍会失败并返回 NULL。
- 不要用
FILE_ATTRIBUTE_READONLY的“不存在”来推断“可写”或“只写” -
FILE_ATTRIBUTE_READONLY对目录有效(影响删除/重命名),对文件仅影响部分 API(如某些旧工具),现代写操作基本无视它 - 真正决定写能力的是
AccessCheck+GetNamedSecurityInfo获取的 DACL,但开销大、代码复杂,一般不用于简单判断
Linux/macOS下用access()检查W_OK是否足够
access("path", W_OK) 是最常用也最贴近需求的方式,但它判断的是**当前进程的有效 UID/GID 下是否具备写权限**,包括:文件所在目录的写权限(影响创建/删除)、文件自身的写权限位(S_IWUSR/S_IWGRP/S_IWOTH)、以及可能存在的 capability 或 ACL。
注意:access() 不检查磁盘满、inode 耗尽、只读挂载等运行时限制,那些要靠后续 open() 或 fwrite() 的 errno(如 ENOSPC, EROFS)捕获。
- 必须用真实路径调用,符号链接会被自动解析(除非加
AT_SYMLINK_NOFOLLOW配合faccessat) - 在 setuid 程序中慎用:
access()检查的是真实 UID,而实际open()用的是有效 UID,存在竞态风险 - 如果只需快速探路,
access(path, W_OK) == 0可信;但关键逻辑仍建议直接open(path, O_WRONLY | O_CREAT, 0644)并处理errno
跨平台C++封装:别试图抽象“只写权限”,聚焦具体动作
没有跨平台、无副作用、100%准确的“判断是否只写”的函数。所谓“只写文件”本身是个模糊概念——用户可能指“能写不能读”,但 POSIX 和 Win32 都不提供原子级的“只写打开且拒绝读”的语义(O_WRONLY 打开后仍可通过 dup() 或 SetFilePointer 配合读操作间接触发读权限检查)。
真正该做的,是把权限判断绑定到你要执行的操作上:
- 想追加日志?直接
fopen(path, "ab")或open(path, O_WRONLY | O_APPEND),失败时看errno/GetLastError() - 想覆盖写?用
fopen(path, "wb"),而不是先access(W_OK)再fopen——省掉一次 syscall,也避免 TOCTOU 竞态 - 需要区分“无权限”和“磁盘满”?检查
errno值:EACCES/EPERM(权限拒绝)、EROFS(只读文件系统)、ENOSPC(空间不足)
为什么“只写属性”在文件系统层几乎不存在
文件系统的权限模型(POSIX DAC / Windows DACL)本质是“允许什么操作”,而非“禁止什么操作”。你无法给一个文件单独设置“只允许写、绝对禁止读”的位——因为读操作依赖于文件内容,而写操作不必然暴露内容。强行模拟(如 chmod 200 file)会导致:普通用户连 stat() 都失败(缺读权限),根本无法确认文件是否存在或大小,实用性归零。
真正接近“只写”的场景,通常是管道、socket 或特殊设备文件(如 /dev/null),它们的“只写”由内核驱动控制,不是普通磁盘文件的属性。
所以当需求文档里出现“检查只写权限”时,大概率是误用了术语——实际要确认的,只是“接下来要写的那个操作能否成功”。盯住 errno,比猜属性靠谱得多。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











