2017-06-02 12 views
5

J'ai besoin d'allouer un gros fichier sans mettre à zéro son contenu. Je produis ces étapes fopen => ftruncate => fclose => mmap => (...work...) => munmap avec des tailles de fichiers énormes (des centaines de gigaoctets). App se bloque sur la résiliation pendant quelques minutes alors que le système essaie de mettre à zéro les octets de fichier - IMHO en raison de l'utilisation ftruncate.Allouer le fichier sur le disque sans mise à zéro

ftruncate(ofd, 0); 

#ifdef HAVE_FALLOCATE 

    int ret = fallocate(ofd, 0, 0, cache_size); 
    if (ret == -1) { 
     printf("Failed to expand file to size %llu (errno %d - %s).\n", cache_size, errno, strerror(errno)); 
     exit(-1); 
    } 

#elif defined(HAVE_POSIX_FALLOCATE) 

    int ret = posix_fallocate(ofd, 0, cache_size); 
    if (ret == -1) { 
     printf("Failed to expand file to size %llu (errno %d - %s).\n", cache_size, errno, strerror(errno)); 
     exit(-1); 
    } 

#elif defined(__APPLE__) 

    fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, cache_size, 0}; 
    int ret = fcntl(ofd, F_PREALLOCATE, &store); 
    if (ret == -1) { 
     store.fst_flags = F_ALLOCATEALL; 
     ret = fcntl(ofd, F_PREALLOCATE, &store); 
    } 
    if (ret == -1) { // read fcntl docs - must test against -1 
     printf("Failed to expand file to size %llu (errno %d - %s).\n", cache_size, errno, strerror(errno)); 
     exit(-1); 
    } 
    struct stat sb; 
    ret = fstat(ofd, &sb); 
    if (ret != 0) { 
     printf("Failed to write to file to establish the size.\n"); 
     exit(-1); 
    } 
    //ftruncate(ofd, cache_size); <-- [1] 

#endif 

Il semble qu'il ne fonctionne pas avec la ligne a commenté [1]. Mais en décommentant cette ligne produit la réduction à zéro de fichier que j'essaye d'éviter. Je me fiche vraiment du contenu de fichier sale avant d'écrire. Je veux juste éviter de raccrocher à la fin de l'application.

SOLUTION:

Selon l » answer@torfo, remplacé tout mon code lié à Apple avec ces quelques lignes:

unsigned long long result_size = cache_size; 
int ret = fcntl(ofd, F_SETSIZE, &result_size); 
if(ret == -1) { 
    printf("Failed set size %llu (errno %d - %s).\n", cache_size, errno, strerror(errno)); 
    exit(-1); 
} 

Mais ne fonctionne que pour super-utilisateur!

+1

** deleted ** ('ftruncate()' devrait également créer un fichier fragmenté, il semble donc que votre OS/système de fichiers ne supporte pas les fichiers fragmentés) –

+0

Si vous avez besoin de créer un fichier énorme sans le mettre à zéro , juste "ftruncate" sans faire les autres choses que vous faites. Cela créera un fichier fragmenté si votre système de fichiers le supporte. 'fallocate' et les autres appels feront l'inverse, ils préalloueront et mettront à zéro les blocs de disque. Vous courez le risque de manquer d'espace disque lorsque vous écrivez dans un fichier fragmenté, mais vous ne perdez pas de temps à le mettre à zéro. – Art

+0

L'application @Art avec 'ftruncate' se bloque pendant quelques minutes à la fin via' Ctrl + C'. – k06a

Répondre

5

Ceci est MacOS X, apparemment.

Vous pouvez essayer de remplacer l'appel ftruncate avec

fcntl(ofd, F_SETSIZE, &size); 

(note a besoin des privilèges root et pourrait créer un trou de sécurité, car il peut fournir un accès au plus ancien contenu du fichier qui a déjà été là, elle doit donc être manipulé avec extrême prudence le « contenu de fichiers sale » vous ne se soucient pas pourrait effectivement être les mots de passe de compte bancaire de l'utilisateur il supprimé il y a une semaine ...)

MacOS X ne supporte pas vraiment les fichiers rares -. Il ne crée et les maintenir, mais son pilote de système de fichiers est très désireux de remplir les trous dès que possible.

+0

Merci! 'fcntl (ofd, F_SETSIZE, & result_size);' fonctionne comme un charme! – k06a

+1

@ k06a Vous * avez * lu * mes préoccupations de sécurité? – tofro

+0

Oui, je m'en fiche des problèmes de sécurité pour ce cas d'utilisation. C'est une génération de parcelles pour l'exploration HDD: https://github.com/r-majere/mjminer/pull/3 – k06a