Как узнать, копируется ли файл? - PullRequest
1 голос
/ 14 мая 2011

В настоящее время я пытаюсь проверить, выполняется ли копирование файла из каталога в другой. Я хотел бы знать, если целевой файл все еще копируется.

Итак, я хотел бы получить количество файловых дескрипторов, открытых для этого файла. Я использую язык C и не могу найти способ решить эту проблему.

Ответы [ 7 ]

2 голосов
/ 14 мая 2011

Если у вас есть контроль, я бы порекомендовал использовать в программе идиому копирования-перемещения , выполняющую копирование:

cp file1 otherdir/.file1.tmp
mv otherdir/.file1.tmp otherdir/file1

mv просто изменяет некоторые записи файловой системы и является атомарным и очень быстрым по сравнению с копией.

0 голосов
/ 11 июля 2013

с помощью boost libs решит проблему

boost::filesystem::fstream fileStream(filePath, std::ios_base::in | std::ios_base::binary);

if(fileStream.is_open())
    //not getting copied
else
    //Wait, the file is getting copied
0 голосов
/ 14 мая 2011

Как упоминалось в poundifdef, функция fstat () может дать вам текущее время модификации. Но fstat также дает вам размер файла.

В те мрачные времена C, когда я наблюдал за файлами, копируемыми различными программами, я всегда не мог их контролировать:

  1. Дождался, пока целевой размер файла не станет> = размером источника, и
  2. Дождался, пока целевое время модификации не станет как минимум на N секунд старше текущего времени. N является числом, таким как 5, и устанавливается больше, если опыт показывает, что это необходимо. Да, 5 секунд кажется экстремальным, но это безопасно.

Если вы не знаете, что является целевым файлом, тогда единственным реальным выбором у вас будет # 2, но используйте большее N, чтобы учесть худшие случаи задержки сети и локального ЦП при здоровом коэффициенте безопасности.

0 голосов
/ 14 мая 2011

Я думаю, что вашей основной ошибкой является попытка синхронизировать программу на C с инструментом оболочки / внешней программой, которая не предназначена для синхронизации.Если у вас есть некоторый уровень контроля над программой / сценарием, выполняющим копирование, вы должны изменить его, чтобы выполнить какую-либо консультативную блокировку (предпочтительно fcntl) для целевого файла.Тогда ваша другая программа может просто заблокировать получение блокировки.

Если вы не имеете никакого контроля над программой, выполняющей копирование, единственные решения зависят от непереносимых хаков, таких как lsof или Linux * 1005.* API.

0 голосов
/ 14 мая 2011

(Этот ответ делает большое, большое предположение, что это будет работать в Linux.)

Исходный код C lsof, инструмент, который сообщает, какие программы в настоящее время имеют дескриптор открытого файла для определенного файла, свободно доступен . Тем не менее, просто чтобы предупредить вас, я не мог ничего понять. Есть ссылки на чтение памяти ядра, поэтому для меня это либо вуду, либо черная магия.

Тем не менее, ничто не мешает вам запускать lsof через вашу собственную программу. Запуск сторонних программ из вашей собственной программы - это обычно то, чего вы стараетесь избегать по нескольким причинам, например, безопасность (если мошенник изменит вредоносную программу на lsof, он будет работать с привилегиями вашей программы, что потенциально может привести к катастрофическому ( последствия), но, изучив исходный код lsof, я пришел к выводу, что не существует общедоступного API для определения, какая программа открыла какой файл. Если вы не боитесь, что люди меняют программы в /usr/sbin, вы можете подумать об этом.

int isOpen(const char* file)
{
    char* command;
    // BE AWARE THAT THIS WILL NOT WORK IF THE FILE NAME CONTAINS A DOUBLE QUOTE
    // OR IF IT CAN SOMEHOW BE ALTERED THROUGH SHELL EXPANSION
    // you should either try to fix it yourself, or use a function of the `exec`
    // family that won't trigger shell expansion.
    // It would be an EXTREMELY BAD idea to call `lsof` without an absolute path
    // since it could result in another program being run. If this is not where
    // `lsof` resides on your system, change it to the appropriate absolute path.
    asprintf(&command, "/usr/sbin/lsof \"%s\"", file);
    int result = system(command);

    free(command);
    return result;
}

Если вам также необходимо знать, в какой программе открыт ваш файл (предположительно cp?), Вы можете использовать popen, чтобы прочитать вывод lsof аналогичным образом. popen дескрипторы ведут себя как fopen дескрипторы, поэтому все, что вам нужно сделать, это fread их и посмотреть, сможете ли вы найти название вашей программы. На моей машине вывод lsof выглядит следующим образом:

$ lsof document.pdf 
COMMAND PID  USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
SomeApp 873 felix  txt    REG   14,3   303260 5165763 document.pdf
0 голосов
/ 14 мая 2011

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

Другой подход - открыть как исходные, так и целевые файлы для чтения и сравнить их размеры.Если они одинакового размера, копия, скорее всего, закончена.Вы можете использовать fseek() и ftell(), чтобы определить размер файла в C:

fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
0 голосов
/ 14 мая 2011

В linux попробуйте команду lsof, которая перечисляет все открытые файлы в вашей системе.

edit 1: Единственная функция языка C, которая приходит на ум, - это функция fstat . Возможно, вы сможете использовать это с полем st_mtime (время последнего изменения) структуры - как только это значение перестанет изменяться (скажем, на 10 секунд), вы можете предположить, что операция копирования файла остановлена. *

edit 2: также в linux вы можете просмотреть / proc / [pid] / fd , чтобы увидеть, какие файлы открыты. Файлы там являются символическими ссылками, но функция C readlink() может подсказать вам его путь, чтобы вы могли увидеть, открыт ли он. Используя getpid(), вы будете знать идентификатор процесса вашей программы (если вы делаете копию файла из вашей программы), чтобы знать, где искать в /proc.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...