Я хочу писать в файл в зависимости от того, существует ли этот файл уже или нет, записывая только в том случае, если он еще не существует (на практике я хочу продолжать пробовать файлы, пока не найду тот, которого не существует).
В следующем коде показано, как потенциально злоумышленник может вставить символическую ссылку, как это предлагается в этом сообщении, между тестом файла и записываемым файлом. Если код запускается с достаточно высокими разрешениями, это может привести к перезаписи произвольного файла.
Есть ли способ решить эту проблему?
import os
import errno
file_to_be_attacked = 'important_file'
with open(file_to_be_attacked, 'w') as f:
f.write('Some important content!\n')
test_file = 'testfile'
try:
with open(test_file) as f: pass
except IOError, e:
# symlink created here
os.symlink(file_to_be_attacked, test_file)
if e.errno != errno.ENOENT:
raise
else:
with open(test_file, 'w') as f:
f.write('Hello, kthxbye!\n')
Ответы:
Изменить : см. Также ответ Дэйва Джонса : из Python 3.3 вы можете использовать
x
флагopen()
для предоставления этой функции.Оригинальный ответ ниже
Да, но без использования стандартного
open()
вызова Python .os.open()
Вместо этого вам нужно будет использовать , что позволяет вам указывать флаги для базового кода C.В частности, вы хотите использовать
O_CREAT | O_EXCL
. На страницеopen(2)
руководстваO_EXCL
для моей системы Unix:Так что это не идеально, но, как ни странно, это самое близкое к тому, чтобы избежать этого состояния гонки.
Изменить: другие правила использования
os.open()
вместо по-open()
прежнему применяются. В частности, если вы хотите использовать возвращенный файловый дескриптор для чтения или записи, вам также понадобится один из флаговO_RDONLY
,O_WRONLY
илиO_RDWR
.Все
O_*
флаги находятся вos
модуле Python , поэтому вам нужно будетimport os
использоватьos.O_CREAT
и т. Д.Пример:
import os import errno flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY try: file_handle = os.open('filename', flags) except OSError as e: if e.errno == errno.EEXIST: # Failed as the file already exists. pass else: # Something unexpected went wrong so reraise the exception. raise else: # No exception, so the file must have been created successfully. with os.fdopen(file_handle, 'w') as file_obj: # Using `os.fdopen` converts the handle to an object that acts like a # regular Python file object, and the `with` context manager means the # file will be automatically closed when we're done with it. file_obj.write("Look, ma, I'm writing to a new file!")
источник
Для справки, Python 3.3 реализует новый
'x'
режим вopen()
функции для покрытия этого варианта использования (только создание, сбой, если файл существует). Обратите внимание, что'x'
режим указывается отдельно. Использование'wx'
результатов вValueError
качестве'w'
избыточна (единственное , что вы можете сделать , если вызов удачен является запись в файл в любом случае, она не может существовать , если вызов успешен):>>> f1 = open('new_binary_file', 'xb') >>> f2 = open('new_text_file', 'x')
Для Python 3.2 и ниже (включая Python 2.x) см. Принятый ответ .
источник
Python 3.2 (r32:88445, Feb 20 2011, 21:30:00)
[MSC v.1500 64 bit (AMD64)] on win32
>>> open("c:/temp/foo.csv","wx")
ValueError: invalid mode: 'wx'
ValueError: must have exactly one of create/read/write/append mode
Этот код легко создаст ФАЙЛ, если он не существует.
import os if not os.path.exists('file'): open('file', 'w').close()
источник
if
оператора, этот код очистит файл.