Verschieben einer Datei unter Linux in C

Lesezeit: 4 Minuten

Benutzeravatar von John Vulconshinz
John Vulconshinz

  • Plattform: Debian Wheezy 3.2.0-4-686-pae
  • Compiler: GCC (Debian 4.7.2-5) 4.7.2 (Code::Blocks)

Ich möchte eine Datei von einem Speicherort an einen anderen verschieben. Nichts ist so kompliziert wie das Verschieben auf verschiedene Laufwerke oder in verschiedene Dateisysteme. Ich weiß, dass die “Standardmethode” darin besteht, einfach die Datei zu kopieren und dann das Original zu entfernen. Aber ich möchte eine Möglichkeit, den Besitz der Datei, den Modus, den letzten Zugriff/die letzte Änderung usw. beizubehalten. Ich gehe davon aus, dass ich die Datei kopieren und anschließend den Besitz, den Modus usw. der neuen Datei bearbeiten muss, aber ich habe keine Ahnung, wie das geht.

Benutzeravatar von Basile Starynkevitch
Basile Starynkevitch

Die übliche Methode zum Verschieben einer Datei in C ist die Verwendung von umbenennen(2)die manchmal scheitern.

Wenn Sie die nicht verwenden können umbenennen(2) syscall (z. B. weil Quelle und Ziel auf unterschiedlichen Dateisystemen liegen), müssen Sie die Größe, Berechtigung und andere Metadaten der Quelldatei mit abfragen Statistik(2); Kopieren Sie die Datenschleife auf lesen (2), schreiben(2) (unter Verwendung eines Puffers von mehreren Kilobyte), offen(2), schließen(2) und die Metadaten verwenden chmod(2), chown(2), Laufzeit(2). Möglicherweise interessieren Sie sich auch für das Kopieren von Attributen mit getxattr(2), setxattr(2), listxattr(2). Sie könnten auch in einigen Fällen verwenden sendfile(2)wie von David C. Rankin kommentiert.

Und wenn sich Quelle und Ziel auf unterschiedlichen Dateisystemen befinden, gibt es keine Möglichkeit, die Bewegung atomar zu machen und Race-Conditions zu vermeiden (Also using umbenennen(2) ist nach Möglichkeit vorzuziehen, da es laut seiner Manpage atomar ist). Die Quelldatei kann während der Verschiebevorgänge immer (durch einen anderen Prozess) geändert werden …

Eine praktische Methode zum Verschieben von Dateien besteht also darin, zunächst Folgendes zu tun: umbenennen(2)und wenn das mit fehlschlägt EXDEV (wann alter Pfad und neuer Weg sich nicht auf demselben gemounteten Dateisystem befinden), müssen Sie Bytes und Metadaten kopieren. Mehrere Bibliotheken bieten dafür Funktionen an, zB Qt QDatei::umbenennen.

Lesen Fortgeschrittene Linux-Programmierung – und sehen Systemaufrufe(2) – für mehr (und versuchen Sie es auch strace manche mv Befehl, um zu verstehen, was es tut). Dieses Buch kann kostenlos und legal heruntergeladen werden (so dass Sie mehrere Exemplare im Internet finden können).

Das /bin/mv Befehl (vgl mv(1)) ist ein Teil von GNU Coreutils welches ist gratis Software. Sie könnten entweder den Quellcode studieren oder verwenden spur(1) um zu verstehen, was dieser Befehl tut (in Bezug auf Systemaufrufe(2)). In einigen Open Source Unix-Shells mögen Schärpe oder Busybox, mv könnte eine eingebaute Shell sein. Siehe auch Pfadauflösung(7) und Kugel(7).

Es gibt subtile Eckfälle (stellen Sie sich einen anderen Prozess oder Pthread vor, der einige Dateioperationen auf demselben Dateisystem, Verzeichnis oder denselben Dateien ausführt). Lesen Sie einige Betriebssystem Lehrbuch für mehr.

Mit einer Mischung aus snprintf(3), System(3), mv(1) könnte schwierig sein, wenn der Dateiname seltsame Zeichen enthält, wie z Tab oder oder Zeilenumbrüche oder beginnt mit einem Anfangsbuchstaben -. Sehen Fehlernummer(3).

  • Vielen Dank für die alternative Option.

    – John Vulconshinz

    20. Juli 2013 um 4:59 Uhr

  • Für Linux, Datei senden bietet eine Methode zum Kopieren über Dateisystemgrenzen hinweg, die effizienter ist als read, write. Das Original sendfile hat Größenbeschränkungen von 0x7ffff000 (2,147,479,552) Bytes, aber Linux hat auch die hinzugefügt sendfile64 Wrapper mit einem breiteren Typ für das Offset-Argument.

    – David C. Rankin

    29. Januar 2018 um 1:26 Uhr


  • Der Link zur erweiterten Linux-Programmierung scheint defekt zu sein.

    – St.Antario

    9. April 2019 um 12:47 Uhr

  • Korrigiert. Aber man konnte es auch finden

    – Basile Starynkevitch

    9. April 2019 um 14:06 Uhr

  • Wow, das ist ein Prozess … Ich denke, ich bleibe bei system (“mv”)

    – Elieser Miron

    24. April 2019 um 19:52 Uhr

kgraneys Benutzeravatar
kgraney

Wenn sich der ursprüngliche und der neue Speicherort für die Datei auf demselben Dateisystem befinden, ist ein “Verschieben” konzeptionell identisch mit einem “umbenennen.”

#include <stdio.h>

int rename (const char *oldname, const char *newname)

  • Gefährlich. Hat Race Conditions – wie alle Dateioperationen, die auf dem Namen beruhen, nicht auf einem Dateizeiger. Sie können überprüfen, ob es sich um die richtige Datei handelt, bevor Sie renmae aufrufen, aber dann vergeht einige Zeit zwischen der Überprüfung und der eigentlichen Umbenennungsoperation. In dieser Zeit ist es möglich, dass die Originaldatei durch eine bösartige Datei ersetzt wird (und solche Sicherheitslücken gab es in echten Anwendungen).

    – ank

    3. Juli 2013 um 1:55 Uhr

  • @atk: Warum glaubst du das? rename(2) ist gefährlich? Ich glaube, es ist atomar, da es sich um einen Syscall und seine handelt man Seite erwähnt Atomarität!

    – Basile Starynkevitch

    3. Juli 2013 um 5:09 Uhr


  • Möglicherweise möchten Sie dem OP mitteilen, wie es erkennen kann, ob sich beide Dateien im selben Dateisystem befinden, und wenn nicht, wie eine Kopierfunktion implementiert wird, und dann zu unlink() das Original.

    – Trojaner

    3. Juli 2013 um 5:46 Uhr

  • @BasileStarynkevitch – Umbenennen ist auf Dateisystemebene atomar. Es ist sofort entweder alter oder neuer Name. Was atk sagt, dass Sie, wenn Sie Code haben, der eine Datei nach Namen (char*) findet und sie dann umbenennt (mit char*), nicht 100% sicher sind, dass die Datei, die Sie beim ersten Mal finden, dieselbe Datei ist, die Sie sind Umbenennen, wenn ein anderer Prozess Dateien auf Ihnen ändert.

    – Mark Lakata

    3. Juli 2013 um 5:57 Uhr

  • Mark Lakata hat den Nagel auf den Kopf getroffen 🙂

    – ank

    6. Juli 2013 um 14:36 ​​Uhr

1437570cookie-checkVerschieben einer Datei unter Linux in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy