Warum wird mmap () - Fehler mit permission denied für die Ziel-Datei eine Datei kopieren Programm?
Möchte ich zu geben versuchen beim kopieren der Inhalt einer Datei auf ein anderes durch die Verwendung von memory-mapped I/O in Linux über mmap()
. Die Absicht ist zu prüfen, selbst wenn das besser als mit fread()
und fwrite()
und wie würde es viel mit großen Dateien (wie paar GiBs zum Beispiel, da wird die Datei eingelesen ganzen möchte ich wissen, wenn ich brauche, um eine solche Menge von Speicher).
Dies ist der code, mit dem ich arbeite und jetzt:
//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);
Ich denke, es kann ein Weg, es zu tun, aber ich bekomme immer einen Fehler beim Versuch die Karte der Ziel-Datei, konkret code 13 (permission denied).
Habe ich nicht die geringste Ahnung, warum es scheitert, kann ich schreiben, dass die Datei da die Datei wird erstellt und alle, und die Datei, die ich versuche zu kopieren, ist nur ein paar von KiBs in der Größe.
Kann jemand vor Ort das problem? Wie kommt es, ich musste die Berechtigung zum anzeigen der original-Datei, aber nicht das Ziel einer?
HINWEIS: Wenn jemand zu verwenden, die Schleife zum kopieren von bytes gesendet in der Frage statt memcpy
zum Beispiel die loop-Zustand sein sollte i--
statt kopieren aller Inhalte. Dank jxh für spotting, dass.
- Können Sie überprüfen, um zu sehen, ob die
ftruncate
Aufruf erfolgreich war? - Danke jxh, die Ziel-Datei scheint entstanden zu sein, mit der entsprechenden Größe. Ich war die überprüfung manuell bis jetzt, ich werde aktualisieren Sie den code, den ich gepostet haben.
- Memory mapping ist nur sinnvoll, wenn Sie es verwenden, um das sammeln von Daten aus einer Quell-Datei. Es ist nicht so effizient wie ein schreiben Ziel. Ich würde sagen, Sie wäre das beste, aus mit
unistd.h
low-level-I/O (open()
,read()
,write()
,fdatasync()
, undclose()
) mit Puffer (chunk-Größen) basiert auf dem, wasfstat()
schlägt für die Dateien; largeish Zweierpotenzen wie 262144 oder größer sonst. Es gibt auch schnellere Möglichkeiten um Dateien zu kopieren, wenn.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Aus der
mmap()
Mann Seite:Die Sie öffnen, um Ihr Ziel-Datei mit
O_WRONLY
. VerwendenO_RDWR
statt.Auch, sollten Sie
memcpy
kopieren der Speicher anstatt mit der eigenen Schleife:Ihre Schleife hat einen Weg von 1 Fehler.
i--
statt oder--i
.Dies funktioniert für mich. Beachten Sie, dass ich hatte das Ziel öffnen O_RDWR. Ich vermute, dass der kernel versucht, Karte, ganze Seiten aus der Datei in den Speicher (Lesen), weil Sie aktualisieren es ein byte oder word zu einem Zeitpunkt, und dass möglicherweise nicht die ganze Seite.
Ein paar andere Punkte:
Brauchen Sie nicht zu schließen und unmap-Kram auf Fehler, wenn Sie nur gehen, um zu beenden.
Memcpy verwenden und nicht schreiben Sie Ihre eigenen byte-kopieren-Schleife. Memcpy wird viel besser optimiert im Allgemeinen. (Obwohl es nicht immer der absolut beste.)
Möchten Sie vielleicht Lesen Sie den source-code unter FreeBSD ist der "cp" - Dienstprogramm. Werfen Sie einen Blick hier und Suche für die Nutzung von mmap. http://svnweb.freebsd.org/base/stable/9/bin/cp/utils.c?revision=225736&view=markup
Original-Datei: O_RDONLY öffnen, MAP_PRIVATE mmap
Ziel-Datei: öffnen O_WRONLY, MAP_SHARED mmap
Müssen Sie öffnen Sie mit O_RDWR flag für die Verwendung MAP_SHARED.
Nicht Sie wirklich brauchen, zu tun MAP_FILE | MAP_SHARED ?
O_RDWR
für die Ziel-Datei, aber MAP_FILE scheint nicht zu existieren in meinemmmap
Mann-Datei.