Как создать разреженный файл программно, в C, на Mac OS X?

Я хотел бы создать разреженный файл, чтобы блоки all-zero не занимали фактического места на диске, пока я не напишу в них данные. Возможно ли это?

7 ответов


Как и в других Юниксах, это особенность файловой системы. Либо файловая система поддерживает его для всех файлов, либо нет. В отличие от Win32, вам не нужно делать ничего особенного, чтобы это произошло. Также, в отличие от Win32, нет штрафа за использование разреженного файла.

в MacOS файловой системой по умолчанию является HFS+, которая делает не поддержка разреженных файлов.

обновление: MacOS используется для поддержки томов UFS с разреженной поддержкой файлов, но это был удален. Ни одна из поддерживаемых файловых систем не поддерживает разреженные файлы.


существует некоторая путаница относительно того, поддерживает ли файловая система Mac OS X по умолчанию (HFS+) отверстия в файлах. Следующая программа демонстрирует, что это не так.

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

void create_file_with_hole(void)
{
    int fd = open("file.hole", O_WRONLY|O_TRUNC|O_CREAT, 0600);
    write(fd, "Hello", 5);
    lseek(fd, 99988, SEEK_CUR); // Make a hole
    write(fd, "Goodbye", 7);
    close(fd);
}

void create_file_without_hole(void)
{
    int fd = open("file.nohole", O_WRONLY|O_TRUNC|O_CREAT, 0600);
    write(fd, "Hello", 5);
    char buf[99988];
    memset(buf, 'a', 99988);
    write(fd, buf, 99988); // Write lots of bytes
    write(fd, "Goodbye", 7);
    close(fd);
}

int main()
{
    create_file_with_hole();
    create_file_without_hole();
    return 0;
}

программа создает два файла, каждый 100,000 байт в длину, один из которых имеет отверстие 99,988 байт.

В Mac OS X 10.5 на разделе HFS+ оба файла занимают одинаковое количество дисковых блоков (200):

$ ls -ls
total 400
200 -rw-------  1 user  staff  100000 Oct 10 13:48 file.hole
200 -rw-------  1 user  staff  100000 Oct 10 13:48 file.nohole

тогда как на CentOS 5, файл без отверстий потребляет 88 больше дисковых блоков, чем другие:

$ ls -ls
total 136
 24 -rw-------  1 user   nobody 100000 Oct 10 13:46 file.hole
112 -rw-------  1 user   nobody 100000 Oct 10 13:46 file.nohole

этот поток становится исчерпывающим источником информации о разреженных файлах. Вот недостающая часть для Win32:

достойная статья с примерами

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

в отношении


hdiutil может обрабатывать разреженные изображения и файлы, но, к сожалению, структура, с которой он связывается, является частной.

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

cristi:~ diciu$ otool-L /usr/bin/hdiutil

/ usr / bin / hdiutil: / Система / Библиотека / PrivateFrameworks / DiskImages.framework / версии / A / DiskImages (совместимость версия 1.0.8, текущая версия 194.0.0) [..]

cristi:~ diciu$ nm / система / библиотека / PrivateFrameworks / DiskImages.framework / версии / A / DiskImages | awk-F' ' '{print $3}' | C++filt / grep-i sparse

[..]

CSparseFile:: sector2Band (длинный длинный)

CSparseFile:: addIndexNode ()

CSparseFile:: readIndexNode(длинный длинный, SparseFileIndexNode*)

CSparseFile:: readHeaderNode (CBackingStore*, SparseFileHeaderNode*, без знака long)

[... вырезать для краткости]

Редактировать

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


Если вы хотите переносимость, последнее средство-написать свою собственную функцию доступа, чтобы управлять индексом и набором блоков.

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

конечно, это приведет к не оптимизированному и медленному доступу, я бы рекомендовал этот apprach только в том случае, если требование экономии места абсолютно критично, и вы есть достаточно времени, чтобы написать набор функций доступа.

и даже в этом случае я бы сначала исследовал, нуждается ли ваша проблема в другом решении. Вероятно, вы должны хранить свои данные по-другому?


Если вы ищете (fseek, ftruncate,...) чтобы пройти конец, размер файла будет увеличен без выделения блоков, пока вы не напишете в отверстия. Но нет способа создать волшебный файл, который автоматически преобразует блоки нулей в отверстия. Ты должен сделать это сам.

Это может быть полезно посмотреть (команда OpenBSD CP вставляет отверстия вместо записи нулей). патч


похоже, OS X поддерживает разреженные файлы на томах UDF. Я попробовал тестовую программу titaniumdecoy на OS X 10.9, и она создала разреженный файл на образе диска UDF. Кроме того, UFS больше не поддерживается в OS X, поэтому, если вам нужны разреженные файлы, UDF-единственная изначально поддерживаемая файловая система, которая их поддерживает.

Я также попробовал программу на SMB shares. Когда сервер Ubuntu (файловая система ext4), программа создает разреженный файл, но "ls-ls" через SMB этого не показывает. Если вы делаете "ls-ls" на самом хосте Ubuntu, он показывает, что файл разрежен. Если сервер является файловой системой Windows XP (NTFS), программа не создает разреженный файл.