Recent

Author Topic: The weird Rewrite bug  (Read 3882 times)

fxeconomist

  • New Member
  • *
  • Posts: 36
The weird Rewrite bug
« on: April 16, 2024, 11:10:22 pm »
So I just hit this thing,

A file that was written cannot be Rewritten (the second time, creation works). Not only that, but assign & erase also don't do anything.
File just needs to be written once. assign(f,'fullpath'); rewrite(f);...close(f); Yes, rewrite is between {$I-} {$I+}. This had no effect.
Code: Pascal  [Select][+][-]
  1. procedure TToroidCoil.SaveToFile(fullpath:string);
  2. var f:text;i:word;
  3. begin
  4. assign(f,fullpath);
  5. {$I-}
  6. rewrite(f);
  7. {$I+}
  8. writeln(f,'# Coil Parameters');
  9. //
  10. close(f);
  11.  

I ran this similar code in FPC with no trouble:

Code: Pascal  [Select][+][-]
  1.   assign(f,'e:\testfilerewrite.txt');
  2.   rewrite(f);
  3.   write(f,random()*100000000);
  4.   except
  5.      on E: Exception do writeln('I/O error');
  6.   end;
  7.   close(f);

ojz0r

  • Jr. Member
  • **
  • Posts: 61
Re: The weird Rewrite bug
« Reply #1 on: April 17, 2024, 03:50:28 am »
Try to use:

Code: Pascal  [Select][+][-]
  1. var
  2.   f: TextFile;
  3. ...
  4. AssignFile(f,fullpath);
  5. ...
  6. CloseFile(f);
  7.  

And see if it works.

Edit: Missed some code.
« Last Edit: April 17, 2024, 03:57:11 am by ojz0r »
Just trying to learn.

fxeconomist

  • New Member
  • *
  • Posts: 36
Re: The weird Rewrite bug
« Reply #2 on: April 17, 2024, 09:50:09 am »
Try to use:

Code: Pascal  [Select][+][-]
  1. var
  2.   f: TextFile;
  3. ...
  4. AssignFile(f,fullpath);
  5. ...
  6. CloseFile(f);
  7.  

And see if it works.

Edit: Missed some code.

This code is from SmartPascal.

Setting the {$i-} only prevents your program from crashing, it does not ignore the IOresults..

If there is a lingering IO error, these functions will be not execute.

So at some point in code, you may have had an error and has set the InOutRes variable to something other than 0.

you should always test IoResult at some point which will report the current error and also clear it.

Allright, so I turned on my computer today and amended the code:

Code: Pascal  [Select][+][-]
  1. function TToroidCoil.SaveToFile(fullpath:string):Word;
  2. var f:text;i:word;r:word;
  3. begin
  4. assign(f,fullpath);
  5. {$I-}
  6. rewrite(f);
  7. {$I+}
  8. r:=IOResult;
  9. if r<>0 then begin SaveToFile:=r;exit;end;
  10. writeln(f,'# Coil Parameters');
  11. //
  12. close(f);
  13. SaveToFile:=0;
  14. end;
  15.  

and then the caller.

Code: Pascal  [Select][+][-]
  1. rocedure TForm1.btnSaveAsOBJClick(Sender: TObject);
  2. var filename:string;i,reply:integer;error:word;
  3. begin
  4.   SaveDialog1.Title:='Save coil as .OBJ file';
  5.   if SaveDialog1.Execute then
  6.   begin
  7.       Filename := Savedialog1.filename;
  8.       if pos('.', Savedialog1.filename) > 0 then
  9.       begin
  10.         I := pos('.', Savedialog1.filename);
  11.         if uppercase(Copy(Savedialog1.filename, I + 1, 3)) <> 'OBJ' then
  12.           filename := copy(filename, 1, I) + 'obj';
  13.       end
  14.       else
  15.       begin
  16.         filename := savedialog1.filename + '.obj';
  17.       end;
  18.       if FileExists(filename) then reply:=MessageBox(0,'File exists! Overwrite ?','Save as .OBJ',MB_YESNO);
  19.                               end else reply:=IDYES;
  20.       if reply=IDYES then begin
  21.          error:=MyToroid.SaveToFile(filename);
  22.          if error<>0 then ShowMessage('An Error Occured!' + #13 +' (error code '+int2str(error,0)+')');
  23.       end;
  24. end;
  25.  

Ran the program, told it to rewrite the file it made last night. Bang, error 5, access denied.
It was so denied I couldn't even delete it manually from Total Commander!

Now, I understand there is something funny.
I remember encountering similar problems when I was coding in FoxPro.
FoxPro has the FOPEN() function, which doesn't ever work in a rewrite mode.
I mean if you read the documentation here ( https://hackfox.github.io/section4/s4g194.html ) you might say, "Well, we just do a fhandle=FOPEN(filename,1)"
But that doesn't work.

For this reason, I had to write a zillion years ago a workaround to restore file functions functionality the way did work in BP 7 at that time.

procedure AssignReset
parameters filename,filehandle
filehandle=FOPEN(filename,0)
return

procedure AssignRewrite
parameters filename,filehandle
if file(filename)==.F.
   filehandle=FCREATE(filename,0)
else
   set safe off
   delete file (filename)
   set safe on
   filehandle=FCREATE(filename,0)
endif
return

procedure AssignAppend
parameters filename,filehandle
if file(filename)==.F.
   filehandle=FCREATE(filename,0)
else
   filehandle=FOPEN(filename,0)
   =FSEEK(filehandle,FileSize(filehandle))
endif
return

Problem is, this workaround doesn't work here in Pascal. If I check if FileExists() and do assign(f);erase(f); then this doesn't work as well.

cdbc

  • Hero Member
  • *****
  • Posts: 1162
    • http://www.cdbc.dk
Re: The weird Rewrite bug
« Reply #3 on: April 17, 2024, 10:06:19 am »
Hi
Hold on... I remember that for text-files, in order to edit/update them, you 'read' the file -> edit said file in memory -> then you *create* a new file with a slightly different name, write the contents to that file -> then you delete the original file -> then you rename the new file to the original name => file edited. This is special for text-files.
Binary files are seekable, thus you can reopen them and write data at arbitrary positions.
I think this is where your /5 ~ Access denied/ comes from...  %)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Nitorami

  • Hero Member
  • *****
  • Posts: 505
Re: The weird Rewrite bug
« Reply #4 on: April 17, 2024, 10:55:05 am »
I don't know what exactly is going on in your code, but when using the DOS file assign/read/write procedures, you must check the IOResult generated by the OS each time you read or write a block of data to the file, not just after opening it.  IOResult is a simple integer value generated by the OS' I/O Routines, and reading it resets it to zero. Failing to read/reset it will get you into trouble with the next IO Access. I found in BP times that handling this correctly may be a bit tricky.

As an old timer, I am used to these old read/write routines from MSDOS times, and I still use them. There are alternatives now like FileCreate/FileOpen/FileClose etc, but I believe they just do the Error Checking internally and wrap an exception handler around.

Bart

  • Hero Member
  • *****
  • Posts: 5297
    • Bart en Mariska's Webstek
Re: The weird Rewrite bug
« Reply #5 on: April 17, 2024, 01:03:23 pm »
For me this (slightly modified) code works as expected:
Code: Pascal  [Select][+][-]
  1. program test;
  2. {$ifdef fpc}
  3. {$mode objfpc}
  4. {$h+}
  5. //{$mode delphi}{$H+}
  6. {$endif}
  7. {$apptype console}
  8.  
  9. uses
  10.   SysUtils;
  11.  
  12. function SaveToFile(fullpath:string):Word;
  13. var
  14.   f:textfile;
  15. begin
  16.   AssignFile(f,fullpath);   //AssignFile is the same as System.Assign
  17.   {$I-}
  18.   Rewrite(f);
  19.   Result:=IOResult;  //<< this will reset InOutRes to zero
  20.   if Result<>0 then
  21.     Exit;
  22.   Writeln(f,'# Coil Parameters');
  23.   Result:=IOResult;
  24.   if Result<>0 then
  25.     Exit;
  26.   CloseFile(f);  // CloseFile is the same as System.Close
  27.   Result := IOResult;
  28.   {$I+}
  29.   SaveToFile:=0;
  30. end;
  31.  
  32. var
  33.   Fn: String;
  34.   Res: Word;
  35.  
  36. begin
  37.   repeat
  38.     write('Filename: ');
  39.     readln(Fn);
  40.     if Fn<> '' then
  41.     begin
  42.       Res := SaveToFile(Fn);
  43.       if Res=0 then
  44.         writeln('Ok')
  45.       else
  46.         writeln('Fail: Res=',Res);
  47.     end;
  48.   until Fn='' ;
  49. end.

When I try to rewrite the same file over and over, it works just fine:
Code: [Select]
C:\Users\Bart\LazarusProjecten\ConsoleProjecten>test
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename: foo.bar
Ok
Filename:

C:\Users\Bart\LazarusProjecten\ConsoleProjecten>type foo.bar
# Coil Parameters

Notice that I check IOResult after each read/write/rewrite/closefile (as Nitorami already pointed out).

Bart

Kays

  • Hero Member
  • *****
  • Posts: 586
  • Whasup!?
    • KaiBurghardt.de
Re: The weird Rewrite bug
« Reply #6 on: April 17, 2024, 01:23:40 pm »
[…] rewrite is between {$I-} {$I+}. […]
[…] Is this intended behavior? […]
This is a user error. The documentation of {$IOChecks} states:
Quote
The effect of this is that IOResult must be checked after each I/O operation for subsequent I/O operations to succeed.
It says “must be checked.” If you insert a call to system.IOResult after each potentially failing I/O operation, subsequent I/O operations remain unaffected.
Yours Sincerely
Kai Burghardt

PascalDragon

  • Hero Member
  • *****
  • Posts: 5519
  • Compiler Developer
Re: The weird Rewrite bug
« Reply #7 on: April 18, 2024, 09:58:53 pm »
I don't know what exactly is going on in your code, but when using the DOS file assign/read/write procedures, you must check the IOResult generated by the OS each time you read or write a block of data to the file, not just after opening it.  IOResult is a simple integer value generated by the OS' I/O Routines, and reading it resets it to zero. Failing to read/reset it will get you into trouble with the next IO Access. I found in BP times that handling this correctly may be a bit tricky.

This depends on the setting of the {$I} switch. If it is {$I-} then one needs to check IOResult manually. If it is {$I+} then the compiler will automatically insert checks that trigger a runtime error. If the SysUtils unit is used in the program that runtime error will be converted to a EInOutError and thus can be handled using ordinary Object Pascal exception handling.

fxeconomist

  • New Member
  • *
  • Posts: 36
Re: The weird Rewrite bug
« Reply #8 on: May 05, 2024, 03:55:03 pm »
No No No

It still doesn't work.

And as proof, I made a Bandicam record.

Yes, the file is still declared as text ; i changed it to textfile and it still does the same.

I put up a Bandicam record of it. Watch it quickly, won't stay long!
https://streamable.com/fovo6o

dseligo

  • Hero Member
  • *****
  • Posts: 1246
Re: The weird Rewrite bug
« Reply #9 on: May 06, 2024, 01:39:58 pm »
What OS and filesystem is that?
Did you try some other location or USB flash drive?
Do you have some special file/directory permissions?
Do you run some AV software, cloud synchronisation, backup software or something similar which could interfere with filesystem?
Did you try to test it on different computer?

Thaddy

  • Hero Member
  • *****
  • Posts: 14614
  • Sensorship about opinions does not belong here.
Re: The weird Rewrite bug
« Reply #10 on: May 07, 2024, 05:04:21 pm »
There is no weird rewrite bug. he needs to keep the handle open and use append.
that was already mentioned? Or if the handle is closed open it and do append(handle).

The proper way to handle this is - of course again - in the manuals:
https://www.freepascal.org/docs-html/rtl/system/seek.html
https://www.freepascal.org/docs-html/rtl/system/append.html#:~:text=Append%20opens%20an%20existing%20file%20in%20append%20mode.,is%20not%20taken%20into%20account%20when%20calling%20Append.
Full example. note:  Filemode=2 meaning r/w. and then reset, not rewrite and then append.
More docs:
https://www.freepascal.org/docs-html/rtl/system/filemode.html

So, now, what? is weird? It has always been that way.
Code: Pascal  [Select][+][-]
  1. program filehandling;
  2. var
  3.   Handle:Text;
  4.   Fn:string = 'test.txt';
  5. begin
  6.   Assign(Handle,Fn);
  7.   Rewrite(Handle);
  8.   writeln(Handle, 'First part');
  9.   Close(Handle);
  10.  
  11.   FileMode := 2; // open read/write
  12.  
  13.   Assign(Handle, Fn);
  14.   Reset(Handle);// NOT rewrite
  15.   Append(Handle);//Goto eof
  16.   Writeln(Handle,'Second part');
  17.   Close(Handle);
  18.   // You may want to restore filemode hereafter.
  19. end.
Code: Bash  [Select][+][-]
  1. cat test.txt
  2. First part
  3. Second part
Please read the manuals first, ask later.
« Last Edit: May 07, 2024, 08:51:58 pm by Thaddy »
bitrate is always calculated like this:sample rate * bitdepth * number of channels.

Thaddy

  • Hero Member
  • *****
  • Posts: 14614
  • Sensorship about opinions does not belong here.
Re: The weird Rewrite bug
« Reply #11 on: May 07, 2024, 06:26:56 pm »
Works on all platforms btw, it is essential Pascal.
(Take note, Bart and the others)

The only thing I can think of that if two different processes are handling the same file, just set the handle for text to nil. Unlikely. It is the filemode.
« Last Edit: May 07, 2024, 06:36:02 pm by Thaddy »
bitrate is always calculated like this:sample rate * bitdepth * number of channels.

tetrastes

  • Sr. Member
  • ****
  • Posts: 493
Re: The weird Rewrite bug
« Reply #12 on: May 07, 2024, 09:24:37 pm »
Please read the manuals first, ask later.

Yes. From manuals:

1.
Quote
FileMode determines how untyped files are opened for reading with Reset.
Not Text.

2.
OP needs exactly Rewrite, not Append. And it should work. https://www.freepascal.org/docs-html/rtl/system/rewrite.html:
Quote
if Rewrite finds a file with the same name as F, this file is truncated to length 0.

Thaddy

  • Hero Member
  • *****
  • Posts: 14614
  • Sensorship about opinions does not belong here.
Re: The weird Rewrite bug
« Reply #13 on: May 07, 2024, 09:59:48 pm »
Does he really wants to kill the file? That was not clear to me. The code looks he wants to append.
Anyway, if an application holds a lock and another application tries to interfear with that, good luck, close and nil the handle. And untyped or typed files does not matter. (at all! >:D )

Reading IOResult in{$I-} state would have told him the file exists or not.
You are being silly and got me angry ( last time well over a year ago)

You deliberatly interpret the documentation wrong.
The only difference between file of text and an untyped file is that you need to use blockwrite with a proper length and check eof. again basic pascal.
« Last Edit: May 07, 2024, 10:37:39 pm by Thaddy »
bitrate is always calculated like this:sample rate * bitdepth * number of channels.

tetrastes

  • Sr. Member
  • ****
  • Posts: 493
Re: The weird Rewrite bug
« Reply #14 on: May 07, 2024, 10:53:46 pm »
Clean your glasses and reread the first post.

Untyped or typed files do matter for FileMode, which has nothing to do with Text files, and which your speculations were about.

I know that people with dementia get angry easily, but still please try to avoid insults.




 

TinyPortal © 2005-2018