LINUX.ORG.RU

Как программно скопировать файл ?


0

0

Задача очень простая. К компу подключается usb-флешка. Нужно её программно подмаунтить и скопировать с неё файлы на винт, опять же программно. С маунтом всё понятно - есть функции mount(...), umount(...). Как скопировать файлы, не пользуясь cp ? Почему нет никаких функций для копирования? Или нужно открыть с флешки файл и читать его через read(), а затем создать файл в нужном месте и писать туда первый файл через write()? Сорри, если вопрос тупой, но всё таки просьба ответить.

anonymous

Да нет, не тупой. Это и есть POSIX API, добро пожаловать, что называется :). Так и надо, читаешь и пишешь, по другому никак.

Можешь ещё посмотреть, как в файловых менеджерах это реализовано, как это сделано в исходниках cp. Хотя и сделать system ('cp'..) тоже не криминально.

welkam ★★
()

> Почему нет никаких функций для копирования?

Почему нет? Есть: open, read, write, creat. С обработкой ошибок по желанию. В классических книжках даже встречается код типа while(fputc(fgetc(FIN), FOUT) != EOF); Не рекомендую, кстати.

Casus ★★★★★
()
Ответ на: комментарий от Casus

Кстати, если хочется поумничать при копировании файла, то можно добавить использование posix_fadvise.

Casus ★★★★★
()

Вот тебе ссылка: http://www.linux.org.ru/view-message.jsp?msgid=1495626, по ней ты узнаешь о разных способах и способАх копирования больше, чем тебе в жизни понадобится 8). ИМХО, лучший из перечисленных там способов - тот, с которого началось обсуждение: mmap + write.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

> ИМХО, лучший из перечисленных там способов - тот, с которого началось обсуждение: mmap + write.

У меня очень глупый вопрос. А зачем избегать read (+posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE))/write в цикле? В смысле, я понимаю, что есть теория о том, что в случае mmap можно избежать копирования kernel->user (не изучал вопрос, не в курсе насколько правда), да только расход на это копирование практически нулевой, скорости носителей значительно более узким местом будут. Будет ли цикл записи по mmap-леной памяти чем-то более красивым/производительным? Почему цикл -- потому, что в задаче не сказан предельный объем файла, а блокироваться во write на гиг данных не всегда допустимо. Или флешка на 8гб (есть такие) и файл больше 4гб, как на 32-х битах его ммапить будем?

Casus ★★★★★
()
Ответ на: комментарий от Casus

> Будет ли цикл записи по mmap-леной памяти чем-то более красивым/производительным?

Насчет красоты - она в глазах смотрящего ;), насчет производительности - да, она будет выше за счет меньшего количества системных вызовов. А если еще и сделать на отмэпленой области madvise(MADV_SEQUENTIAL), то ядро будет делать readahead, так что однонитевая программа копирования сможет запускать физически параллельный В/В, и к тому же ядро будет оптимально управлять страничным кэшем. Заметь - от нас для этого требуется 1 вызов madvise. При решении с read/write В/В будет полностью (или почти полностью) последовательным. И если выигрыш в количестве системных вызовов копирования сильно не ускорит (хотя и сэкономит CPU), параллельный ввод/вывод (теоретически) должен дать заметный выигрыш.

> Почему цикл -- потому, что в задаче не сказан предельный объем файла, а блокироваться во write на гиг данных не всегда допустимо.

Ты прав, цикл понадобится. Но я не вижу ничего плохого в том, чтобы заблокироваться на write гига данных - в конце концов, write прерывается сигналом.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

С другой стороны, если сделать posix_fadvise(POSIX_FADV_WILLNEED) и/или posix_fadvise(POSIX_FADV_SEQUENTIAL), это должно дать тот же параллельный В/В. В таком случае за вариантом с mmap остается выигрыш в количестве системных вызовов и в красоте ;)

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

> При решении с read/write В/В будет полностью (или почти полностью) последовательным.

Я про posix_fadvise зачем упомянул?

POSIX_FADV_WILLNEED and POSIX_FADV_NOREUSE both initiate a non-blocking read of the specified region into the page cache. The amount of data read may be decreased by the kernel depending on VM load. (A few megabytes will usually be fully satisfied, and more is rarely useful.)

Casus ★★★★★
()
Ответ на: комментарий от tailgunner

> write прерывается сигналом.

write в regular file _не_ прерывается сигналом, процесс находится в D state, пока не завершится write. И даже SIGKILL не поможет. Хорошо заметно на NFS.

Casus ★★★★★
()
Ответ на: комментарий от Casus

> Тема файлов больше 4гб не раскрыта :)

Осмелюсь не согласиться! "Ты прав, цикл понадобится." tailgunner (*) (30.07.2006 0:51:02)

Кстати, не 4Г, а 2Г или даже меньше (я бы копировал 1Г кусками) - макс. размер пользовательского адресного пространства вполне может оказаться ~2Г ;)

>Я про posix_fadvise зачем упомянул?

>POSIX_FADV_WILLNEED and POSIX_FADV_NOREUSE both initiate a non-blocking read

Я тоже это написал :)

tailgunner ★★★★★
()
Ответ на: комментарий от Casus

>> write прерывается сигналом.

>write в regular file _не_ прерывается сигналом

Похоже, что так. Значит, если нужна прерывабельность, вариант с длинными write из mmap не прокатывает.

> процесс находится в D state

Процесс находится в R+, но всё равно - его даже kill -9 не берет :( Косяк-с.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Если процесс делает write из (я пробовал с malloc(3)'ed ) памяти юзера, то write(2) загоняет процесс в D (если это то, что показывает ps :]). Сигналами не душится. (linux-2.6.17)

sf ★★★
()
Ответ на: комментарий от Casus

> mmap в цикле, внутри которого цикл по write? Классный "лучший вариант" :)


Ах, да, совсем забыл.

ERRORS
ENODEV The underlying filesystem of the specified file does not support memory mapping.

Я не помню кто в линуксе не поддерживает mmap, но помню, что такие есть (vfat? автор флешки хотел...)

Casus ★★★★★
()
Ответ на: комментарий от Casus

> mmap в цикле, внутри которого цикл по write? Классный "лучший вариант" :)

А что не так? Он по-любому более экономный - число системных вызовов и копирование памяти.

>Ах, да, совсем забыл.

>ERRORS

>ENODEV The underlying filesystem of the specified file does not support memory mapping.

>Я не помню кто в линуксе не поддерживает mmap, но помню, что такие есть (vfat? автор флешки хотел...)

Это чисто теоретическая ошибка. Во-первых, VFAT давно (с самого начала?) поддерживает mmap на чтение, во-вторых, IIRC такая поддержка требуется для выполнения бинарей и легко реализуется.

tailgunner ★★★★★
()
Ответ на: комментарий от ananas

> man sendfile

sendfile был бы идеальным вариантом, но не прокатывает :( Не работает файл -> файл. По крайней мере мне говорит "Invalid argument".

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>Ты прав, цикл понадобится. Но я не вижу ничего плохого в том, чтобы >заблокироваться на write гига данных - в конце концов, write >прерывается сигналом.

write (без O_DIRECT) будет в цикле для всей области выделять кэш страницы, делать prepare_write, копировать данные и commit_write. Стандартный блочный prepare_write на целые страницы просто выделяет блоки на диске под страницу, commit_write ничего существенного не делает. Запись этих кэш страниц будет происходить в своем порядке (со временем, либо при нехватке памяти).

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

IMHO, можно выделить небольшой (но достаточный) кусок памяти и делать кусками read/write при O_DIRECT. Вот размер буфера - интересный момент.

Murr ★★
()
Ответ на: комментарий от Murr

> Поскольку копирование через кэш убъет весь полезный кэш приложений (выдавив кэшем прочитанного файла и записанного файла), то, по-моему, выигрыш от zero-copy или контекстных переключений - копеечный...

Об оптимизации использования кэшей madvise и posix_fadvise писалось выше. Не читал или не считаешь эффективным? :)

tailgunner ★★★★★
()
Ответ на: комментарий от Murr

Вот, кстати, тема O_DIRECT тоже мне кажется не однозначной. При O_DIRECT запись будет очевидно синхронной, а без него может загрязнять page cache и несколько распараллеливать работу read/write. Так что fdatasync тоже не помешает перед закрытием файла.

Casus ★★★★★
()

Интересно, автору исходного вопроса всё ещё интересно? :)

Casus ★★★★★
()
Ответ на: комментарий от tailgunner

>Об оптимизации использования кэшей madvise и posix_fadvise писалось >выше. Не читал или не считаешь эффективным? :)

Так они только делают readahead... а кэш все так же засирается. Кстати, про madvise и всех минусах копирования через кэш я писал еще в старой ветке. ;)

Murr ★★
()
Ответ на: комментарий от Casus

>При O_DIRECT запись будет очевидно синхронной, а без него может >загрязнять page cache и несколько распараллеливать работу read/write.

Запись не будет совсем уж синхронной. Все-таки есть определенная работа по сливанию блоков у elevator. А если диск не сильно фрагментирован и обращений к кэшу файлов в будущем не будет, то на отложенной записи выигрыша не должно быть.

Murr ★★
()
Ответ на: комментарий от Murr

> Запись не будет совсем уж синхронной. Все-таки есть определенная работа по сливанию блоков у elevator.

Я понимаю про O_SYNC, не понимаю только как write при O_DIRECT может завершиться не записав данные. Ведь как только write завершился, я имею право менять содержимое буфера, который писался, а если он ещё не записался, то это фигня-с получится. Т.е. при O_DIRECT ядро либо вернёт управление потоку после того как всё запишет, либо после того, как данные куда-то себе скопирует и запишет после. В последнем случае пользы от O_DIRECT никакой, так что такого я подозреваю просто не бывает.

> А если диск не сильно фрагментирован и обращений к кэшу файлов в будущем не будет, то на отложенной записи выигрыша не должно быть.

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

Casus ★★★★★
()
Ответ на: комментарий от Murr

>>Об оптимизации использования кэшей madvise и posix_fadvise писалось выше. Не читал или не считаешь эффективным? :)

>Так они только делают readahead... а кэш все так же засирается.

Цитата из man madvise(MADV_SEQUENTIAL): "pages in the given range can be aggressively read ahead, and may be freed soon after they are accessed".

Так что за кэш я бы не волновался :)

tailgunner ★★★★★
()
Ответ на: комментарий от Casus

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

Я тут несколько погорячился, подразумевал, когда писал, совсем другое, что выигрыш от отложенной записи может состоять в более лучшем распределении данных на диске, процесс аллокирования будет больше информации иметь. Ну и ещё при отложенной записи write может возвращать управление сразу, переходя к read, что распрараллеливает ввод-вывод.

Casus ★★★★★
()
Ответ на: комментарий от Casus

>Т.е. при O_DIRECT ядро либо вернёт управление потоку после того как всё >запишет

Поэтому и полезно сделать буфер сравнительно большим. Но, понятно, что слишком большим он тоже быть не должен, иначе возникают те же проблемы, что и с вытеснением кэша.

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

Какой выигрыш на ноутбуке? Вариант с mmap/write(без O_DIRECT) вытесняет кэша порядка 2*size. Вариант с mmap/write (с O_DIRECT) вытесняет кэша порядка size. Вариант с read/write (оба с O_DIRECT) не вытесняет кэша, вполне эффективно заполняет elevator и нормально группирует запись на нефрагментированных дисках. Ноутбуку же прочитать лишний раз 2*size выплюнутых в pagefile данных (или грязных данных в файл, или просто порезанный чистый кэш), я думаю, будет совсем некстати. Было бы интересно посмотреть, как в Win сделан CopyFile...

Murr ★★
()
Ответ на: комментарий от tailgunner

>Цитата из man madvise(MADV_SEQUENTIAL): "pages in the given range can >be aggressively read ahead, and may be freed soon after they are >accessed".

В Linux нет свободной памяти (разве что в вырожденных случаях)... только page cache. Любые новые данные в page cache - это выплюнутые полезные старые.

Murr ★★
()
Ответ на: комментарий от Casus

>процесс аллокирования будет больше информации иметь

Он происходит синхронно... в prepare_write... я тут или в ветке по ссылке пытался вкратце описать процесс.

>Ну и ещё при отложенной записи write может возвращать управление сразу, > переходя к read, что распрараллеливает ввод-вывод.

Это интересный момент. Надо будет подумать на прогулке. :)

Murr ★★
()
Ответ на: комментарий от Murr

> Любые новые данные в page cache - это выплюнутые полезные старые.

С этим никто и не спорит. Вопрос в том, какие именно данные будут выплевываться. При MADV_SEQUENTIAL из кэша будут вытесняться данные _этого же_ файла - ибо они больше не нужны, сканирование последовательное.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>При MADV_SEQUENTIAL из кэша будут вытесняться данные _этого же_ файла - > ибо они больше не нужны, сканирование последовательное.

Вы переоцениваете значение этого флажка. Вытеснение страниц, IMHO, происходит по универсальному алгоритму. Насколько я вижу в 2.6.17 VM_SequentialReadHint проверяется только при page fault и делает readahead.

Murr ★★
()
Ответ на: комментарий от Murr

> Вы переоцениваете значение этого флажка.

Это то, что сказал man :)

> Насколько я вижу в 2.6.17

Сейчас нет времени лезть в ядро :(

tailgunner ★★★★★
()
Ответ на: комментарий от Murr

Если задача - сохранить кэш, то madvise(MADV_DONTNEED) спасет. Он-то реализован :)

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

>Вот тебе ссылка: http://www.linux.org.ru/view-message.jsp?msgid=1495626,

в моём случае мне перед собственно копированием надо было просканировать файл на наличие некоторых сигнатур что собственно оправдало кеширование при чтении.

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

cvv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.