Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6848
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von af0815 »

Ich würde trotzdem einen Bugreport machen, weil es sein kann, das dieses Verhalten nicht gewünscht ist. Speziell wäre die Frage, ob es in Delphi korrekt funktionier, weil wenn es dort geht, ist es definitiv ein Bug.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von Jorg3000 »

Gute Idee.
Da ich auch Delphi 11 habe, habe ich dort gerade in den Quellcode von FileExists() geguckt (das hätte ich ja auch eher machen können).
Und siehe da, in Delphi wird es bei FollowLink=TRUE ganz anders gehandhabt, nämlich so: Wenn das Attribut faSymLink gesetzt ist, wird nicht etwa die Link-Ziel-Adresse nachverfolgt wie in FreePascal, sondern es wird einfach versucht die Datei mit dem übergebenen Dateinamen zum Lesen zu öffnen. Und das klappt auch bei Schattenkopien problemlos! Somit funktioniert es in Delphi wie erwartet, in FreePascal jedoch nicht immer. :oops: ... nämlich bei Schattenkopien nicht, weil man auf jenen System-Ordner keine direkte Zugriffserlaubnis hat.

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von Jorg3000 »

Moin!
Ich habe mich gerade bei Gitlab registriert und es als Bug gemeldet.

https://gitlab.com/freepascal.org/fpc/s ... sues/41150

NoCee
Beiträge: 174
Registriert: Do 3. Mär 2011, 21:34
OS, Lazarus, FPC: WinXp/7/10 Opensuse13.2/Leap15.3 (L 2.2.0 FPC 3.2.2 )
CPU-Target: Intel 32/64Bit, ARM9
Wohnort: Ulm

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von NoCee »

Hallo zusammen,

ich habe auf Windows Servern genau das gegenteilige Problem.
FileExists(FileName) liefert true aber beim Öffnen der wirklich vorhandenen Datei
gibt’s dann einen Fehler. Beim nächsten log in die csv-Datei läufts wieder ganz normal.
Es handelt sich bei dem Laufwerk um ein Netzwerklaufwerk. Der Server ist eine virtuelle Maschine.
Beim log in eine Datei die dabei auf C: liegt gibt’s keine Probleme.
Auf dem Netzlaufwerk hab ich mehrmals am Tag dieses Verhalten.
Es werden hier am Tag in Richtung 3000 Textzeilen geloggt.

Könnte es sein daß ich da mit den gleichen Schwierigkeiten zu kämpfen habe?
Dann würde ich den work around mal probieren. Unsere IT kann mir da nicht helfen,
das muß an der Software liegen.

Gruß
NoCee

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von Jorg3000 »

Hi NoCee!
Das wird eher ein Problem beim Öffnen der Datei sein.
Denn in deinem Fall liefert FileExists() ja das Richtige (true wenn Datei vorhanden), aber das Öffnen schlägt fehl.
Ich vermute es hat was mit dem FileMode oder FileShare-Attribut beim Öffnen zu tun.
Wie öffnest/lädst du die Datei?

NoCee
Beiträge: 174
Registriert: Do 3. Mär 2011, 21:34
OS, Lazarus, FPC: WinXp/7/10 Opensuse13.2/Leap15.3 (L 2.2.0 FPC 3.2.2 )
CPU-Target: Intel 32/64Bit, ARM9
Wohnort: Ulm

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von NoCee »

Hallo Jorg3000,

geöffnet wird in etwa so: if FileExists(logfile) then append(logfile)
das append in einem try block abgesichert sonst schmiert die ganze Software ab.
Hab ich früher ohne gehabt aber auf C: da ist nie was passiert, nur auf dem Netzlaufwerk.
Das Textfile wird morgens immer neu erstellt und dann den ganzen Tag genutzt.
Ich behelfe mir da indem ich den String im Ram halte. Beim nächsten String der kommt,
werden beide gespeichert. Und das funktioniert dann. Es sind noch nie mehr als 1 String im Ram
gesichert worden. Damit ich das sehe hab ich da mal einen Zähler eingebaut.

Jetzt hab ich gehofft, daß das mit dem Thema Schattendatei zu tun haben könnte.
Aber da hört es bei mir schon lange auf. Schattendatei hab ich noch nicht mal gehört.

Vielen Dank für deine Unterstützung
Gruß
NoCee

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von Jorg3000 »

Moin!
Folgendes ist mein Vorschlag für eine Append-Funktion, die ohne FileExists() auskommt.
Aber auch hier gibt es eine Race Condition zwischen einem fehlschlagenden Append() und einem ersatzweisen Rewrite().

Code: Alles auswählen

 
function AppendStringToFile(const FileName, FileHeader, Content: String): Boolean;
var
  LogFile: Text;
begin
  Result:=false;
  AssignFile(LogFile, FileName);

  try
    Append(LogFile);
  except
    on E: EInOutError do
     begin
      if E.ErrorCode<>2 then Exit; // Runtime Error 2 = Datei existiert nicht
      try
        Rewrite(LogFile);
        if FileHeader<>'' then WriteLn(LogFile,FileHeader);
       except
        CloseFile(LogFile);
        Exit;
      end;
     end;
  end;

  try
    WriteLn(LogFile,Content);
    Result:=true;
  finally
    CloseFile(LogFile);
  end;
end; 
 
Hat jemand einen besseren Vorschlag auf Append/Rewrite-Basis?
Dann sollten wir es anschließend für folgende Seite vorschlagen: https://wiki.freepascal.org/File_Handling_In_Pascal
... denn das dortige Beispiel finde ich schlecht, weil es sich gar nicht um eine nicht existierende Datei kümmert.
Grüße, Jörg

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 385
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Vorsicht bei FileExists() und Schattenkopien unter Windows Server

Beitrag von Jorg3000 »

NoCee, in deinem Fall könnte es vielleicht sein, dass die Datei von einem anderen Process vorübergehend gesperrt ist.
Mit folgender Funktion könnte man es z.B. 3x versuchen, bevor es endgültig scheitert.

Code: Alles auswählen

 
  function RetryAppendStringToFile(const Filename, Header, Content: String; MaxRetries: Integer = 3): Boolean;
  var
    Attempt: Integer;
  begin
    Result := False;
    // evtl. hier vorab prüfen, ob der Filename leer oder zulässig ist

    for Attempt := 1 to MaxRetries do
    begin
      if AppendStringToFile(Filename, Header, Content) then Exit(true);
      Sleep(500);  // 500 Millisekunden vor dem nächsten Versuch warten 
    end;
  end;
  

Antworten