Pourquoi ne mmap() échoue avec l'autorisation refusée pour le fichier de destination de la copie d'un fichier de programme?
J'aimerais essayer de copier le contenu d'un fichier à un autre en utilisant memory mapped I/O sous Linux via mmap()
. L'intention est de vérifier par moi-même si c'est mieux que d'utiliser fread()
et fwrite()
et comment serait-il traiter de gros fichiers (comme quelques Lardons par exemple, puisque le fichier est lu en entier, je veux savoir si j'ai besoin d'avoir une telle quantité de mémoire pour elle).
C'est le code, je travaille avec maintenant:
//Open original file descriptor:
int orig_fd = open(argv[1], O_RDONLY);
//Check if it was really opened:
if (orig_fd == -1) {
fprintf(stderr, "ERROR: File %s couldn't be opened:\n", argv[1]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
exit(EX_NOINPUT);
}
//Idem for the destination file:
int dest_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
//Check if it was really opened:
if (dest_fd == -1) {
fprintf(stderr, "ERROR: File %s couldn't be opened:\n", argv[2]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
//Close original file descriptor too:
close(orig_fd);
exit(EX_CANTCREAT);
}
//Acquire file size:
struct stat info = {0};
if (fstat(orig_fd, &info)) {
fprintf(stderr, "ERROR: Couldn't get info on %s:\n", argv[1]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
//Close file descriptors:
close(orig_fd);
close(dest_fd);
exit(EX_IOERR);
}
//Set destination file size:
if (ftruncate(dest_fd, info.st_size)) {
fprintf(stderr, "ERROR: Unable to set %s file size:\n", argv[2]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
//Close file descriptors:
close(orig_fd);
close(dest_fd);
exit(EX_IOERR);
}
//Map original file and close its descriptor:
char *orig = mmap(NULL, info.st_size, PROT_READ, MAP_PRIVATE, orig_fd, 0);
if (orig == MAP_FAILED) {
fprintf(stderr, "ERROR: Mapping of %s failed:\n", argv[1]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
//Close file descriptors:
close(orig_fd);
close(dest_fd);
exit(EX_IOERR);
}
close(orig_fd);
//Map destination file and close its descriptor:
char *dest = mmap(NULL, info.st_size, PROT_WRITE, MAP_SHARED, dest_fd, 0);
if (dest == MAP_FAILED) {
fprintf(stderr, "ERROR: Mapping of %s failed:\n", argv[2]);
fprintf(stderr, "%d - %s\n", errno, strerror(errno));
//Close file descriptors and unmap first file:
munmap(orig, info.st_size);
close(dest_fd);
exit(EX_IOERR);
}
close(dest_fd);
//Copy file contents:
int i = info.st_size;
char *read_ptr = orig, *write_ptr = dest;
while (--i) {
*write_ptr++ = *read_ptr++;
}
//Unmap files:
munmap(orig, info.st_size);
munmap(dest, info.st_size);
Je pense que c'est peut-être une façon de le faire, mais je reçois un message d'erreur en essayant de carte le fichier de destination, concrètement, code 13 (permission denied).
Je n'ai pas la moindre idée pourquoi est-elle défaillante, je peux écrire dans ce fichier car le fichier est créé et tous et le fichier que je suis en train de copier est juste un couple de ces services dans la taille.
Quelqu'un peut-il repérer le problème? Comment ai-je eu l'autorisation de la carte le fichier d'origine mais pas la destination?
REMARQUE: Si quelqu'un est d'utiliser la boucle pour copier des octets publié dans la question de la place de memcpy
par exemple, la condition de la boucle doit être i--
au lieu de copier tout le contenu. Grâce à jxh pour s'apercevoir qu'.
ftruncate
appel a réussi?Merci jxh, le fichier de destination semble être créés avec la taille appropriée. J'ai été vérifier manuellement jusqu'à maintenant, je vais mettre à jour le code que j'ai posté.
Mappage de la mémoire n'est utile que si vous l'utiliser pour recueillir les données à partir d'un fichier source. Ce n'est pas aussi efficace que l'écriture de la cible. Je dirais que vous seriez mieux à l'aide de
unistd.h
faible niveau I/O (open()
, read()
, write()
, fdatasync()
, et close()
) avec tampons (tailles de segment) basé sur ce que fstat()
suggère de fichiers; largeish des puissances de deux, comme 262144 ou plus autrement. Il y a même des manières plus rapides pour copier des fichiers.
OriginalL'auteur James Russell | 2013-06-19
Vous devez vous connecter pour publier un commentaire.
De la
mmap()
homme page:Vous ouvrez votre fichier de destination avec
O_WRONLY
. UtilisationO_RDWR
à la place.Aussi, vous devez utiliser
memcpy
pour copier la mémoire plutôt que d'utiliser votre propre boucle:De votre boucle a un par 1 bug.
i--
au lieu ou--i
.OriginalL'auteur jxh
Cela fonctionne pour moi. Notez que j'ai dû ouvrir la destination O_RDWR. Je soupçonne que le noyau tente de cartographier l'ensemble des pages du fichier dans la mémoire (lecture) parce que vous êtes à jour un octet ou un mot à la fois, et qui risquent de ne pas modifier l'ensemble de la page.
Un couple de d'autres points:
Vous n'avez pas besoin de fermer et annuler le mappage des trucs sur d'erreur si vous êtes juste de quitter.
Utilisation memcpy et ne pas écrire votre propre octet-la copie de la boucle. Memcpy sera beaucoup mieux optimisé en général. (Si ce n'est pas toujours le meilleur.)
Vous voudrez peut-être lire le code source de FreeBSD "cp" de l'utilitaire. Jetez un oeil ici et de recherche pour l'utilisation de mmap. http://svnweb.freebsd.org/base/stable/9/bin/cp/utils.c?revision=225736&view=balisage
L'exécution de ces nettoyages est inutile à partir d'une justesse point de vue, mais il ne aider à assainir le code lors de l'utilisation d'un débogueur mémoire.
Vous pouvez être sûr qu'un système de type Unix, permet de nettoyer la plupart des ressources lors de votre processus de sorties (ou est tué). Les exceptions sont la plupart du temps des choses avec des noms dans le système de fichiers (fichiers, périphériques, nommé sockets, etc.)
Je vois, merci pour l'info.
OriginalL'auteur rptb1
Fichier d'origine: O_RDONLY ouvert, MAP_PRIVATE mmap
fichier de destination: O_WRONLY ouvert, MAP_SHARED mmap
Vous devez ouvrir avec O_RDWR drapeau pour l'utilisation de MAP_SHARED.
N'avez-vous pas réellement besoin de faire MAP_FILE | MAP_SHARED ?
O_RDWR
pour le fichier de destination, mais MAP_FILE il ne semble pas exister dans monmmap
homme de fichier.OriginalL'auteur CancerSoftware