English Amiga Board


Go Back   English Amiga Board > Coders > Coders. System

 
 
Thread Tools
Old 02 January 2024, 17:24   #1
Krashan
Hardware Designer
 
Join Date: Aug 2018
Location: Bialystok/Poland
Age: 50
Posts: 178
Creating a file in RAM: sets IoErr

AmigaOS 3.0. When I open a file for writing in RamDisk with
Open("RAM:foo", MODE_NEWFILE);
and the file does not exist before, following
IoErr()
returns 205 (ERROR_OBJECT_NOT_FOUND) in spite of the file being created successfully.

It does not happen when I do the same anywhere on harddisk (FFS, if it matters).
IoErr()
is still 0 then.

Is it a bug?
Krashan is offline  
Old 02 January 2024, 19:01   #2
thomas
Registered User
 
thomas's Avatar
 
Join Date: Jan 2002
Location: Germany
Posts: 7,001
Could be a bug. OS 3.0 is very old. But does it really matter? If Open() returns a non-zero value, it succeeded. You need to check IoErr only if Open returns null.
thomas is offline  
Old 02 January 2024, 23:04   #3
hooverphonique
ex. demoscener "Bigmama"
 
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,624
As thomas said, you can't rely on IoErr() if there is no error (unless explicitly specified so by the operation in question).
hooverphonique is offline  
Old 05 January 2024, 17:08   #4
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Well, actually, you should, and actually, IoErr() should be 0 on success (unless documented otherwise). This is a defect of the RAM-handler.
Thomas Richter is offline  
Old 05 January 2024, 21:29   #5
Bruce Abbott
Registered User
 
Bruce Abbott's Avatar
 
Join Date: Mar 2018
Location: Hastings, New Zealand
Posts: 2,584
Autodocs 3.1: dos.doc

dos.library/IoErr

NAME
IoErr -- Return extra information from the system
SYNOPSIS
error = IoErr()
D0

LONG IoErr(void)
FUNCTION
Most I/O routines return zero to indicate an error. When this
happens
(or whatever the defined error return for the routine)
this routine may be called to determine more information. It is
also used in some routines to pass back a secondary result.

Note: there is no guarantee as to the value returned from IoErr()
after a successful operation, unless to specified by the routine
.
RESULTS
error - integer
Bruce Abbott is offline  
Old 05 January 2024, 22:23   #6
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Except that ACTION_FINDOUTPUT aka Open() shall create a 0 IoErr() on success. If it does not, it is a bug. There are functions in the dos.library which do not set IoErr(), or which set it to other values on success, but Open() is none of them.
Thomas Richter is offline  
Old 06 January 2024, 10:36   #7
Olaf Barthel
Registered User
 
Join Date: Aug 2010
Location: Germany
Posts: 532
Quote:
Originally Posted by Krashan View Post
AmigaOS 3.0. When I open a file for writing in RamDisk with
Open("RAM:foo", MODE_NEWFILE);
and the file does not exist before, following
IoErr()
returns 205 (ERROR_OBJECT_NOT_FOUND) in spite of the file being created successfully.

It does not happen when I do the same anywhere on harddisk (FFS, if it matters).
IoErr()
is still 0 then.

Is it a bug?
No, as far as I can tell. It is a by-product of how the ram-handler implementation is designed, which focuses on code reuse in order to keep its size "manageable" (for some values of manageable, anyway).

When you call
Open("RAM:foo", MODE_NEWFILE)
, ram-handler will check if there already is an object named "foo". If it's a file, then checks will follow to determine whether it can be overwritten (it could be write-protected, a Lock or FileHandle may be associated with it). If it's a directory, then it can never be overwritten by a file. That sort of thing...

But it all begins by checking if there is a directory entry of that name. ram-handler reuses the code which underpins the
Lock()
operation, among other things, and this function will put an error code of ERROR_OBJECT_NOT_FOUND into a global variable if there is no directory or file of that name.

This global variable value will persist when the
Open("RAM:foo", MODE_NEWFILE)
call returns, even if it succeeds, and its value will go into the secondary result member of the DosPacket which underpins the file system interaction. That value will become available to you when you call the
IoErr()
function.

That said, you should be aware that the value returned by the
IoErr()
function is meaningless without context. Hence, if
Open("RAM:foo", MODE_NEWFILE)
successfully returns a pointer to a FileHandle, then the
IoErr()
function value is meaningless. It only becomes meaningful if
Open("RAM:foo", MODE_NEWFILE)
returns NULL.

There is some ambiguity here, I grant you. But for functions such as
Lock()
,
Delete()
,
Rename()
, etc. an indication of failure means that an error code will be available through
IoErr()
. This is a protocol or contract, if you will.
Olaf Barthel is offline  
Old 06 January 2024, 11:09   #8
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Quote:
Originally Posted by Olaf Barthel View Post
No, as far as I can tell. It is a by-product of how the ram-handler implementation is designed, which focuses on code reuse in order to keep its size "manageable" (for some values of manageable, anyway).
No, Olaf, I beg you. This is an implementation detail that leaks outside, and that should not leak outside. If an operation via a packet succeeds, the Res2 of the packet shall be zero, as simple as that. There are unfortunately a couple of dos.library functions that do not set IoErr consistently in some cases, but that's also something I would call a defect that should better be fixed.
Thomas Richter is offline  
Old 06 January 2024, 13:39   #9
Olaf Barthel
Registered User
 
Join Date: Aug 2010
Location: Germany
Posts: 532
Quote:
Originally Posted by Thomas Richter View Post
No, Olaf, I beg you. This is an implementation detail that leaks outside, and that should not leak outside. If an operation via a packet succeeds, the Res2 of the packet shall be zero, as simple as that. There are unfortunately a couple of dos.library functions that do not set IoErr consistently in some cases, but that's also something I would call a defect that should better be fixed.


I already checked what it takes to make Result2 consistently come up with 0 if an operation succeeds. It makes ram-handler significantly larger (this has to go into every single packet handling function), and we're already tight in terms of ROM space.

If I should stumble down this rabbit hole, I need to save space elsewhere. Right now, the only thing which I believe might be easy to axe is the setdosdate function in dos.library. What do you think? Is booting off a BCPL file system even possible in Kickstart 2.x and beyond?
Olaf Barthel is offline  
Old 06 January 2024, 13:39   #10
hooverphonique
ex. demoscener "Bigmama"
 
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,624
Quote:
Originally Posted by Thomas Richter View Post
Except that ACTION_FINDOUTPUT aka Open() shall create a 0 IoErr() on success. If it does not, it is a bug. There are functions in the dos.library which do not set IoErr(), or which set it to other values on success, but Open() is none of them.
That doesn't really matter much since the dos documentation explicitly specifies not to rely on IoErr when an operation returns success.
hooverphonique is offline  
Old 06 January 2024, 13:43   #11
Olaf Barthel
Registered User
 
Join Date: Aug 2010
Location: Germany
Posts: 532
Quote:
Originally Posted by hooverphonique View Post
All that doesn't matter since the dos documentation explicitly specifies not to rely on IoErr when an operation returns success.
The real problem is that "nobody" seems to read the documentation, and with good reason. It tends to be unhelpful and incomplete. Even the exceptionally well-researched "The Amiga Guru book" has its limitations, with errata unlikely to be published in the future
Olaf Barthel is offline  
Old 06 January 2024, 14:13   #12
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Quote:
Originally Posted by Olaf Barthel View Post
I already checked what it takes to make Result2 consistently come up with 0 if an operation succeeds. It makes ram-handler significantly larger (this has to go into every single packet handling function), and we're already tight in terms of ROM space.
Frankly, I doubt that this makes much of a difference. If the handler provides 32 packets (estimated), we need in worst case (actually, it is not that bad) 32x "if (result == ok) result2 = 0", which accounts to 32 branches (4 bytes) and resetting result2 32 times (~6 bytes), tihs accounts to 320 bytes estimated. Let's make this even 400. I doubt that it is *that* tight*.



Quote:
Originally Posted by Olaf Barthel View Post
If I should stumble down this rabbit hole, I need to save space elsewhere. Right now, the only thing which I believe might be easy to axe is the setdosdate function in dos.library. What do you think? Is booting off a BCPL file system even possible in Kickstart 2.x and beyond?

My original 1.2 boot disk booted fine under 3.2. But if you want to axe off something, I would look in the blib.c and all the BCPL emulation nonsense. This can run right into a software alert instead. The only thing remains are BCPL startup functions for the port-handler and "CLI" in createtask, and this should be moderately easy to get rid of either. At least, it would be more than 400 bytes you can save.
Thomas Richter is offline  
Old 06 January 2024, 14:17   #13
Thomas Richter
Registered User
 
Join Date: Jan 2019
Location: Germany
Posts: 3,233
Quote:
Originally Posted by Olaf Barthel View Post
The real problem is that "nobody" seems to read the documentation, and with good reason. It tends to be unhelpful and incomplete. Even the exceptionally well-researched "The Amiga Guru book" has its limitations, with errata unlikely to be published in the future
That is exactly why I try to create something that is a bit more helpful and a bit more complete. Concerning IoErr(), the issue is that the original documentation does not document much, and there are plenty functions in the dos.library that do not set IoErr consistently, but I also tried to document these cases, though I would rather prefer to mark these as defects rather than as features.



But it is a long story, and it takes a while to review. I'm now in the middle of the second iteration, checking every function and every description again, finding many defects, but nobody is perfect and certainly there are still errata left. Right in the middle of chapter 7 btw.

As always, suggestions for improvement are welcome.
Thomas Richter is offline  
Old 06 January 2024, 15:00   #14
Olaf Barthel
Registered User
 
Join Date: Aug 2010
Location: Germany
Posts: 532
Quote:
Originally Posted by Thomas Richter View Post
Frankly, I doubt that this makes much of a difference. If the handler provides 32 packets (estimated), we need in worst case (actually, it is not that bad) 32x "if (result == ok) result2 = 0", which accounts to 32 branches (4 bytes) and resetting result2 32 times (~6 bytes), tihs accounts to 320 bytes estimated. Let's make this even 400. I doubt that it is *that* tight*.
I've been there before and the simple changes required to work around or replace existing ram-handler code rarely stay simple. The number of bugs/side effects which survive the previous attempt to squash them remains surprisingly constant. That said, the 'C' version of ram-handler had fewer bugs than the original version, but the new bugs were more complex


Quote:
My original 1.2 boot disk booted fine under 3.2.
Yes, but it did not use a BCPL file system As far as I can tell, the only client of the setdosdate function is the Kickstart 1.x default file system. If the system time is 0 (unset), it will use the "Volume last altered date and time" DateStamp of the root directory of the boot volume to set the system time through setdosdate.

Fun fact: the "Volume last altered date and time" DateStamp does not contain the date and time of the last change made to the volume. It is more specific: the default file system updates it only when changes made to the bitmap are written back to disk. Basically, whenever storage space is released or allocated, the DateStamp will be updated, eventually.

Quote:
But if you want to axe off something, I would look in the blib.c and all the BCPL emulation nonsense. This can run right into a software alert instead. The only thing remains are BCPL startup functions for the port-handler and "CLI" in createtask, and this should be moderately easy to get rid of either. At least, it would be more than 400 bytes you can save.
Some of the BCPL emulation nonsense is still being used and will impact the boot process for Workbench 1.x era disks, if broken. I discovered this the hard way when I introduced a memset() into the Examine/ExNext code of ram-handler which cleared the entire FileInfoBlock contents, including the reserved portion. Bad idea: the BCPL commands "Dir", "List", etc. use a much shorter form of the FileInfoBlock than is defined in even the Kickstart 1.0 "libraries/dos.h" header file, which results in corrupting the BCPL stack.

This is an undocumented trap for file system developers. Basically, the FileInfoBlock structure as defined by the 3.0 header files only works for 'C' and assembly language code. If the client happens to be a legacy BCPL program, you can expect only the fields fib_DiskKey..fib_Comment to be accessible. If you write beyond the end of the fib_Comment field in your file system code, you may trash the BCPL stack.

Last edited by Olaf Barthel; 06 January 2024 at 16:02.
Olaf Barthel is offline  
Old 10 January 2024, 19:23   #15
Krashan
Hardware Designer
 
Join Date: Aug 2018
Location: Bialystok/Poland
Age: 50
Posts: 178
Thank you all for extensive explanations. I have modified my code, so it only checks
IoErr()
when
Open()
fails.
Krashan is offline  
Old 12 January 2024, 05:45   #16
tygre
Returning fan!
 
tygre's Avatar
 
Join Date: Jan 2011
Location: Montréal, QC, Canada
Posts: 1,434
PS.
Quote:
Originally Posted by Olaf Barthel View Post
The number of bugs/side effects which survive the previous attempt to squash them remains surprisingly constant.
Isn't that one of Lehman’s Laws?
tygre is offline  
Old 15 January 2024, 16:03   #17
Olaf Barthel
Registered User
 
Join Date: Aug 2010
Location: Germany
Posts: 532
Quote:
Originally Posted by tygre View Post
PS.

Isn't that one of Lehman’s Laws?
Definitely sounds a bit like it. The recent rework (ahem) by yours truly was performed with the goals to render the code more readable, more maintainable and more robust, with no new features added and code size growing only in the low 20-100 bytes, if possible.

ram-handler is hard to maintain because the 'C' implementation is beholden to the design principles of the Kickstart 1.x BCPL version. Simple algorithms (not necessarily a bad thing), short functions which do the absolute minimum of what is required of them, terse variable and function names and code documentation which tends towards the decorative rather than the illuminating

You'd hope that this foundation would make it easier to spot something amiss, but your hopes would be dashed so very quickly. ram-handler is simple, if not primitive, because it has to deliver, with very little code spent on making it work.

The 'C' version uses function and variable naming a little better than the BCPL precursor, but it's often unhelpful because some data structure naming makes it hard to distinguish between the different types which, curiously, have very similar names. Part of my rewrite was to try and make the naming of things clearer so that you can tell from the name what you are dealing with. Without that foundation, maintaining the code becomes so much harder

ram-handler is big on code reuse for the sake of keeping the code size under control. This has its perks, but they come with a Spaghettic Code tax. Yes, it is shorter and possibly faster, but you may wonder at some point if it's too much of a distraction from finding and fixing the bugs which hide in loops of the Spaghetti.

And there were whole families of bugs hiding in plain sight, such as in the code which manages the memory allocation/free/resize operations. For example, due to a combination of bugs, closing a file just opened would almost always end up reallocating the memory spent on the last data chunk of the file, even if the file was unchanged. The code allocated new memory, copied the old data from the block to be replaced, then removed the old one, added the new one and freed the old block. Completely unnecessary, and not even a bit artful.

Figuring out how much memory was being used and how that would relate to the total amount of memory installed on the Amiga was mostly guesswork, with some of the maintenance operations squirreled away into subroutines where nobody would ever look for them.

As with all the file systems which came from the Tripos legacy, the ram-handler code rarely knew its own limitations, if at all. Not just file sizes, also name length for volumes and paths.

Code reuse for the benefit of keeping ram-handler small had curious side effects. A file lock and a file handle were basically the same data structure type and you could in some dark corners of ram-handler use both interchangeably. How's that for fun? Looks like a magic trick, except when it goes wrong.

I have some small hopes that the next person to walk into the current ram-handler code will no longer feel an uncanny urge to get the hell out of here before something slinky emerges from a ventilation shaft and grins without smiling...
Olaf Barthel is offline  
Old 16 January 2024, 15:33   #18
koobo
Registered User
 
koobo's Avatar
 
Join Date: Sep 2019
Location: Finland
Posts: 363
Quote:
Originally Posted by Olaf Barthel View Post
ram-handler is hard to maintain because
I have some small hopes that the next person to walk into the current ram-handler code will no longer feel an uncanny urge to get the hell out of here before something slinky emerges from a ventilation shaft and grins without smiling...
That was a delightful read, thank you Olaf!
koobo is online now  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Amiga File Server - TOSEC Sets CodyJarrett project.Amiga File Server 5 19 February 2022 11:32
creating HDZ file pucci support.WinUAE 6 04 November 2011 09:13
Creating an empty hdf file Harko33 support.WinUAE 1 25 September 2011 23:46
Creating a #?.info file bytemind project.WHDLoad 24 15 May 2010 09:26
Creating a SFS HDF file Bloodwych support.WinUAE 21 01 January 2007 16:53

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 17:29.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.11231 seconds with 15 queries