Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Ich bin dabei, in eines meiner Programme eine Rename Funktion einzubauen, wobei immer eine ganze Liste abgearbeitet werden soll. Um ein stimmiges User Interface zu erreichen, möchte ich dafür im Vorfeld die Berechtigungen prüfen. Bisher habe ich nur geprüft, ob ich schreibberechtigt bin oder sonstige Konflikte entstehen könnten. Ein Beispiel im Anhang. Aber das scheint nicht auszureichen. Bei einigen Dateien bekomme ich Fehlermeldungen, obwohl die Zugriffsberechtigungen auf 777 stehen. Der bisherige Test läuft etwa so ab:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | ...
for( i = 1; i <= num; i++ ) {
error_t = 0;
...
// testen ob frei
if( stat( rnl[i].o, &st ) == 0 ) {
if( S_ISREG(st.st_mode)==0 || (st.st_mode & S_IWUSR)==0 ) {
error_t = 1;
fprintf( stderr, "No access: %s\n", rnl[i].o );
} else {
if ( stat( rnl[i].n, &st ) == 0 ){
error_t = 1;
fprintf( stderr, "Ziel nicht frei: %s\n", rnl[i].n );
}
}
}
...
|
wobei auch "S_IWOTH" nicht immer funktioniert. Dabei ist noch anzumerken, dass in der Rename_Liste (rnl) das "o" für den alten und "n" für den neuen Namen steht. Wobei noch anzumerken ist, das die chaotischen Sprachmeldungen nur der Fehlersuche dienen und nicht im fertigen Produkt auftauchen sollen (jedenfalls nicht so). Was habe ich nicht beachtet oder könnte ich besser machen?
- Bilder
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@Dakuan: Du musst auf dem Verzeichnis die entsprechenden Rechte haben, denn Umbenennen ändert ja nicht die Datei, sondern das oder die beteiligten Verzeichnisse. Ausserdem müssen Quelle und Ziel auf dem gleichen Dateisystem liegen. Ich weiss nicht ob Du dabei dann auch so Randfälle wie UnionFS berücksichtigen willst, wo auch innerhalb des gleichen Verzeichnisses Dateien auf unterschiedlichen Dateisystem liegen können, und umbenennen nicht so einfach gehen muss.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Ups, da hast Du mich jetzt auf dem linken Fuß erwischt. Mir ist momentan nicht klar, wie ich die Berechtigung für das aktuelle Verzeichnis überprüfen kann. Da muss ich wohl noch etwas nachlesen.
Ausserdem müssen Quelle und Ziel auf dem gleichen Dateisystem liegen.
Das ist sicher gestellt. Ich will ja nur die Dateinamen ändern (nicht verschieben). Alle Dateien befinden sich innerhalb eines Verzeichnisses, aber es können recht viele sein, weswegen ich ja mit Listen arbeiten möchte.
... ob Du dabei dann auch so Randfälle wie UnionFS berücksichtigen willst,...
Das hatte ich bisher noch gar nicht auf dem Schirm 😳 . Mir ist nur aufgefallen, das ich von einigen Dateien zwar den Namen sehen kann, diese aber nicht anzeigen darf und auch von einigen, die ich anzeigen darf, das Umbenennen verweigert wird.
|
Neral
Anmeldungsdatum: 3. Oktober 2007
Beiträge: 229
|
@Dakuan: Die Dateiattribute sind auch noch wichtig: chattr +i ... zum Beispiel verhindert ein Umbenennen.
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@Duakan: ACLs könnten vielleicht auch noch eine Rolle spielen. Du solltest den Code also auf jeden Fall so schreiben, dass er auch damit klar kommt wenn etwas nicht umbenannt werden konnte, auch wenn alle Tests an die Du gedacht hast, etwas anderes vorhergesagt haben. Irgendwas ist immer… ☺
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Danke für den Hinweis, das kannte ich noch nicht. Und ich habe gerade festgestellt, dass die Sache deutlich komplizierter ist als ich dachte. Z.B. habe ich gerade festgestellt, dass ich eine schreibgeschützte Datei umbenennen kann. Hatte doch wieder vergessen, dass das eine Sache des Verzeichnisses ist. Außerdem muss ich die Prüfung verfeinern, denn auch wenn ich eine Datei nicht umbenennen darf, sollten trotzdem die Kollisionen angezeigt werden. Warum muss das alles so kompliziert sein?
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
@Marc_BlackJack_Rintsch ACLs könnten vielleicht auch noch eine Rolle spielen.
Das macht die Sache aber richtig kompliziert.
Du solltest den Code also auf jeden Fall so schreiben, dass er auch damit klar kommt wenn etwas nicht umbenannt werden konnte,...
Das habe ich gerade fertig (debuggt). Da ich mit einer Liste arbeite, kann ich mir die Zustände merken. Ich bin gerade dabei, in dem Fenster Layout einen Platz für den Undo-Button frei zu machen.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Ich setze das jetzt mal auf gelöst, obwohl ich noch nicht die Zeit gefunden habe, das alles umzusetzen. Das Wetter war zu schön und ich war viel zu ungeduldig. Daher habe ich erstmal auf die Fehlererkennung gesetzt, und das Programm auf echte Dateien losgelassen. Dabei hat sich gezeigt, das die Undo Funktion Gold wert ist, jedenfalls für mich, als hoffnungsvoller Anwärter auf die Tippfehlerweltmeisterschaft 😉
|
Neral
Anmeldungsdatum: 3. Oktober 2007
Beiträge: 229
|
Selbst wenn du alle Möglichkeiten vorher testen würdest und dir sicher sein könntest, die Rechte zum Verschieben zu haben, musst du trotzdem damit umgehen können, dass jemand zwischen deiner Rechteprüfung und dem eigentlichen Umbenennen irgendwas macht, was das Umbenennen fehlschlagen lässt. Stichwort TOCTTOU. Ich würde eine einfache Heuristik nehmen und dann mit eventuellen Fehlern sinnvoll umgehen bzw. den Nutzer darüber benachrichtigen.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Stichwort TOCTTOU.
Das Stichwort kannte ich noch nicht, die Effekte aber schon. Marc_BlackJack_Rintsch hat's ja auch schon gesagt: Irgendwas ist immer…
Deswegen hatte ich das Programm auch erst nach der Fertigstellung der Undo-Funktion auf echte Dateien losgelassen. Was mich momentan noch beschäftigt, ist einen Algorithmus zu finden, mit dem das Programm auch sich überlappende Bereiche verschieben kann. Also wenn ein durchgehend nummerierter Block von 20 Dateien um 10 Zähler verschoben werden soll (analog zu memmove()). Bisher ergibt das für die ersten 10 Dateien eine Kollision. Aber wenn man die Liste in diesem Fall rückwärts abarbeitet funktioniert es. Das sind so die kleinen Dinge, die oft erst beim praktischen Einsatz auffallen.
|
Neral
Anmeldungsdatum: 3. Oktober 2007
Beiträge: 229
|
Dakuan schrieb: Was mich momentan noch beschäftigt, ist einen Algorithmus zu finden, mit dem das Programm auch sich überlappende Bereiche verschieben kann.
Ich würde versuchen, erst alle Dateien mit einem neuen eindeutigen Namen umzubenennen (den man zum Beispiel mit tempnam erzeugen kann) und dann die eigentliche Umbenennung zu machen. Also quasi den Algorithmus von memmove zu implementieren. 😉
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@Neral: Nicht so ganz, denn das würde ja für memmove bedeuten, das zusätzlicher, temporärer Speicher benötigt würde. Keine mir bekannte Implementierung macht das tatsächlich. ☺
|
Neral
Anmeldungsdatum: 3. Oktober 2007
Beiträge: 229
|
@Marc_BlackJack_Rintsch: Natürlich kann man das optimieren, dass memmove O(1) Speicher braucht, aber ist das nicht eher ein Implementierungsdetail? Wenn die manpage sagt, dass memmove sich so verhält, als würde ein temporärer Speicher existieren, was ist dann „der Algorithmus“ von memmove ‽
|
Marc_BlackJack_Rintsch
Ehemalige
Anmeldungsdatum: 16. Juni 2006
Beiträge: 4577
Wohnort: Berlin
|
@Neral: Klares Jain. ☺ In der Beschreibung steht auch, dass der Rückgabewert ein Zeiger auf den dest -Speicherbereich ist. Da steht nicht, das die Funktion fehlschlagen kann wenn nicht genug Speicher für einen temporären Speicherbereich vorhanden ist und dann beispielsweise NULL zurückgegeben wird. Und ich habe wie gesagt noch nie eine Implementierung gesehen die tatsächlich temporären Speicher verwendet. Das würde ich auch nicht als optimiert beschreiben, sondern als normale Implementierung.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6345
Wohnort: Hamburg
|
Bei einer vorherigen Scriptlösung bin ich tatsächlich den Weg über temporäre Zwischendateien gegangen. Allerdings habe ich dabei auch keine wirklich sichere Lösung realisiert. Ich glaube nicht, das bei memmove() zusätzlicher Speicher benötigt wird. Da kann man ja unterstellen, das der Bereich lückenlos ist. Man muss also nur die Adressen vergleichen und kann dann entscheiden, ob man von oben oder unten kopiert. Bei meinen Rename Problem ist das zwar auch meistens gegeben, aber (theoretisch) eben nicht immer, und die Software muss das erkennen können. Das macht die Sache umständlich (und ich hasse umständliche Lösungen). Also wenn man TOCTTOU ernst nimmt, ist die Verwendung von temporären Namen eine (theroretische) zusätzliche Fehlerquelle, die man durch geschickte Software vermeiden könnte. Wenn mir allerdings keine bessere Lösung einfällt, muss ich wohl darauf zurückgreifen und auf eine gute Fehlererkennung und ggf. einer Undo-Funktion vertrauen.
|