Безопасно ли перемещать файл, к которому добавляется?

У меня есть процесс node.js, который использует fs.appendFile, чтобы добавить строки в file.log. Добавляются только полные строки из примерно 40 символов в строке. вызовы выглядят как fs.appendFile("start-end"), а не 2 вызова типа fs.appendFile("start-") и fs.appendFile("end"). Если я переведу этот файл на file2.log, я уверен, что никакие строки не будут потеряны или скопированы частично?

28 голосов | спросил Fluffy 28 +03002014-10-28T13:25:47+03:00312014bEurope/MoscowTue, 28 Oct 2014 13:25:47 +0300 2014, 13:25:47

2 ответа


36

Пока вы не перемещаете файл по границам файловой системы, операция должна быть безопасной. Это связано с механизмом, как происходит «перемещение».

Если вы mv файл в той же файловой системе, файл фактически не затронут, а только файловая система запись изменяется.

$ mv foo bar

действительно что-то вроде

$ ln foo bar
$ rm foo

Это создаст ссылку hard (вторая запись каталога) для файла (на самом деле это индекс, обозначенный позицией файловой системы) foo с именем bar и удалите foo. Поскольку теперь, когда вы удаляете foo, есть вторая запись файловой системы, указывающая на foo, удаление старой записи foo фактически не удаляет блоки, принадлежащие к inode .

Ваша программа с удовольствием добавит файл в любом случае, поскольку его открытый файл-дескриптор указывает на индексный дескриптор файла, а не на запись в файловой системе.

Примечание. . Если ваша программа закрывает и открывает файл между записью, у вас будет файл new , созданный со старой записью файловой системы!

Перемещение файловой системы:

Если вы перемещаете файл по границам файловой системы, все становится некрасиво. В этом случае вы не можете гарантировать постоянство сохранения вашего файла, поскольку mv будет фактически

  • создать новый файл в целевой файловой системе
  • скопировать содержимое старого файла в новый файл
  • удалить старый файл

или

$ cp /path/to/foo /path/to/bar
$ rm /path/to/foo

соответственно.

$ touch /path/to/bar
$ cat < /path/to/foo > /path/to/bar
$ rm /path/to/foo

В зависимости от того, будет ли копирование заканчиваться в конце файла во время записи вашего приложения, может случиться, что у вас есть только половина строки в новом файле.

Кроме того, если ваше приложение не закрывает и не возобновляет старый файл, оно будет продолжать запись в старый файл, даже если он кажется удаленным: ядро ​​знает, какие файлы открыты, и хотя он удалит файловую систему запись, он не будет удалять индексный индекс старого файла и связанные блоки, пока ваше приложение не закроет его открытый файл-дескриптор.

ответил Andreas Wiese 28 +03002014-10-28T13:54:07+03:00312014bEurope/MoscowTue, 28 Oct 2014 13:54:07 +0300 2014, 13:54:07
9

Поскольку вы говорите, что используете node.js, я предполагаю, что вы будете использовать ---- +: = 0 =: + ---- (или fs.rename()) для переименования файлов. Этот метод node.js документирован для использования системного вызова rename (2) , который сам по себе не касается самого файла, а просто изменяет имя, в котором оно указано в файловой системе:

  

" переименовать () переименовывает файл, перемещая его между каталогами, если это необходимо. Любые другие жесткие ссылки на файл (созданные с помощью ссылки (2)) не затронуты. Открытые дескрипторы файлов для oldpath также не затронуты. "

В частности, обратите внимание на последнее приведенное выше предложение, в котором говорится, что любые дескрипторы открытых файлов (например, ваша программа будет использовать для записи в файл) будут продолжать указывать на нее даже после ее переименования. Таким образом, не будет никакой потери данных или повреждения, даже если файл будет переименован, пока он записывается одновременно.


Как отмечает Андреас Вайзе в своем ответе , системный вызов rename (2) (и, следовательно, fs.renameSync() в node.js) не будет работать через границы файловой системы. Таким образом, попытка переместить файл в другую файловую систему таким образом просто завершится неудачей.

Unix fs.rename() пытается скрыть это ограничение, обнаружив ошибку и вместо этого переместив файл, скопировав его содержимое в новый файл и удалив оригинал. К сожалению, перемещение таких файлов, как эта , делает потерю данных о рисках, если файл перемещается во время записи. Таким образом, если вы хотите безопасно переименовать файлы, которые могут быть одновременно записаны, вы должны not использовать mv ( или, по крайней мере, вы должны быть абсолютно уверены, что новый и старый путь находятся в одной и той же файловой системе).

ответил Ilmari Karonen 28 +03002014-10-28T22:07:25+03:00312014bEurope/MoscowTue, 28 Oct 2014 22:07:25 +0300 2014, 22:07:25

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132