Go: Vorschlag: os: Create/Open/OpenFile() set FILE_SHARE_DELETE auf Windows

Erstellt am 16. Mai 2019  ·  194Kommentare  ·  Quelle: golang/go

Unter Linux & MacOS können wir dies schreiben; unter Windows schlägt es mit einer "Freigabeverletzung" fehl:

path := "delete-after-open"
fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
if err != nil { ... }
err = os.Remove(path)            // or os.Rename(path, path+"2")
if err != nil { ... }
fd.Close()

Wenn Sie unter Windows entwickeln und unter Linux usw. bereitstellen und Ihr Code auf diesem _undokumentierten_ GOOS=windows-Verhalten von os.Rename() & .Remove() beruht, ist er defekt und möglicherweise anfällig. Beachten Sie, dass das Paket "os" _fünfzehn Erwähnungen_ anderer Windows-spezifischer Verhaltensweisen enthält.

Um dies zu beheben, syscall.Open() unter https://golang.org/src/syscall/syscall_windows.go#L272
braucht sharemode |= FILE_SHARE_DELETE

Microsoft empfiehlt, dies als Standard festzulegen: https://github.com/golang/go/issues/32088#issuecomment -502850674
Rust hat es zum Standard gemacht: https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html
Mingw-w64 hat es vor sieben Jahren zum Standard gemacht:
https://sourceforge.net/p/mingw-w64/code/HEAD/tree/stable/v3.x/mingw-w64-headers/include/ntdef.h#l858
Erlang hat es vor über sechs Jahren zum Standard gemacht: erlang/ otp@0e02f48
Python konnte es aufgrund von Einschränkungen der MSVC-Laufzeit nicht übernehmen: https://bugs.python.org/issue15244

~Deshalb sollte syscall.Open() standardmäßig file_share_delete verwenden und syscall sollte beides bereitstellen:
a) einen globalen Schalter zum Deaktivieren (für alle vorhandenen Apps, die auf dessen Abwesenheit angewiesen sind) und
b) ein Flag zur Verwendung mit os.OpenFile(), um es für ein bestimmtes Datei-Handle zu deaktivieren.~

Update nach https://github.com/golang/go/issues/32088#issuecomment-532784947 von @rsc :
a) os.Create/Open/OpenFile() sollte file_share_delete unter Windows
b) syscall.Open() unter Windows sollte ein Flag akzeptieren, das file_share_delete aktiviert, und
c) syscall unter Windows sollte eine Konstante für das neue Flag exportieren.

Die Dokumentation zu os.Remove() sollte auch beachten, dass man Folgendes tun muss, um einen Dateinamen nach dem Löschen einer geöffneten Datei unter Windows wiederzuverwenden: os.Rename(path, unique_path); os.Remove(unique_path) .

API-Dokumente gewinnen
https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea

Wenn es einen Grund gibt, dies nicht zu tun, sollte dies in os.Remove() & .Rename() dokumentiert werden.

cc @alexbrainman
@gopherbot OS-Windows hinzufügen

FrozenDueToAge OS-Windows Proposal Proposal-FinalCommentPeriod release-blocker

Hilfreichster Kommentar

Ich werde versuchen, hier die Perspektive des Windows-Teams darzustellen ... wir würden es vorziehen, wenn Go einfach immer FILE_SHARE_DELETE ohne Option setzt. Im Allgemeinen, um die Portierung zu/von Windows zu vereinfachen, würden wir ein konsistentes Verhalten mit Linux bevorzugen, und ich sehe nicht, warum Windows-Benutzer oder -Software das Standardverhalten !FILE_SHARE_DELETE so bevorzugen würden, dass dies eine Ausnahme von der Regel darstellt.

Ein interessanter Hinweis, im Gegensatz zu @mattns Kommentar: In der neuesten Version von Windows haben wir DeleteFile (auf NTFS) aktualisiert, um ein "POSIX" -Löschen durchzuführen, bei dem die Datei sofort aus dem Namespace entfernt wird, anstatt darauf zu warten, dass alle geöffnet sind Handles auf die zu schließende Datei. Es respektiert immer noch FILE_SHARE_DELETE, verhält sich aber ansonsten eher wie POSIX Unlink. Diese Funktionalität wurde für WSL hinzugefügt und wurde standardmäßig auch für Windows-Software als sinnvoll erachtet.

Mit anderen Worten, wenn Sie das Testprogramm von mattn und die Sequenz von del, dir usw. unter der neuesten Windows-Version ausführen, werden Sie sehen, dass die Datei sofort nach dem Löschen der Datei aus dem Namespace verschwindet, nicht nach dem Beenden des Testprogramms. Genau wie Linux.

Daher nehmen wir sogar in Windows selbst mit seinem deutlich größeren Anwendungskompatibilitätsrisiko kleine Änderungen vor, um die Portierung von Nicht-Windows-Software auf Windows zu erleichtern. Ich ermutige Go wirklich, dasselbe zu tun.

Alle 194 Kommentare

/cc @alexbrainman

syscall.Open() unter https://golang.org/src/syscall/syscall_windows.go#L272
sollte sharemode := ... | FILE_SHARE_DELETE

Warum sollte es?

Alex

FILE_SHARE_DELETE aktiviert das obige Codebeispiel, das unter MacOS & Linux funktioniert, aber unter Windows fehlschlägt. Es ist auch notwendig für:

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
defer fd.Close()
_, err = fd.Write(...)
err = fd.Sync()  // file now safe to share
err = os.Rename(path, path+"2")
_, err = fd.Read(...)

FILE_SHARE_DELETE aktiviert das obige Codebeispiel, das unter MacOS & Linux funktioniert, aber unter Windows fehlschlägt.

Warum passen wir nicht stattdessen den MacOS- und Linux-Code an?

Es ist auch notwendig für:

Ich verstehe nicht, was Sie sagen wollen.

Alex

@networkimprov Sie müssen Remove nach Close() unter Windows aufrufen.

path := "delete-after-open"
fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
if err != nil { panic(err) }
fd.Close()
err = os.Remove(path)            // or os.Rename(path, path+"2")
if err != nil { panic(err) }

@alexbrainman Wenn Sie eine zuverlässige Datei-E/A durchführen (wie bei Datenbanken), ist es üblich, eine Datei mit einem temporären Namen zu erstellen, sie zu schreiben, zu fsync und umzubenennen.

Geöffnete Dateien können unter Unix standardmäßig umbenannt oder gelöscht werden. Es scheint ein Versehen zu sein, dass das Windows-Flag für diese Funktion nicht gesetzt ist. Ich bezweifle, dass wir das Go-Team davon überzeugen werden, die Funktionsweise für Linux und MacOS zu ändern :-)

@mattn Bitte wenden Sie den von mir beschriebenen Fix an und versuchen Sie den von mir geposteten Code.

Ich bezweifle, dass wir das Go-Team davon überzeugen werden, die Funktionsweise für Linux und MacOS zu ändern :-)

Mir geht es gut, so wie es jetzt ist.

Alex

Gibt es einen Grund dafür, diese allgemeine Funktion in Windows wegzulassen?

Können Sie in syscall_windows.go einen Schalter bereitstellen, damit wir das Unix-Verhalten beim Programmstart auswählen können?

Es ist in Ordnung, dass wir neue APIs oder Flags hinzufügen. Aber ich habe Einwände, das derzeitige Verhalten zu ändern. Da FILE_SHARE_DELETE nicht dem Unix-Verhalten entspricht.

#include <windows.h>
#include <stdio.h>

int
main(int argc, char* argv[]) {
  HANDLE h = CreateFile("test.txt",
      GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
      NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  getchar();
  char buf[256] = {0};
  DWORD nread;
  printf("%d\n", ReadFile(h, buf, 256, &nread, NULL));
  printf("%s,%d\n", buf, nread);
  return 0;
}

Vervollständigen Sie diesen Code unter Windows und versuchen Sie, als test.exe auszuführen. Während diese App auf einen Tastendruck wartet, öffnen Sie eine neue cmd.exe, löschen Sie "test.txt" wie folgt.

image

Die Datei kann gelöscht werden, bleibt aber dort, während der Prozess existiert. Diese Änderung wird also nicht gut für Ihre Erwartungen funktionieren.

Mir ist klar, dass der Verzeichniseintrag nicht entfernt wurde, aber in den Dokumenten steht

Nachfolgende Aufrufe von CreateFile zum Öffnen der Datei schlagen mit ERROR_ACCESS_DENIED fehl.

Daher verstehe ich dein Bildschirmprotokoll nicht.

Wie auch immer, ein Schalter wie dieser wäre in Ordnung:

syscall.OpenFileShareDelete = true

Ich möchte erwähnen, dass ich schon bei der Arbeit davon gebissen wurde.

Grundsätzlich hatten wir:

f, err := os.Open(...)
if err != nil { ... }
defer f.Close()

// lots of code

if err := os.Rename(...); err != nil { ... }

Der Code lief auf unseren Unix-basierten CI-Plattformen gut, aber unter Windows explodierte er.

Vorausgesetzt, es gibt keine seltsamen Nebenwirkungen, wäre es schön, wenn die Dinge einfach funktionieren würden .

IIRC haben wir in der Vergangenheit einige Anpassungen am Verhalten von GOOS=windows & plan9 vorgenommen, um der Unix-Semantik besser zu entsprechen. Es würde mir nichts ausmachen, dies zu einem weiteren solchen Fall zu machen, wenn die Semantik nah genug ist. Der Kommentar von

Ich möchte jedoch keine globale Option sehen. Das scheint nur ein Debugging-Albtraum zu sein.

@bradfitz
Wahrscheinlich nicht, bitte beachte meinen Kommentar hier
https://groups.google.com/forum/#!topic/golang -dev/R79TJAzsBfM
oder wenn Sie möchten, kann ich den Inhalt hier kopieren, da es auch eine mögliche Lösung gibt, obwohl ich dies nicht als Standardverhalten implementieren würde, da dies nicht mit dem Verhalten von Windows-Programmen vereinbar wäre, sondern eher ein Workaround, um ein ähnliches Kreuz zu erstellen -os Erfahrung.

@guybrand schreibt im golang-dev-Thread:

mein Programm schreibt eine Datei namens "my.data" und ruft dann ein anderes Programm auf und wartet nicht darauf, dass es endet ... dieses Programm lädt beispielsweise diese Datei hoch, was 10 Sekunden dauert (nennen Sie dieses andere Programm "Uploader") .
...
Wenn mein Programm .Remove unter Windows aufruft (FILE_SHARE_DELETE ist aktiviert):
...
Uploader würde eine Fehlermeldung erhalten, die ihm mitteilt, dass die Datei entfernt wurde (wahrscheinlich EOF).

Angenommen, "uploader" öffnet die Datei, bevor "mein Programm" os.Remove() aufruft, ich glaube, Sie haben den Win-API-Dokumenten widersprochen:

_DeleteFile markiert eine Datei zum Löschen beim Schließen. Daher tritt das Löschen der Datei nicht auf, bis das letzte Handle für die Datei geschlossen wird. Nachfolgende Aufrufe von CreateFile zum Öffnen der Datei schlagen mit ERROR_ACCESS_DENIED._ fehl.

Bezüglich "Kopplung eines _open_osfhandle() des CreateFile mit einem _fdopen", können Sie auf Beispielcode verweisen?

Wenn wir FILE_SHARE_DELETE hinzufügen, verwenden viele Programmierer es fälschlicherweise, um das Unix-Verhalten zu simulieren. In diesem Fall können Sie für jedes Betriebssystem eine durch Build-Einschränkungen getrennte Funktion erstellen. Und es sollte os.NewFile() , verwenden Sie FILE_SHARE_DELETE unter Windows.

Erstellen Sie eine Funktion, die durch Build-Einschränkungen für jedes Betriebssystem getrennt ist ... geben Sie os.NewFile() zurück, verwenden Sie FILE_SHARE_DELETE unter Windows

Um die Funktionalität von os.OpenFile() beizubehalten, scheint dieser Plan die Neuimplementierung aller folgenden Punkte zu erfordern:

os.OpenFile()
openFileNolog()
Datei öffnen()
openDir()
neue Datei()
fixLongPath()
syscall.Open()
makeInheritSa()

@networkimprov

@guybrand schreibt im golang-dev-Thread:

mein Programm schreibt eine Datei namens "my.data" und ruft dann ein anderes Programm auf und wartet nicht darauf, dass es endet ... dieses Programm lädt beispielsweise diese Datei hoch, was 10 Sekunden dauert (nennen Sie dieses andere Programm "Uploader") .
...
Wenn mein Programm .Remove unter Windows aufruft (FILE_SHARE_DELETE ist aktiviert):
...
Uploader würde eine Fehlermeldung erhalten, die ihm mitteilt, dass die Datei entfernt wurde (wahrscheinlich EOF).

Angenommen, "Uploader" öffnet die Datei, bevor "mein Programm" os.Remove() aufruft, haben Sie dann nicht den Win-API-Dokumenten widersprochen?

DeleteFile markiert eine Datei zum Löschen beim Schließen. Daher tritt das Löschen der Datei nicht auf, bis das letzte Handle für die Datei geschlossen wird. Nachfolgende Aufrufe von CreateFile zum Öffnen der Datei schlagen mit ERROR_ACCESS_DENIED fehl.

Bezüglich "Kopplung eines _open_osfhandle() des CreateFile mit einem _fdopen", können Sie auf Beispielcode verweisen?

Ich sehe keinen Widerspruch zur WIndows-API, bitte weisen Sie auf einen Widerspruch hin.

Was ein Codebeispiel betrifft, habe ich ein wenig gegoogelt und Folgendes gefunden:
http://blog.httrack.com/blog/2013/10/05/creating-deletable-and-movable-files-on-windows/

ABER
Bitte beachten Sie - dies führt nur intern zu einem Nix-ähnlichen Verhalten, jedes andere externe Programm, das damit arbeitet, wird es unterbrechen (da es zu 99% die Standard-Windows-API verwendet).

@networkimprov
Wenn du meinst "das klingt wie "dir my.data" würde die Datei anzeigen, soweit ich mich erinnere war dies das Verhalten bis Windows .... XP oder 7 (weiß nicht mehr welches) und seitdem geändert (vielleicht versteckt sich der Explorer einfach) es irgendwie) - Ich kann das nächste Mal, wenn ich meine Windows-Umgebung starte, erneut testen (kommt alle paar Wochen vor...)

Wenn Sie meinen "das klingt so, als könnten andere Prozesse mit einem Handle für die Datei immer noch in der Lage sein, die Datei zu lesen und in sie zu schreiben", würde ich wetten, dass Sie in der Sekunde, in der Sie in eine solche Datei schreiben lesen, einen Fehler im "EOF" -Stil erhalten - müssen aber erneut bestätigen, dass sie zu 100 % positiv sind.

In jedem Fall wäre mein Punkt (an dieser Stelle - ich nehme "Seiten" im "nativen" vs. "os-agnostischen" Punkt) - selbst wenn Sie eine Lösung im _fdopen-Stil implementieren, würden Sie eine Inkonsistenz zwischen Ihrem Service und bekommen alle anderen ausführbaren Dateien, mit denen Sie zusammenarbeiten, daher kann die Verwendung nur in Interaktion mit anderen ausführbaren go-Dateien (oder seltenen Diensten, die fds direkt verwenden) erfolgen.

Mit anderen Worten - Ihre App wäre das "klugste Kind der Klasse" - das kein anderes Kind verstehen kann.
Zwei Beispiele von vielen, die mir einfallen:
Eingänge :
Meine App lädt eine Datei herunter, der Antivirus identifiziert ihre Schädlinge und löscht/unter Quarantäne (==umbenennen) sie, wenn ich fd verwende - meine App könnte immer noch damit machen, was sie will (was coll ist, aber möglicherweise enden kann) einen Virus zu treffen...)
Ausgänge :
Meine App leitet eine Datei an einen anderen ("Uploader"-ähnlichen) Dienst weiter und löscht sie. Ich habe sogar einen Tester in go geschrieben, um zu sehen, ob alles gut funktioniert - und der Test besteht.
Jetzt verwende ich anstelle meines Go-Tests Filezilla, wir übertragen, dropbx API, was auch immer
es würde fehlschlagen / sich nicht so verhalten, wie mein Test funktioniert ...

Halten Sie es immer noch für sinnvoll, dies auf das Standardverhalten zu ändern?

Gibt es einen Grund dafür, diese allgemeine Funktion in Windows wegzulassen?

Ich habe diese Frage nie in Betracht gezogen. Ich weiß nicht.

Die Funktionsweise von Go-Dateien unter Windows stimmt mit allen anderen Entwicklertools überein, die ich in meinem Leben verwendet habe. Es würde mich überraschen, wenn Go-Dateien so funktionieren würden, wie Sie es vorschlagen. Ich vermute auch, es würde viele bestehende Programme kaputt machen.

Alex

Ich vermute auch, es würde viele bestehende Programme kaputt machen.

@alexbrainman Ich habe auch einen Schalter vorgeschlagen, um ihn zu aktivieren, anstatt den Standard zu ändern.

@bradfitz es gibt syscall.SocketDisableIPv6, das unterscheidet sich nicht wirklich von einem Flag, um das Verhalten von syscall.Open() anzupassen.

Da syscall_windows*.go besagt
func Open(path string, mode int, perm uint32) (fd Handle, err error) {
....
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)

und type_windows*.go hat
FILE_SHARE_DELETE = 0x00000004

Alles ist ziemlich fertig, die Frage ist nur, wie man das Flag implementiert.
Ich mag die globale Option nicht, da sie nicht explizit ist, und obwohl sich ein einzelner Entwickler vielleicht daran erinnern kann, dass er os.DeleteUponLastHandleClosed = 1 gesetzt hat, ist dies keine gute Vorgehensweise für langfristige oder mehrere Entwickler.
Andere Optionen wären entweder das Festlegen einer bestimmten reservierten Nummer für Flags, wie in:
fd, err := os.OpenFile(Pfad, os.O_RDWR|os.O_CREATE|os.DELETE_WHEN_FREED, 0600)
wohingegen DELETE_WHEN_FREED für env sogar 0 sein kann. außer Fenster,

Eine andere Möglichkeit wäre, den perm-Parameter zu verwenden, der für Windows nicht unterstützt wird, dies kann etwas umständlich werden
fd, err := os.OpenFile(Pfad, os.O_RDWR|os.O_CREATE, 777)
777 ist reserviert, also benötigen wir entweder eine 1777 oder eine -777 ro, die beide Systeme unterstützt
zu machen ist lesbar DELETE_WHEN_FREED | 777

Die letzte Option, die mir einfällt, ist os.OpenDeletableFile(
Was wäre os.OpenFile auf nix's und
Dreh dich
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
an Fenstern

Alle oben genannten Lösungen sind einfach zu implementieren, etwas mehr Zeit zum Testen (Cross-OS), brauchen nur einen Voter ...

Eine Möglichkeit, dieses Verhalten zu unterstützen, ohne die Standardeinstellungen zu ändern oder die API-Oberfläche zu erweitern, könnte darin bestehen, einfach syscall.FILE_SHARE_DELETE in den flag Parameter von os.OpenFile unter Windows zu akzeptieren und ihn in die berechnete sharemode Wert. Da die syscall.O_* (und damit os.O_* ) Flags unter Windows ohnehin erfundene Werte verwenden , könnten sie so konstruiert werden, dass sie nicht mit irgendwelchen Windows-spezifischen Flags kollidieren, die man einschließen wollte. Glücklicherweise vermeiden sie bereits Kollisionen mit syscall.FILE_SHARE_DELETE .

Ich würde mich auf jeden Fall stark dagegen wehren, das Standardverhalten zu ändern. Wenn Sie FILE_SHARE_DELETE als Standard festlegen, würden Sie in Bezug auf die Unfähigkeit, ein rassefreies Dateisystem-Traversal sicherzustellen, in die gleiche Position wie POSIX-Systeme bringen. Da dieses Flag optional ist, benötigt Windows nicht das Äquivalent von openat , renameat , readlinkat usw.

Ich habe nicht wirklich darüber nachgedacht, was wir hier tun sollen, aber ich möchte eines klarstellen:

Können Sie in syscall_windows.go einen Schalter bereitstellen, damit wir das Unix-Verhalten beim Programmstart auswählen können?

Wir werden dies nicht tun. Das würde es für ein einzelnes Programm unmöglich machen, verschiedene Pakete zu verwenden, die ein unterschiedliches Verhalten erwarten.

@havoc-io
Ihr Vorschlag würde fehleranfällige Programme erstellen, da sich syscall.FILE_SHARE_DELETE vom POSIX-Standardverhalten unterscheidet.
Bitte beachten Sie, dass die Autoren von syscall_windows*.go sich des FILE_SHARE_DELETE-Flags bewusst waren (es ist dort drin) und entschieden, dass es nicht das bevorzugte Verhalten ist.
Wieso den?

lass uns Liams Code nehmen, er
defer fd.Close()
löscht/umbenennt
und dann lesen/schreiben

die tatsächliche Sortierreihenfolge ist also
offen
als gelöscht markieren
Lesen/Schreiben (und wahrscheinlich auch Cross-Process/Cross-Go-Routine-Lesen-Schreiben)
nah dran

Das aktuelle Windows-Verhalten warnt den Entwickler "das ist falsch", der Entwickler würde wahrscheinlich auch das Löschen verschieben
Wenn Sie FILE_SHARE_DELETE hinzufügen, können Sie in Windows "als Löschen markieren, obwohl die Datei geöffnet ist", ABER ein anderer Prozess / eine gleichzeitig laufende Goroutine, die versuchen würde, zwischen dem Löschen und dem Schließen auf die Datei zuzugreifen (was wahrscheinlich die längere Aufgabe in diesem Code ist) ) würde versagen
Ergebnis: Anstelle eines konsequenten "Sie können das"-Verhalten - erhalten Sie manchmal ein "manchmal - besonders wenn es viele gleichzeitige Benutzer gibt, schlägt es fehl und ich weiß nicht warum.
Sie lösen das Problem also nicht, sondern behandeln nur einen bestimmten Anwendungsfall, bei dem der Entwickler "das nur einmal ausführt".
Meine Stimme ist natürlich für das konsequente Verhalten...

Wie unterscheidet sich das von Posix?
Sobald die Datei als gelöscht markiert ist, befindet sie sich nicht mehr in der Dateitabelle, sie existiert nur noch als fd, sodass eine andere Routine/ein anderer Prozess eine Datei mit demselben Namen erstellen kann.

Ich denke, wir sollten aufhören, nach einer "gleichen Lösung" zu suchen, da es Unterschiede gibt, die wir innerhalb von go nicht auflösen werden (Groß-/Kleinschreibung beachten Dateinamen? :) wir werden Linux 5.2 machen lassen...)

Insgesamt sieht es so aus, als würde man nach einer Lösung für eine temporäre Datei suchen, wenn ja, unterstützt Windows GetTempFileName, was als Standardlösung für eine Datei angesehen werden kann, die "verwendet und dann in den Papierkorb" geworfen wird.

Wenn wir andererseits einem Entwickler erlauben möchten, Löschvorgänge in Windows zu verschieben, ist dies möglich, siehe meine obigen Vorschläge, aber der Entwickler muss die Verantwortung dafür übernehmen und das Bewusstsein verstehen - daher muss es ein Flag mit einer guten Namenskonvention sein.

Der Hauptzweck dieser Funktion besteht darin, eine geöffnete Datei nach der Erstellung umzubenennen:

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
_, err = fd.Write(...)
err = fd.Sync()  // file now safe to share
err = os.Rename(path, shared_path)
// os.Close() at program exit

Ich weiß nicht, warum Sie nicht ein Flag os.O_WRNDEL (Windows umbenennen/löschen; auf anderen Plattformen ein No-Op) hinzufügen und die Unterschiede dieses Modus mit Unix dokumentieren; dass eine gelöschte Datei in ihrem Verzeichnis verbleibt, aber nicht geöffnet werden kann, bis os.Close(). Erwähnen Sie auch, dass das Verschieben der Datei in ein temporäres Verzeichnis vor dem Löschen ein Unix-ähnliches Verhalten bietet.

@guybrand Ich glaube, du missverstehst meinen Vorschlag. Ich befürworte nicht, dass FILE_SHARE_DELETE standardmäßig aktiviert ist - tatsächlich bin ich aus den im zweiten Absatz meines Kommentars genannten Gründen dagegen. Mein Vorschlag war ein Mechanismus, der es Benutzern ermöglicht, sich FILE_SHARE_DELETE Verhalten von os Pakets verwenden. Dieser Vorschlag bietet einen Mechanismus dafür, ohne die API-Oberfläche eines Pakets zu erweitern.

Ich weiß nicht, warum Sie kein Flag os.O_WRNDEL hinzufügen würden (Windows umbenennen/löschen; auf anderen Plattformen ein No-Op)

@networkimprov Das ist im Wesentlichen das, was ich vorschlage, außer dass es keinen Sinn macht, ein neues Flag zu definieren, da bereits ein vollkommen gültiges existiert: syscall.FILE_SHARE_DELETE . Die einzige Implementierungsänderung wäre, auf dieses Flag in syscall.Open unter Windows zu achten und Prüfungen hinzuzufügen, um sicherzustellen, dass keine zukünftigen Ergänzungen zu syscall.O_* / os.O_* Flags mit diesem Flag kollidieren. Die Dokumentation für os.OpenFile könnte dann aktualisiert werden, um die Akzeptanz dieses Flags unter Windows widerzuspiegeln.

@havoc-io Entschuldigung für das Missverständnis, das war mein Takeout von:
" ... um syscall.FILE_SHARE_DELETE einfach zu akzeptieren ... in den berechneten Sharemode ..."

Das Hinzufügen von os.O_WRNDEL entspricht meinem zweiten Vorschlag, abgesehen davon, dass er für den Entwickler in Bezug auf "wie wäre das Verhalten" nicht explizit genug ist, vielleicht os.WADRNDEL - Windows erlauben verzögertes Umbenennen/Löschen).

@alexbrainman Ich habe auch einen Schalter vorgeschlagen, um ihn zu aktivieren, anstatt den Standard zu ändern

Ich bin nicht interessiert. Danke schön.

Alex

Das Umbenennen von

Entschuldigung, ich frage noch einmal, was ist Ihr Vorschlag? Öffnende Datei löschen? Öffnende Datei umbenennen? beide?

Drei von uns schlagen jetzt eine neue Flagge vor, zB

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE| os._WRNDEL, 0600)

fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE| syscall.FILE_SHARE_DELETE, 0600)

Drei von uns schlagen jetzt eine neue Flagge vor

Ich denke, dass ein neues Flag unangemessen ist, insbesondere eines, das von jemandem, der den Code liest, nicht leicht analysiert werden kann. Die Verwendung von syscall.FILE_SHARE_DELETE wäre viel expliziter und klarer und würde dem Leser sofort signalisieren, dass etwas plattformspezifisches passiert.

Auf POSIX-Plattformen ist dies bereits erlaubt. Es gibt viele POSIX-spezifische (und sogar plattformspezifische) open Flags, die nicht im os Paket enthalten sind. Es wäre beispielsweise nicht sinnvoll, etwas wie os._DEVTONLY hinzuzufügen, um Darwins Flag O_EVTONLY , da Sie das Flag einfach aus dem Paket syscall direkt an os.OpenFile , zB:

os.OpenFile(..., os.O_RDONLY | syscall.O_EVTONLY, ...)

In diesem Fall wird das plattformspezifische Flag an den zugrunde liegenden open -Systemaufruf weitergegeben.

Wenn FILE_SHARE_DELETE Verhalten wirklich etwas ist, das die Leute brauchen, dann ist die Antwort meiner Meinung nach einfach os.OpenFile Lage zu versetzen, Flags auf ähnliche Weise auf den zugrunde liegenden CreateFileW Aufruf unter Windows herunterzuschrauben. Zumindest für FILE_SHARE_DELETE .

Eine Beispielimplementierung finden Sie hier .

@networkimprov

Drei von uns schlagen jetzt eine neue Flagge vor, zB

Was erwarten Sie von der Flagge?

Das Umbenennen von

Richtig, aber beide benötigen FILE_SHARE_DELETE, um zugelassen zu werden, während die Datei geöffnet ist
Wenn Sie sich auf meine vorgeschlagene Terminologie beziehen, können wir
os.WARNDFDEL - Windows erlauben Umbenennen und verzögertes Löschen ist etwas zu lang, ich selbst würde überhaupt ein Akronym verwenden WINDOWS_ALLOW_OPENNED_FILE_RENAME_OR_DEFFERED_DELETE
ist IMO besser.

@guybrand Ich os Paket ein neues plattformspezifisches Flag mit einem komplexen Namen und undurchsichtigem Verhalten hinzuzufügen, wenn es dafür seit Jahrzehnten ein perfekt gutes Flag gibt ( FILE_SHARE_DELETE ). Die Verwendung von syscall.FILE_SHARE_DELETE als Flag dafür ist viel klarer und eindeutiger. Wie ich oben erwähnt habe, gibt es viele POSIX-spezifische und plattformspezifische Flags, die nicht zum os Paket hinzugefügt werden, aber dennoch von diesem akzeptiert werden.

syscall.FILE_SHARE_DELETE ist nur Windows; wir brauchen etwas, das anderswo nicht möglich ist. Vielleicht sollte es in pkg os erscheinen, mit einem WIN- oder WINDOWS-Präfix?

@mattn pls siehe den obigen Patch von @havoc-io

wir brauchen etwas, das anderswo nicht möglich ist.

@networkimprov Das Flag muss nicht anderswo existieren . Ihr Windows-Code sieht nur so aus:

import (
    "syscall"
    "os"
)

file, err := os.OpenFile(..., os.O_RDWR | syscall.FILE_SHARE_DELETE, ...)

Ja, dieser Code muss auf der Plattform gegatet werden, aber Sie müssen dies wahrscheinlich sowieso tun, da das Verhalten mit diesem Flag nicht mit dem von POSIX-Systemen übereinstimmt. Oder, wenn Sie den gleichen Code auf allen Plattformen verwenden möchten, können Sie Ihre eigene Konstante definieren (mit einem Wert von syscall.FILE_SHARE_DELETE auf Windows und 0 auf Nicht-Windows-Systemen) und übergeben es zu os.OpenFile . Dies ist genau das, was Sie tun würden, wenn Sie ein plattformspezifisches O_* Flag os Pakets ist (z. B. O_EVTONLY auf Darwin oder O_ASYNC unter Linux).

Wenn ich Code schreibe, erwarte ich, dass er plattformübergreifend ist, FILE_SHARE_DELETE existiert nicht in syscall_*, nur in Windows (und wird daher nicht auf anderen Systemen kompiliert).

Können wir 0x4 const verwenden, da es:
FILE_SHARE_DELETE = 0x00000004

Abgesehen davon, dass sie hässlich sind,
netbsd_arm
O_NDELAY = 0x4
O_NONBLOCK = 0x4

Die Verwendung von 0x4 würde den Code in netbsd_arm anders erstellen.

Entweder fügen wir FILE_SHARE_DELETE zu allen Plattformen hinzu, Windows sind 0x4, andere 0x0 und "verwerfen" es oder erstellen ein spezielles Flag für dieses Problem.

UND sowieso müssen wir syscall_windows* ändern
Funktion öffnen (
...
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | isDeleteOn )
wobei isDeleteOn prüft, ob der Modus das neue Flag enthält

@guybrand

Wenn ich Code schreibe, erwarte ich, dass er plattformübergreifend ist

Ich möchte Sie warnen, dass Ihr Code nicht plattformübergreifend ist, nur weil derselbe os.OpenFile Aufruf auf mehreren Plattformen kompiliert wird. Es gibt eine Reihe von Sicherheitsüberlegungen unter Windows, die Sie bei der Verwendung von FILE_SHARE_DELETE berücksichtigen müssen, und die Semantik der Dateilebenszyklen ist zwischen POSIX- und Windows-Systemen so unterschiedlich, dass es wirklich schwer ist, sich ein Szenario vorzustellen, in dem Dateihandhabungscode würde zwischen den Plattformen nicht zumindest ein bisschen anders aussehen. Die Verwendung von FILE_SHARE_DELETE versetzt Sie im Wesentlichen in eine Situation vor POSIX.1-2008, ohne jegliche Möglichkeit, ein rassefreies Durchlaufen des Dateisystems sicherzustellen (und ohne den Vorteil des POSIX-Dateizugriffs nach unlink für open Dateien).

Wie auch immer, wenn Sie ein Flag mit einem Wert von syscall.FILE_SHARE_DELETE unter Windows und 0 auf anderen Plattformen haben möchten, können Sie dies immer noch problemlos mit Ihrer eigenen konstanten Definition tun, die von Build-Tags gesteuert wird, und dann Ihr Hauptcode, der os.OpenFile aufruft, kann auf allen Plattformen gleich sein (unter Verwendung dieses benutzerdefinierten Flags).

Es gibt viele plattformspezifische Flags, die in syscall Paketen anderer Plattformen vorhanden sind, aber sie können nicht alle durch das os Paket verfügbar gemacht werden und auf Plattformen, auf denen sie sich befinden, nicht aktiviert werden. t unterstützt. Wenn Sie plattformspezifischen Code und Verhalten wünschen, müssen Sie zum Paket syscall greifen.

Das einzige, was die Go-Standardbibliothek hier (potenziell) tun sollte, ist syscall.FILE_SHARE_DELETE in syscall.Open (und folglich os.OpenFile ) unter Windows zu unterstützen.

Wie ich in erwähnt oben , Wenn wir FILE_SHARE_DELETE hinzufügen, werden viele Programmierer verwenden es fälschlicherweise Unix Verhalten zu simulieren. Aber es ist nicht gut. Denken Sie beispielsweise an den Fall, dass eine Anwendung erstellt wird, um eine Datei zu überwachen. Es wird unterstützt, dass die Datei von anderen Anwendungen nicht gefunden werden darf, wenn eine Anwendung eine Datei löscht. Aber FILE_SHARE_DELETE markieren nur zum späteren Löschen. Die Datei bleibt. Unter UNIX funktioniert es gut, Windows jedoch nicht. Bitte verwenden Sie FILE_SHARE_DELETE NICHT zum Simulieren des UNIX-Verhaltens.

@mattn Ich stimme Ihren Bedenken zu - Leute können versuchen, das Flag aus Bequemlichkeit zu verwenden, damit Windows-Code "wie POSIX-Systeme funktioniert", ohne die subtilen Auswirkungen zu verstehen. Ich denke jedoch, dass sie sich möglicherweise die Zeit genommen haben, um zu verstehen, was es tut, wenn sie zum Paket syscall gehen müssen, um auf dieses Flag zuzugreifen.

@mattn , für Unix-ähnliches Verhalten würden Apps 2 zusätzliche Zeilen plattformneutralen Codes benötigen:

fd, err := os.OpenFile(path, ... | syscall.FILE_SHARE_DELETE, 0600)
...
tmp_path := mkTempName()
err = os.Rename(path, tmp_path)  // works immediately; path is now available
err = os.Remove(tmp_path)

Um dies zu dokumentieren, ist ein Satz in der Dokumentation für os.OpenFile() erforderlich.

Bitte zwingen Sie mich nicht, einen Patch an pkg syscall zu verteilen, den jeder anwenden muss, der an meinem Windows-Code arbeitet! Siehe auch https://github.com/golang/go/issues/32088#issuecomment -493876119.

Ich denke, in den meisten Fakten sind wir uns alle einig, formulieren Sie es einfach anders, damit ich versuche, es zusammenzufassen und eine Vorgehensweise festzulegen:

  1. Einverstanden: Windows und POSIX unterscheiden sich im obigen Verhalten und wir sollten nicht versuchen, dasselbe Verhalten anzustreben.
  2. Einverstanden: Die Anfrage, FILE_SHARE_DELETE als Flag zuzulassen, ist nützlich
  3. Vorschlag: Lassen Sie das Ticket in "support FILE_SHARE_DELETE" ändern, damit es eher nach einer Funktionsanfrage als nach einem Fehler klingt
  4. Weitgehend Einigkeit: Das Feature sollte ein Entwickler-Flag auf Programmebene sein, kein Basispaket.

Aktionspunkte:

  1. syscall_windows.go ändern
    Funktion öffnen (
    ...
    sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | (mode & FILE_SHARE_DELETE) )
  2. Entwickler, die dieses Verhalten nutzen möchten, würden entweder
    file, err := os.OpenFile(..., os.O_RDWR | syscall.FILE_SHARE_DELETE, ...)
    oder wenn sie möchten, dass ihr Programm plattformübergreifend ist, erstellen Sie eine interne Flagge von:

mycode_windows.go
const OPENFILEFLAG = syscall.FILE_SHARE_DELETE
mycode_others.go
const OPENFILEFLAG = 0

und dann verwende:
file, err := os.OpenFile(..., os.O_RDWR | OPENFILEFLAG, ...)

Wenn dies vereinbart wird, ist die Korrektur minimal (ein Liner), mit sehr geringem Risiko

Lasst uns darüber abstimmen und wir können das schnell beheben

Einverstanden: Die Anfrage, FILE_SHARE_DELETE als Flag zuzulassen, ist nützlich

Ich bin damit noch nicht einverstanden, da ich den Zweck dieses Problems nicht verstehe.

Zweck: Entwicklern ermöglichen, geöffnete Dateien umzubenennen oder zu löschen.

Was fehlt: syscall_windows.go derzeit hart codiert :
func Open(path string, mode int, perm uint32) (fd Handle, err error) {
...
sharemode := uint32(**FILE_SHARE_READ | FILE_SHARE_WRITE**)

Vorgeschlagene Änderung:
Wenn der Entwickler einen Modusparameter mit aktiviertem bitweise 4 (FILE_SHARE_DELETE) übergibt, ändert sich der Freigabemodus entsprechend um
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | **(mode & FILE_SHARE_DELETE)** )

Ich frage mich immer noch, warum Sie Close() nicht vor Rename() oder Remove() aufrufen. Sie können den Code der Standardbibliothek von Go lesen. Die Dateien werden mit Close() vor Rename() oder Remove() geschlossen. Warum müssen Sie Close() nach Renamoe/Rename aufrufen?

Ich bin mir nicht sicher, was der Geschäftsfall ist, den @networkimprov in Betracht zieht. Mein Takeout wäre eine temporäre freigegebene Datei - meine App und eine andere App verwenden diese Datei, ich möchte sicherstellen (selbst wenn meine App abstürzt) diese Datei wird nicht mehr existieren, nachdem ich fertig bin - also erstelle ich es, entferne es () und wenn ich es entweder schließe oder meine App geschlossen wird - wird die Datei entfernt.

aber es sieht so aus, als ob @networkimprov das verwenden möchte, also wahrscheinlich ein anderer Anwendungsfall.

Wie in https://github.com/golang/go/issues/32088#issuecomment -494305074 erwähnt, müssen wir eine umbenannte Datei möglicherweise nicht schließen, bis das Programm beendet wird.

@mattn , bestehen Sie bitte nicht darauf, dass wir niemals eine Betriebssystemfunktion verwenden sollten, die C- und C++-Entwickler verwenden können.

Ich möchte sicherstellen, dass diese Datei (auch wenn meine App abstürzt) nicht mehr existiert, wenn ich fertig bin

@guybrand A defer Anweisung nicht in jeder Art von Absturz laufen garantiert, so dass , wenn Sie versuchen , das Löschen von Dateien , um sicherzustellen, dann einen Aufschieben os.Remove Betrieb ist kein verlässlicher Weg gehen Sie darüber. Wenn Sie möchten, dass eine Datei automatisch gelöscht wird, ist eine temporäre Datei, die das System löscht, eine bessere Option. Wenn Sie einen Dateispeicherort wünschen, der von zwei Programmen geteilt wird, sollte er durch Sperren koordiniert werden (zB fcntl Sperren unter POSIX und LockFileEx / UnlockFileEx unter Windows), nicht durch Dateiexistenz .

Wie in #32088 (Kommentar) erwähnt, müssen wir eine umbenannte Datei möglicherweise nicht schließen, bis das Programm beendet wird.
@mattn , bestehen Sie bitte nicht darauf, dass wir niemals eine Betriebssystemfunktion verwenden sollten, die C- und C++-Entwickler verwenden können.

@networkimprov Ein Umbenennen-nach-Öffnen-Vorgang ist ein gültiger Anwendungsfall, aber wenn Sie das Programm sind, das die Datei HANDLE , können Sie das nicht bereits tun? Der einzige Zweck von FILE_SHARE_DELETE darin, anderen Prozessen zu erlauben, die Datei umzubenennen, während Sie sie geöffnet halten. In jedem Fall können Sie mit FILE_SHARE_DELETE jetzt, Sie müssen nur manuell invoke CreateFileW und übergeben , um das Ergebnis ab os.NewFile . Ein Beispiel, wie das aussieht, finden Sie hier . Das resultierende HANDLE kann einfach an os.NewFile .

@mattn Ich stimme Ihnen CreateFileW manuell aufzurufen (mit diesem Flag angegeben) und dann das Ergebnis an os.NewFile weiterzugeben, also ist es vielleicht nicht nötig fügen Sie Unterstützung dafür hinzu.

@havoc-io gibt es kein os.File.Rename(). Das wäre eine gute Lösung, aber es ist eine relativ schwere Aufgabe.

Re CreateFileW + os.NewFile(), siehe https://github.com/golang/go/issues/32088#issuecomment -493876119.

@havoc-io

Ich möchte sicherstellen, dass diese Datei (auch wenn meine App abstürzt) nicht mehr existiert, wenn ich fertig bin
@guybrand Eine
Genau das meinte ich, als ich sagte "auch wenn meine App abstürzt".

die einzigen Argumente, die ich für seine Existenz sehen kann, sind Vollständigkeit und Parität der Kontrolle zwischen POSIX und Windows
Ich bin nicht der Meinung, dass dies "Vollständigkeit und Parität der Kontrolle zwischen POSIX und Windows" bringen würde - IMO würde es den Entwickler nur verwirren, zu denken, dass das Verhalten dasselbe ist, wenn es nicht gleich ist. Ich habe oben einige Beispiele gegeben.

einfaches manuelles Aufrufen von CreateFileW
Das ist wirklich ein Tweak, einfach oder nicht, und mit anderen Worten: "Wir wollen das in go nicht unterstützen", was übrigens eine ok Entscheidung IMO ist, aber der Anforderer ist @networkimprov nicht ich.

Zu Ihrer Information: Aus diesem Grund haben wir die Verwendung von FILE_SHARE_DELETE aufgegeben.

CL: https://codereview.appspot.com/8203043/

Commit in erlang/otp: https://github.com/erlang/otp/commit/0e02f488971b32ff9ab88a3f0cb144fe5db161b2

Python: https://bugs.python.org/issue15244

@havoc-io gibt es kein os.File.Rename(). Das wäre eine gute Lösung, aber es ist eine relativ schwere Aufgabe.
Re CreateFileW + os.NewFile(), siehe #32088 (Kommentar).

@networkimprov Kannst du nicht einfach os.Rename(file.Name(), <target>) ? Das ist das Schöne daran, dass Go nicht standardmäßig FILE_SHARE_DELETE aktiviert hat - Sie wissen, dass file.Name() immer noch auf etwas Gültiges zeigt, da Sie die Datei HANDLE (etwas, das Sie t Garantie auf POSIX, auch nicht mit renameat ). In Bezug auf CreateFileW + os.NewFile Großteil des in Ihrem Kommentar beschriebenen Stapels irrelevant werden, und makeInheritSa ist mit ziemlicher Sicherheit etwas, das Sie nicht wollen (es ist nur da, um POSIXs zu simulieren schlechtes Standardverhalten bei der Vererbung von Dateideskriptoren - es ist nicht die Standardeinstellung). Das einzige, was Sie verpassen würden, wäre die interne fixLongPath Pfadfunktion, die für die von Ihnen beschriebenen Anwendungsfälle wahrscheinlich nicht erforderlich ist.

@guybrand Nur um zu verdeutlichen was ich meine...

Vollständigkeit: Vollständigkeit der API-Oberfläche (dh die Möglichkeit, FILE_SHARE_DELETE wenn Sie es aus irgendeinem Grund verwenden möchten)
Kontrollparität: Die Möglichkeit, Flags für CreateFileW über den Parameter flag os.OpenFile anzugeben. Zum Beispiel kann ich syscall.O_NOFOLLOW durch os.OpenFile auf POSIX routen, aber ich kann syscall.FILE_FLAG_OPEN_REPARSE_POINT durch os.OpenFile unter Windows routen. Aber auch hier denke ich, dass die totale Parität der Kontrolle hier ein Wunschtraum ist, da das os Paket um POSIX-APIs herum modelliert ist. Ich greife gerne nach syscall.CreateFileW wenn es nötig ist.

@mattn danke für die Links. Die Go-CL war das Patchen des syscall.Open() _default_. Die Diskussion gibt keinen allgemeinen Grund, ein _flag_ für Open() zu verbieten. Es stellt fest, dass ein Paket von Drittanbietern eine os.File ohne das Flag zurückgeben kann, aber das ist nur ein Problem, wenn der Aufrufer versucht, diese Datei umzubenennen/zu löschen – ein seltener Fall.

Der Python-Thread weist darauf hin, dass Sie eine geöffnete Datei vor dem Löschen umbenennen sollten, wie ich oben geschrieben habe.

Erlang ist seit mehr als sechs Jahren FILE_SHARE_DELETE als _default_ hatte.

Wenn man über die Erlang-Erfahrung und den oben verlinkten Python-Thread nachdenkt, ist Folgendes offensichtlich:

  1. File_share_delete als Standard funktioniert gut in einer plattformübergreifenden Umgebung; Die einzige Einschränkung besteht darin, dass der Benutzercode eine Datei unmittelbar vor dem Entfernen in einen eindeutigen Namen umbenennen sollte (eine triviale Änderung), wenn der ursprüngliche Dateiname wiederverwendet werden kann.
  2. Die meisten Windows-Programme können file_share_delete nicht verwenden, einfach weil die MSVC-Laufzeit dies nur in Kombination mit O_TEMPORARY zulässt.

Daher würde ich schlussfolgern, dass syscall.Open() standardmäßig file_share_delete verwenden sollte und syscall ein globales Flag bereitstellen sollte, zu deaktivieren (zB Debugging).

Wenn bei diesem Ansatz während des 1.14-Zyklus Probleme auftreten, kann stattdessen die explizite Flag-Methode angewendet werden.

Daher würde ich schlussfolgern, dass syscall.Open() standardmäßig file_share_delete verwenden sollte und syscall ein globales Flag bereitstellen sollte, um es bei Bedarf zu deaktivieren (zB Debugging).

@networkimprov Abgesehen davon, dass eine große Anzahl bestehender Programme auf subtile und nicht so subtile Weise zerstört wird, wäre die Einführung dieses Flags jetzt ein Sicherheitsproblem für Programme, die auf das Fehlen von FILE_SHARE_DELETE angewiesen sind . Insbesondere würde es eine Reihe von Sicherheitslücken vom Zeitpunkt der Überprüfung bis zum Zeitpunkt der Nutzung für Programme eröffnen, die sich auf die Unveränderlichkeit von Dateien und Verzeichnissen verlassen, die sie offen halten.

Bearbeiten: Weitere Informationen darüber, warum das Ändern der Standardeinstellung eine schlechte Idee ist und mit ziemlicher Sicherheit bestehende Programme bricht, finden Sie unter Hyrums Gesetz .

Der häufigste Fall von Go unter Windows ist die Entwicklung für die Bereitstellung unter Linux oder einem anderen Unix.

Wenn Ihr Code von einem GOOS=windows-Verhalten abhängt, ist er unter Linux beschädigt und möglicherweise anfällig. Wir haben also bereits ein mögliches Sicherheitsproblem.

os.Rename() & .Remove() dokumentieren keine Unterschiede unter Windows, sodass niemand vermuten würde, dass sie existieren. Wenn Sie sie jetzt dokumentieren, wird der vorhandene Code nicht repariert. Die Inkompatibilität zu beheben und einen Blogbeitrag dazu zu veröffentlichen, würde viel mehr helfen.

Beachten Sie, dass es Erlang schon eine Weile gab, bevor es file_share_delete als Standard annahm.

Der häufigste Fall von Go unter Windows ist die Entwicklung für die Bereitstellung unter Linux oder einem anderen Unix.

Wenn Ihr Code von einem GOOS=windows-Verhalten abhängt, ist er unter Linux beschädigt und möglicherweise anfällig. Wir haben also bereits ein mögliches Sicherheitsproblem.

@networkimprov

Nach dieser Logik sollte auch die Dateiöffnungsinfrastruktur unter Windows so geändert werden, dass Dateideskriptoren standardmäßig über die Prozesserstellung hinweg vererbbar sind, damit sie dem Standardverhalten von POSIX entsprechen. Vorhandene Programme können dafür verantwortlich gemacht werden, dass sie sich auf das vorherige Standardverhalten der Laufzeit-/Standardbibliothek verlassen, und eine CVE-Vorlage kann in die Versionshinweise aufgenommen werden, damit Benutzer ihre Programme einreichen können.

Aber das ist natürlich nicht das, was getan wird, und stattdessen beugen sich die Laufzeit- und Standardbibliothek von Go nach hinten, um das standardmäßige und schlecht entwickelte Verhalten von POSIX zu umgehen und zu versuchen, das zu spiegeln, was Windows tut.

Beim gemeinsamen Dateizugriff verhält es sich ähnlich. Windows hatte wohl das richtige Design, und POSIX.1-2008 musste eine Reihe von Funktionen hinzufügen, um seine Designbeschränkungen zu umgehen.

Wie @mattn bereits mehrfach erwähnt hat, führt das Einschließen von FILE_SHARE_DELETE beim Öffnen von Dateien dazu, dass sich Windows NICHT wie POSIX verhält – es wird immer noch signifikante Verhaltensunterschiede geben, die mit diesem Flag viel deutlicher werden als unterschiedliche os.Remove und os.Rename Verhalten.

Ich würde argumentieren, dass, wenn Ihr Code universell auf dem Verhalten einer beliebigen Plattform beruht, er auf anderen Plattformen beschädigt und möglicherweise anfällig ist (und dazu gehört auch das Verlassen auf das Verhalten von POSIX unter Windows). Wenn Sie sich nicht die Zeit nehmen, Plattformvariationen in Ihrem Code zu verstehen und zu berücksichtigen, betreiben Sie keine plattformübergreifende Entwicklung.

Auf jeden Fall hat @ianlancetaylor bereits sein Veto gegen die Idee eingelegt , ein globales Flag zu verwenden, um das Einschalten zu steuern, daher bezweifle ich ernsthaft, dass Sie es nach dem Ändern der Standardeinstellung deaktivieren werden.

Meiner Meinung nach besteht die einzige nicht verletzende (und nicht sicherheitskompromittierende) Option darin, Unterstützung für syscall.FILE_SHARE_DELETE in syscall.Open s flag Argument hinzuzufügen oder einfach zu erzwingen Benutzer, die die FILE_SHARE_DELETE Funktionalität wünschen, verwenden CreateFileW + os.NewFile . Ja, es erfordert ein wenig Arbeit von Entwicklern, die dieses Verhalten wollen, aber Win32 und POSIX sind grundlegend unterschiedliche Biester und es ist erstaunlich, dass die Laufzeit- und Standardbibliothek genauso gute Arbeit leisten wie sie, um ihre Unterschiede zu ebnen. Es gibt noch viele weitere signifikante Unterschiede zwischen diesen Plattformen, die sich in der Standardbibliothek manifestieren, z. B. völlig unterschiedliche Berechtigungsmodelle, die Tatsache, dass os.File.Chmod unter Windows nicht funktioniert, os.Chown Windows nicht funktioniert Windows, die Tatsache, dass der interne Poller verschiedene Dateitypen auf verschiedenen Plattformen unterstützt usw. Die Laufzeit- und Standardbibliothek von Go tun ihr Bestes (und machen es gut), aber sie sind kein Allheilmittel für plattformübergreifende Entwicklungsprobleme. Irgendwann müssen Entwickler mit diesen Unterschieden alleine umgehen. Das Hinzufügen einer Breaking Change zum Modifizieren (beachten Sie, dass ich nicht richtig gesagt habe) einen obskuren Verhaltensrandfall macht für mich keinen Sinn.

Ich wollte einen weiteren Anwendungsfall dafür teilen.

Wenn die Docker-Log-Rotationslogik derzeit daran arbeitet, dass die Docker-Engine das aktive Log in den Namen .1 umbenennt, erstellen Sie ein neues mit dem alten Namen.
Jeder Client, der das Protokoll aktiv mit dem Befehl docker logs --follow <container>
wird feststellen, dass von Dateisystemereignissen:
https://github.com/moby/moby/blob/916eabd459fe707b5c4a86377d12e2ad1871b353/daemon/logger/loggerutils/logfile.go#L552 -L593

Es gibt auch diese Logik, die dazu führt, dass Windows diese Ereignisse sofort bemerkt:
https://github.com/moby/moby/blob/916eabd459fe707b5c4a86377d12e2ad1871b353/daemon/logger/loggerutils/logfile.go#L670 -L676

All dies funktioniert unter Linux gut, aber unter Windows schlägt das Rotieren des Protokolls The process cannot access the file because it is being used by another process. fehl, wenn Clients dem Protokoll folgen (Problem: https://github.com/moby/moby/issues/39274 )

Da es möglich ist, haben n Zahl derjenigen Kunden, der folgende Protokoll werden würde es ihnen drehen , bevor Datei zum ersten collect all den offenen Dateihandles und schließen sehr schwierig sein , so dass ich wirklich schön sehen , möchte Unterstützung haben für syscall.FILE_SHARE_DELETE Flagge.

Hallo! Kurzer Hintergrund: Ich arbeite an der Chrome CI-Infrastruktur. Wir portieren unseren Low-Level-Worker-Code auf Go. Wir führen täglich Hunderttausende von Testaufrufen unter Windows durch.

Ich habe alle Kommentare gelesen und hoffe, dass das Folgende eine klare und korrekte Zusammenfassung der Meinung jedes Einzelnen ist.

Unser Anwendungsfall besteht darin, ausführbare Go-Dateien unter Windows zu erstellen , um sie unter Windows auszuführen, im @networkimprov . Ich werde diesen Anwendungsfall "POSIX-Verhalten unter Windows annehmen" in diesem Kommentar ignorieren, da es einfach eine falsche Annahme ist und @mattn dazu gebracht hat, die Unterschiede hervorzuheben, was IMHO ein strittiger Punkt ist, mehr dazu weiter unten.

Im Rahmen unserer Migration benötigen wir FILE_SHARE_DELETE, teilweise aufgrund der Rotation der Protokolldateien, ähnlich wie bei #39274. Es kommt vor, dass dies auch ein Problem für Ausgabe Nr. 25965 ist.

Ich stimme zu, dass @ianlancetaylor das gesamte Toolchain-Verhalten ändert, wie in https://codereview.appspot.com/8203043/ vorgeschlagen, ist keine gute Idee. Ein unmittelbares Problem, das einem bei diesem Vorschlag in den Sinn kommt, wenn ein Datei-Handle als Sperrdatei verwendet wird. Wir verwenden dieses Verhalten. Und was @havoc-io gesagt hat. Also ignorieren wir das auch.

Um es noch einmal zu sagen, ich werde diese Vorschläge im Rest dieses Kommentars ignorieren:

  • Versuchen, sich genauso zu verhalten wie POSIX, das wird nicht funktionieren
  • Globales Verhalten als Opt-out (oder kein Opt-out!) ändern, das den Benutzern schadet

Dies lässt uns mit einem Pro-Call-Flag mit einem Namen, der eindeutig Windows-spezifisch ist. Genau das schlägt @guybrand vor.

Bei allem Respekt, ich verstehe den Einwand von @guybrand vorschlägt, ist vernünftig. Ja, Windows verhält sich in Bezug auf die Dateifreigabe anders. Es ist wie bei den Rechten zum Löschen von Dateien, unter Windows ist vielerlei Hinsicht. Ein Einwand gegen ein Windows-spezifisches Flag mit der Haltung, dass "Entwickler sein Verhalten missverstehen könnten", ist keine Tatsache, sondern eine Meinung. Sie gehen davon aus, dass Entwickler nicht wissen, was sie tun, oder die Dokumentation auf MSDN nicht lesen. Dies ist ein berechtigter Einwand für den allgemeinen Fall 😎, aber kein starker Einwand, da ein legitimer Anwendungsfall als optionales Flag blockiert wird.

Ironischerweise bedeutet dies, dass ich, bis dieses Problem behoben ist, zur Behebung von #25965 'go run' ändern muss, um CreateFileW direkt aufzurufen 🙃 da wir auch FILE_FLAG_DELETE_ON_CLOSE benötigen.

Danke!

Ich möchte nur wissen, wie ein Fall existiert, um zu wissen, ob wir eine neue Funktion (golang.org/x/sys?) zum Öffnen/Erstellen einer Datei mit neuen Attributen implementieren oder das ursprüngliche Verhalten ändern sollten. Derzeit, soweit ich das aus den obigen Kommentaren entnehmen kann:

  1. Erstellen einer löschbaren (umbenennbaren) Datei für die Protokollierung.
  2. Erstellen einer Datei für eine temporäre Datei, die beim Schließen gelöscht wird.

Für 1 kann eine neue Funktion bereitgestellt werden, um eine Datei mit den Attributen zu erstellen/zu öffnen. Und wir können die Datei mit logger.SetOutput(file) setzen.

Für 2, kann auch mit neuer Funktion erstellen/öffnen.

Übrigens, ich vermute, dass #25965 nicht mit diesem Problem zusammenhängt. Wahrscheinlich ist es eine Einschränkung von Windows.

(Auf jeden Fall können wir das Verzeichnis nicht löschen, in dem die mit diesem Attribut geöffnete Datei existiert)

@mattn Können Sie den Kompromiss erklären zwischen:

  • Hinzufügen einer komplett neuen Funktion in golang.org/x/sys
  • Unterstützung eines neuen Flags (bereits definiert!) für OpenFile(). [1]

Ich verstehe nicht, warum wir die erste statt der zweiten bevorzugen sollten.

[1] Mir ist gerade aufgefallen, dass ich hier angenommen habe, das Verhalten von os.OpenFile() zu ändern, aber das Problem ruft Open() auf.

Zunächst einmal ist das syscall-Paket bereits gesperrt. Also suche ich nach einer Möglichkeit, dies zu beheben, ohne das syscall-Paket zu ändern.

Übrigens, ich vermute, dass #25965 nicht mit diesem Problem zusammenhängt. Wahrscheinlich ist es eine Einschränkung von Windows.

(Auf jeden Fall können wir das Verzeichnis nicht löschen, in dem die mit diesem Attribut geöffnete Datei existiert)

@mattn das stimmt nicht ganz. FILE_SHARE_DELETE Flag ermöglicht es Ihnen, diese Dateien in einen anderen Ordner zu verschieben, damit Sie den ursprünglichen entfernen können. Hier ist ein einfaches PowerShell-Beispiel dafür:

# Create folder and open new file with FILE_SHARE_DELETE flag
New-Item -Type Directory -Path C:\folder1
$file = [System.IO.File]::Open("C:\folder1\test.txt", "Create", "ReadWrite", "Delete")

# Create temp folder and move all open files to there
New-Item -Type Directory -Path C:\folder1-removing
Get-ChildItem -Path C:\folder1 -Recurse | Move-Item -Destination C:\folder1-removing\

# Remove original folder
Remove-Item -Path C:\folder1

# Trigger removal for files on temp folder (NOTE! Those will exist on disk until they are closed).
Get-ChildItem -Path C:\folder1-removing -File -Recurse | Remove-Item -Force

# Close file and remove temp folder
$file.Close()
Remove-Item -Path C:\folder1-removing

Zunächst einmal ist das syscall-Paket bereits gesperrt. Also suche ich nach einer Möglichkeit, dies zu beheben, ohne das syscall-Paket zu ändern.

@mattn Wenn es sich nur um ein Problem mit dem Einfrieren der API handelt , könnte syscall.Open , wie oben erwähnt / demonstriert , einfach angepasst werden, um syscall.FILE_SHARE_DELETE zu verstehen, wodurch das Problem gelöst wird, ohne die API zu ändern.

Wenn es sich um ein Einfrieren der Implementierung handelt, könnte die Änderung an der golang.org/x/sys/windows Open Funktion von golang.org/x/sys/windows und dann in das Paket internal/syscall werden. Der Code file_windows.go verwendet bereits Funktionen von internal/syscall . Die einzige Inkonsistenz wäre dann, dass syscall.Open dieses Flag nicht verstehen würde, aber die meisten Leute, die auf die Low-Level-Windows-API-Funktionalität zugreifen möchten, verwenden sowieso golang.org/x/sys/windows und wahrscheinlich CreateFile statt Open .

Der Vorschlag, der das Syscall-Paket "lock-down" initiierte, besagt:
_Das Core-Repository hängt nicht von den go.sys-Paketen ab_

Das Ändern von x/sys würde den Aufrufern von os.OpenFile() also nicht helfen. Aber internal/syscall könnte Open() hinzufügen, und os.OpenFile() würde es aufrufen.

@maruel , das Docker-Projekt und vermutlich viele andere haben das Unix-Verhalten für os.Rename() & .Remove() von geöffneten Dateien angenommen, da das Paket "os" kein Windows-spezifisches Verhalten für sie erwähnt, aber __fünfzehn Erwähnungen__ von anderes Windows-Verhalten.

Das Core-Repository hängt nicht von den go.sys-Paketen ab
Aber internal/syscall könnte Open() hinzufügen, und os.OpenFile() würde es aufrufen.

@networkimprov Okay, ich hatte den irrtümlichen Eindruck, dass internal/syscall eine vom Hersteller angebotene Teilmenge von golang.org/x/sys , aber so oder so denke ich, dass dies die richtige Strategie ist ( internal/syscall/windows.Open hinzufügen). Dies würde natürlich unter der Annahme erfolgen, dass das Verhalten von syscall.Open aufgrund des Einfrierens unveränderlich ist. Idealerweise könnte es direkt geändert werden, möglicherweise mit entsprechenden Änderungen in golang.org/x/sys/windows.Open .

Obwohl das syscall-Paket eingefroren ist, können wir es ändern, um Fehler zu beheben oder schwerwiegende Mängel zu beheben. Insbesondere könnten wir es ändern, um das Betriebssystempaket besser zu unterstützen.

Aber wenn Leute syscall.Open direkt aufrufen, dann sollten sie das x/sys/windows-Paket verwenden, nicht das syscall-Paket.

Aber wenn Leute syscall.Open direkt aufrufen, dann sollten sie das x/sys/windows-Paket verwenden, nicht das syscall-Paket.

Ich glaube nicht, dass jemand syscall.Open direkt anrufen möchte - es ist nur das Ziel der Diskussion, weil es os.OpenFile (so dass das Hinzufügen von Unterstützung für FILE_SHARE_DELETE in syscall.Open fügt Unterstützung für die Verwendung des Flags mit os.OpenFile ).

Danke. Es ist in Ordnung, das syscall-Paket zu ändern, um Änderungen am os-Paket zu unterstützen.

Danke @ianlancetaylor und @havoc-io . Ein formellerer Vorschlag von dem, was ich oben bemerkt habe:

  • Ändern Sie syscall.Open() mit der ausdrücklichen Absicht , os.OpenFile() das Akzeptieren von FILE_SHARE_DELETE (und schließlich FILE_FLAG_DELETE_ON_CLOSE als potenzielle Nachfolge) zu ermöglichen.
  • Aktualisieren Sie die os.OpenFile()-Dokumentation, um das neue Nur-Windows-Flag zu beschreiben.
  • Aktualisieren Sie die Dokumentation zu os.OpenFile(), os.Rename() und os.Remove(), um den Unterschied im Verhalten zwischen POSIX und Windows zu verdeutlichen.

Der dritte Punkt besteht darin, die Bedenken von @networkimprov zu adressieren. Ich verstehe die Herausforderung dort, und obwohl es nicht in der Verantwortung der Sprache liegen sollte, die Funktionsweise des Betriebssystems zu beschreiben, stimme ich @mattn zu, dass diese Fälle subtil genug sind, um mehr Dokumentation zu rechtfertigen. Ich denke, das Dokument zum Umbenennen und Entfernen kann sofort verbessert werden, ohne dass auf eine Verhaltensänderung gewartet werden muss.

Ich bin bereit, dazu beizutragen, wenn es Zustimmung gibt.

Dies lässt uns mit einem Pro-Call-Flag mit einem Namen, der eindeutig Windows-spezifisch ist.

Schlagen Sie eine neue os.Open-Flagge vor? Dann sollte das Flag von allen Betriebssystemen unterstützt werden - das ist ein ganzer Punkt des os-Pakets - betriebssystemunabhängig sein. Was wäre also die Semantik dieser Flagge? Und Sie würden einige neue Tests benötigen, die bestätigen, dass das Flag wie dokumentiert funktioniert.

Ich verstehe nicht, warum Sie mit dem syscall-Paket nicht den Code schreiben können, den Sie benötigen. Ich glaube nicht, dass Ihr Code gut mit anderen Windows-Programmen koexistieren wird. Und vielleicht ist es unter besonderen Umständen in Ordnung. Aber ich möchte nicht, dass Leute diese Funktionalität auf die leichte Schulter nehmen - daher sollte sie nicht Teil der Standardbibliothek sein.

Alex

@alexbrainman
bitte sieh das

@alexbrainman
bitte sieh das

Ich habe nachgesehen. Ich sehe immer noch nicht, wie alle Ihre vorgeschlagenen Änderungen auf anderen Betriebssystemen funktionieren werden. Welche Tests müssen Sie durchführen, um Ihre vorgeschlagene Änderung umzusetzen?

Alex

unter Angabe dieser

wohingegen DELETE_WHEN_FREED für env sogar 0 sein kann. außer Fenster

Also - nichts zum Testen auf anderen Betriebssystemen, der Aufruf für:
fd, err := os.OpenFile(Pfad, os.O_RDWR|os.O_CREATE|os.DELETE_WHEN_FREED, 0600)
in Windows würde das const in 4 . übersetzen
fd, err := os.OpenFile(Pfad, os.O_RDWR|os.O_CREATE| 4 , 0600)
Während andere ( 0 )
fd, err := os.OpenFile(Pfad, os.O_RDWR|os.O_CREATE| 0 , 0600)

nichts zu testen auf anderen Betriebssystemen

Ich sehe nicht, wie wir ein neues Betriebssystempaket const oder eine Variable hinzufügen könnten, die nur unter Windows verwendet werden kann.

c:\>go doc os
package os // import "os"

Package os provides a platform-independent interface to operating system
functionality. 
...
The os interface is intended to be uniform across all operating systems.
Features not generally available appear in the system-specific package
syscall.

Alex

Alex die Antwort auf deinen Einwand wurde zuerst hier angegeben https://github.com/golang/go/issues/32088#issuecomment -494157514

Ein Test ist trivial

_, err := os.OpenFile(path, os.O_CREATE | syscall.FILE_SHARE_DELETE, 0);
err = os.Rename(path, path+"2")

Wir sind an dem Punkt angelangt, an dem jemand einen Patch einreichen könnte; Ich vermute, @ianlancetaylor würde es akzeptieren.

Ich habe die Einstellung FILE_SHARE_DELETE als Teil von #32188 untersucht, aber festgestellt, dass die Einstellung die Fehlerrate von os.Rename und io.ReadFile Aufrufen empirisch nicht reduziert; eine Wiederholungsschleife war sowieso noch erforderlich.

Ich wäre sehr daran interessiert, einen Test zu sehen, der einen signifikanten beobachtbaren Unterschied zum Setzen dieses Flags zeigt, da ich seine Auswirkungen selbst nicht wirklich verstehe.

Ich habe vor einigen Jahren mit FILE_SHARE_DELETE experimentiert und es hat sich verhalten
anders.
Ich kann wahrscheinlich meine Windows-Umgebung neu starten. und schau nach, wenn es helfen würde,
aber es wäre ~Go 1.3 oder so.

Am Mo, 10. Juni 2019 um 17:44 Uhr, Bryan C. Mills [email protected]
schrieb:

Ich habe die Einstellung FILE_SHARE_DELETE als Teil von #32188 untersucht
https://github.com/golang/go/issues/32188 , aber festgestellt, dass es eingestellt ist
hat die Fehlerrate von os.Rename und . empirisch nicht reduziert
io.ReadFile-Aufrufe; eine Wiederholungsschleife war sowieso noch erforderlich.

Ich würde mich sehr über einen Test freuen, der eine signifikante
beobachtbarer Unterschied zum Setzen dieses Flags, weil ich es nicht wirklich tue
verstehe die Auswirkungen selbst.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/golang/go/issues/32088?email_source=notifications&email_token=ABNEY4VVIVJ2IEWQPWCWBZTPZZSETA5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXZLOKTORDN5WWZ
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/ABNEY4STTW7U526HPO6TUHDPZZSETANCNFSM4HNPNYIA
.

@bcmills , #32188 lesen Ich nehme an, dass Sie Fehler von os.Rename() in einer Datei gesehen haben, die während der Umbenennung _nicht geöffnet_ war? Ich kann mir vorstellen, dass man das NTFS-Journal überholen könnte, das meiner Meinung nach für alle Verzeichniswechseloperationen geschrieben ist, und dadurch einen Fehler verursachen; aber ich habe keine ahnung welcher fehler das sein soll.

Die Anforderung hier, FILE_SHARE_DELETE in syscall.Open() zu aktivieren, besteht darin, os.Rename() zu erlauben, mit geöffneten Dateien zu arbeiten. Ich habe dieses Flag mit 1.12 auf Win7 getestet, es funktioniert; und scheitert ohne.

Ich habe os.Rename () nicht speziell unter Windows "unter Last" getestet, aber seit dem Aktivieren von fsd keine unerwarteten Fehler von os.Rename () bei geöffneten Dateien gesehen. Ich werde dies melden, wenn ich dies tue.

Ich nehme an, dass Sie Fehler von os.Rename() in einer Datei gesehen haben, die während der Umbenennung nicht geöffnet war?

Ja.

Ich habe keine Ahnung, welcher Fehler das sein soll.

Empirisch gesehen sind die Fehler, die ich sehe (von MoveFileEx , ReplaceFile und/oder sind CreateFile ) ERROR_ACCESS_DENIED , ERROR_SHARING_VIOLATION , und ERROR_FILE_NOT_FOUND .

Die Anforderung hier, FILE_SHARE_DELETE in syscall.Open() zu aktivieren, besteht darin, os.Rename() zu erlauben, mit geöffneten Dateien zu arbeiten. Ich habe dieses Flag mit 1.12 auf Win7 getestet, es funktioniert; und scheitert ohne.

Richtig; Die damit verbundenen Probleme, die ich zu lösen versuche, sind, dass gleichzeitige Aufrufe von os.Rename erfolgreich sind und dass Aufrufe von io.ReadFile gleichzeitig mit os.Rename erfolgreich sind. Ein einzelnes os.Rename zu bringen, mit bestehenden Handles zu arbeiten, mag ein Schritt in die richtige Richtung sein, aber ich denke nicht, dass es für die Art von Anwendungsfällen ausreicht, für die wir das POSIX rename .

Ich wäre sehr daran interessiert, einen Test zu sehen, der einen signifikanten beobachtbaren Unterschied zum Setzen dieses Flags zeigt, da ich seine Auswirkungen selbst nicht wirklich verstehe.

@bcmills PowerShell-Beispiel, da ich viel schneller schreibe als Go

New-Item -Type Directory -Path C:\folder1
for($i=0; $i -le 1000; $i++)
{
    $temp = [System.IO.File]::Open("C:\folder1\test.txt", "Create", "ReadWrite", "Delete")
    Set-Variable -Name "file$i" -Value $temp -Force
    $TempName = "C:\folder1\test.txt." + (New-Guid).Guid
    Rename-Item -Path C:\folder1\test.txt -NewName $TempName
    Remove-Item -Path $TempName -Force
}

Danach befinden sich tausend test.txt.??? Dateien unter C:\folder1 aber wenn Sie PowerShell schließen, werden diese Dateien entfernt.

Was das FILE_SHARE_DELETE Flag eigentlich bewirkt, ermöglicht es Ihnen, geöffnete Dateien umzubenennen/zu verschieben/zu entfernen, aber Sie müssen trotzdem sicherstellen, dass die Zieldateinamen eindeutig sind, da sie auf der Festplatte existieren, solange die Handles geöffnet sind.

"Employ the POSIX rename" ist in Windows unmöglich, und vielleicht ist das der Grund für die Fehler, die Sie erhalten.

POSIX:

Datei "Dateiname" erstellen
Lesen/Schreiben von "Dateiname"
"Dateiname" löschen

Datei "Dateiname" erstellen
...
"Dateiname" löschen

würde funktionieren, da jede Create-Datei ein Diff fd haben würde.

Fenster:
Datei "Dateiname" erstellen
Lesen/Schreiben von "Dateiname"
"Dateiname" löschen

Datei "Dateiname" erstellen - Boom, Freigabeverletzung

Sollte ganz einfach zu rekonstruieren sein...

Was kann FILE_SHARE_DELETE dann tun?
Erlaube verzögertes Löschen, während die Datei geöffnet ist.

Das ist es.

Am Mo, 10. Juni 2019 um 19:32, Olli Janatuinen [email protected]
schrieb:

Ich würde mich sehr über einen Test freuen, der eine signifikante
beobachtbarer Unterschied zum Setzen dieses Flags, weil ich es nicht wirklich tue
verstehe die Auswirkungen selbst.

@bcmills https://github.com/bcmills PowerShell-Beispiel, während ich das schreibe
viel schneller als Go

New-Item -Type Directory -Path C:folder1for($i=0; $i -le 1000; $i++)
{
$temp = [System.IO.File]::Open("C:folder1test.txt", "Create", "ReadWrite", "Delete")
Set-Variable -Name "file$i" -Wert $temp -Force
$TempName = "C:ordner1test.txt." + (Neue-Anleitung).Anleitung
Rename-Item -Pfad C:folder1test.txt -NewName $TempName
Remove-Item -Path $TempName -Force
}

Danach wird es tausend test.txt geben.??? Dateien unter
C:Ordner1, aber wenn Sie PowerShell schließen, werden diese Dateien entfernt.

Welches FILE_SHARE_DELETE-Flag erlaubt es Ihnen also?
Geöffnete Dateien umbenennen/verschieben/entfernen, aber Sie müssen immer noch sicherstellen, dass das Ziel
Dateinamen sind eindeutig, da sie auf der Festplatte so lange existieren wie Handles
sind offen.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/golang/go/issues/32088?email_source=notifications&email_token=ABNEY4WSTWIUVNVHLYMBFY3PZZ62DA5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTORW2
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/ABNEY4VS5XF3EXB6QPBWVQ3PZZ62DANCNFSM4HNPNYIA
.

erlauben Sie Aufrufe von io.ReadFile gleichzeitig mit os.Rename, um erfolgreich zu sein

@bcmills Ich denke, dass man immer mit dem gesetzten fsd-Flag arbeiten sollte, vorausgesetzt, es läuft nicht gleichzeitig mit anderen Threads, die dieselbe Sequenz für nicht verwandte Dateien versuchen. Und es sollte normalerweise ohne die Flagge fehlschlagen.

Dieser Aspekt des Testskripts hat korrekterweise einen Fehler in Windows syscall.Open() gefunden. Aber niemand anderer, der in diesem Thread kommentiert, möchte, dass es behoben wird :-( also ja, patchen Sie das Skript.

TLDR:
kleine sichere Änderung an syscal_windows.go und funktioniert wie erwartet.

erklärt:
Also, hier ist, was ich getan habe, funktioniert wie erwartet und kein Risiko (IMO)

  1. syscal_windows.go anpassen
func Open(path string, mode int, perm uint32) (fd Handle, err error) {

sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | (mode & FILE_SHARE_DELETE))

der Zusatz ist: "| (mode & FILE_SHARE_DELETE)"
wenn der entwickler mode & 4 set nicht schickt (warum sollte er - das hat vorher noch nie funktioniert...) - hat sich nichts geändert, also ein Code wie

os.OpenFile(filename,os.O_RDWR|os.O_CREATE, 0600)

wird sich GENAU wie vor der Änderung verhalten, nur Entwickler, die dies tun

os.OpenFile(filename,os.O_RDWR|os.O_CREATE  | 4 , 0600)

wird die Veränderung "fühlen" müssen

  1. habe den Code ausgeführt
package main

import (
    "fmt"
    "os"
)

func main() {
    filename := "./myfile"
    if f ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("Open file %s error : %s" , filename, err.Error())
    } else if _,err:= f.WriteString("bla bla") ;err!=nil{
        fmt.Printf("writing to %s returned error : %s" , filename, err.Error())
    } else if err := os.Remove(filename);err!=nil{
        fmt.Printf("removing %s returned error : %s" , filename, err.Error())
    }
}

und es hat funktioniert

  1. Habe den Code ohne |4 ausgeführt und es ist fehlgeschlagen
  2. habe den Code mit einer kleinen Ergänzung ausgeführt:
package main

import (
    "fmt"
    "os"
)

func main() {
    filename := "./myfile"
    if f ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("Open file %s error : %s" , filename, err.Error())
    } else if _,err:= f.WriteString("bla bla") ;err!=nil{
        fmt.Printf("writing to %s returned error : %s" , filename, err.Error())
    } else if err := os.Remove(filename);err!=nil{
        fmt.Printf("removing %s returned error : %s" , filename, err.Error())
    } else if secondF ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("reOpen file %s error : %s" , filename, err.Error())
    } else {
        secondF.Close()
    }
}

und natürlich scheiterte es am zweitenF
Aber das ist die erwartete Verhalten in den Fenstern - keine Notwendigkeit, „Belastungstest“ - es gibt keine Gleichzeitigkeit Option auf latente .Remove, so denke ich , können wir sicher in dieser Halbzeit eine Linie zu syscal_windows hinzufügen, ohne einen bestehenden Code zu beeinträchtigen, und damit nur Entwickler ,

alles was wir tun müssen (fett gedruckt):
syscal_windows.go:
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | (mode & FILE_SHARE_DELETE) )

Ich habe die Einstellung FILE_SHARE_DELETE als Teil von #32188 untersucht, aber festgestellt, dass die Einstellung die Fehlerrate von os.Rename und io.ReadFile Aufrufen empirisch nicht reduziert; eine Wiederholungsschleife war sowieso noch erforderlich.

Ich wäre sehr daran interessiert, einen Test zu sehen, der einen signifikanten beobachtbaren Unterschied zum Setzen dieses Flags zeigt, da ich seine Auswirkungen selbst nicht wirklich verstehe.

@bcmills jetzt können Sie Einheit / Regressionstests für diese aus finden https://github.com/olljanat/go/commit/3828f1a5d0ebb69b4c459d5243799ded36ac1ee8 momentan nicht es auf Fehler The process cannot access the file because it is being used by another process. auf Windows und beginnt zu arbeiten , nachdem FILE_SHARE_DELETE -Flag ist im Code enthalten.

Notiz! dass Sie unter Windows immer noch diesen Schritt benötigen, der die Protokolldatei example.log.1 in einen zufälligen/eindeutigen Namen verschiebt, weil das Umbenennen von example.log in example.log.1 zum Fehler Access is denied. fehlschlagen würde auch wenn das FILE_SHARE_DELETE Flag aktiviert ist. Das ist eine plattformspezifische Sache, um die sich Entwickler kümmern müssen.

/cc @jhowardmsft @jterry75 @jstarks @ddebroy Zur Info ; dieses könnte dich auch interessieren.

@kevpar - Zu

Wenn irgendwelche Leute, die dem Thread beitreten, Gründe nennen können (zB vorhandener Code ist defekt), um dies als Standard zu machen, vs. verfügbar über Windows-only-Flag in os.OpenFile(), melden Sie sich!

@networkimprov IMO sollte es mit dem Nur-Windows-Flag gehandhabt werden, da der Entwickler sowieso auch einige andere Windows-spezifische Dinge verarbeiten muss, wie in meinem Protokollrotationsbeispiel.

Wie ich jedoch sehe, wurden einige Microsoft-Mitarbeiter zu einer Diskussion eingeladen, daher ist es interessant zu sehen, ob sie dies anders sehen.

Hat irgendjemand übrigens damit begonnen, eine neue Lösung dafür zu entwickeln? Irgendwelche Freiwilligen?

@olljanat
Wenn es sich um einen Fix-as-a-Flag handelt, dann ist der Fix ein Einzeiler, bitte lesen Sie:
https://github.com/golang/go/issues/32088#issuecomment -500562223

Ich werde versuchen, hier die Perspektive des Windows-Teams darzustellen ... wir würden es vorziehen, wenn Go einfach immer FILE_SHARE_DELETE ohne Option setzt. Im Allgemeinen, um die Portierung zu/von Windows zu vereinfachen, würden wir ein konsistentes Verhalten mit Linux bevorzugen, und ich sehe nicht, warum Windows-Benutzer oder -Software das Standardverhalten !FILE_SHARE_DELETE so bevorzugen würden, dass dies eine Ausnahme von der Regel darstellt.

Ein interessanter Hinweis, im Gegensatz zu @mattns Kommentar: In der neuesten Version von Windows haben wir DeleteFile (auf NTFS) aktualisiert, um ein "POSIX" -Löschen durchzuführen, bei dem die Datei sofort aus dem Namespace entfernt wird, anstatt darauf zu warten, dass alle geöffnet sind Handles auf die zu schließende Datei. Es respektiert immer noch FILE_SHARE_DELETE, verhält sich aber ansonsten eher wie POSIX Unlink. Diese Funktionalität wurde für WSL hinzugefügt und wurde standardmäßig auch für Windows-Software als sinnvoll erachtet.

Mit anderen Worten, wenn Sie das Testprogramm von mattn und die Sequenz von del, dir usw. unter der neuesten Windows-Version ausführen, werden Sie sehen, dass die Datei sofort nach dem Löschen der Datei aus dem Namespace verschwindet, nicht nach dem Beenden des Testprogramms. Genau wie Linux.

Daher nehmen wir sogar in Windows selbst mit seinem deutlich größeren Anwendungskompatibilitätsrisiko kleine Änderungen vor, um die Portierung von Nicht-Windows-Software auf Windows zu erleichtern. Ich ermutige Go wirklich, dasselbe zu tun.

@jstarks , danke, dass du mich rechtfertigt. Ich habe eine Menge Hitze in diesem Thread für diese Position genommen.

Ich würde eine globale Option zum Deaktivieren von fsd vorschlagen, falls Windows-Bereitstellungen auf das aktuelle undokumentierte Verhalten angewiesen sind.

@ianlancetaylor stimmst du zu?

Da das Standardverhalten von CreateFile darin besteht, dass die öffnende Datei nicht gelöscht werden kann, denke ich, dass wir das Standardverhalten beibehalten sollten. Jemand möchte vielleicht das ursprüngliche Verhalten. Zum Beispiel kann es Programmierer geben, die überprüfen, ob ihre Anwendung funktioniert, indem sie die Datei nicht löschen können.

Das Verhalten von Python entspricht dem aktuellen Verhalten von Go. Und ich habe noch nie gehört, dass Python plant, das Verhalten zu ändern, das geöffnete Dateien nicht löschen kann.

Ich habe mir nicht die Zeit genommen, eine ernsthafte Meinung zu diesem Thema zu entwickeln, aber ich glaube nicht, dass eine globale Option eine gute Wahl ist. Wir sollten entweder das aktuelle Verhalten beibehalten (und vielleicht ein Flag hinzufügen, um das andere Verhalten auszuwählen) oder wir sollten das Verhalten ändern (und vielleicht ein Flag hinzufügen, um das ursprüngliche, aktuelle Verhalten auszuwählen).

In Bezug auf die Änderung des Standardverhaltens müssen wir uns meiner Meinung nach fragen, ob es wahrscheinlicher ist, dass eine Änderung des Verhaltens ein Go-Programm repariert, das für die Ausführung auf Unix- und Windows-Systemen geschrieben wurde, oder ob es wahrscheinlicher ist, dass eine Änderung des Verhaltens wird ein Go-Programm zerstören, das für die Ausführung auf Windows-Systemen geschrieben wurde. Darauf kenne ich die Antwort nicht.

Wie @mattn vorschlägt, lohnt es sich auch zu fragen, was andere Sprachen tun.

Wenn es zum Standard wird und alle Windows-Bereitstellungen davon abhängen, stelle ich mir vor, dass sie sowohl ein os.OpenFile()-Flag als auch eine globale Option zum Zurückschalten für Übergangszwecke wünschen.

Es gibt eine globale Option zum Deaktivieren von IPv6, die ich zuletzt überprüft habe.

Eine Möglichkeit, die Auswirkungen zu entdecken, besteht darin, sie auf Trinkgeld zu ändern (und im Blog anzukündigen?) und zu sehen, was gemeldet wird.

Python und Erlang werden beide im Ausgabetext erwähnt:
Erlang hat es vor über sechs Jahren zum Standard gemacht: erlang/ otp@0e02f48
Python wollte, konnte aber aufgrund von Einschränkungen der MSVC-Laufzeit nicht: https://bugs.python.org/issue15244

Ich werde versuchen, hier die Perspektive des Windows-Teams darzustellen ... wir würden es vorziehen, wenn Go einfach immer FILE_SHARE_DELETE ohne Option setzt. Im Allgemeinen, um die Portierung zu/von Windows zu vereinfachen, würden wir ein konsistentes Verhalten mit Linux bevorzugen, und ich sehe nicht, warum Windows-Benutzer oder -Software das Standardverhalten !FILE_SHARE_DELETE so bevorzugen würden, dass dies eine Ausnahme von der Regel darstellt.

In der neuesten Version von Windows haben wir DeleteFile (auf NTFS) aktualisiert, um einen "POSIX"-Löschvorgang durchzuführen, bei dem die Datei sofort aus dem Namespace entfernt wird, anstatt darauf zu warten, dass alle geöffneten Handles der Datei geschlossen werden. Es respektiert immer noch FILE_SHARE_DELETE, verhält sich aber ansonsten eher wie POSIX Unlink. Diese Funktionalität wurde für WSL hinzugefügt und wurde standardmäßig auch für Windows-Software als sinnvoll erachtet.

@jstarks das ist ein sehr interessantes Detail. Ist das etwas, von dem wir erwarten können, dass Microsoft auch auf ältere Betriebssystemversionen zurückportiert? Ich denke besonders an Windows Server 2019, die neueste, gerade veröffentlichte LTSC-Version, die noch lange unterstützt wird.

Als ob Microsoft das tun würde, würde ich es vorziehen, FILE_SHARE_DELETE standardmäßig auch auf Go zu aktivieren.

Java, C# und alle anderen wichtigen Sprachen, die mir bekannt sind, verwenden das Standardverhalten des Betriebssystems. Meiner Meinung nach sollte das Standardverhalten dem Betriebssystem-Implementierer überlassen werden. Wenn Windows wirklich den POSIX-Ansatz bezüglich des Öffnens von Dateien annehmen möchte, sollten sie dieses Risiko eingehen und dies wie bei DeleteFile tun.

Ich denke, die Go-Bibliothek sollte es ermöglichen, Dateien zum Löschen von Freigaben zu erstellen/zu öffnen. Ich kann ein praktisches Beispiel im Umgang mit dem Dateimodus geben. Bei der Portierung von Hadoop auf Windows müssen wir zusätzliche Anstrengungen unternehmen, um eine spezielle Methode in JNI zu erstellen, um das gemeinsam genutzte Delete-Datei-Handle oder den Stream zu erhalten.

https://github.com/apache/hadoop/search?q=getShareDeleteFileInputStream&unscoped_q=getShareDeleteFileInputStream

@jstarks

Wenn ich sage

In der neuesten Version von Windows haben wir DeleteFile (auf NTFS) aktualisiert, um ein "POSIX" -Löschen durchzuführen, bei dem die Datei sofort aus dem Namespace entfernt wird

meinst du, dass die geöffnete datei nur als fd bleibt und der Code unten:

package main

import (
    "fmt"
    "os"
)

func main() {
    filename := "./myfile"
    if f ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("Open file %s error : %s" , filename, err.Error())
    } else if _,err:= f.WriteString("bla bla") ;err!=nil{
        fmt.Printf("writing to %s returned error : %s" , filename, err.Error())
    } else if err := os.Remove(filename);err!=nil{
        fmt.Printf("removing %s returned error : %s" , filename, err.Error())
    } else if secondF ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{
        fmt.Printf("reOpen file %s error : %s" , filename, err.Error())
    } else {
        secondF.Close()
    }
}

wird nicht scheitern

} else if secondF ,err := os.OpenFile(filename,os.O_RDWR|os.O_CREATE|4, 0600);err!=nil{

nach dem Anwenden des vorgeschlagenen Fixes ?

Wenn ja, ist das echt cool!

In Bezug auf die Änderung des Standardverhaltens müssen wir uns meiner Meinung nach fragen, ob es wahrscheinlicher ist, dass eine Änderung des Verhaltens ein Go-Programm repariert, das für die Ausführung auf Unix- und Windows-Systemen geschrieben wurde, oder ob es wahrscheinlicher ist, dass eine Änderung des Verhaltens wird ein Go-Programm zerstören, das für die Ausführung auf Windows-Systemen geschrieben wurde. Darauf kenne ich die Antwort nicht.

Es gibt kein problem to be fixed , auf dem ein Unix-Programm unter Windows ausgeführt wird. Windows handhabt das Löschen geöffneter Dateien anders als Unix. Es ist vergleichbar mit der Groß-/Kleinschreibung bei Dateinamen: Unix beachtet die Groß-/Kleinschreibung und Windows beachtet die Groß-/Kleinschreibung nicht. Gegen beide Unterschiede können wir nichts tun.

Und während John versichert, dass Microsoft versucht, die Dinge zu ändern, würde ich warten, bis die Änderung da ist. Und viele Windows-Benutzer verwenden immer noch Windows 7 und alle anderen Windows-Versionen. John würdest du auch Windows 7 aktualisieren?

Ich denke, wir sollten Microsoft die Änderung überlassen. Wenn wir Go-Benutzer reparieren, wird es immer noch Nicht-Go-Entwickler geben. Microsoft müsste sich also trotzdem damit auseinandersetzen.

Außerdem hat FILE_SHARE_DELETE seine eigenen Geigen. Lesen Sie beispielsweise https://bugs.python.org/issue15244

Tatsächlich ist es nicht ganz dieselbe Semantik wie Unix.

Nachdem Sie die Datei gelöscht haben, können Sie keine Datei mit demselben Namen erstellen oder das Verzeichnis löschen, in dem sie enthalten ist, bis das Handle geschlossen wurde.

Sie können dies jedoch umgehen, indem Sie die Datei an einen anderen Ort verschieben (z. B. in das Stammverzeichnis), bevor Sie sie löschen.

Es gibt wahrscheinlich viele andere, von denen wir nichts wissen. Wir haben FILE_SHARE_DELETE überhaupt nicht verwendet. Schlagen Sie vor, dass wir die Go-Bibliotheken so ändern, dass sie standardmäßig FILE_SHARE_DELETE verwenden, und dann warten, bis sich Benutzer über ihre kaputten Programme beschweren?

Wie @mattn vorschlägt, lohnt es sich auch zu fragen, was andere Sprachen tun.

Ich habe nur Mingw C überprüft - es verhält sich genau wie Go. Sobald die Datei mit fopen geöffnet wurde, kann sie nicht gelöscht werden, bis fclose aufgerufen wird. Ich wäre überrascht, wenn eines der Microsoft-Entwicklungstools (C, C++, C#, VB und andere) anders ist.

Und ich sehe nicht, wie wir das Standardverhalten so ändern könnten. Einige Programme haben möglicherweise eine Datei speziell geöffnet, sodass sie von anderen Programmen nicht gelöscht werden kann. Das ist meiner Ansicht nach ein gültiger Ansatz unter Windows. Wir müssen es in Zukunft unterstützen.

Alex

Vor 7 Jahren hinzugefügt, glaube ich:
https://sourceforge.net/p/mingw-w64/code/HEAD/tree/stable/v3.x/mingw-w64-headers/include/ntdef.h#l858

Bisher hat niemand Fälle von Go-Apps gepostet, die vom aktuellen undokumentierten Windows-Verhalten abhängen. Aber wir haben mindestens 4 Fälle von Go-Apps gehört, die unter Windows deswegen fehlgeschlagen sind.

Wie oben erwähnt, gibt es einen einfachen Fix für die Wiederverwendung von Dateinamen nach os.Remove(), den wir dokumentieren sollten:
os.Rename(path, unique_path); os.Remove(unique_path)

Bisher hat niemand Fälle von Go-Apps gepostet, die vom aktuellen undokumentierten Windows-Verhalten abhängen.

Diese Leute wissen nicht einmal, dass es möglich ist, Go-Bugs zu melden.

Sie sollten nicht erwarten, dass diese Benutzer die Go-Problemliste auf Änderungen überwachen, in der Hoffnung, dass etwas sie betrifft. Sie haben das Leben zu leben. Es liegt an uns, die von ihnen verwendeten Werkzeuge nicht zu zerstören.

Alex

Alex, du bist offensichtlich nicht überzeugt. Dann sehe ich zwei mögliche Wege nach vorne, damit Leute in Go portablen Code schreiben können:

  1. ein neues Opt-in-Flag für Open , das FILE_SHARE_DELETE für Windows bedeutet und für die anderen Betriebssysteme ignoriert wird. Wir würden dann jeden ermutigen, der Code schreibt, der erwartet, dass die POSIX-Semantik dieses Flag überall weitergibt; oder,
  2. ein neues Go-Paket posix (in irgendeinem Repo) mit einer Funktion, Open , die CreateFile mit FILE_SHARE_DELETE umschließt, sich aber ansonsten wie os.Open verhält. Auf Nicht-Windows-Plattformen würde es einfach os.Open direkt aufrufen. Wir würden dann jeden ermutigen, der Code schreibt, der erwartet, dass die POSIX-Semantik überall posix.Open anstelle von os.Open .

Beide Ansätze erfordern, dass Linux-Entwickler zusätzliche Maßnahmen ergreifen, um das POSIX-Verhalten unter Windows beizubehalten, aber zumindest sind diese besser, als einmalige CreateFile-Wrapper zu schreiben (wie wir es gerade für containerd getan haben).

Alex, du bist offensichtlich nicht überzeugt.

Ich bin nicht überzeugt. Aber Sie müssen mich nicht überzeugen, Sie müssen Go Team überzeugen. Sie werden die Entscheidung treffen.

  1. ein neues Opt-in-Flag für Open , das FILE_SHARE_DELETE für Windows bedeutet und für die anderen Betriebssysteme ignoriert wird. Wir würden dann jeden ermutigen, der Code schreibt, der erwartet, dass die POSIX-Semantik dieses Flag überall weitergibt; oder,

Ich mag diese Option auch nicht.

Zuallererst soll das os-Paket die Möglichkeit bieten, die für jedes Betriebssystem verfügbar ist. Alles OS-spezifische sollte in syscall oder golang.org/x/sys/windows oder in jedes andere Paket, das wir mögen, eingehen.

Zweitens mache ich mir Sorgen, dass ich am Ende den Dateityp FILE_SHARE_DELETE in meinem Programm bekomme, auch wenn ich nicht möchte. Stellen Sie sich vor, ich importiere ein externes Paket, das den Dateimodus FILE_SHARE_DELETE verwendet. Woher soll ich wissen, dass ein Teil meines Codes FILE_SHARE_DELETE ? Ich müsste den Quellcode des Pakets grep erstellen. Oder die Paketdokumentation müsste ihre Benutzer warnen. Ich nehme an, dies könnte auch passieren, wenn ein Paketautor einfach syscall.CreateFile mit FILE_SHARE_DELETE direkt verwendet. Aber ich denke, wenn FILE_SHARE_DELETE für das Betriebssystempaket gesegnet ist, wird dies häufiger vorkommen. Ich vermute, Linux-Benutzer, die nichts über Windows wissen, würden dieses Flag standardmäßig verwenden, um ihre Linux-Programmportierung auf Windows "einfacher" zu machen.

Drittens müssten wir das Flag FILE_SHARE_DELETE dokumentieren. Wir können nicht einfach POSIX sagen. Wir müssten beschreiben, was die Flagge macht. In einfachen Worten. Denken Sie auch daran:

Tatsächlich ist es nicht ganz dieselbe Semantik wie Unix.

Nachdem Sie die Datei gelöscht haben, können Sie keine Datei mit demselben Namen erstellen oder das Verzeichnis löschen, in dem sie enthalten ist, bis das Handle geschlossen wurde.

Sie können dies jedoch umgehen, indem Sie die Datei an einen anderen Ort verschieben (z. B. in das Stammverzeichnis), bevor Sie sie löschen.

von https://github.com/golang/go/issues/32088#issuecomment -504321027. Auch das müssten wir dokumentieren. Und all die anderen Funktionen, die das FILE_SHARE_DELETE Flag mit sich bringt.

Viertens müssten wir neue Tests für FILE_SHARE_DELETE hinzufügen. Was wären das für Tests? Was passiert, wenn wir vergessen, einige Funktionen zu testen, nur um später festzustellen, dass die Funktionalität nicht mit dem Flag FILE_SHARE_DELETE ? Wir können das FILE_SHARE_DELETE Flag nicht entfernen, wenn es uns nicht gefällt. Einmal drin, bleibt es. Und das müssen wir in Zukunft unterstützen.

2. ein neues Go-Paket posix (in irgendeinem Repo) mit einer Funktion, Open , die CreateFile mit FILE_SHARE_DELETE umschließt, sich aber ansonsten wie os.Open verhält

Ich sehe nicht, wie das möglich ist. Wenn es möglich ist, sollten Sie das Paket jedoch selbst erstellen können. Zum Beispiel als github.com/jstarks/posix. Nein? Wir könnten das Paket unter golang.org/x/sys/windows/posix oder so hinzufügen, aber ich sehe keinen großen Unterschied.

Alex

os-Paket soll eine Einrichtung bieten, die für jedes Betriebssystem verfügbar ist ...
wir müssten das Flag FILE_SHARE_DELETE dokumentieren. Wir können nicht einfach POSIX sagen...
wir müssten neue Tests für FILE_SHARE_DELETE hinzufügen. Was wären das für Tests?

All dies wurde oben angesprochen.

wenn ich ein externes Paket importiere, das den Dateimodus FILE_SHARE_DELETE verwendet. Woher soll ich das wissen?

Dies ist ein weiteres Argument dafür, es zum Standard zu machen und ein globales Flag bereitzustellen, um es zu deaktivieren.

Ich habe auf golang-nuts gepostet, um nach betroffenen Windows-Apps zu suchen; Ich werde es alle paar Tage anpingen, damit es sichtbar bleibt. Wenn das nicht viel auftaucht, sollte es die Standardeinstellung für Trinkgeld für 1.14 sein, um die Dinge zu klären.
https://groups.google.com/d/topic/golang-nuts/8BiP_mPoCd4/discussion

Dies ist ein weiteres Argument dafür, es zum Standard zu machen und ein globales Flag bereitzustellen, um es zu deaktivieren.

Übrigens. Was soll dieses Flag unter Linux tun? Vermissen wir eigentlich auch die Funktionalität, um Dateien in Linux so zu öffnen, dass sie nicht von anderen Prozessen gelöscht werden können? Basierend auf diesem https://gavv.github.io/articles/file-locks/#open -file-description-locks-fcntl sollte es möglich sein, es auf modernen Linux-Versionen zu implementieren.

Das Flag (zB var OpenWithout_FILE_SHARE_DELETE = false ) würde in syscall_windows.go definiert, da es das Verhalten von syscall.Open() beeinflusst.

Ein Flag für etwas Linux-spezifisches hätte einen anderen Namen und wäre in syscall_linux.go definiert. Ich weiß nicht, wie ich das Löschen einer geöffneten Datei unter Linux anders als über Berechtigungen für das Verzeichnis verhindern kann. Der von Ihnen angegebene Link beschreibt das "advisorische" Sperren.

@jstarks Bevor wir die Einführung des FILE_SHARE_DELETE Betracht ziehen, müssen wir auch entscheiden, was zu tun ist, wenn Go nicht in der Lage ist, die laufende ausführbare Datei zu löschen. Ich glaube nicht, dass FILE_SHARE_DELETE Flag uns hier helfen kann. Kann es? Wenn wir das Löschen einer noch laufenden ausführbaren Datei nicht implementieren können, können wir keine POSIX-Kompatibilität beanspruchen. Und das FILE_SHARE_DELETE Flag sieht aus wie eine halbe Lösung.

Darüber hinaus können wir manchmal keine ausführbare Datei eines Prozesses löschen, der sogar abgeschlossen wurde. Siehe zum Beispiel #25965, #19491 und #32188 für Details. Grundsätzlich rufen wir WaitForSingleObject auf dem Prozess-Handle auf, bis es signalisiert. Dies garantiert jedoch nicht, dass die ausführbare Datei gelöscht werden kann. Wir mussten 5 Millisekunden warten, bevor wir versuchten, die Datei zu löschen. Und selbst das funktioniert nicht immer - https://github.com/golang/go/issues/25965#issuecomment -482037476

Auch unabhängig von diesem Problem, aber da ich Ihre Aufmerksamkeit habe, können Sie uns vielleicht helfen, den Windows-Arm-Port wiederzubeleben. Siehe #32135 für Details. Grundsätzlich hat @jordanrh1 Go auf Windows-Arm portiert, aber wir haben keinen Windows-Arm-Builder mehr. Wir wissen also nicht einmal, ob der Port noch funktioniert oder defekt ist. Wenn Sie uns helfen könnten, den Builder zum Laufen zu bringen, könnten wir vielleicht versuchen, den Windows-am-Port weiterhin zu unterstützen. Andernfalls könnte der Port entfernt werden - https://github.com/golang/go/wiki/PortingPolicy Ich weiß nicht, ob jemand daran interessiert ist, Go-Programme unter Windows 10 Iot auszuführen, aber wir haben diese Unterstützung bereits. Es wäre traurig, es zu verlieren, nur weil wir keinen funktionierenden Baumeister haben.

Danke schön.

Alex

Beachten Sie diesen Lösungsvorschlag zum Löschen temporärer ausführbarer Dateien: https://github.com/golang/go/issues/25965#issuecomment -495636291

Keine Ergebnisse von Golang-Nuss-Posts; einen neuen Thread gestartet:
https://groups.google.com/d/topic/golang-nuts/aRvSo3iKvJY/discussion

Zumindest ein nicht ganz so hypothetisches Problem, das meiner Meinung nach untersucht werden sollte, wäre die Auswirkung auf Dateisperren und Programme, die darauf angewiesen sind.

Das Öffnen jedes Datei-Handles mit FILE_SHARE_DELETE würde die Semantik von LockFileEx effektiv zu der von POSIX-Advisory-Sperren schwächen, da jede Datei mit FILE_SHARE_DELETE Angabe entfernt werden kann, selbst wenn eine Sperre ist in einem Bereich dieser Datei gespeichert. 1

Dies gilt natürlich nur für LockFileEx Aufrufe mit dem von os.File.Fd Deskriptor, aber genau das wird in der beliebtesten Go-Dateisperrbibliothek (die derzeit 33 bekannte Importer hat , einschließlich Docker) gemacht , gVisor und Kubernetes). Es wird auch in Terraform gemacht und LockFileEx wird in vielen anderen Go-Codes verwendet .

Ich denke immer noch, dass diese Änderung im besten Fall ein unüberlegtes Unterfangen (und im schlimmsten Fall eine CVE-Fabrik) ist. Ich sehe wirklich nicht, wie die trüben Vorteile den klaren Codebruch aufwiegen, der auftreten wird.

Ich denke auch, dass die meisten Golang-Nuts-Benutzer die Auswirkungen dieser Änderung nicht vollständig verstehen werden. Mit Genehmigung des Go-Teams könnte ein Post auf golang-dev effektiver sein, um Diskussionen zu erzeugen (insbesondere, da dies eine grundlegende Änderung ist). Tatsächlich betrifft es technisch die Go-Toolchain, die ebenfalls LockFileEx in der oben genannten Weise verwendet .


1 Ja, ich weiß, dass einige der Windows-Sperrerzwingungen immer noch stärker wären als unter POSIX, aber wenn Sie die Datei nuklearisieren können, dann geht die Verwendung einer Sperrdatei für die Ressourcenreservierung aus dem Fenster.

Ich habe an golang-dev gepostet, als ich das Problem öffnete.
https://groups.google.com/d/topic/golang-dev/R79TJAzsBfM/discussion

Ist eine der aufgelisteten Bibliotheken _abhängig_ vom GOOS=windows-Verhalten? Sie haben wiederholt behauptet, dass diese Änderung bestehenden Code zerstören würde, haben aber nie Beweise geliefert.

Hören Sie bitte auf, sensationelle, unhaltbare Aussagen zu machen. Es klärt nichts, und ich finde es beleidigend.

Ich habe an golang-dev gepostet, als ich das Problem öffnete. https://groups.google.com/d/topic/golang-dev/R79TJAzsBfM/discussion

Es scheint, als hätte jeder dort die Idee aus eigenen Gründen abgeschossen (alle ähneln denen, die zuvor in diesem Thread erwähnt wurden), aber wenn die Idee jetzt auftaucht, diese Änderung in Go 1.14 anzuwenden, eine Fortsetzung dazu Thread könnte nützlich sein (mit einem Erinnerungslink zu dieser Diskussion).

Hängt eine der aufgelisteten Bibliotheken vom Verhalten GOOS=windows ab? Sie haben wiederholt behauptet, dass diese Änderung bestehenden Code zerstören würde, haben aber nie Beweise geliefert.

Das würde eine vollständige Sicherheitsbewertung (von viel Code) erfordern, um sicher zu sein. Ich denke, ich habe sicherlich genug Beweise dafür geliefert, dass sich die Leute auf ein Verhalten verlassen, das sich mit der Einführung dieses Flags sichtbar ändern würde. Und das ist nur öffentlich verfügbarer Code auf GitHub.

Hören Sie bitte auf, sensationelle, unhaltbare Aussagen zu machen. Es klärt nichts, und ich finde es beleidigend.

Wenn Links und Code nicht ausreichend unterstützt werden, weiß ich nicht, was in Ihrem Buch stehen würde. Sie werden keinen Code finden, der aufgrund dieser Änderung aufhört zu kompilieren, aber Sie werden sicherlich Code finden, der sich anders verhält, und viele Leute würden diesen Code aufgrund dieser Verhaltensänderungen als "kaputt" betrachten.

Nehmen Sie meinen Einwand nicht persönlich, ich denke, jeder hier (einschließlich Sie) versucht nur, seinen Beitrag zur Verbesserung der Sprache hinzuzufügen. Wenn Sie sich für eine grundlegende Veränderung einsetzen wollen, sollten Sie mit gesundem Widerstand rechnen.

Wie ich oben erklärt habe, hat das Löschen einer Datei mit FILE_SHARE_DELETE nicht dieselbe Funktion wie die von UNIX. Versuchen Sie beispielsweise diese Schritte.

Haupt c

#include <windows.h>
#include <stdio.h>

int
main() {
  // ensure delete the file
  DeleteFile("test.txt");

  // create test.txt with FILE_SHARE_DELETE
  HANDLE h = CreateFile("test.txt",
      GENERIC_READ | GENERIC_WRITE,
      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
      NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  puts("waiting 10sec, please run watch.exe on another cmd.exe");
  Sleep(10000);
  if (DeleteFile("test.txt")) {
    puts("deleted");
  }
  getchar();
  return 0;
}

watch.c

#include <stdio.h>
#include <shlwapi.h>

int
main() {
  // waiting test.txt will be removed.
  while (PathFileExists("test.txt")) {
    puts("watching...");
    Sleep(1000);
  }
  // now test.txt should not exists. So this is possible to create new file
  system("notepad test.txt");
  return 0;
}

Makefile

all : main.exe watch.exe

watch.exe : watch.c
    gcc -o watch.exe watch.c -lshlwapi

main.exe : main.c
    gcc -o main.exe main.c

Führen Sie zuerst main.exe und dann watch.exe aus. Unter UNIX entfernt unlink(2) die Datei sofort. So kann ein anderer Prozess, der die Existenz der Datei überwacht, eine neue Datei mit demselben Dateinamen erstellen. Unter Windows zeigt notepad.exe jedoch einen Fehlerdialog "Zugriffsverletzung" an, da Windows die Datei nicht sofort löscht. Was damit passiert, kann ich dir nicht sagen. Sicherheitsproblem? Wichtige Dateien verloren? Entschuldigung, ich weiß es nicht.

@havoc-io Windows löscht eine geöffnete Datei erst, wenn sie geschlossen wird, und hält nur Sperren für geöffnete Dateien. Die Verwendung von Sperren impliziert also keine Abhängigkeit vom Fehler von os.Remove(). Bitte geben Sie Beispiele an, die speziell von diesem Fehler abhängen.

Ich werde den golang-dev-Thread nächste Woche anpingen. Zwei Personen antworteten darauf; man hatte diese Ausgabe nicht gelesen und auch keine Beispiele geliefert.

Sensationelle, nicht haltbare Behauptungen sind kein "gesunder Widerstand".

@havoc-io Windows löscht eine geöffnete Datei erst, wenn sie geschlossen wird, und hält nur Sperren für geöffnete Dateien. Die Verwendung von Sperren impliziert also keine Abhängigkeit vom Fehler von os.Remove(). Bitte geben Sie Beispiele an, die speziell von diesem Fehler abhängen.

@networkimprov Sie

Sperrdateien (wie mit LockFileEx gesperrt) werden normalerweise verwendet, um eine Ressource zu schützen. Ein Beispiel könnte sein, sicherzustellen, dass nur eine einzige Instanz eines Daemons ausgeführt wird. Wenn ein Windows Go-Daemon eine Datei öffnet und dann LockFileEx für die Datei ausführt und erfolgreich eine exklusive Sperre erlangt, kann er zu Recht davon ausgehen, dass die Sperrdatei darunter nicht entfernt wird. Wenn jedoch FILE_SHARE_DELETE standardmäßig aktiviert ist, ist der gesamte vorhandene Code, der diese Annahme macht, nicht mehr richtig. Wenn ein zusätzlicher Agent diese Sperrdatei entfernen würde (zB ein Benutzer, der versehentlich ein Verzeichnis löscht), könnte der ursprüngliche Daemon noch laufen, wenn ein neuer gestartet wird.

Sperrdateien können auch für die Pipeline von Befehlen verwendet werden, wenn das Flag LOCKFILE_FAIL_IMMEDIATELY weggelassen wird, was dazu führt, dass LockFileEx auf den Zugriff auf die Sperre wartet. Wenn die Sperrdatei versehentlich entfernt wird, kann dies dazu führen, dass mehrere Befehle gleichzeitig ausgeführt werden, die in der Pipeline hätten ausgeführt werden sollen.

Sensationelle, nicht haltbare Behauptungen sind kein "gesunder Widerstand".

Niemand macht in diesem Thread sensationelle oder unhaltbare Behauptungen. Jede einzelne Person, die Ihrem Vorschlag nicht zugestimmt hat, einschließlich mir selbst, hat solide Argumente geliefert, die durch Code unterstützt werden. Ebenso wie die Leute, die Ihren Vorschlag unterstützt haben.

Bitte überprüfen Sie die WinAPI-Dokumente; Windows löscht eine geöffnete Datei nicht, bis sie geschlossen wird, und hält nur LockFileEx()-Sperren für geöffnete Dateien, sodass eine Sperre nicht bestehen bleiben kann, wenn die Datei geschlossen wird, unabhängig vom Löschen. Ein Versuch, eine gesperrte (dh geöffnete) Datei nach dem Löschen zu öffnen, würde einen Fehler anzeigen, sodass keine zweite Sperre erlangt werden könnte. Threads, die auf eine Sperre warten, haben die Datei geöffnet, würden also nicht durch Löschen unterbrochen.

Sofern ich die Dokumente nicht falsch gelesen habe, werden Ihre letzten beiden Szenarien nicht unterstützt. Und das war sensationell und wurde nicht unterstützt: "Diese Änderung scheint im schlimmsten Fall eine CVE-Fabrik zu sein. Ich sehe wirklich nicht, wie die trüben Vorteile den klaren Code-Bruch überwiegen, der auftreten wird."

@networkimprov Das Problem besteht darin, dass Sperrdateien mit Ressourcenbeschränkung normalerweise auf dem Dateipfad basieren. Das zugrunde liegende Dateiobjekt darf nicht gelöscht werden, bis die Datei geschlossen wird, aber wenn es über DeleteFile , ist es nicht über den vorherigen Pfad auf dem Dateisystem 1 zugänglich, und dadurch können andere Sperrdateien erstellt werden an diesem Pfad, wodurch der Zweck der Sperrdatei negiert wird.

Ich glaube nicht, dass es ein sensationeller Kommentar war - es scheint ziemlich klar zu sein, dass so etwas ein Sicherheitsproblem verursachen könnte, wenn der Code auf bestimmten Betriebssysteminvarianten angewiesen ist, die nicht mehr wahr sind. Und die Vorteile hier scheinen ziemlich unklar zu sein (wie mehrere Leute kommentiert haben: Dies stimmt nicht mit dem Windows-Verhalten mit POSIX überein) und der Bruch scheint ziemlich klar zu sein (er unterbricht zumindest bestimmte Sperrverhalten).

1 Zumindest scheint dies beim Testen und basierend auf diesem Kommentar der Fall

Re "In der neuesten Version von Windows haben wir DeleteFile (auf NTFS) aktualisiert, um einen 'POSIX'-Löschvorgang durchzuführen, bei dem die Datei sofort aus dem Namespace entfernt wird" von https://github.com/golang/go/issues/ 32088#issuecomment -502850674. AFAIK, dass diese Version von Windows nicht freigegeben ist. Auf welche Tests beziehen Sie sich?

Zu den Vorteilen, ich denke, Sie sollten den gesamten Thread überprüfen.

AFAIK, dass diese Version von Windows nicht freigegeben ist.

@networkimprov Ich glaube, das ist unter Windows 10 bereits der Fall. Ich scheine in der Lage zu sein, eine mit LockFileEx gesperrte Datei zu entfernen, wenn FILE_SHARE_DELETE CreateFileW beim Öffnen der Datei auf

DeleteFileW() würde in diesem Szenario keinen Fehler ausgeben. Woher wissen Sie, dass es sofort aus dem Dateisystem entfernt wurde oder beim Schließen der Datei / App entfernt wurde? Haben Sie versucht, die Datei nach dem Entfernen zu öffnen/neu zu erstellen?

Tatsächlich betrifft es technisch die Go-Toolchain, die _auch_ LockFileEx in der oben genannten Weise verwendet.

Innerhalb des go Befehls wollen wir unbedingt die POSIX-Semantik und sollten uns in keiner Weise auf das Fehlen von FILE_SHARE_DELETE . Tatsächlich habe ich das Paket cmd/go/internal/robustio speziell hinzugefügt, um die Abweichungen der Windows-Dateisperrung von POSIX _umzugehen_.

@ianlancetaylor Ich habe wiederholt an golang-nuts & -dev gepostet und um Kommentare von jedem Projekt gebeten, das auf dem aktuellen (undokumentierten) Windows-syscall.Open()-Verhalten beruht. Es hat sich kein einziger Anwendungsfall herauskristallisiert.

Da oben mehrere Anwendungsfälle aufgetaucht sind, die FILE_SHARE_DELETE benötigen (und Microsoft ausdrücklich darum gebeten hat, es zu verwenden), setzen wir dieses Flag standardmäßig in der Vorabversion 1.14 und prüfen erneut, ob Anwendungsfälle für die ursprüngliche Verhaltensoberfläche während des Zyklus vorhanden sind.

Wie zuvor in diesem Thread vorgeschlagen, könnte jemand, der einen open()-Aufruf ohne dieses Flag benötigt, seinen eigenen rollen, indem er CreateFileW() & os.NewFile() .

Können wir dafür wenigstens einen Knopf freigeben?

Dies ist sehr nützlich, um die Protokollrotation in Windows zu implementieren.

Dies ist sehr nützlich, um die Protokollrotation in Windows zu implementieren.

Ich bin mir nicht sicher, aber ich vermute, dass es nicht funktioniert, da FILE_SHARE_DELETE es nicht erlaubt, eine neue Datei mit dem ursprünglichen Dateinamen zu erstellen, wenn das Handle der Datei nicht geschlossen ist.

@Random-Liu fragst du nach einer Möglichkeit, fsd auf Open() zu aktivieren oder zu deaktivieren?

@mattn Bei mir funktioniert es. Nach os.Rename der alten Protokolldatei kann ich eine neue Protokolldatei mit dem ursprünglichen Namen erstellen und den Daemon anweisen, die Protokolldatei erneut zu öffnen.

@networkimprov Ich möchte FILE_SHARE_DELETE aktivieren. Ich verwende derzeit syscall.CreateFile direkt.

Meine Windows-Version:

Major  Minor  Build  Revision
-----  -----  -----  --------
10     0      17763  0

@Random-Liu Aber ich denke, wir können dies nicht zum Simulieren des UNIX-Verhaltens verwenden.

https://github.com/golang/go/issues/32088#issuecomment -510345908

Externe Anwendung kann nicht auf den ursprünglichen Dateinamen zugreifen.

mattn, dieser Punkt muss nicht immer wiederholt werden. Es wurde bereits erwähnt, dass wir die Notwendigkeit (unter Windows) dokumentieren müssen, eine Datei vor dem Löschen umzubenennen, wenn der Dateiname wiederverwendbar sein muss, bevor das Handle geschlossen wird.

Wenn die Datei vor dem Schließen von der Anwendung selbst umbenannt wird, gibt es meiner Meinung nach keine Vorteile für Benutzer, die logrotate durchführen möchten.

@ianlancetaylor erneut versuchen: https://github.com/golang/go/issues/32088#issuecomment -526074116

Ich habe dieses Problem als Release-Blocker markiert.

@bcmills könnte ich dich für eine CL interessieren?

Diese Zeile: https://golang.org/src/syscall/syscall_windows.go#L291
Benötigt nur: sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)

Bearbeiten: Ein Test zur Überprüfung würde eine Datei erstellen und dann versuchen, sie umzubenennen, bevor sie geschlossen wird.

Wir brauchen das bald, damit alle Probleme vor dem Einfrieren auftauchen können ...

Außerdem sollte in den os.Remove()-Dokumenten erwähnt werden, dass unter Windows eine geöffnete Datei umbenannt werden sollte, bevor sie entfernt wird, wenn der Dateiname zur Wiederverwendung verfügbar sein muss, bevor die Datei geschlossen wird. Windows schließt das Löschen einer geöffneten Datei erst ab, wenn sie geschlossen wird.

Anscheinend erfüllt die neueste Version von Windows https://github.com/golang/go/issues/32088#issuecomment -502850674. Weitere Informationen finden Sie unter https://github.com/papertrail/go-tail/pull/10#issuecomment -529460973. Wir können jetzt den Namen einer gelöschten Datei wiederverwenden, selbst wenn noch offene Handles für die alte Datei vorhanden sind, vorausgesetzt, diese Handles wurden mit dem Freigabemodus FILE_SHARE_DELETE geöffnet. Kein Umbenennen vor dem Löschen erforderlich. Vielleicht macht es endlich Sinn, FILE_SHARE_DELETE in Go standardmäßig zu setzen?

Das ist die Absicht; Wir brauchen nur jemanden, der eine CL einreicht. (Würde ich, aber ich kann keinen CLA unterschreiben.)
Meine vorherigen beiden Kommentare beschreiben die notwendigen Änderungen...

@jstarks @jordanrh1 @thaJeztah

Frage:
Wie erreichen wir ein konsistentes Verhalten?
Wenn das Programm unter "neuesten Windows" ausgeführt wird, würde es das Erstellen einer Datei mit einem ähnlichen Namen wie eine Datei mit "ausstehendem Löschen" ermöglichen, ältere Versionen werden bei einem Fehler abgebrochen.

Dies kann tatsächlich heißen: "Tests / Qa bestanden, funktioniert aber bei den meisten Zielen nicht" jetzt, und
"funktioniert normalerweise, und manchmal nicht" in der Zukunft (ein Entwickler, der in 2 Jahren einen Fehler "Datei bereits beendet" erhält, wird sich nicht reproduzieren können).

Wir müssen herausfinden, wie wir "alte" Versionen identifizieren und entweder das Standardverhalten für diese ändern oder den Fehler verbessern, wenn "ein Löschvorgang aussteht" - ich bin mir nicht sicher, wie wir das tun können.
Und wenn wir es nicht können, wie gehen wir mit Inkonsistenz um.

@guybrand Wie oben erwähnt, dokumentieren wir, dass unter Windows "eine geöffnete Datei vor dem Entfernen umbenannt werden sollte, wenn der Dateiname zur Wiederverwendung verfügbar sein muss, bevor die Datei geschlossen wird."

Dies funktioniert für alte & neue Windows-Versionen sowie POSIX.

Das klingt nach einem anderen Ansatz: "Immer vor Wiederverwendung umbenennen, auch auf neuem Windows oder POSIX"
Ich mag es - es unterstützt eine gängige Praxis, die überall erfolgreich sein wird.

Änderung https://golang.org/cl/194957 erwähnt dieses Problem: syscall: allow FILE_SHARE_DELETE on syscall.Open on Windows

Der golang-nuts Thread ist hier und hatte keine Antworten. Das scheint darauf hinzudeuten, dass sich niemand, der golang-nuts liest und von diesem Verhalten weiß, darauf verlässt.

Die golang-dev Threads gibt es hier und hier , und letzterer (der neuere Thread) hat auch keine Einwände erhoben.

@alexbrainman -2 hat die CL aufgrund eines offensichtlichen Mangels an Entscheidung implementiert, daher habe ich dieses Problem in NeedsDecision damit wir eine klare Richtung erhalten.

Für mich persönlich scheint die Entscheidung klar zu sein: Angesichts der Tatsache, dass die Leute von Microsoft in diesem Thread die Änderung des Standardverhaltens unterstützen, um FILE_SHARE_DELETE (https://github.com/golang/go/issues/32088 #issuecomment-502850674) und dass es niemanden auf golang-nuts auf die eine oder andere Weise zu interessieren scheint, sollten wir es tun.

Die Einwände, die ich in diesem Thread gesehen habe, scheinen in zwei Kategorien zu fallen:

  1. Das Anliegen von @alexbrainman (https://github.com/golang/go/issues/32088#issuecomment-504321027) und @mattn (https://github.com/golang/go/issues/32088#issuecomment-494417146) scheint zu sein, dass Benutzer, die POSIX-Semantik erwarten, verwirrt sein können, da das Verhalten immer noch nicht mit POSIX übereinstimmt. (Aber es ist bereits so, dass Open unter Windows keine POSIX-Semantik bietet, daher scheint mir diese Sorge unabhängig von der vorgeschlagenen Änderung zu sein.)

  2. Die Sorge von @havoc-io (https://github.com/golang/go/issues/32088#issuecomment-510314947) scheint zu sein, dass FILE_SHARE_DELETE die Invarianten von dateisperrenden Paketen bei der Ausführung unter Windows verringern wird . Aber dieses Argument erscheint mir etwas verwirrend, da das konkrete Paket, das als Beispiel dient ( github.com/gofrs/flock ) ausdrücklich darauf hinweist, dass „das Sperrverhalten nicht garantiert auf jeder Plattform gleich ist“, und aus einer kurzen Prüfung Keines der konkreten Beispiele scheint sich auf das Windows-spezifische Zusammenspiel zwischen Sperren und Dateilöschen zu verlassen.

Der Kommentar in https://github.com/golang/go/issues/32088#issuecomment -498690757 fasziniert mich jedoch:

Ich stimme zu, dass @ianlancetaylor das gesamte Toolchain-Verhalten ändert, wie in https://codereview.appspot.com/8203043/ vorgeschlagen, ist keine gute Idee. Ein unmittelbares Problem, das einem bei diesem Vorschlag in den Sinn kommt, wenn ein Datei-Handle als Sperrdatei verwendet wird. Wir verwenden dieses Verhalten.

@maruel , könnten Sie näher erläutern, wie Ihr Programm auf der Windows-spezifischen Interaktion zwischen Dateisperre und Dateilöschung oder Umbenennung beruht?

Wir in Chrome infra verwenden die Dateipräsenz als Sperrmechanismus. Ich würde sagen, dass Sie sich über diesen Anwendungsfall nicht zu viele Gedanken machen sollten. In der Praxis reicht die Semantik von O_CREATE + Global\\ Namespace ersetzt werden, was wir bereits in der Python-Codebasis tun.

Diese Lösung wird nicht erwähnt:

path := "delete-after-open"
fd, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
if err != nil { ... }
// defer statements are executed in LIFO
defer os.Remove(path)            // or defer os.Rename(path, path+"2")
if err != nil { ... }
defer fd.Close()

Es hat zwei Nachteile:

  • Close() ist nicht direkt nach Open()
  • Die Wiederherstellung des Fehlercodes ist komplizierter

@iwdgo Diese Lösung ist für die Verwendung in einem einzelnen Prozess vorgesehen. Der Großteil der obigen Diskussion dreht sich um den gleichzeitigen Zugriff von mehreren Prozessen. Das macht die Flagge wichtig.

Um @bcmills Re-Cap des Problems zu ergänzen, haben wir uns drei weitere plattformübergreifende Entwicklungstools angesehen:

Mingw-w64 hat es vor sieben Jahren zum Standard gemacht:
https://sourceforge.net/p/mingw-w64/code/HEAD/tree/stable/v3.x/mingw-w64-headers/include/ntdef.h#l858

Erlang hat es vor über sechs Jahren zum Standard gemacht: erlang/ otp@0e02f48

Python konnte es aufgrund von Einschränkungen der MSVC-Laufzeit zu dem Zeitpunkt, zu dem es in Betracht gezogen wurde, nicht übernehmen: https://bugs.python.org/issue15244

Auch ein zweites Golang-Mutter-Gewinde sah keine Einwände:
https://groups.google.com/d/topic/golang-nuts/aRvSo3iKvJY/discussion

Möchten Sie FILE_SHARE_DELETE als Standard für Open() festlegen? Unsere Diskussion sollte das nicht sein.

  1. Die Sorge von @alexbrainman ( #32088 (Kommentar) ) ... scheint zu sein, dass das Verhalten immer noch nicht mit POSIX übereinstimmt ...

Meine Hauptsorge ist, die Programme der Leute zu brechen. Ähnlich wie bei @minux unter https://codereview.appspot.com/8203043/#msg10

ein weiterer Grund: Leute die Windows benutzen akzeptieren, dass sie nicht umbenennen können oder
Das Entfernen einer geöffneten Datei ist die Norm und hat sich bereits daran gewöhnt.

Wir können das Verhalten des Go 1.0-Programms hier nicht stillschweigend ändern, vielleicht Leute
hängen tatsächlich davon ab.

Was ist mit dem Kompatibilitätsversprechen von Go 1.0 passiert? Wo steht in https://golang.org/doc/go1compat , dass es in Ordnung ist, das Verhalten beim Öffnen von Dateien zu ändern, wenn Sie Ihre Absicht bei go-nuts ankündigen?

Vielleicht können wir dieses Verhalten ändern, sobald wir Go 2 einführen? Können wir Module verwenden, um vorhandenen Code vor dem Brechen zu schützen? Liege ich falsch an der Annahme, dass die Module dafür entwickelt wurden?

Für mich persönlich scheint die Entscheidung klar zu sein: Angesichts der Tatsache, dass die Leute von Microsoft in diesem Thread die Änderung des Standardverhaltens unterstützen, um FILE_SHARE_DELETE ...

Wenn Microsoft in diesem Bereich für Sie die Autorität ist, sollten Sie sich ansehen, was Microsoft-Entwicklungstools tun.

Ich habe dieses Programm verwendet https://play.golang.org/p/4ZPmV6Df3SD ähnlich dem, was @mattn unter https://github.com/golang/go/issues/32088#issuecomment -493753714 gepostet hat

Microsoft (R) C/C++ Optimierungscompiler Version 19.16.27030.1 für x64
Urheberrecht (C) Microsoft Corporation. Alle Rechte vorbehalten.

Und wenn ich das Programm ausführe, konnte ich die Datei C:\Users\Alex\AppData\Local\Temp\a.txt nicht löschen, bis das Programm existierte.

Gleiches mit ähnlichem C#-Programm https://play.golang.org/p/SuM2iWYpZir, das ich kürzlich verwendet habe

Microsoft (R) Visual C#-Compiler-Version 2.10.0.0 (b9fb1610)
Urheberrecht (C) Microsoft Corporation. Alle Rechte vorbehalten.

Ähnlich ist dieses C-Programm https://play.golang.org/p/6HgxePzEW_W, das mit dem neuesten Mingw erstellt wurde

gcc (x86_64-win32-seh-rev0, erstellt vom MinGW-W64-Projekt) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.

haben den gleichen Effekt. Bei keinem dieser Tools ist das Flag FILE_SHARE_DELETE standardmäßig festgelegt.

Und persönlich sehe ich keine Vorteile dieser Änderung. Dazu gehören auch meine Go-Beiträge. Wir können immer noch keine ausführbaren Dateien löschen, während der Prozess ausgeführt wird. Wir werden immer noch Probleme beim Löschen von Verzeichnissen haben, wenn die aktuellen Verzeichnisse eines Prozesses dort festgelegt sind.

Alex

Möchten Sie FILE_SHARE_DELETE als Standard für Open() festlegen?

Die Absicht ist, dass os.Open standardmäßig FILE_SHARE_DELETE verwendet. Dieses https://golang.org/cl/194957 ist der Plan.

Alex

Meine Hauptsorge ist, die Programme der Leute zu brechen

Bisher kann niemand auf ein einziges Beispiel für ein Programm hinweisen, das kaputt gehen würde, weil es darauf beruht, einen Fehler zu erhalten, wenn versucht wird, eine mit Go geöffnete Datei umzubenennen/zu entfernen. Es gibt jedoch dokumentierte Fälle, in denen das aktuelle Verhalten Go-Apps unter Windows unterbricht.

Was ist mit dem Kompatibilitätsversprechen von Go 1.0 passiert?

Die Go-Dokumentation für os.Rename() & .Remove() enthält keine Informationen zu dieser Windows-Funktion, enthält jedoch 15 Erwähnungen anderer Windows-spezifischer Verhaltensweisen. Übrigens, Go 2 wurde ausgeliefert: https://blog.golang.org/go2-here-we-come

gcc (x86_64-win32-seh-rev0, erstellt vom MinGW-W64-Projekt) 7.3.0

Wessen C-Lib verwenden Sie mit gcc – vielleicht die von Microsoft? Mingw-w64 ist bei v6.0 und enthält FILE_SHARE_DELETE in FILE_SHARE_VALID_FLAGS.

Wie oben zu Python dokumentiert, hat die MSVC-Laufzeit in der Vergangenheit aus unbekannten Gründen bestimmte CreateFile()-Flagkombinationen nicht zugelassen. Ich weiß nicht, ob das immer noch der Fall ist, aber es kann der Grund sein, warum MS ihre C-Lib fopen() nicht geändert hat.

Ich sehe keine Vorteile dieser Änderung.

Die Vorteile wurden oben wiederholt von mehreren Personen erläutert; insbesondere das Zulassen von os.Rename() für eine geöffnete Datei.

Als Vorschlag markieren, weil die Diskussion nicht leicht zusammenläuft.

Um zu versuchen, das Thema und die Diskussion bisher zusammenzufassen:

  • Wenn auf Unix-Systemen ein Prozess eine Datei öffnet, kann ein zweiter Prozess diese Datei entfernen. Der ursprüngliche Prozess kann die Datei weiter verwenden (sie hat keinen Namen mehr), einschließlich Lese- und Schreibvorgänge, die erfolgreich sind. Der Dateiinhalt wird nicht von der Festplatte entfernt, bis der letzte offene Verweis verschwindet.

  • Wenn auf Windows-Systemen ein Prozess eine Datei öffnet, kann ein zweiter Prozess diese Datei standardmäßig _nicht_ entfernen. Eine Datei kann nur entfernt werden, wenn kein anderer Prozess sie geöffnet hat. Das FILE_SHARE_DELETE-Flag ändert dieses Verhalten: Wenn alle geöffneten Verweise auf die Datei mit FILE_SHARE_DELETE geöffnet wurden, kann ein anderer Prozess DeleteFile aufrufen, und es wird erfolgreich statt fehlschlagen.

Das Windows-Verhalten mit FILE_SHARE_DELETE scheint sich noch subtil von Unix zu unterscheiden. Auf der MSDN-Seite steht:

Die Funktion DeleteFile schlägt fehl, wenn eine Anwendung versucht, eine Datei zu löschen, bei der andere Handles für normale E/A geöffnet sind, oder als speicherabgebildete Datei (FILE_SHARE_DELETE muss beim Öffnen anderer Handles angegeben worden sein).

Die Funktion DeleteFile markiert eine Datei beim Schließen zum Löschen. Daher tritt das Löschen der Datei nicht auf, bis das letzte Handle für die Datei geschlossen wird. Nachfolgende Aufrufe von CreateFile zum Öffnen der Datei schlagen mit ERROR_ACCESS_DENIED fehl.

Das heißt, die Datei _name_ wird nicht aus dem Dateisystem entfernt, bis die offenen Verweise verschwinden. Dies unterscheidet sich von Unix, wo der Name verschwindet, bevor die offenen Referenzen geschlossen werden. Wenn Sie also die Datei entfernen, um eine Datei gleichen Namens neu zu erstellen, funktioniert das unter Unix, aber nicht unter Windows, nicht einmal mit FILE_SHARE_DELETE.

Der ursprüngliche Vorschlag war, syscall.Open so zu ändern, dass dieses Flag immer gesetzt wird. Angesichts der Tatsache, dass syscall in der Nähe der Kernel-Schnittstelle sein soll, scheint das Hinzufügen dieses Flags fehl am Platz. Aber wir könnten stattdessen überlegen, ob es während os.Open / os.OpenFile gesetzt werden soll.

@alexbrainman hat argumentiert, dass Unix und Windows unterschiedlich sind, sie würden auch dann unterschiedlich bleiben, wenn wir dieses Flag setzen, und daher sollten wir die Sache nicht verwirren, indem wir diese Änderung hinter dem Rücken der Benutzer vornehmen.

@jstarks von Microsoft sagt, dass Microsoft es vorziehen würde, dass wir FILE_SHARE_DELETE automatisch setzen und dass die "neueste Version" von Windows (unklar welche oder ob sie veröffentlicht wird) DeleteFile so ändert, dass die Unix-Semantik des Namens bei der Rückkehr von DeleteFile verschwindet. Wenn wir dies tun würden, würden wir unter dem neuesten Windows wirklich das gleiche Verhalten unter Unix und Windows erhalten.

@networkimprov argumentiert, dass wir die Änderung vornehmen sollten und dass es keine tatsächlichen Beispiele für Programme gibt, die kaputt gehen würden.

@alexbrainman scheint

@mattn hat auch vorgeschlagen, dass wir das Flag nicht automatisch setzen sollten, zum Teil, weil es sich (zumindest bis jeder das neueste Windows verwendet) immer noch von Unix unterscheidet.

Insgesamt versucht Paket os, eine portable API bereitzustellen, und es scheint, als ob - insbesondere bei der Windows-Änderung - das automatische Setzen des Flags dabei helfen würde. Es gibt andere Flags, die wir in os.Open automatisch setzen, um das Verhalten für Benutzer weniger überraschend zu machen, insbesondere O_CLOEXEC (close-on-exec). Jedes Programm, das unter Windows abbricht, weil dieses Flag in os.Open gesetzt wird, würde auch unter Unix zwangsläufig abbrechen, oder?

Vor allem, da mindestens ein Ingenieur bei Microsoft sagt, dass wir es einstellen sollten, scheint es in Ordnung zu sein, es im Paket os einzustellen. Leute, die das Flag nicht setzen wollen, können trotzdem auf das Paket syscall zurückgreifen.

@alexbrainman und @mattn , nehmen wir an, wir setzen das Flag in os.Open. Wir wissen, dass einige Programme besser funktionieren würden. Haben Sie konkrete Beispiele für echte (oder wahrscheinliche) Programme, die kaputt gehen würden? Wären diese Programme unter Unix nicht schon kaputt? Danke.

@rsc , danke für deinen Beitrag. Das Aktivieren im Paket "os" funktioniert für mich. Wenn dies übernommen wird, sollte der Vollständigkeit halber ein Flag syscall.Open() zum Aktivieren von FILE_SHARE_DELETE bereitgestellt werden.

Um Ihre Zusammenfassung zu verdeutlichen, sind Prozessgrenzen kein Faktor; die Effekte sind innerhalb eines einzigen Prozesses gleich. Und das Flag wirkt sich auch auf das Umbenennen von Dateien aus; mit dem Flag wird es im Gegensatz zum Löschen von Dateien sofort abgeschlossen. (Und das ermöglicht eine Problemumgehung für die Verfügbarkeit von Dateinamen unmittelbar nach dem Löschen.)

Danke @networkimprov. Ja, ich verstehe, dass Prozessgrenzen nicht unbedingt relevant sind; es macht die Situationen nur einfacher zu beschreiben.

Ich habe den Titel geändert und den Aktionsplan im Hefttext überarbeitet:

a) os.Create/Open/OpenFile() sollte file_share_delete unter Windows immer aktivieren,
b) syscall.Open() unter Windows sollte ein Flag akzeptieren, das file_share_delete aktiviert, und
c) syscall unter Windows sollte eine Konstante für das neue Flag exportieren.

Die Dokumentation zu os.Remove() sollte auch beachten, dass man Folgendes tun muss, um einen Dateinamen nach dem Löschen einer geöffneten Datei unter Windows wiederzuverwenden: os.Rename(path, unique_path); os.Remove(unique_path) .

Die Möglichkeit, dass ein Benutzer eine exklusive Verarbeitung unter Verwendung des aktuellen os.Open-Verhaltens von Go implementiert, kann nicht geleugnet werden.

Es gibt jedoch dokumentierte Fälle, in denen das aktuelle Verhalten Go-Apps unter Windows unterbricht.

Was ist das? Wie lauten die Ausgabenummern? Und was meinst du mit dem Wort break ? Wann sind sie kaputt gegangen?

Wessen C-Lib verwenden Sie mit gcc – vielleicht die von Microsoft? Mingw-w64 ist bei v6.0 und enthält FILE_SHARE_DELETE in FILE_SHARE_VALID_FLAGS.

Ich weiß nicht. Ich habe gerade die Datei x86_64-7.3.0-release-win32-seh-rt_v5-rev0.7z aus dem Internet heruntergeladen. Du kannst danach googeln. Es ist die Version 7.3.

Ich sehe keine Vorteile dieser Änderung.

Die Vorteile wurden oben mehrfach erläutert, ...

Sie haben das Wort personally aus Ihrem Angebot weggelassen. Ich rede über meine eigenen Bedürfnisse. Und dazu gehören auch meine Go-Projektbeiträge.

Um zu versuchen, das Thema und die Diskussion bisher zusammenzufassen:

Sie haben nicht gesagt, dass Microsoft-Entwicklertools unter Windows dieses Flag standardmäßig nicht bereitstellen. Siehe meinen Kommentar https://github.com/golang/go/issues/32088#issuecomment -531713562

Du hast auch meinen Kommentar zur Go 1-Kompatibilität ignoriert

Was ist mit dem Kompatibilitätsversprechen von Go 1.0 passiert? Wo steht in https://golang.org/doc/go1compat , dass es in Ordnung ist, das Verhalten beim Öffnen von Dateien zu ändern, wenn Sie Ihre Absicht bei go-nuts ankündigen?

Wie passt diese Änderung in das Kompatibilitätsversprechen von Go 1.0?

Insgesamt versucht Paket os, eine portable API bereitzustellen, und es scheint, als ob - insbesondere bei der Windows-Änderung - das automatische Setzen des Flags dabei helfen würde.

Ich stimme zu, dass diese Änderung auf Leute abzielt, die Unix-Software auf Windows portieren.

Leider zu Lasten der Windows-Benutzer. Diese Änderung wird für Windows-Benutzer und -Entwickler überraschend sein, da keine anderen Programme oder Tools unter Windows auf diese Weise funktionieren. Vielleicht in Zukunft, aber noch nicht.

Und selbst für Leute, die Unix-Software auf Windows portieren, macht diese Änderung IMHO ziemlich schlechte Arbeit. Siehe We still won't be able to delete executable files while process is running. We will still have problems deleting directories if any process have their current directories set there. Teil meines Kommentars https://github.com/golang/go/issues/32088#issuecomment -531713562

Es gibt andere Flags, die wir in os.Open automatisch setzen, um das Verhalten für Benutzer weniger überraschend zu machen, insbesondere O_CLOEXEC (close-on-exec). Jedes Programm, das unter Windows abbricht, weil dieses Flag in os.Open gesetzt wird, würde auch unter Unix zwangsläufig abbrechen, oder?

Ich weiß nicht, was du hier meinst. O_CLOEXEC unter Windows bedeutet, zu verhindern, dass Dateihandles in den untergeordneten Prozess gelangen. Und O_CLOEXEC wird immer in os.Open unter Windows gesetzt. So kann auf keine mit os.Open geöffnete Datei durch den untergeordneten Prozess unter Windows zugegriffen werden. Na und? Es klingt vernünftig.

Wären diese Programme unter Unix nicht schon kaputt?

Ich verstehe deine Frage nicht.

Haben Sie konkrete Beispiele für echte (oder wahrscheinliche) Programme, die kaputt gehen würden?

Ich weiß nicht, ob ich solche Programme habe. Es ist unmöglich zu sagen. Ich erinnere mich nicht an alle Programme, die ich geschrieben habe. Ich erinnere mich nicht, was sie tun.

Aber ich könnte mir vorstellen, dass ein Windows-Dienst eine vordefinierte Datei öffnet, sagen wir c:\mysvc.txt , und sie geöffnet hält. Stellen Sie sich ein anderes Programm vor, das überprüft, ob der Dienst aktiv ist, und den Dienst bei Bedarf neu startet. Dieses andere Programm kann einfach versuchen, c:\mysvc.txt löschen, und wenn die Datei weg ist, kann es sicher davon ausgehen, dass der Dienstprozess tot ist.

Außerdem kann ich mir vorstellen, dass einige Programme verhindern möchten, dass Benutzer ihre Dateien löschen oder verschieben - https://stackoverflow.com/questions/11318663/prevent-a-user-from-deleting-moving-or-renaming-a-file

Alex

Hier ist eine Datenpunkt-Neubereitstellung von Go unter Windows:
Win8 wurde vor 7 Jahren ausgeliefert.
Dieser Go-Fehler, der Win8+ betrifft, wurde erst vor 5 Monaten gemeldet: #31528

@rsc Jedes Programm, das beim Versuch, eine mit Go geöffnete Datei umzubenennen/zu entfernen, einen Fehler erwartet, ist unter Unix defekt. Zum Beispiel das Szenario c:\mysvc.txt Alex.

Wenn man unter Windows entwickelt und unter Linux/etc (oder umgekehrt) bereitstellt, könnte dies eine Fehlerquelle sein.

Unser Anwendungsfall ist, dass wir einen Logger haben, der sich in eine Datei protokolliert.
Protokolldatei unterstützt Rotation (zB nächster Schreibvorgang, wenn Protokolldatei > maxSize ist, dann rotieren).
Wir haben auch Reader, die diese Dateien öffnen und geöffnet halten, während sie gelesen werden.

Ohne die Möglichkeit, FILE_SHARE_DELETE , können wir keine Rotation (Umbenennen und/oder Löschen) durchführen, solange aktive Leser vorhanden sind.

@mattn :

Die Möglichkeit, dass ein Benutzer eine exklusive Verarbeitung unter Verwendung des aktuellen os.Open-Verhaltens von Go implementiert, kann nicht geleugnet werden.

Das mag sein, aber ein solcher Code ist unter Unix sowieso falsch. Package os soll eine portable Schnittstelle sein. Auch interessieren uns eher _tatsächliche_ Programme als an Möglichkeiten.

@alexbrainman :

Sie haben nicht gesagt, dass Microsoft-Entwicklertools unter Windows dieses Flag standardmäßig nicht bereitstellen. Siehe meinen Kommentar #32088 (Kommentar)

Ja, aber das ist C; wir sprechen über Go. Wir ahmen die C-APIs im Allgemeinen nicht nach. Wir versuchen, eine weitgehend portierbare Abstraktion im Paket os bereitzustellen. Der Punkt an O_CLOEXEC war, dass auf Unix-Systemen os.Open O_CLOEXEC setzt, obwohl es nicht standardmäßig im entsprechenden C-Aufruf gesetzt ist. Wir _tun_ versuchen, nützliche Standardeinstellungen bereitzustellen, die sich auf allen Systemen ungefähr gleich verhalten.

Was die Kompatibilität mit Go 1 angeht, scheint es in Ordnung zu sein, ein Corner-Case-Verhalten auf einem Betriebssystem zu ändern, um es besser mit anderen Betriebssystemen auszurichten. Wir versprechen nicht, alle systemübergreifenden Inkompatibilitäten für alle Zeiten zu erhalten.

Windows-Benutzer, die auf dem Window-spezifischen Verhalten bestehen, haben immer die Möglichkeit, das Paket syscall zu verwenden, was deutlich machen würde, dass das erreichte Verhalten wirklich nur für Windows gilt.

Haben Sie noch einmal konkrete Beispiele für echte Programme, die kaputt gehen würden?

@ cpuguy83 , danke für den realen Anwendungsfall eines Programms, dem geholfen würde.

@rsc Wie Sie sagen, habe ich die Breaking-Effekte von FILE_SHARE_DELETE noch nicht herausgefunden. Ebenso wurde keine Bestätigung gefunden, dass logrotate durch diese Änderung implementiert werden kann.

Sobald Go jedoch diese Änderung enthält, die die Datei löschen kann, erwartet der Benutzer dieses Verhalten, obwohl Go durch diese Änderung Logrotate unter Windows nicht implementieren kann. Daher müssen wir uns diese Änderung gut überlegen. Grundsätzlich kann Windows keine Dateien löschen, die nicht mit FILE_SHARE_DELETE gekennzeichnet sind. Benutzer denken möglicherweise, dass diese Änderung es Go ermöglicht, alle Dateien zu löschen. Insbesondere können von os.NewFile mit handle erstellte Dateien Methoden der os.File-Struktur manipulieren, obwohl dieses Flag nicht gesetzt ist. Der Programmierer sollte wissen, dass die Datei unter Windows gelöscht werden kann oder nicht, denke ich. Ich bevorzuge einen Mechanismus, der es ermöglicht, FILE_SHARE_DELETE per Flag für os.OpenFile anstelle des Standardwerts zu übergeben. Ich denke, das Standardverhalten sollte dem des Betriebssystems folgen.

Ja, aber das ist C; wir sprechen über Go.

Und C# auch. Ich habe es nicht untersucht, aber ich bin mir ziemlich sicher, dass sich jedes andere Entwicklungstool unter Windows so verhält.

Was die Kompatibilität mit Go 1 angeht, scheint es in Ordnung zu sein, ein Corner-Case-Verhalten auf einem Betriebssystem zu ändern, um es besser mit anderen Betriebssystemen auszurichten.

Es ist Eckfall für Nicht-Windows-Benutzer. Für Windows-Benutzer ist dieses Verhalten Standard.

Haben Sie noch einmal konkrete Beispiele für echte Programme, die kaputt gehen würden?

Betrachten Sie mein obiges Service-Beispiel konkret.

@ cpuguy83 , danke für den realen Anwendungsfall eines Programms, dem geholfen würde.

@cpuguy83 kannst du mehr zu deinem Problem sagen. Ich würde gerne sehen, wie diese Änderung Ihr Problem löst, daher würde ich gerne etwas echten Code sehen. Wenn Sie ein kleines Programm bereitstellen können, das jetzt defekt ist, aber funktioniert, sobald dieses Problem behoben ist, würden Sie dies begrüßen. Es muss nicht gebaut werden, aber es sollte zumindest genug bieten, damit jeder urteilen kann. Danke schön.

Grundsätzlich kann Windows keine Dateien löschen, die nicht mit FILE_SHARE_DELETE gekennzeichnet sind. Benutzer denken möglicherweise, dass diese Änderung es Go ermöglicht, alle Dateien zu löschen.

Ich stimme zu, das ist ein guter Punkt. Es konnten nur Dateien gelöscht werden, die von Go-Programmen geöffnet wurden. Alle anderen Dateien, die von Nicht-Go-Programmen geöffnet wurden, bleiben jedoch weiterhin unlöschbar. Das macht os.Remove unvorhersehbar - manchmal funktioniert es und manchmal nicht.

Alex

Ich habe Code, der ein gepatchtes syscall.Open() aufruft, das geöffnete Dateien umbenennt. So implementieren Sie die Protokollrotation; Es klappt.

// several processes or goroutines do this
   fd, err := os.OpenFile("log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, ...)
   _, err = fd.Write(log_entry) // one or more times
   err = fd.Close()

// log rotator process does this
   err := os.Rename("log", "log_old") // active writers not disturbed
   fmt.Println(err) // "sharing violation" without FILE_SHARE_DELETE

Aber das musste dir niemand sagen :-/

Natürlich kann eine os.File von os.NewFile() viele andere Eigenschaften haben als die von os.Create/Open/OpenFile(), das ist ein Feature, keine Überraschung.

Sie behaupten, dass das Verhalten von Microsoft C fopen() das Standardverhalten von Windows ist; das ist nicht wahr. Es gibt keinen Standardfreigabemodus von CreateFile(); es ist nicht FILE_SHARE_READ | FILE_SHARE_WRITE .

Sie behaupten, dass bereitgestellte Windows-Programme im Allgemeinen davon ausgehen, dass __Programme anderer Hersteller__ Dateien immer auf eine bestimmte Weise öffnen. Wenn dies der Fall wäre, hätte Microsoft uns nicht aufgefordert, file_share_delete standardmäßig zu aktivieren.

@networkimprov

Aber das musste dir niemand sagen :-/

Ich möchte wissen, dass der externe Prozess die Datei in allen Fällen korrekt entfernen und umbenennen kann.

Was ich wissen möchte ist: Nach dem Einfügen dieser Änderung wird die Protokolldatei von Go ausgegeben, das vom externen Prozess ausgeführte Logrotate funktioniert einwandfrei und es funktioniert ohne Fehler als produktionsbereit.

@alexbrainman

Leider ist der Code kompliziert, aber das ist echter Code aus der realen Welt: https://github.com/moby/moby/blob/master/daemon/logger/loggerutils/logfile.go

Die vorgeschlagene Abschwächung besteht derzeit darin, nur os.OpenFile und syscall.Open zu teilen: https://github.com/moby/moby/pull/39974/files

Um es klar zu sagen, würde es ausreichen, nur die Option zu haben, FILE_SHARE_DELETE von OpenFile oder sogar zu syscall.Open zu übergeben, um unseren Fall zu bearbeiten.

Leider ist der Code kompliziert, aber das ist echter Code aus der realen Welt: https://github.com/moby/moby/blob/master/daemon/logger/loggerutils/logfile.go

Die vorgeschlagene Abschwächung besteht derzeit darin, nur os.OpenFile und syscall.Open zu teilen: https://github.com/moby/moby/pull/39974/files

@cpuguy83 danke für den

Leider bietet mein kurzer Blick darauf nicht genügend Informationen, um zu beurteilen, ob dieses aktuelle Problem die Lösung ist. Ich müsste mit Repro beginnen (wahrscheinlich dies https://github.com/moby/moby/issues/39274#issuecomment-497966709) und von dort nehmen. Ich bin mir nicht sicher, wann ich dafür Zeit habe. Wenn Sie einen besseren Vorschlag als meinen Plan haben, lassen Sie es mich wissen.

Alex

Unten ist eine funktionierende Demo der Standard-Practice-Log-Rotation, mit 100 Goroutinen, die bei jedem Öffnen der Log-Datei 50 Zeilen in Intervallen von 0,1 bis 2 Sekunden protokollieren, und einer anderen Goroutine, die das Log in 1-Minuten-Intervallen rotiert. Ich habe dies gestern mehrere Stunden lang auf einem Win7-Laptop ohne Fehler ausgeführt.

Es wurde mit einem Patch für syscall.Open() erstellt, der FILE_SHARE_DELETE aktiviert; es scheitert sonst. Ohne dieses Flag könnte man sich ein komplexeres Protokollierungsschema ausdenken, aber es gibt viele andere Verwendungen dafür; Mein eigener Code benennt geöffnete Dateien aus verschiedenen Gründen um.

@rsc , ich glaube, damit ist der Fall für Ihren Vorschlag abgeschlossen, falls noch Zweifel bestehen. (Und wie oben erwähnt, habe ich wiederholt in golang-dev und golang-nuts nach Projekten gefragt, die auf dem aktuellen Verhalten basieren, ohne Ergebnisse.)

package main

import (
   "fmt"
   "os"
   "math/rand"
   "syscall"
   "time"
)

const kLogFile = "winrotate"

func main() {
   syscall.Open_FileShareDelete = true
   rand.Seed(time.Now().UnixNano())

   for a := 0; a < 100; a++ {
      go runLog()
   }

   fmt.Println("rotating to "+ kLogFile +"N.txt")
   for a := 0; true; a++ {
      if a >= 5 {
         a = 0
      }
      time.Sleep(60 * time.Second)
      err := os.Rename(kLogFile +".txt", kLogFile + string('0'+a) +".txt")
      if err != nil {
         fmt.Println(err)
         os.Exit(1)
      }
   }
}

const kLineVal = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func runLog() {
   aLine := make([]byte, 102)
   for {
      aFd, err := os.OpenFile(kLogFile +".txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
      if err != nil {
         fmt.Println(err)
         return
      }
      for _, aV := range kLineVal {
         for a := range aLine {
            aLine[a] = byte(aV)
         }
         aEnd := aV - ('z' - 100) // limit line len to 100
         copy(aLine[aEnd:], []byte{'\r','\n'})
         _, err = aFd.Write(aLine[:aEnd + 2])
         if err != nil {
            fmt.Println(err)
            return
         }
         time.Sleep(time.Duration(100 + rand.Intn(1900)) * time.Millisecond)
      }
      err = aFd.Close()
      if err != nil {
         fmt.Println(err)
         return
      }
   }
}

Patch auf syscall_windows.go:

diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index de05840..e1455d5 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -245,6 +245,8 @@ func makeInheritSa() *SecurityAttributes {
    return &sa
 }

+var Open_FileShareDelete = false
+
 func Open(path string, mode int, perm uint32) (fd Handle, err error) {
    if len(path) == 0 {
        return InvalidHandle, ERROR_FILE_NOT_FOUND
@@ -270,6 +272,9 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
        access |= FILE_APPEND_DATA
    }
    sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
+   if Open_FileShareDelete {
+       sharemode |= FILE_SHARE_DELETE
+   }
    var sa *SecurityAttributes
    if mode&O_CLOEXEC == 0 {
        sa = makeInheritSa()

@networkimprov Die Datei wird nicht von einem externen Prozess umbenannt. Wenn das Umbenennen der Datei im gleichen Prozess erfolgt, gibt es andere Möglichkeiten, dies zu implementieren.

https://github.com/mattn/go-sizedwriter/blob/master/_example/example.go#L14

Unten ist eine funktionierende Demo der Standard-Practice-Log-Rotation

Vielen Dank für Ihr Beispiel, @networkimprov . Ich kann jetzt sehen, was Sie zu tun versuchen.

Das einzige Problem mit Ihrem Code besteht darin, dass, wenn ein externer Prozess Dateien, in die Sie schreiben, ohne FILE_SHARE_DELETE öffnet, Sie das gleiche Problem wie jetzt haben, unabhängig von den Änderungen, die wir in Go vornehmen.

@cpuguy83 Ich werde mir Ihr Problem nicht @networkimprov Beispiel mir ein Bild davon gibt, was er versucht machen.

Alex

Alex, man kann den Umbenennungsversuch wiederholen, wenn der Zugriff von außen erlaubt ist, oder die aktive Protokolldatei einschränken, wenn nicht.

Mattn, das Umbenennen von Rotieren erfolgt normalerweise in einem separaten Prozess.

Hier scheint es keinen klaren Konsens zu geben. Die Entwickler mit Unix-Hintergrund scheinen dies zu befürworten, aber zwei unserer aktivsten Windows-Entwickler ( @alexbranman und @mattn) sind es nicht. Die Änderung würde auch nur die neueste Version von Windows wirklich vereinheitlichen, die das neue Unix-ähnliche Verhalten für FILE_SHARE_DELETE hat.

Es könnte sich lohnen, dieses Thema in einigen Jahren noch einmal aufzugreifen, um zu sehen, wie weit verbreitet das neue Flag-Verhalten ist und ob sich andere Sprachen zu einem gemeinsamen Verhalten angenähert haben. Wenn jemand in etwa zwei Jahren eine neue Ausgabe einreichen möchte, um dies zu überdenken, wäre das in Ordnung.

Angesichts des fehlenden Konsens scheint dies jedoch vorerst ein wahrscheinlicher Rückgang zu sein .

Eine Woche offen für letzte Kommentare.

Gibt es Streit, nur die Option zur Verfügung zu stellen?

Wenn wir mehr Stimmen zum Mitmachen suchen, wäre ich definitiv dafür, _etwas_ zu tun. Im Moment besteht die einzige Lösung darin, buchstäblich eine Menge Code aus der Standardbibliothek von Go zu kopieren, eine Zeile zu ändern und diese Abzweigung dann für immer zu pflegen. Jede Implementierung eines Log-Monitors oder Live-"Tails" scheint dies schließlich zu tun.

Ein Beispiel finden Sie unter https://github.com/elastic/beats/blob/master/libbeat/common/file/file_windows.go#L85 -L103

Wenn ich richtig gefolgt bin, besteht dieser Vorschlag eigentlich aus zwei Teilen:

  1. Erlaube die Verwendung des Flags FILE_SHARE_DELETE beim Öffnen einer Datei -
    Die Implementierung sollte einfach und sicher sein, der Entwickler müsste dies explizit tun
    Fordern Sie diesen Modus an, wenn Sie eine neue Datei öffnen
  2. Aktivieren Sie dieses Flag standardmäßig - kann riskant sein und wird nur gut unterstützt
    bei Verwendung der letzten Windows 10 Build.

Wenn alle bei 1 zustimmen würden, können wir das Flag vielleicht einfach zulassen, wenn Entwickler
Fordern Sie es vorerst ausdrücklich an und besuchen Sie 2 in ein paar Jahren erneut.

Am Mittwoch, 2. Oktober 2019, 19:32 Uhr schrieb Mark Dascher, [email protected] :

Wenn wir mehr Stimmen zum Mitmachen suchen, wäre ich definitiv dafür
etwas zu tun. Im Moment besteht die einzige Lösung darin, a buchstäblich zu kopieren
eine Menge Code aus der Standardbibliothek von Go, eine Zeile ändern und dann
behalte diese Gabel für immer bei. Jede Implementierung eines Log-Monitors oder Live
"tail" scheint dies schließlich zu tun.

Ein Beispiel finden Sie unter
https://github.com/elastic/beats/blob/master/libbeat/common/file/file_windows.go#L85 -L103


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/golang/go/issues/32088?email_source=notifications&email_token=ABNEY4VFQLSYVI66ENT6G4LQMTLJ7A5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXH14ORDNP3
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/ABNEY4U5L3WFZYNIUOSEY2TQMTLJ7ANCNFSM4HNPNYIA
.

Definitiv für _mindestens_ 1. (Erlaube die Verwendung des Flags FILE_SHARE_DELETE beim Öffnen einer Datei)

Nur um meinen vorherigen Vorschlag zu wiederholen und mit der Beispielimplementierung fortzufahren :

Das syscall.FILE_SHARE_DELETE Flag würde gut in den os.OpenFile flag Parameter von os.OpenFile passen und würde einen trivialen Mechanismus bieten, um dieses Verhalten bei Bedarf zu aktivieren. Es kollidiert nicht mit anderen os.O_* Flags unter Windows (und dies kann erzwungen/konstruiert werden) und bietet eine idiomatische Möglichkeit, das systemspezifische Dateiöffnungsverhalten anzugeben (sofern os ' s POSIX-orientierte Schnittstelle kann unter Windows als idiomatisch betrachtet werden). Dies ist die gleiche Route, die bereits verwendet wird, um systemspezifisches Dateiöffnungsverhalten auf POSIX-Plattformen (zB syscall.O_DIRECTORY unter Linux) zu übergeben.

Selbst wenn die Entscheidung getroffen wird, es nicht standardmäßig zu aktivieren (was meiner Meinung nach der richtige Anruf ist), stimme ich zu, dass das Flag seine Anwendungsfälle hat (einschließlich der von @networkimprov hervorgehobenen) und dass es nützlich wäre, es zu sein Sie können es einschalten, ohne auf CreateFileW Aufrufe und das Kopieren von Boilerplate-Code zurückgreifen zu müssen.

Bitte beachten Sie die obige Alternative [1], die es Entwicklern ermöglicht, bei Bedarf FILE_SHARE_DELETE zu setzen und gespaltene Teile des Go-Standardbibliothekscodes zu verhindern.

__Rust__ setzt dieses Flag auch standardmäßig und ermöglicht es Ihnen, jede der FILE_SHARE_*-Optionen _auszuschalten_.
https://doc.rust-lang.org/std/os/windows/fs/trait.OpenOptionsExt.html

@rsc könnte ich fragen, welche der gegen den Vorschlag

@networkimprov Nachdem Sie den gesamten Vorschlag und die Diskussion gelesen haben, müssen Sie dies meiner Meinung nach schließen und ein neues Problem explizit zum Hinzufügen eines neuen Windows-spezifischen Flags zum ossyscall-Paket erneut öffnen. Dadurch würde sichergestellt, dass das neue Verhalten ein Opt-in und kein Opt-out ist. Der aktuelle Vorschlag impliziert eine Änderung des bestehenden Codes, was die Leute beunruhigt.

@rsc könnte ich fragen, welche der gegen den Vorschlag

Es tut mir leid, aber so funktioniert das Angebotsverfahren nicht. Es reicht nicht aus, die Argumente anderer zu "widerlegen". "Ziel des Vorschlagsverfahrens ist es, zeitnah einen allgemeinen Konsens über das Ergebnis zu erzielen." Über den weiteren Weg gibt es hier keinen klaren Konsens. Es wurden technische Argumente vorgebracht , die wichtige Go-Entwickler, die wesentliche Beiträge zur Windows-Portierung @alexbrainman und @mattn), nicht überzeugen konnten. Abgesehen von dem Mangel an klarem Konsens gibt es heute kein klares Anzeichen für die Dringlichkeit, etwas zu tun: Go funktionierte unter Windows fast 10 Jahre lang, bevor dieses Problem eingereicht wurde. Alles in Ruhe zu lassen bedeutet, dass Go weiterhin so gut funktioniert wie immer.

Ich habe Nr. 34681 eingereicht, um eine einfachere Möglichkeit zum Öffnen von Dateien mit FILE_SHARE_DELETE zu bieten, falls diese (noch wahrscheinlich) abgelehnt wird. Es schien hilfreicher, einen neuen Thread zu eröffnen, der sich auf diese Idee beschränkt, als diesen, der sehr lang geworden ist, fortzusetzen.

@rsc , bevor du dies

Zu Beginn dieser Diskussion war er gegen ein neues os.OpenFile()-Flag, das file_share_delete setzt, aus den gleichen Gründen, aus denen er mit Ihrem os.Create/Open/OpenFile()-Vorschlag nicht einverstanden war. Er befürchtet, dass andere Programme davon ausgehen, dass niemand jemals Dateien auf diese Weise öffnet, weil MSVC fopen() dies nicht kann. Diese (noch nicht spezifizierten) Programme werden daher Go-Programme brechen, die das Flag setzen.

Alex, man kann den Umbenennungsversuch wiederholen, wenn der Zugriff von außen erlaubt ist, ...

Wenn Sie bereit sind, die Umbenennung in einer Schleife durchzuführen, müssen Sie nichts am Go-Repo-Code ändern. Ihr Programm wird so gut funktionieren, wie es jetzt funktioniert.

Im Moment besteht die einzige Lösung darin, buchstäblich eine Menge Code aus der Standardbibliothek von Go zu kopieren, eine Zeile zu ändern und diese Abzweigung dann für immer zu pflegen.

Ich denke, das Kopieren von Code in ein separates Paket ist in Ordnung. Bei der Untersuchung von https://github.com/moby/moby/pull/39974 kam mir die gleiche Idee. Ich glaube nicht, dass es viel Code gibt, der gewartet werden muss. Tatsächlich habe ich genau das implementiert

https://github.com/alexbrainman/goissue34681

Fühlen Sie sich frei zu kopieren oder zu verwenden, wie es ist. Vielleicht gibt es so viel Interesse an dieser Funktionalität, dass Sie tatsächlich ein richtiges Paket erstellen, das von anderen geteilt und verwendet werden kann. Auf diese Weise können Sie es auf dem neuesten Stand halten und Fehler beheben.

@rsc , bevor du dies

Bitte versuche

https://github.com/alexbrainman/goissue34681

Erste. Wenn Sie aus irgendeinem Grund nicht zufrieden sind, können wir das Hinzufügen neuer Funktionen zu Go Repo besprechen.

Danke schön.

Alex

Ich bin wirklich enttäuscht von dieser Antwort.

Das Kopieren dieser großen Menge an Code, die größtenteils noch nicht einmal verstanden wird (wie
in warum tut dies, was es tut), nur damit wir eine einzelne Option hinzufügen können
dass das System selbst unterstützt, nur das Go, wahrscheinlich nehme ich nicht an
nicht einmal absichtlich, bietet keine Möglichkeit, die Option auch nur an . weiterzugeben
syscall.Open scheint eine lächerliche Situation zu sein.

Warum muss ich syscall.Open neu schreiben, um diese Option zu übergeben?

Am Samstag, 5. Oktober 2019 um 18:43 Uhr schrieb Alex Brainman [email protected] :

Alex, man kann den Umbenennungsversuch wiederholen, wenn der Zugriff von außen erlaubt ist, ...

Wenn Sie bereit sind, die Umbenennung zu wiederholen, müssen Sie nichts ändern
im Go-Repo-Code. Ihr Programm wird so gut funktionieren, wie es jetzt funktioniert.

Im Moment besteht die einzige Lösung darin, buchstäblich eine Menge Code aus dem zu kopieren
Gos Standardbibliothek, ändern Sie eine Zeile und behalten Sie diese Verzweigung dann für immer bei.

Ich denke, das Kopieren von Code in ein separates Paket ist in Ordnung. Während der Untersuchung
moby/moby#39974 https://github.com/moby/moby/pull/39974 Das gleiche habe ich auch
Idee. Ich glaube nicht, dass es viel Code gibt, der gewartet werden muss. Tatsächlich bin ich
genau das umgesetzt

https://github.com/alexbrainman/goissue34681

Fühlen Sie sich frei zu kopieren oder zu verwenden, wie es ist. Vielleicht gibt es ja so viel Interesse an
Mit dieser Funktionalität erstellen Sie tatsächlich ein geeignetes Paket, das geteilt werden kann
und von anderen genutzt. Auf diese Weise können Sie es auf dem neuesten Stand halten und Fehler beheben.

@rsc https://github.com/rsc , bevor Sie dies ablehnen, hören wir was
Alex denkt an deinen O_ALLOW_DELETE-Vorschlag.

Bitte versuche

https://github.com/alexbrainman/goissue34681

Erste. Wenn Sie aus irgendeinem Grund nicht zufrieden sind, können wir das Hinzufügen neuer besprechen
Funktionalität zum Go-Repo.

Danke schön.

Alex


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/golang/go/issues/32088?email_source=notifications&email_token=AAGDCZXHULQEMHAPTO6ZUJTQNFGE7A5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTI-06WS
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAGDCZWYUNMCTAGO567AV73QNFGE7ANCNFSM4HNPNYIA
.

>

  • Brian Goff

Ich bin wirklich enttäuscht von dieser Antwort.

Es tut mir leid, dass Sie so empfinden. Aber haben Sie tatsächlich versucht, mein Paket zu verwenden?

Alex

@rsc , da Alex auch ein os.OpenFile() Flag ablehnt, sollten wir nichts tun?

Wie wäre es, diese Funktion hinter ein Build-Flag zu setzen?

Ob "Go fast 10 Jahre lang unter Windows einwandfrei funktionierte", war dies definitiv nicht, falls Sie eine geöffnete Datei umbenennen mussten. (Es war in den letzten 7 Jahren auch auf Windows 8/10-Laptops defekt.)

Ich habe meinen eigenen Fork von os.OpenFile und syscall.Open bereits in moby/moby.

Warum sind wir hier so abweisend?

Am Dienstag, 8. Oktober 2019 um 01:47 Uhr schrieb Alex Brainman [email protected] :

Ich bin wirklich enttäuscht von dieser Antwort.

Es tut mir leid, dass Sie so empfinden. Aber haben Sie tatsächlich versucht, mein Paket zu verwenden?

Alex


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/golang/go/issues/32088?email_source=notifications&email_token=AAGDCZRV72GY4IJQJVJWMYTQNRCIHA5CNFSM4HNPNYIKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTORDN5WW2EAT
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAGDCZRNYSMIE6BX77XJVWDQNRCIHANCNFSM4HNPNYIA
.

>

  • Brian Goff

Ich würde vorschlagen, dass dieser spezielle Vorschlag abgelehnt wird. Wir werden nicht eine Reihe von TOCTOU-Sicherheitsfehlern für Windows-Benutzer einführen, die sich auf das vorhandene Verhalten von os.OpenFile verlassen haben.

Die größere Frage hier lautet: "Wie können wir Go-Benutzern die große Vielfalt interessanter Flags für die Windows-Funktionen CreateFile und NtCreateFile zugänglich machen?" Ich gehe davon aus, dass wir diese in verschiedenen Vorschlägen ansprechen können, aber sicherlich nicht, indem wir sie alle standardmäßig aktivieren, wie dies hier suggeriert.

@zx2c4 hast du den ganzen Thread gelesen? Wir konnten trotz wiederholter Versuche keinen einzigen Fall eines Go-Nutzers identifizieren, der sich auf das bestehende, undokumentierte Verhalten verlässt.

Es ist eine Woche her seit https://github.com/golang/go/issues/32088#issuecomment -537590826, und es gibt immer noch keinen klaren Konsens, was bedeutet, dass wir dies ablehnen sollten.

Abgelehnt.

Ich habe eine Zusammenfassung der Optionen mit Vor- und Nachteilen in https://github.com/golang/go/issues/34681#issuecomment -565853605 gepostet.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen