Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-08

TFileStream.SetSize sometimes fails

12 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Mattias Gaertner

I want to replace the content of an existing file (keeping the type and rights). I used:

fs := TFileStream.Create(Filename, fmOpenWrite or fmShareDenyNone);
fs.Size := 0;
fs.Write(.....);
fs.Free;

But it does not always work. The line fs.Size does not clear the file on every file system. So the fs.Write only replaces the first part of the file.

See http://bugs.freepascal.org/view.php?id=13931

Any idea, what to do instead?

Mattias

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 12 lines
I want to replace the content of an existing file (keeping the type and rights). I used: fs := TFileStream.Create(Filename, fmOpenWrite or fmShareDenyNone); fs.Size := 0; fs.Write(.....); fs.Free; But it does not always work. The line fs.Size does not clear the file on every file system. So the fs.Write only replaces the first part of the file.

If it depends on the filesystem, then you should complain with the linux kernel people ?

Size=0 results in a ftruncate(Handle,0) call

Part of a strace (ex20 from the baseunix unit docs, fptruncate call)

open("test.dat", O_WRONLY|O_LARGEFILE) = 3
ftruncate(3, 60) = 0
close(3) = 0

So we can state that FPC's ftruncate does work, it passes the args to the kernel. If the kernel does not actually truncate the file, there is little FPC can do.

Why not simply remove/backup and subsequently recreate the file ?

Michael.

Mattias Gaertner
to Michael Van Canneyt
Show quoted text 19 lines
On Thu, 13 Aug 2009, Mattias Gaertner wrote: > > I want to replace the content of an existing file (keeping the type > and rights). I used: > > fs := TFileStream.Create(Filename, fmOpenWrite or fmShareDenyNone); > fs.Size := 0; > fs.Write(.....); > fs.Free; > > But it does not always work. The line fs.Size does not clear the > file on every file system. So the fs.Write only replaces the first > part of the file. If it depends on the filesystem, then you should complain with the linux kernel people ?

I'm not sure if it is a kernel thing. I don't have a vbox to test. That's why I ask. Maybe someone knows more.

Show quoted text 11 lines
Size=0 results in a ftruncate(Handle,0) call Part of a strace (ex20 from the baseunix unit docs, fptruncate call) open("test.dat", O_WRONLY|O_LARGEFILE) = 3 ftruncate(3, 60) = 0 close(3) = 0 So we can state that FPC's ftruncate does work, it passes the args to the kernel. If the kernel does not actually truncate the file, there is little FPC can do.

Yes. The code worked pretty well for years on many systems. But you know the story of the ext4 bug. I hope this is not something like that.

Why not simply remove/backup and subsequently recreate the file ?

This will loose the access rights and type of the file.

Mattias

Martin
to Mattias Gaertner
Mattias Gaertner wrote 25 lines
On Thu, 13 Aug 2009 21:46:23 +0200 (CEST) Michael Van Canneyt wrote: > On Thu, 13 Aug 2009, Mattias Gaertner wrote: > >> I want to replace the content of an existing file (keeping the type >> and rights). I used: >> >> fs := TFileStream.Create(Filename, fmOpenWrite or fmShareDenyNone); >> fs.Size := 0; >> fs.Write(.....); >> fs.Free; >> >> But it does not always work. The line fs.Size does not clear the >> file on every file system. So the fs.Write only replaces the first >> part of the file. >> > If it depends on the filesystem, then you should complain with the > linux kernel people ? > I'm not sure if it is a kernel thing. I don't have a vbox to test. That's why I ask. Maybe someone knows more.

Have a look here:
http://www.virtualbox.org/ticket/2257

It never was fixed, just no-one was able to reproduce for some time. However it was with an xp guest on an ubunto host => we have it the other way round

Luca Olivetti
to Mattias Gaertner: On Thu, 13 Aug 2009 21:46:23 +0200 (CEST) I'm not sure if it is a kernel thing. I don't…

En/na Mattias Gaertner ha escrit:

Yes. The code worked pretty well for years on many systems. But you know the story of the ext4 bug. I hope this is not something like that.

It was not a bug, and if you're doing it on ext4 (and probably xfs) it's possible that what you're seeing is a workaround to the problem

http://www.h-online.com/open/Ext4-data-loss-explanations-and-workarounds--/news/112892

Bye

Luca
Michael Van Canneyt
to Mattias Gaertner: On Thu, 13 Aug 2009 21:46:23 +0200 (CEST) I'm not sure if it is a kernel thing. I don't…
Mattias Gaertner wrote 42 lines
On Thu, 13 Aug 2009 21:46:23 +0200 (CEST) Michael Van Canneyt wrote: > > > On Thu, 13 Aug 2009, Mattias Gaertner wrote: > >> >> I want to replace the content of an existing file (keeping the type >> and rights). I used: >> >> fs := TFileStream.Create(Filename, fmOpenWrite or fmShareDenyNone); >> fs.Size := 0; >> fs.Write(.....); >> fs.Free; >> >> But it does not always work. The line fs.Size does not clear the >> file on every file system. So the fs.Write only replaces the first >> part of the file. > > If it depends on the filesystem, then you should complain with the > linux kernel people ? I'm not sure if it is a kernel thing. I don't have a vbox to test. That's why I ask. Maybe someone knows more. > Size=0 results in a ftruncate(Handle,0) call > > Part of a strace (ex20 from the baseunix unit docs, fptruncate call) > > open("test.dat", O_WRONLY|O_LARGEFILE) = 3 > ftruncate(3, 60) = 0 > close(3) = 0 > > So we can state that FPC's ftruncate does work, it passes the args to > the kernel. If the kernel does not actually truncate the file, there > is little FPC can do. Yes. The code worked pretty well for years on many systems. But you know the story of the ext4 bug. I hope this is not something like that.

I don't know the story of the ext4 bug, I can only say that the Size=0 gets translated to ftruncate(handle,0), which, if it works as described, should set the file size to zero.

If it does not - no matter what the circumstances - it is a kernel bug, not an FPC bug.

Show quoted text 5 lines
> Why not simply remove/backup and subsequently recreate the file ? This will loose the access rights and type of the file.

Why does that matter ? I don't think the IDE needs to preserve these.

If the IDE needs to regenerate some files, it is natural that this would happen. I can imagine an option 'mode for new files', but that's as far as it goes, and in each case it will be limited by whatever the umask() function has set.

The IDE fails already on more simple matters:

Try saving a project file in the IDE which has been set to read-only. The IDE will complain about the lpi file, and the 'Retry' button hangs the IDE. (at least here on a Linux system). If I set the lpr file to read-only, then the project lpr file is not saved at all with no warning whatsoever, but is marked as saved.

This does not bother me (they are corner cases IMHO, where problems can be expected), I simply think the IDE should not try to be too smart.

Michael.

Mattias Gaertner
to Luca Olivetti: En/na Mattias Gaertner ha escrit: It was not a bug, and if you're doing it on ext4 (and…
Show quoted text 11 lines
En/na Mattias Gaertner ha escrit: > > Yes. The code worked pretty well for years on many systems. But > you know the story of the ext4 bug. I hope this is not something > like that. It was not a bug, and if you're doing it on ext4 (and probably xfs) it's possible that what you're seeing is a workaround to the problem http://www.h-online.com/open/Ext4-data-loss-explanations-and-workarounds--/news/112892

Sorry. I know, that it is not a bug from posix pov. The unexpected behavior of ext4 only happens on system crash. So, I doubt that this has to do with TFileStream.SetSize. I was just wondering if there might be another posix compliant behavior that let TFileStream.SetSize fail on some file systems. That's why I mentioned the ext4 story.

Mattias

David W Noon
to Michael Van Canneyt: I don't know the story of the ext4 bug, I can only say that the Size=0 gets translated to…

On Fri, 14 Aug 2009 09:19:40 +0200 (CEST), Michael Van Canneyt wrote about Re: [fpc-pascal] TFileStream.SetSize sometimes fails:

On Thu, 13 Aug 2009, Mattias Gaertner wrote:

[snip]

> This will loose the access rights and type of the file. Why does that matter ? I don't think the IDE needs to preserve these.

Any program that updates a file and in so doing alters the security mask or deletes any ACL's or extended attributes of that file is intrinsically broken.

If I have a source file to which I have assigned an ACL permitting another specific user to access the file, that ACL *must* stay in place. Likewise, if I have set a security mask to keep other users in my group out of a file, i.e. 0600, that security mask must be preserved.

Regards, Dave [RLU #314465] ======================================================================= (David W Noon) =======================================================================
Martin
to Michael Van Canneyt: If it depends on the filesystem, then you should complain with the linux kernel people ?…
Michael Van Canneyt wrote 26 lines
On Thu, 13 Aug 2009, Mattias Gaertner wrote: > I want to replace the content of an existing file (keeping the type and > rights). I used: > > fs := TFileStream.Create(Filename, fmOpenWrite or fmShareDenyNone); > fs.Size := 0; > fs.Write(.....); > fs.Free; > > But it does not always work. The line fs.Size does not clear the file on > every file system. So the fs.Write only replaces the first part of the > file. If it depends on the filesystem, then you should complain with the linux kernel people ? Size=0 results in a ftruncate(Handle,0) call Part of a strace (ex20 from the baseunix unit docs, fptruncate call) open("test.dat", O_WRONLY|O_LARGEFILE) = 3 ftruncate(3, 60) = 0 close(3) = 0 So we can state that FPC's ftruncate does work, it passes the args to the kernel. If the kernel does not actually truncate the file, there is little FPC can do.

Well the only case were it fails (at least were we know that it is truncate that fails) is VBox shared folders. And indeed it seems they do have a bug. http://www.virtualbox.org/ticket/3712 or the one I can reproduce http://www.virtualbox.org/ticket/4771

However in c I can specify

   open(fname, O_WRONLY | O_TRUNC );

which does work (bypasses the bug)

I haven't seen an equvivalent to O_TRUNC in fpc ?

Martin

Michael Van Canneyt
to Martin
Martin wrote 38 lines
Michael Van Canneyt wrote: > On Thu, 13 Aug 2009, Mattias Gaertner wrote: >> I want to replace the content of an existing file (keeping the type and >> rights). I used: >> >> fs := TFileStream.Create(Filename, fmOpenWrite or fmShareDenyNone); >> fs.Size := 0; >> fs.Write(.....); >> fs.Free; >> >> But it does not always work. The line fs.Size does not clear the file on >> every file system. So the fs.Write only replaces the first part of the >> file. > If it depends on the filesystem, then you should complain with the linux > kernel people ? > > Size=0 results in a ftruncate(Handle,0) call > Part of a strace (ex20 from the baseunix unit docs, fptruncate call) > > open("test.dat", O_WRONLY|O_LARGEFILE) = 3 > ftruncate(3, 60) = 0 > close(3) = 0 > > So we can state that FPC's ftruncate does work, it passes the args to the > kernel. > If the kernel does not actually truncate the file, there is little FPC can > do. Well the only case were it fails (at least were we know that it is truncate that fails) is VBox shared folders. And indeed it seems they do have a bug. http://www.virtualbox.org/ticket/3712 or the one I can reproduce http://www.virtualbox.org/ticket/4771 However in c I can specify open(fname, O_WRONLY | O_TRUNC ); which does work (bypasses the bug) I haven't seen an equvivalent to O_TRUNC in fpc ?

Sure there is:

uses baseunix;
Var
   H : integer;
begin
   h:=fpOpen(fname,O_WrOnly or o_trunk)
end.

But that is not relevant:
a) FPC itself should not work around kernel/vbox bugs. b) It would not help in Mattias' case anyway...

Michael.

Martin
to Michael Van Canneyt
Michael Van Canneyt wrote 22 lines
On Fri, 14 Aug 2009, Martin wrote: > > However in c I can specify > open(fname, O_WRONLY | O_TRUNC ); > which does work (bypasses the bug) > > I haven't seen an equvivalent to O_TRUNC in fpc ? Sure there is: uses baseunix; Var H : integer; begin h:=fpOpen(fname,O_WrOnly or o_trunk) end. But that is not relevant: a) FPC itself should not work around kernel/vbox bugs. b) It would not help in Mattias' case anyway...

I never said FPC should workaround, and I am not in favour for the Lazarus to do so.

Then again, if that had been a cross platform argument, there would be no reason (IMHO) why lazarus could not set the flag , when opening the file. If it had been cross-platform....

Martin

Michael Van Canneyt
to Martin
Martin wrote 29 lines
Michael Van Canneyt wrote: > On Fri, 14 Aug 2009, Martin wrote: >> >> However in c I can specify >> open(fname, O_WRONLY | O_TRUNC ); >> which does work (bypasses the bug) >> >> I haven't seen an equvivalent to O_TRUNC in fpc ? > > Sure there is: > > uses baseunix; > > Var > H : integer; > > begin > h:=fpOpen(fname,O_WrOnly or o_trunk) > end. > > But that is not relevant: > a) FPC itself should not work around kernel/vbox bugs. > b) It would not help in Mattias' case anyway... I never said FPC should workaround, and I am not in favour for the Lazarus to do so. Then again, if that had been a cross platform argument, there would be no reason (IMHO) why lazarus could not set the flag , when opening the file. If it had been cross-platform....

Windows has TRUNCATE_EXISTING, so in theory we could introduce fmTruncate to be used in conjunction with fmOpenwrite, and then Mattias could use it in the TFileStream constructor.

(As a side node: TRUNCATE_EXISTING also had/has bug when working on remote files, you can find this in Microsofts Knowledge Base ;-))

Michael.