我想创建一个只有用户可读和可写(0600
)的文件。
唯一的方法是使用如下所示的 os.open()
吗?
import os
fd = os.open('/path/to/file', os.O_WRONLY, 0o600)
myFileObject = os.fdopen(fd)
myFileObject.write(...)
myFileObject.close()
理想情况下,我希望能够使用with
关键字,这样我就可以自动关闭对象。是否有更好的方法来完成我上面做的事情?
我想创建一个只有用户可读和可写(0600
)的文件。
唯一的方法是使用如下所示的 os.open()
吗?
import os
fd = os.open('/path/to/file', os.O_WRONLY, 0o600)
myFileObject = os.fdopen(fd)
myFileObject.write(...)
myFileObject.close()
理想情况下,我希望能够使用with
关键字,这样我就可以自动关闭对象。是否有更好的方法来完成我上面做的事情?
问题在哪里?file.close()
会关闭文件,即使是使用os.open()
打开的。
with os.fdopen(os.open('/path/to/file', os.O_WRONLY | os.O_CREAT, 0o600), 'w') as handle:
handle.write(...)
with
。而且在问题的示例中,文件最终还是通过 myFileObject.close()
关闭的。 - vartecO_CREAT
。请参考答案的当前版本。 - Asclepiusumask
特定的问题。我已经发布了一个答案来解决这个问题。 - Asclepiusumask
问题。import os
import stat
# Define file params
fname = '/tmp/myfile'
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL # Refer to "man 2 open".
mode = stat.S_IRUSR | stat.S_IWUSR # This is 0o600.
umask = 0o777 ^ mode # Prevents always downgrading umask to 0.
# For security, remove file with potentially elevated mode
try:
os.remove(fname)
except OSError:
pass
# Open file descriptor
umask_original = os.umask(umask)
try:
fdesc = os.open(fname, flags, mode)
finally:
os.umask(umask_original)
# Open file handle and write to file
with os.fdopen(fdesc, 'w') as fout:
fout.write('something\n')
0600
,可以更清楚地指定为八进制数0o600
。更好的方法是使用stat
模块。os.O_EXCL
和os.O_CREAT
将防止由于竞争条件而创建文件。这是必要的次要安全措施,以防止打开可能已经存在具有潜在提高的mode
的文件。在Python 3中,如果文件存在,则会引发FileExistsError
和[Errno 17]。umask
设置为0
或0o777 ^ mode
可能导致os.open
设置错误的mode
(权限)。这是因为默认的umask
通常不是0
,并且它将应用于指定的mode
。例如,如果我的原始umask
是2
即0o002
,并且我指定的模式是0o222
,如果我未先设置umask
,则生成的文件实际上可能具有mode
为0o220
,这不是我想要的。根据man 2 open
,创建的文件的模式为mode & ~umask
。
umask
尽快恢复到其原始值。此获取和设置不是线程安全的,在多线程应用程序中必须使用threading.Lock
。
有关umask的更多信息,请参阅此线程。
umask
问题,已经解决了我的问题。 - Nobilisos.open(mode=0666)
保存Python文件时,每个文件的权限都变成了0600。但这个解决方案解决了这个问题。 - ostrokachwith
只是些花头。
所以,请将这个回答视为“不要这样做”的示例;
原始帖子
您可以使用os.chmod
来代替:
>>> import os
>>> name = "eek.txt"
>>> with open(name, "wt") as myfile:
... os.chmod(name, 0o600)
... myfile.write("eeek")
...
>>> os.system("ls -lh " + name)
-rw------- 1 gwidion gwidion 4 2011-04-11 13:47 eek.txt
0
>>>
(Note that 在 Python 中使用八进制需要显式指定前缀"0o
",例如"0o600
"。在 Python 2.x 版本中,写成0600
也可以运行,但这两种方式都已经被弃用且易误导。)os.open
创建文件,并使用os.fdopen
从os.open
返回的文件描述符获取Python文件对象。fd = os.open('/path/to/file', os.O_WRONLY, 0o600)
不能保证权限被拒绝给所有用户。它只会尝试为当前用户设置读写权限(如果umask允许),就是这样!
在两个非常不同的测试系统上,使用默认的umask,此代码创建一个带有-rw-r--r--的文件,并且使用umask(0)创建一个带有-rw-rw-rw-的文件,这显然不是期望的结果(并且存在严重的安全风险)。
如果你想确保文件没有设置任何组和其他用户的权限位,你必须先umask这些位(记住 - umask是权限的拒绝):
os.umask(0o177)
import os
if os.path.isfile(file):
os.remove(file)
original_umask = os.umask(0o177) # 0o777 ^ 0o600
try:
handle = os.fdopen(os.open(file, os.O_WRONLY | os.O_CREAT, 0o600), 'w')
finally:
os.umask(original_umask)
flags
的理想值可能是 os.O_WRONLY | os.O_CREAT | os.O_EXCL
。请注意,os.O_EXCL
可以防止打开已经存在的文件。 - Asclepiusos.open()
的权限将被设置(在掩码umask后)为创建文件时提供的权限。0o600确实意味着文件将是go-rwx。但这并不意味着文件是u+rw(因为umask)。有关详细信息,请参见open(2)
man页面。可能会让您困惑的是,该模式仅适用于文件创建;如果文件已经存在,则会忽略它。 - marcelmtry:
oldumask = os.umask(0)
fdesc = os.open(outfname, os.O_WRONLY | os.O_CREAT, 0o600)
with os.fdopen(fdesc, "w") as outf:
# ...write to outf, closes on success or on exceptions automatically...
except IOError, ... :
# ...handle possible os.open() errors here...
finally:
os.umask(oldumask)
fdesc = os.open(outfname, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
而且文件对象是这样的:
with os.fdopen(fdesc, "a") as outf:
os.open
指定的mode
将永远不会被应用。之前存在的模式将被保留。 - Asclepius我会做得不同。
from contextlib import contextmanager
@contextmanager
def umask_helper(desired_umask):
""" A little helper to safely set and restore umask(2). """
try:
prev_umask = os.umask(desired_umask)
yield
finally:
os.umask(prev_umask)
# ---------------------------------- […] ---------------------------------- #
[…]
with umask_helper(0o077):
os.mkdir(os.path.dirname(MY_FILE))
with open(MY_FILE, 'wt') as f:
[…]