From 0169f0276915fd26a594a912bc48c71260402cc5 Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 01/12] dos: move the fh_Flags values into their own header dos64.library shares them with dos.library. --- rom/dos/dos_fhflags.h | 21 +++++++++++++++++++++ rom/dos/dos_intern.h | 8 +------- 2 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 rom/dos/dos_fhflags.h diff --git a/rom/dos/dos_fhflags.h b/rom/dos/dos_fhflags.h new file mode 100644 index 0000000000..6adba9bb01 --- /dev/null +++ b/rom/dos/dos_fhflags.h @@ -0,0 +1,21 @@ +#ifndef DOS_FHFLAGS_H +#define DOS_FHFLAGS_H + +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: FileHandle fh_Flags definitions, shared between dos.library + and dos64.library. The flags are AROS specific and therefore + PRIVATE - they describe dos.library's buffering state and + must not be interpreted by applications. +*/ + +#define FHF_WRITE 0x80000000 +#define FHF_BUF 0x00000001 +#define FHF_APPEND 0x00000002 +#define FHF_LINEBUF 0x00000004 +#define FHF_NOBUF 0x00000008 +#define FHF_OWNBUF 0x00000010 +#define FHF_FLUSHING 0x00000020 + +#endif /* DOS_FHFLAGS_H */ diff --git a/rom/dos/dos_intern.h b/rom/dos/dos_intern.h index 25afd52cd2..fd29408b5a 100644 --- a/rom/dos/dos_intern.h +++ b/rom/dos/dos_intern.h @@ -94,13 +94,7 @@ struct vfp }; /* fh_Flags. The flags are AROS specific and therefore PRIVATE.. */ -#define FHF_WRITE 0x80000000 -#define FHF_BUF 0x00000001 -#define FHF_APPEND 0x00000002 -#define FHF_LINEBUF 0x00000004 -#define FHF_NOBUF 0x00000008 -#define FHF_OWNBUF 0x00000010 -#define FHF_FLUSHING 0x00000020 +#include "dos_fhflags.h" #define FPUTC(f,c) \ (((struct FileHandle *)BADDR(f))->fh_Flags&FHF_WRITE&& \ From b37065ce6bc983da6b80f9b6c2912bd14937e416 Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 02/12] m68k: call library functions that return 64 bits The linklib stubs of a function returning QUAD or UQUAD paste the return type into the call macro name. Map those names to the plain macros, which return d0/d1. --- arch/m68k-all/include/gencall.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/m68k-all/include/gencall.c b/arch/m68k-all/include/gencall.c index 50cb01549c..5319a3f80f 100644 --- a/arch/m68k-all/include/gencall.c +++ b/arch/m68k-all/include/gencall.c @@ -515,6 +515,16 @@ static const char libextra[] = "#define __AROS_LC3LONG __AROS_LC3\n" "#define __AROS_LC4LONG __AROS_LC4\n" "#define __AROS_LC5LONG __AROS_LC5\n" +"/* 64-bit results are returned in d0/d1, which the plain call macros\n" +" already reassemble, so these map straight through */\n" +"#define __AROS_LC2QUAD __AROS_LC2\n" +"#define __AROS_LC3QUAD __AROS_LC3\n" +"#define __AROS_LC4QUAD __AROS_LC4\n" +"#define __AROS_LC5QUAD __AROS_LC5\n" +"#define __AROS_LC2UQUAD __AROS_LC2\n" +"#define __AROS_LC3UQUAD __AROS_LC3\n" +"#define __AROS_LC4UQUAD __AROS_LC4\n" +"#define __AROS_LC5UQUAD __AROS_LC5\n" "\n" "# define AROS_LDQUAD1(t,n,q1,bt,bn,o,s) \\\n" " __AROS_LD_PREFIX t AROS_SLIB_ENTRY(n,s,o) ( \\\n" From 8d43d36d32d647e032b5601e3a26cbaa8bef63d7 Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 03/12] dos: use the MorphOS compatible 64-bit DOS structures FileInfoBlock is a single structure; fib_Size64, fib_NumBlocks64 and fib_ActExtFlags overlay fib_Reserved at the MorphOS V51 offsets, 64 bit members are 2 byte aligned on 32 bit targets. FileInfoBlock32 and FileInfoBlock64 stay as names of it. ExAllData gets ed_Size64 and ED_SIZE64, RecordLock64 the MorphOS layout, InfoData64 is the standard InfoData followed by 64 bit block counts. --- compiler/include/dos/dos.h | 133 ++++++++++++--------- compiler/include/dos/dosextens.h | 30 +---- compiler/include/dos/exall.h | 43 +++---- compiler/include/dos/record.h | 26 ++-- rom/dos/exall.c | 11 +- rom/filesys/afs/filehandles3.c | 2 +- rom/filesys/afs/os_unix_support.h | 2 + rom/filesys/pfs3/fs/directory.c | 10 +- workbench/network/smbfs/source_code/main.c | 2 +- 9 files changed, 123 insertions(+), 136 deletions(-) diff --git a/compiler/include/dos/dos.h b/compiler/include/dos/dos.h index 9fbb80fe51..cbbe335937 100644 --- a/compiler/include/dos/dos.h +++ b/compiler/include/dos/dos.h @@ -60,10 +60,31 @@ struct DateStamp this value, as it may change in future versions. */ #define MAXCOMMENTLENGTH 80 +/* + * 64-bit integers in the DOS structures below follow the Amiga ABI, where + * they are only 2-byte aligned (the MorphOS headers use pack(2)). 32-bit + * ARM and PowerPC compilers align them to 8 bytes by default, which would + * move them away from the offsets other systems and binary handlers use. + * 64-bit AROS has no foreign layout to match and keeps natural alignment. + */ +#if (__WORDSIZE == 64) +#define AROS_DOS64_ALIGN +#else +#define AROS_DOS64_ALIGN __attribute__((__packed__, __aligned__(2))) +#endif + /* Structure used to describe a directory entry. Note that not all fields are supported by all filesystems. This structure should be allocated - with AllocDosObject(). */ -struct FileInfoBlock64 + with AllocDosObject(). + + The 64-bit size fields (fib_Size64, fib_NumBlocks64) overlay the reserved + area as defined by MorphOS (tm) V51. They are filled by the 64-bit examine + calls (dos64.library Examine64(), ExNext64(), ExamineFH64(), packets + ACTION_EXAMINE_OBJECT64, _NEXT64, _FH64). Everything before them keeps + the classic layout, so the block is the same size as before and the + 32-bit calls can use it as well. fib_DiskKey is IPTR as handlers may + store a pointer in it. */ +struct FileInfoBlock { IPTR fib_DiskKey; /* See for definitions. Generally: if this is >= 0 @@ -81,49 +102,47 @@ struct FileInfoBlock64 UBYTE fib_FileName[MAXFILENAMELENGTH]; LONG fib_Protection; /* The protection bits (see below). */ LONG fib_EntryType; - UQUAD fib_Size; /* The size of the file. */ - UQUAD fib_NumBlocks; /* Number of blocks used for file. */ - struct DateStamp fib_Date; /* Date of last change to file. */ - /* The filecomment. Follows the same BSTR/CSTR rules as fib_FileName */ - UBYTE fib_Comment[MAXCOMMENTLENGTH]; - UWORD fib_OwnerUID; /* UserID of fileowner. */ - UWORD fib_OwnerGID; /* GroupID of fileowner. */ - UBYTE fib_Reserved[32]; /* PRIVATE */ -}; - -struct FileInfoBlock32 -{ - IPTR fib_DiskKey; - /* See for definitions. Generally: if this is >= 0 - the file described is a directory, otherwise it is a plain file. */ - LONG fib_DirEntryType; - /* The filename. - * - * User applications should always treat this as ASCIIZ. - * - * NOTE: This is created as a BCPL string in the ACTION_EXAMINE_* - * filesystem handler code, but is converted to a C style - * '\0'-terminated string by the Dos/Examine???() functions. - * - */ - UBYTE fib_FileName[MAXFILENAMELENGTH]; - LONG fib_Protection; /* The protection bits (see below). */ - LONG fib_EntryType; - LONG fib_Size; /* The size of the file. */ + LONG fib_Size; /* The size of the file. 0 from the + 64-bit calls when it does not + fit; see fib_Size64. */ LONG fib_NumBlocks; /* Number of blocks used for file. */ struct DateStamp fib_Date; /* Date of last change to file. */ /* The filecomment. Follows the same BSTR/CSTR rules as fib_FileName */ UBYTE fib_Comment[MAXCOMMENTLENGTH]; UWORD fib_OwnerUID; /* UserID of fileowner. */ UWORD fib_OwnerGID; /* GroupID of fileowner. */ - UBYTE fib_Reserved[32]; /* PRIVATE */ + union + { + UBYTE fib_un_Reserved[32]; /* PRIVATE */ + struct + { + UQUAD fib_un_ext_Size64 AROS_DOS64_ALIGN; + UQUAD fib_un_ext_NumBlocks64 AROS_DOS64_ALIGN; + ULONG fib_un_ext_Pad0[3]; + UWORD fib_un_ext_Pad1; + UBYTE fib_un_ext_ActExtFlags; + UBYTE fib_un_ext_ReqExtFlags; + } fib_un_ext; + } fib_un; }; -#if (__DOS64) -#define FileInfoBlock FileInfoBlock64 -#else -#define FileInfoBlock FileInfoBlock32 -#endif +#define fib_Reserved fib_un.fib_un_Reserved +#define fib_Size64 fib_un.fib_un_ext.fib_un_ext_Size64 /* 64-bit size of the file */ +#define fib_NumBlocks64 fib_un.fib_un_ext.fib_un_ext_NumBlocks64 /* 64-bit number of blocks */ +/* Extensions the handler filled in (FIBEXTF_ flags). Must be 0 when an + ACTION_EXAMINE_*64 packet is sent. The 64-bit size and block count + do not need a flag; they are always filled. */ +#define fib_ActExtFlags fib_un.fib_un_ext.fib_un_ext_ActExtFlags +/* Extensions requested from the handler (FIBEXTF_ flags), or 0. */ +#define fib_ReqExtFlags fib_un.fib_un_ext.fib_un_ext_ReqExtFlags + +/* No FIBEXTF_ extensions are defined on AROS yet. Bit 0 is kept free + for compatibility: MorphOS uses it (FIBEXTB_POSIXDATE) for a POSIX + date in place of fib_Date. */ + +/* Former names: the 64-bit examine calls use the standard structure */ +#define FileInfoBlock32 FileInfoBlock +#define FileInfoBlock64 FileInfoBlock /* Protection bits for files (fib_Protection). */ /* Flags for owner (they are active-low, i.e. not set means the action is @@ -171,37 +190,41 @@ struct FileInfoBlock32 **********************************************************************/ /* Structure used in Info(). Must be longword-aligned. */ -struct InfoData64 +struct InfoData { LONG id_NumSoftErrors; /* Number of soft errors on device. */ LONG id_UnitNumber; /* Unit number of device. */ LONG id_DiskState; /* State the current volume is in (see below). */ - UQUAD id_NumBlocks; /* Number of blocks on device. */ - UQUAD id_NumBlocksUsed; /* Number of blocks in use. */ + LONG id_NumBlocks; /* Number of blocks on device. */ + LONG id_NumBlocksUsed; /* Number of blocks in use. */ LONG id_BytesPerBlock; /* Bytes per block. */ LONG id_DiskType; /* Type of disk (see below). */ BPTR id_VolumeNode; IPTR id_InUse; /* Set, if device is in use. */ }; -struct InfoData32 +/* AROS extension, used by dos64.library Info64() and ACTION_INFO64: the + standard InfoData followed by 64-bit block counts. The leading part is + identical to struct InfoData, so the block can also be filled by + ACTION_INFO; id_NumBlocks and id_NumBlocksUsed then hold the 32-bit + values. Allocate it with AllocDosObject64(DOS64_INFODATA, NULL). */ +struct InfoData64 { - LONG id_NumSoftErrors; /* Number of soft errors on device. */ - LONG id_UnitNumber; /* Unit number of device. */ - LONG id_DiskState; /* State the current volume is in (see below). */ - LONG id_NumBlocks; /* Number of blocks on device. */ - LONG id_NumBlocksUsed; /* Number of blocks in use. */ - LONG id_BytesPerBlock; /* Bytes per block. */ - LONG id_DiskType; /* Type of disk (see below). */ - BPTR id_VolumeNode; - IPTR id_InUse; /* Set, if device is in use. */ + LONG id_NumSoftErrors; + LONG id_UnitNumber; + LONG id_DiskState; + LONG id_NumBlocks; /* 32-bit count, may be clamped */ + LONG id_NumBlocksUsed; /* 32-bit count, may be clamped */ + LONG id_BytesPerBlock; + LONG id_DiskType; + BPTR id_VolumeNode; + IPTR id_InUse; + UQUAD id_NumBlocks64 AROS_DOS64_ALIGN; /* Number of blocks on device. */ + UQUAD id_NumBlocksUsed64 AROS_DOS64_ALIGN; /* Number of blocks in use. */ }; -#if (__DOS64) -#define InfoData InfoData64 -#else -#define InfoData InfoData32 -#endif +/* Former name */ +#define InfoData32 InfoData /* id_DiskState */ #define ID_WRITE_PROTECTED 80 /* Volume is write-protected. */ diff --git a/compiler/include/dos/dosextens.h b/compiler/include/dos/dosextens.h index 1367158e34..e806f503bc 100644 --- a/compiler/include/dos/dosextens.h +++ b/compiler/include/dos/dosextens.h @@ -290,29 +290,7 @@ struct DevProc should not use this structure in any way and only use library-calls to access files. Treat this structure as PRIVATE. If you want to create this structure nevertheless, use AllocDosObject(). */ -struct FileHandle64 -{ - /* The next three are used with packet-based filesystems */ - ULONG fh_Flags; - LONG fh_Interactive; /* interactive handle flag */ - struct MsgPort * fh_Type; /* port to send packets to */ - - BPTR fh_Buf; - UQUAD fh_Pos; - UQUAD fh_End; - - SIPTR fh_Funcs; - SIPTR fh_Func2; - SIPTR fh_Func3; - SIPTR fh_Args; - SIPTR fh_Arg2; - - /* v39+ */ - IPTR fh_BufSize; /* Size of buffered io buffer */ - BPTR fh_OrigBuf; /* Always the same as fh_Buf */ -}; - -struct FileHandle32 +struct FileHandle { /* The next three are used with packet-based filesystems */ ULONG fh_Flags; @@ -334,12 +312,6 @@ struct FileHandle32 BPTR fh_OrigBuf; /* Always the same as fh_Buf */ }; -#if (__DOS64) -#define FileHandle FileHandle64 -#else -#define FileHandle FileHandle32 -#endif - /* Original AmigaOS aliases */ #define fh_Port fh_Interactive #define fh_Func1 fh_Funcs diff --git a/compiler/include/dos/exall.h b/compiler/include/dos/exall.h index a12c1b5f70..10b4398f6f 100644 --- a/compiler/include/dos/exall.h +++ b/compiler/include/dos/exall.h @@ -15,19 +15,23 @@ #ifndef UTILITY_HOOKS_H # include #endif +#ifndef DOS_DOS_H +# include +#endif /* Structure (as used in ExAll()), containing information about a file. This structure is only as long as it need to be. If is for example ED_SIZE was specified, when calling ExAll(), this structure only consists of the fields ed_Name through ed_Size. Therefore you can use the ED_ definitions below as longword offsets into this structure. */ -struct ExAllData64 +struct ExAllData { - struct ExAllData64 * ed_Next; + struct ExAllData * ed_Next; UBYTE * ed_Name; /* Name of the file. */ LONG ed_Type; /* Type of file. See . */ - UQUAD ed_Size; /* Size of file. */ + ULONG ed_Size; /* Size of file. With ED_SIZE64, 0 when the size + does not fit in 31 bits (see ed_Size64). */ ULONG ed_Prot; /* Protection bits. */ /* The following three fields are de facto an embedded datestamp @@ -41,35 +45,13 @@ struct ExAllData64 UWORD ed_OwnerUID; /* The owner ID. */ UWORD ed_OwnerGID; /* The group-owner ID. */ -}; - -struct ExAllData32 -{ - struct ExAllData32 * ed_Next; - - UBYTE * ed_Name; /* Name of the file. */ - LONG ed_Type; /* Type of file. See . */ - ULONG ed_Size; /* Size of file. */ - ULONG ed_Prot; /* Protection bits. */ - - /* The following three fields are de facto an embedded datestamp - structure (see ), which describes the last modification - date. */ - ULONG ed_Days; - ULONG ed_Mins; - ULONG ed_Ticks; - UBYTE * ed_Comment; /* The file comment. */ - - UWORD ed_OwnerUID; /* The owner ID. */ - UWORD ed_OwnerGID; /* The group-owner ID. */ + /* MorphOS (tm) V51 compatible extension, filled for ED_SIZE64 */ + UQUAD ed_Size64 AROS_DOS64_ALIGN; /* 64-bit size of file. */ }; -#if (__DOS64) -#define ExAllData ExAllData64 -#else -#define ExAllData ExAllData32 -#endif +/* Former name */ +#define ExAllData32 ExAllData /* Type argument for ExAll(). Each number includes the information of all lower numbers, too. If you specify for example ED_SIZE, you will get @@ -85,6 +67,9 @@ struct ExAllData32 #define ED_DATE 5 /* Last modification date. */ #define ED_COMMENT 6 /* Addtional file comment. */ #define ED_OWNER 7 /* Owner information. */ +#define ED_SIZE64 8 /* 64-bit size of file (ed_Size64). MorphOS (tm) + compatible; handlers that do not support it + fail with ERROR_BAD_NUMBER. */ /* Structure as used for controlling ExAll(). Allocate this structure by using diff --git a/compiler/include/dos/record.h b/compiler/include/dos/record.h index 1099988fe4..a918417d26 100644 --- a/compiler/include/dos/record.h +++ b/compiler/include/dos/record.h @@ -24,28 +24,26 @@ /* Structure as passed to LockRecords() and UnLockRecords(). */ -struct RecordLock64 +struct RecordLock { BPTR rec_FH; /* (struct FileHandle *) The file to get the current record from. */ - UQUAD rec_Offset; /* The offset, the current record should start. */ - UQUAD rec_Length; /* The length of the current record. */ + ULONG rec_Offset; /* The offset, the current record should start. */ + ULONG rec_Length; /* The length of the current record. */ ULONG rec_Mode; /* The mode od locking (see above). */ }; -struct RecordLock32 +/* 64-bit version, as passed to dos64.library LockRecords64() and + UnLockRecords64(). Same layout as the MorphOS (tm) V51 structure. */ +struct RecordLock64 { - BPTR rec_FH; /* (struct FileHandle *) The file to get the current - record from. */ - ULONG rec_Offset; /* The offset, the current record should start. */ - ULONG rec_Length; /* The length of the current record. */ - ULONG rec_Mode; /* The mode od locking (see above). */ + BPTR rec_FH; /* The file (struct FileHandle *). */ + UQUAD rec_Offset AROS_DOS64_ALIGN; /* Start of the record. */ + UQUAD rec_Length AROS_DOS64_ALIGN; /* Length of the record. */ + ULONG rec_Mode; /* The mode of locking (see above). */ }; -#if (__DOS64) -#define RecordLock RecordLock64 -#else -#define RecordLock RecordLock32 -#endif +/* Former name */ +#define RecordLock32 RecordLock #endif /* DOS_RECORD_H */ diff --git a/rom/dos/exall.c b/rom/dos/exall.c index 7e0abfc5ee..7e495f019e 100644 --- a/rom/dos/exall.c +++ b/rom/dos/exall.c @@ -61,6 +61,7 @@ ED_DATE - date information (3 longwords) ED_COMMENT - file comment (NULL if no comment exists) ED_OWNER - owner user and group id + ED_SIZE64 - 64-bit size in bytes (ed_Size64) This is an incremental list, meaning that if you specify ED_OWNER you will get ALL attributes! @@ -150,7 +151,8 @@ offsetof(struct ExAllData,ed_Days), offsetof(struct ExAllData,ed_Comment), offsetof(struct ExAllData,ed_OwnerUID), - sizeof(struct ExAllData) + offsetof(struct ExAllData,ed_Size64), /* ED_OWNER: up to ed_OwnerGID */ + sizeof(struct ExAllData) /* ED_SIZE64 */ }; /* Reset the 'fake' error */ @@ -219,7 +221,7 @@ } while (0) - if (data > ED_OWNER) + if (data > ED_SIZE64) /* We don't have that many fields to fill in... */ err = ERROR_BAD_NUMBER; else @@ -247,6 +249,11 @@ /* Switch over the requested fields and fill them as appropriate. */ switch(data) { + case ED_SIZE64: + /* Only the 32-bit size is known here */ + curr->ed_Size64 = (UQUAD)(ULONG)icontrol->fib->fib_Size; + + /* Fall through */ case ED_OWNER: curr->ed_OwnerUID = icontrol->fib->fib_OwnerUID; curr->ed_OwnerGID = icontrol->fib->fib_OwnerGID; diff --git a/rom/filesys/afs/filehandles3.c b/rom/filesys/afs/filehandles3.c index dbe589462b..1e1164e87e 100644 --- a/rom/filesys/afs/filehandles3.c +++ b/rom/filesys/afs/filehandles3.c @@ -25,7 +25,7 @@ static const ULONG sizes[]= offsetof(struct ExAllData,ed_Days), offsetof(struct ExAllData,ed_Comment), offsetof(struct ExAllData,ed_OwnerUID), - sizeof(struct ExAllData) + offsetof(struct ExAllData,ed_Size64) /* ED_OWNER: up to ed_OwnerGID */ }; ULONG examineEAD diff --git a/rom/filesys/afs/os_unix_support.h b/rom/filesys/afs/os_unix_support.h index f4d5b6c489..a140312607 100644 --- a/rom/filesys/afs/os_unix_support.h +++ b/rom/filesys/afs/os_unix_support.h @@ -145,6 +145,7 @@ struct InfoData { #define ED_DATE 5 #define ED_COMMENT 6 #define ED_OWNER 7 +#define ED_SIZE64 8 struct ExAllData { struct ExAllData *ed_Next; UBYTE *ed_Name; @@ -157,6 +158,7 @@ struct ExAllData { UBYTE *ed_Comment; UWORD ed_OwnerUID; UWORD ed_OwnerGID; + uint64_t ed_Size64; }; struct ExAllControl { ULONG eac_Entries; diff --git a/rom/filesys/pfs3/fs/directory.c b/rom/filesys/pfs3/fs/directory.c index 5b53a8187a..6f55b3e9bc 100644 --- a/rom/filesys/pfs3/fs/directory.c +++ b/rom/filesys/pfs3/fs/directory.c @@ -1181,7 +1181,7 @@ static ULONG FillInData(struct ExAllData *buffer, LONG type, break; case ED_OWNER: -#if defined(__MORPHOS__) +#if defined(__MORPHOS__) || defined(__AROS__) size = offsetof(struct ExAllData, ed_Size64); break; @@ -1220,7 +1220,7 @@ static ULONG FillInData(struct ExAllData *buffer, LONG type, buffer->ed_Next = NULL; switch (type) { -#if defined(__MORPHOS__) +#if defined(__MORPHOS__) || defined(__AROS__) case ED_SIZE64: #if ROLLOVER if (direntry->type == ST_ROLLOVERFILE) @@ -1292,7 +1292,7 @@ BOOL ExamineAll(lockentry_t *object, UBYTE *buffer, ULONG buflen, } /* check type field */ -#if defined(__MORPHOS__) +#if defined(__MORPHOS__) || defined(__AROS__) if (type > ED_SIZE64 || type < ED_NAME) #else if (type > ED_OWNER || type < ED_NAME) @@ -4164,7 +4164,7 @@ static ULONG FillInDDEData(struct ExAllData *buffer, LONG type, size = offsetof(struct ExAllData, ed_OwnerUID); break; case ED_OWNER: -#if defined(__MORPHOS__) +#if defined(__MORPHOS__) || defined(__AROS__) size = offsetof(struct ExAllData, ed_Size64); break; case ED_SIZE64: @@ -4196,7 +4196,7 @@ static ULONG FillInDDEData(struct ExAllData *buffer, LONG type, buffer->ed_Next = NULL; switch (type) { -#if defined(__MORPHOS__) +#if defined(__MORPHOS__) || defined(__AROS__) case ED_SIZE64: buffer->ed_Size64 = GetDDFileSize(dde, g); #endif diff --git a/workbench/network/smbfs/source_code/main.c b/workbench/network/smbfs/source_code/main.c index cb7453f6d0..f882a75ebe 100755 --- a/workbench/network/smbfs/source_code/main.c +++ b/workbench/network/smbfs/source_code/main.c @@ -4427,7 +4427,7 @@ Action_ExamineAll( case ED_OWNER: - ec.ec_MinSize = sizeof(struct ExAllData); + ec.ec_MinSize = offsetof(struct ExAllData,ed_Size64); break; } From 3e5167e7f588cf51440f3d43fbba2a1e7910034a Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 04/12] dos: add dos64.library dos64.library has the 64 bit calls: Seek64(), SetFileSize64(), GetFilePosition64(), GetFileSize64(), ChangeFilePosition64(), ChangeFileSize64(), Read64() and Write64(), Examine64(), ExNext64(), ExamineFH64() and ExamineName64(), Info64(), the record locking calls and AllocDosObject64(). It is version 51.0 and takes the 64 bit arguments with AROS_LHAQUAD. The examine calls send ACTION_EXAMINE_OBJECT64, _NEXT64 and _FH64 on all systems. A handler that does not know them gets the 32 bit calls, and for a file of 2 GiB or more ACTION_GET_FILE_SIZE64 is asked for the size: with DupLock and OpenFromLock in Examine64(), by name in the directory in ExNext64(). A file that cannot be opened keeps the clamped size. ExamineName64() reads the entry from the parent directory when a file open for writing cannot be locked, so the size of a file being written is available. --- compiler/include/dos/dos64.h | 144 +++++++++++++ rom/dos64/allocdosobject64.c | 75 +++++++ rom/dos64/changefileposition64.c | 60 ++++++ rom/dos64/changefilesize64.c | 66 ++++++ rom/dos64/dos64.conf | 44 ++++ rom/dos64/dos64_init.c | 32 +++ rom/dos64/dos64_intern.h | 135 ++++++++++++ rom/dos64/dos64_packet.c | 112 ++++++++++ rom/dos64/dos64_support.c | 340 +++++++++++++++++++++++++++++++ rom/dos64/examine64.c | 81 ++++++++ rom/dos64/examinefh64.c | 89 ++++++++ rom/dos64/examinename64.c | 141 +++++++++++++ rom/dos64/exnext64.c | 79 +++++++ rom/dos64/freedosobject64.c | 61 ++++++ rom/dos64/getfileposition64.c | 73 +++++++ rom/dos64/getfilesize64.c | 66 ++++++ rom/dos64/info64.c | 103 ++++++++++ rom/dos64/isfilesystem64.c | 87 ++++++++ rom/dos64/lockrecord64.c | 97 +++++++++ rom/dos64/lockrecords64.c | 76 +++++++ rom/dos64/mmakefile.src | 31 +++ rom/dos64/read64.c | 95 +++++++++ rom/dos64/seek64.c | 64 ++++++ rom/dos64/setfilesize64.c | 69 +++++++ rom/dos64/unlockrecord64.c | 85 ++++++++ rom/dos64/unlockrecords64.c | 64 ++++++ rom/dos64/write64.c | 94 +++++++++ rom/mmakefile.src | 6 +- 28 files changed, 2468 insertions(+), 1 deletion(-) create mode 100644 compiler/include/dos/dos64.h create mode 100644 rom/dos64/allocdosobject64.c create mode 100644 rom/dos64/changefileposition64.c create mode 100644 rom/dos64/changefilesize64.c create mode 100644 rom/dos64/dos64.conf create mode 100644 rom/dos64/dos64_init.c create mode 100644 rom/dos64/dos64_intern.h create mode 100644 rom/dos64/dos64_packet.c create mode 100644 rom/dos64/dos64_support.c create mode 100644 rom/dos64/examine64.c create mode 100644 rom/dos64/examinefh64.c create mode 100644 rom/dos64/examinename64.c create mode 100644 rom/dos64/exnext64.c create mode 100644 rom/dos64/freedosobject64.c create mode 100644 rom/dos64/getfileposition64.c create mode 100644 rom/dos64/getfilesize64.c create mode 100644 rom/dos64/info64.c create mode 100644 rom/dos64/isfilesystem64.c create mode 100644 rom/dos64/lockrecord64.c create mode 100644 rom/dos64/lockrecords64.c create mode 100644 rom/dos64/mmakefile.src create mode 100644 rom/dos64/read64.c create mode 100644 rom/dos64/seek64.c create mode 100644 rom/dos64/setfilesize64.c create mode 100644 rom/dos64/unlockrecord64.c create mode 100644 rom/dos64/unlockrecords64.c create mode 100644 rom/dos64/write64.c diff --git a/compiler/include/dos/dos64.h b/compiler/include/dos/dos64.h new file mode 100644 index 0000000000..14fcf55dec --- /dev/null +++ b/compiler/include/dos/dos64.h @@ -0,0 +1,144 @@ +#ifndef DOS_DOS64_H +#define DOS_DOS64_H + +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: 64-bit filesystem I/O support definitions, for use with + dos64.library and 64-bit aware filesystem handlers. +*/ + +#ifndef DOS_DOS_H +# include +#endif +#ifndef DOS_DOSEXTENS_H +# include +#endif +#ifndef DOS_RECORD_H +# include +#endif + +/********************************************************************** + ********************** 64-bit Packet types *************************** + **********************************************************************/ + +/* + * MorphOS (tm) compatible extensions (V51). 64-bit values are passed by + * pointer, so the packets are the same on 32-bit and 64-bit systems: + * + * ACTION_SEEK64 dp_Arg1 fh_Arg1, dp_Arg2 QUAD *position, + * dp_Arg3 mode, dp_Arg4 QUAD *oldposition + * ACTION_SET_FILE_SIZE64 dp_Arg1 fh_Arg1, dp_Arg2 QUAD *offset, + * dp_Arg3 mode, dp_Arg4 QUAD *newsize + * ACTION_LOCK_RECORD64 dp_Arg1 fh_Arg1, dp_Arg2 UQUAD *offset, + * dp_Arg3 UQUAD *length, dp_Arg4 mode, + * dp_Arg5 timeout + * ACTION_FREE_RECORD64 dp_Arg1 fh_Arg1, dp_Arg2 UQUAD *offset, + * dp_Arg3 UQUAD *length + * ACTION_QUERY_ATTR dp_Arg1 attribute (FQA_), dp_Arg2 APTR storage, + * dp_Arg3 storage size + * + * dp_Res1 is DOSTRUE on success, or DOSFALSE with the error in dp_Res2; + * the results are stored through the pointers. + * + * ACTION_EXAMINE_OBJECT64, ACTION_EXAMINE_NEXT64 and ACTION_EXAMINE_FH64 + * take the same arguments as the 32-bit packets (dp_Arg1 the lock, or + * fh_Arg1 for _FH64; dp_Arg2 a BPTR to a struct FileInfoBlock). The handler + * fills the standard fields and fib_Size64/fib_NumBlocks64 (see ), + * with fib_Size 0 for sizes above 2^31-1, and sets fib_ActExtFlags. The + * sender must set fib_ActExtFlags to 0 and fib_ReqExtFlags to the + * extensions it wants (or 0). + * + * A handler that does not know a packet answers DOSFALSE with + * ERROR_ACTION_NOT_KNOWN. + */ +#ifndef ACTION_SEEK64 +#define ACTION_SEEK64 26400 +#define ACTION_SET_FILE_SIZE64 26401 +#define ACTION_LOCK_RECORD64 26402 +#define ACTION_FREE_RECORD64 26403 +#define ACTION_QUERY_ATTR 26407 +#define ACTION_EXAMINE_OBJECT64 26408 +#define ACTION_EXAMINE_NEXT64 26409 +#define ACTION_EXAMINE_FH64 26410 +#endif + +/* ACTION_QUERY_ATTR attributes (MorphOS (tm) compatible) */ +#ifndef FQA_MaxFileNameLength +#define FQA_MaxFileNameLength 0 /* LONG */ +#define FQA_MaxVolumeNameLength 1 /* LONG */ +#define FQA_MaxFileSize 2 /* QUAD */ +#define FQA_IsCaseSensitive 3 /* LONG */ +#define FQA_DeviceType 4 /* LONG */ +#define FQA_NumBlocks 6 /* QUAD */ +#define FQA_NumBlocksUsed 7 /* QUAD */ +#endif + +/* + * AROS extension: 64-bit volume information. + * Arguments as for ACTION_INFO, but dp_Arg2 points (BPTR) to a + * struct InfoData64 (see ): the standard InfoData followed by + * the 64-bit block counts. + */ +#define ACTION_INFO64 2020 + +#if (__WORDSIZE != 64) +/* + * AmigaOS 4 (tm) compatible 64-bit packet layout, used on 32-bit + * systems for the ACTION_CHANGE_FILE_POSITION64, ACTION_GET_FILE_POSITION64, + * ACTION_CHANGE_FILE_SIZE64 and ACTION_GET_FILE_SIZE64 packets, where the + * standard DosPacket fields are too small to carry 64-bit values. + * + * This structure overlays the standard DosPacket. The originator must + * additionally store the object (fh_Arg1) in the *standard* packet's + * dp_Arg1 field, set dp_Res0 to DP64_INIT, and place the 64-bit + * argument(s) in the fields below. + * + * On 64-bit AROS builds this structure is not used (see below). + */ +struct DosPacket64 +{ + struct Message * dp_Link; /* Pointer to a standard exec message. */ + struct MsgPort * dp_Port; /* Reply-Port of that packet. */ + + LONG dp_Type; /* 8: Packet type (ACTION_...) */ + LONG dp_Res0; /* 12: Set to DP64_INIT by the originator */ + ULONG dp_Res2; /* 16: Secondary result (IoErr() value) */ + LONG dp_Pad0; /* 20: see the alignment note below */ + QUAD dp_Res1; /* 24: 64-bit primary result */ + LONG dp_Arg1; /* 32: the object (fh_Arg1) */ + LONG dp_Pad1; /* 36 */ + QUAD dp_Arg2; /* 40: 64-bit argument */ + ULONG dp_Arg3; /* 48: 32-bit argument (e.g. seek mode) */ + ULONG dp_Arg4; /* 52: struct FileHandle * */ + QUAD dp_Arg5; /* 56: must be zero to validate dp_Arg4 */ +}; + +/* + * On 64-bit AROS the standard DosPacket argument and result fields are + * already 64-bit wide (SIPTR), so these four packets carry their 64-bit + * values directly in dp_Arg2/dp_Res1 of a standard packet there. + * + * The padding above is deliberate and must not be removed. The 64-bit + * fields of this packet sit at fixed offsets (dp_Res1 at 24, dp_Arg2 at + * 40, dp_Arg5 at 56), which is what a handler on the other side reads + * and writes. Those offsets are what a compiler that gives a 64-bit type + * 8-byte alignment produces on its own - but m68k aligns them to 4, so + * without the padding every 64-bit field would sit 4 bytes early and the + * two sides would disagree about where the result is. Spelling the + * padding out keeps the layout identical whatever the ABI decides. + */ + +#define DP64_INIT (-3) +#endif + +/********************************************************************** + ******************* AllocDosObject64() types ************************* + **********************************************************************/ + +/* Objects allocatable with dos64.library/AllocDosObject64() */ +#define DOS64_FIB 1 /* struct FileInfoBlock */ +#define DOS64_INFODATA 2 /* struct InfoData64 */ +#define DOS64_RECORDLOCK 3 /* struct RecordLock64 */ + +#endif /* DOS_DOS64_H */ diff --git a/rom/dos64/allocdosobject64.c b/rom/dos64/allocdosobject64.c new file mode 100644 index 0000000000..93cac1701b --- /dev/null +++ b/rom/dos64/allocdosobject64.c @@ -0,0 +1,75 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Create 64-bit dos objects. +*/ + +#include +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2(APTR, AllocDosObject64, + +/* SYNOPSIS */ + AROS_LHA(ULONG, type, D1), + AROS_LHA(const struct TagItem *, tags, D2), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 21, Dos64) + +/* FUNCTION + Creates a dos object of a given type, for use with the 64-bit + dos64.library functions. Free the object with FreeDosObject64() + when done. + + INPUTS + type - object type (DOS64_FIB, DOS64_INFODATA, DOS64_RECORDLOCK, + see ) + tags - future extensions, pass NULL + + RESULT + Pointer to the new object, or NULL on failure. IoErr() gives + additional information in that case. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + FreeDosObject64(), dos.library/AllocDosObject() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + ULONG size; + + switch (type) + { + case DOS64_FIB: + size = sizeof(struct FileInfoBlock); + break; + case DOS64_INFODATA: + size = sizeof(struct InfoData64); + break; + case DOS64_RECORDLOCK: + size = sizeof(struct RecordLock64); + break; + default: + SetIoErr(ERROR_BAD_NUMBER); + return NULL; + } + + return AllocVec(size, MEMF_PUBLIC | MEMF_CLEAR); + + AROS_LIBFUNC_EXIT +} /* AllocDosObject64 */ diff --git a/rom/dos64/changefileposition64.c b/rom/dos64/changefileposition64.c new file mode 100644 index 0000000000..d2633c0db2 --- /dev/null +++ b/rom/dos64/changefileposition64.c @@ -0,0 +1,60 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Change the current 64-bit position in a file (boolean result). +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2QUAD1(LONG, ChangeFilePosition64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + AROS_LHA(LONG, mode, D2), + AROS_LHAQUAD(QUAD, position, D3, D4), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 9, Dos64) + +/* FUNCTION + Changes the current read/write position in a file with full + 64-bit range. Behaves like Seek64() but returns a boolean + result instead of the previous position, matching the + AmigaOS 4 style API. + + INPUTS + file - filehandle + mode - Where to count from. Either OFFSET_BEGINNING, + OFFSET_CURRENT or OFFSET_END. + position - relative offset in bytes (positive, negative or 0). + + RESULT + Boolean success indicator; on DOSFALSE, IoErr() gives + additional information. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + Seek64(), GetFilePosition64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + return (dos64_SeekBuffered(DOS64Base, file, position, mode) == -1) + ? DOSFALSE : DOSTRUE; + + AROS_LIBFUNC_EXIT +} /* ChangeFilePosition64 */ diff --git a/rom/dos64/changefilesize64.c b/rom/dos64/changefilesize64.c new file mode 100644 index 0000000000..84923d3629 --- /dev/null +++ b/rom/dos64/changefilesize64.c @@ -0,0 +1,66 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Change the size of a file, 64-bit version (boolean result). +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2QUAD1(LONG, ChangeFileSize64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + AROS_LHA(LONG, mode, D2), + AROS_LHAQUAD(QUAD, size, D3, D4), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 10, Dos64) + +/* FUNCTION + Change the size of a file with full 64-bit range. Behaves like + SetFileSize64() but returns a boolean result instead of the + new size, matching the AmigaOS 4 style API. + + INPUTS + file - filehandle + mode - OFFSET_BEGINNING, OFFSET_CURRENT or OFFSET_END + size - relative size + + RESULT + Boolean success indicator; on DOSFALSE, IoErr() gives + additional information. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + SetFileSize64(), GetFileSize64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fh = BADDR(file); + + if (fh == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return DOSFALSE; + } + + return (dos64_SetFileSize(DOS64Base, fh, size, mode, FALSE) == -1) + ? DOSFALSE : DOSTRUE; + + AROS_LIBFUNC_EXIT +} /* ChangeFileSize64 */ diff --git a/rom/dos64/dos64.conf b/rom/dos64/dos64.conf new file mode 100644 index 0000000000..07e094810a --- /dev/null +++ b/rom/dos64/dos64.conf @@ -0,0 +1,44 @@ +##begin config +version 51.0 +basename Dos64 +libbase DOS64Base +libbasetype struct Dos64Base +libbasetypeextern struct Library +residentpri -121 +options noexpunge +##end config + +##begin cdef +#include +#include +#include +#include +#include +##end cdef + +##begin cdefprivate +#include "dos64_intern.h" +##end cdefprivate + +##begin functionlist +QUAD Seek64(BPTR file, LONG mode, QUAD position) (D1, D2, D3/D4) +QUAD SetFileSize64(BPTR file, LONG mode, QUAD offset) (D1, D2, D3/D4) +QUAD GetFilePosition64(BPTR file) (D1) +QUAD GetFileSize64(BPTR file) (D1) +LONG ChangeFilePosition64(BPTR file, LONG mode, QUAD position) (D1, D2, D3/D4) +LONG ChangeFileSize64(BPTR file, LONG mode, QUAD size) (D1, D2, D3/D4) +QUAD Read64(BPTR file, APTR buffer, QUAD length) (D1, D2, D3/D4) +QUAD Write64(BPTR file, CONST_APTR buffer, QUAD length) (D1, D2, D3/D4) +LONG Examine64(BPTR lock, struct FileInfoBlock *fib, struct TagItem *tags) (D1, D2, D3) +LONG ExNext64(BPTR lock, struct FileInfoBlock *fib, struct TagItem *tags) (D1, D2, D3) +LONG ExamineFH64(BPTR fh, struct FileInfoBlock *fib, struct TagItem *tags) (D1, D2, D3) +LONG Info64(BPTR lock, struct InfoData64 *parameterBlock) (D1, D2) +BOOL LockRecord64(struct RecordLock64 *rec, ULONG timeout) (D1, D2) +BOOL LockRecords64(struct RecordLock64 *recArray, ULONG timeout) (D1, D2) +BOOL UnLockRecord64(struct RecordLock64 *rec) (D1) +BOOL UnLockRecords64(struct RecordLock64 *recArray) (D1) +APTR AllocDosObject64(ULONG type, const struct TagItem *tags) (D1, D2) +void FreeDosObject64(ULONG type, APTR ptr) (D1, D2) +LONG IsFileSystem64(BPTR file) (D1) +LONG ExamineName64(CONST_STRPTR name, struct FileInfoBlock *fib, struct TagItem *tags) (D1, D2, D3) +##end functionlist diff --git a/rom/dos64/dos64_init.c b/rom/dos64/dos64_init.c new file mode 100644 index 0000000000..4df44046eb --- /dev/null +++ b/rom/dos64/dos64_init.c @@ -0,0 +1,32 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: dos64.library initialisation. +*/ + +#include +#include + +#include + +#include "dos64_intern.h" + +#include LC_LIBDEFS_FILE + +static int Dos64_Init(struct Dos64Base *DOS64Base) +{ + DOS64Base->d64_DosBase = (struct DosLibrary *)OpenLibrary("dos.library", 50); + + return DOS64Base->d64_DosBase != NULL; +} + +static int Dos64_Expunge(struct Dos64Base *DOS64Base) +{ + if (DOS64Base->d64_DosBase) + CloseLibrary(&DOS64Base->d64_DosBase->dl_lib); + + return TRUE; +} + +ADD2INITLIB(Dos64_Init, 0) +ADD2EXPUNGELIB(Dos64_Expunge, 0) diff --git a/rom/dos64/dos64_intern.h b/rom/dos64/dos64_intern.h new file mode 100644 index 0000000000..88f1fc76fa --- /dev/null +++ b/rom/dos64/dos64_intern.h @@ -0,0 +1,135 @@ +#ifndef DOS64_INTERN_H +#define DOS64_INTERN_H + +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Internal definitions for dos64.library +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct Dos64Base +{ + struct Library d64_Lib; + struct DosLibrary *d64_DosBase; +}; + +/* + * Inside the library functions the base parameter is named DOS64Base; + * route the dos.library interface through the base we opened at init. + * (proto/dos.h is included above, so its libbase declaration is not + * affected by this macro.) + */ +#define DOSBase (DOS64Base->d64_DosBase) + +/* Filehandle buffering flags, shared with dos.library */ +#include "dos_fhflags.h" + +/* + * Errors that indicate the filesystem does not understand a packet + * type, meaning we should fall back to the 32-bit operation. + */ +#define dos64_UnsupportedAction(err) \ + ((err) == ERROR_ACTION_NOT_KNOWN || \ + (err) == ERROR_NOT_IMPLEMENTED || \ + (err) == ERROR_BAD_NUMBER) + +/* + * A value-returning packet did not give us an answer, so the caller + * should ask again over the 32-bit path. + * + * Handlers reply to a packet they will not service with either -1 or + * the canonical DOSFALSE, so accept both res1 values - but do not go + * on to insist on a particular error code. Filesystems report refusing + * these packets in whatever terms suit them (pfs3 answers them with + * ERROR_NOT_A_DOS_DISK when it has no valid disk, for instance), and a + * code we failed to anticipate must not be mistaken for a result. + * + * Testing the error rather than the result also keeps the genuine + * answer zero - an empty file, or position zero - distinguishable from + * DOSFALSE: those come back with no error and are returned as-is. + * + * Falling back is always safe here. These packets only ever ask a + * question or reposition a file; reads and writes never travel this + * way, so nothing can be done twice by asking again. + */ +#define dos64_UnsupportedPkt(ret, err) \ + (((ret) == -1 || (ret) == DOSFALSE) && ((err) != 0)) + +/* + * The 64-bit structures must keep their published layout: the MorphOS (tm) + * V51 offsets on 32-bit systems (64-bit integers 2-byte aligned), natural + * alignment on 64-bit systems. Fail the build if a compiler moves a field. + */ +#define DOS64_LAYOUT_CHECK(name, cond) typedef char dos64_layout_##name[(cond) ? 1 : -1] +#if (__WORDSIZE == 64) +DOS64_LAYOUT_CHECK(fib_size, __builtin_offsetof(struct FileInfoBlock, fib_Size) == 128); +DOS64_LAYOUT_CHECK(fib_size64, __builtin_offsetof(struct FileInfoBlock, fib_Size64) == 232); +DOS64_LAYOUT_CHECK(fib_nblk64, __builtin_offsetof(struct FileInfoBlock, fib_NumBlocks64) == 240); +DOS64_LAYOUT_CHECK(fib_actext, __builtin_offsetof(struct FileInfoBlock, fib_ActExtFlags) == 262); +DOS64_LAYOUT_CHECK(fib_total, sizeof(struct FileInfoBlock) == 264); +DOS64_LAYOUT_CHECK(ead_size64, __builtin_offsetof(struct ExAllData, ed_Size64) == 56); +DOS64_LAYOUT_CHECK(rec_offset, __builtin_offsetof(struct RecordLock64, rec_Offset) == 8); +DOS64_LAYOUT_CHECK(rec_total, sizeof(struct RecordLock64) == 32); +DOS64_LAYOUT_CHECK(id_nblk64, __builtin_offsetof(struct InfoData64, id_NumBlocks64) == 48); +#else +DOS64_LAYOUT_CHECK(fib_size, __builtin_offsetof(struct FileInfoBlock, fib_Size) == 124); +DOS64_LAYOUT_CHECK(fib_size64, __builtin_offsetof(struct FileInfoBlock, fib_Size64) == 228); +DOS64_LAYOUT_CHECK(fib_nblk64, __builtin_offsetof(struct FileInfoBlock, fib_NumBlocks64) == 236); +DOS64_LAYOUT_CHECK(fib_actext, __builtin_offsetof(struct FileInfoBlock, fib_ActExtFlags) == 258); +DOS64_LAYOUT_CHECK(fib_total, sizeof(struct FileInfoBlock) == 260); +DOS64_LAYOUT_CHECK(ead_size64, __builtin_offsetof(struct ExAllData, ed_Size64) == 40); +DOS64_LAYOUT_CHECK(rec_offset, __builtin_offsetof(struct RecordLock64, rec_Offset) == 4); +DOS64_LAYOUT_CHECK(rec_length, __builtin_offsetof(struct RecordLock64, rec_Length) == 12); +DOS64_LAYOUT_CHECK(rec_total, sizeof(struct RecordLock64) == 24); +DOS64_LAYOUT_CHECK(id_nblk64, __builtin_offsetof(struct InfoData64, id_NumBlocks64) == 36); +#endif + +/* + * A MorphOS style packet (results stored through pointers, dp_Res1 a + * success flag) succeeded. dp_Res2 is cleared before the packet is sent, + * so a handler that answers an unknown packet with a non-zero dp_Res1 + * still sets an error and is not mistaken for success. + */ +#define dos64_PktOK(ret, err) (((ret) != DOSFALSE) && ((err) == 0)) + +/* Largest chunk handed to the 32-bit ACTION_READ/ACTION_WRITE packets */ +#define DOS64_IOCHUNK 0x40000000 + +/* dos64_packet.c */ +SIPTR dos64_SendPkt(struct Dos64Base *DOS64Base, struct MsgPort *port, LONG action, + SIPTR arg1, SIPTR arg2, SIPTR arg3, SIPTR arg4, SIPTR arg5, + SIPTR *res2); +#if (__WORDSIZE != 64) +QUAD dos64_SendPkt64OS4(struct Dos64Base *DOS64Base, struct MsgPort *port, LONG action, + SIPTR object, QUAD arg64, LONG arg32, SIPTR *res2); +#endif + +/* dos64_support.c */ +QUAD dos64_Seek(struct Dos64Base *DOS64Base, struct FileHandle *fh, + QUAD position, LONG mode); +QUAD dos64_SeekBuffered(struct Dos64Base *DOS64Base, BPTR file, + QUAD position, LONG mode); +QUAD dos64_SetFileSize(struct Dos64Base *DOS64Base, struct FileHandle *fh, + QUAD offset, LONG mode, BOOL wantsize); +QUAD dos64_GetFileSize(struct Dos64Base *DOS64Base, struct FileHandle *fh); +void dos64_FixFIB64(struct FileInfoBlock *fib); +void dos64_PrepFIB64(struct FileInfoBlock *fib); +void dos64_FixSizeFH(struct Dos64Base *DOS64Base, struct FileHandle *fh, + struct FileInfoBlock *fib); +void dos64_SetFIBSize(struct FileInfoBlock *fib, UQUAD size); +LONG dos64_Examine32(struct Dos64Base *DOS64Base, BPTR lock, + struct FileInfoBlock *fib, LONG action); + +#endif /* DOS64_INTERN_H */ diff --git a/rom/dos64/dos64_packet.c b/rom/dos64/dos64_packet.c new file mode 100644 index 0000000000..27396fac1a --- /dev/null +++ b/rom/dos64/dos64_packet.c @@ -0,0 +1,112 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: dos64.library packet transport helpers. +*/ + +#include +#include +#include + +#include "dos64_intern.h" + +/* + * Send a packet to a filesystem handler and wait for the result. + * Values travel in the standard DosPacket argument slots, which are + * SIPTR-sized (i.e. 64-bit on 64-bit systems). Returns dp_Res1; if + * res2 is non-NULL it receives dp_Res2 (the IoErr() value). + */ +SIPTR dos64_SendPkt(struct Dos64Base *DOS64Base, struct MsgPort *port, LONG action, + SIPTR arg1, SIPTR arg2, SIPTR arg3, SIPTR arg4, SIPTR arg5, + SIPTR *res2) +{ + SIPTR res; + + res = DoPkt(port, action, arg1, arg2, arg3, arg4, arg5); + if (res2) + *res2 = IoErr(); + + return res; +} + +#if (__WORDSIZE != 64) +/* + * On 32-bit systems the standard packet arguments cannot carry 64-bit + * values, so the AmigaOS 4 style ACTION_*64 packets use the + * struct DosPacket64 overlay (see ): the object (fh_Arg1) + * goes into the standard dp_Arg1 slot, dp_Res0 is set to DP64_INIT and + * the 64-bit argument travels in the overlay's dp_Arg2. + * + * The overlay is larger than a standard DosPacket, so a private message + * and packet pair is built here instead of using DOS_STDPKT. + */ +QUAD dos64_SendPkt64OS4(struct Dos64Base *DOS64Base, struct MsgPort *port, LONG action, + SIPTR object, QUAD arg64, LONG arg32, SIPTR *res2) +{ + struct Process *me = (struct Process *)FindTask(NULL); + struct + { + struct Message msg; + struct DosPacket64 pkt64; + } *sp; + struct DosPacket *dp; + QUAD res; + + if (me->pr_Task.tc_Node.ln_Type != NT_PROCESS) + { + SetIoErr(ERROR_ACTION_NOT_KNOWN); + if (res2) + *res2 = ERROR_ACTION_NOT_KNOWN; + return -1; + } + + sp = AllocVec(sizeof(*sp), MEMF_PUBLIC | MEMF_CLEAR); + if (sp == NULL) + { + SetIoErr(ERROR_NO_FREE_STORE); + if (res2) + *res2 = ERROR_NO_FREE_STORE; + return -1; + } + + dp = (struct DosPacket *)&sp->pkt64; + sp->msg.mn_Node.ln_Name = (char *)dp; + sp->msg.mn_Length = sizeof(sp->pkt64); + dp->dp_Link = &sp->msg; + dp->dp_Type = action; + dp->dp_Arg1 = object; /* standard slot, as handlers expect */ + sp->pkt64.dp_Res0 = DP64_INIT; /* marks the packet as 64-bit capable */ + sp->pkt64.dp_Arg1 = object; /* the object, where a 64-bit handler looks */ + sp->pkt64.dp_Arg2 = arg64; + sp->pkt64.dp_Arg3 = arg32; + sp->pkt64.dp_Arg5 = 0; /* zero validates dp_Arg4 */ + + SendPkt(dp, port, &me->pr_MsgPort); + if (WaitPkt() != dp) + Alert(AN_AsyncPkt); + + /* + * The overlay's dp_Res0 (holding the DP64_INIT marker) shares its + * offset with the standard packet's dp_Res1. A handler that + * understands the 64-bit packet preserves the marker and answers + * through the overlay fields; a plain 32-bit handler answers + * through the standard fields, overwriting the marker. This is + * what tells the two reply forms apart. + */ + if (sp->pkt64.dp_Res0 == DP64_INIT) + { + res = sp->pkt64.dp_Res1; + if (res2) + *res2 = sp->pkt64.dp_Res2; + } + else + { + res = dp->dp_Res1; + if (res2) + *res2 = dp->dp_Res2; + } + + FreeVec(sp); + return res; +} +#endif diff --git a/rom/dos64/dos64_support.c b/rom/dos64/dos64_support.c new file mode 100644 index 0000000000..0a46450bba --- /dev/null +++ b/rom/dos64/dos64_support.c @@ -0,0 +1,340 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: dos64.library internal support - 64-bit operations with + 32-bit delegation when the filesystem lacks 64-bit support. +*/ + +#include +#include +#include + +#include "dos64_intern.h" + +/* + * Seek on the underlying filesystem, returning the previous position. + * Tries the 64-bit packets first and falls back to ACTION_SEEK when + * the handler does not understand them. + */ +QUAD dos64_Seek(struct Dos64Base *DOS64Base, struct FileHandle *fh, + QUAD position, LONG mode) +{ + SIPTR err = 0; + QUAD ret, old; + +#if (__WORDSIZE == 64) + /* + * MorphOS style single-packet seek: the new position and the previous + * position travel by pointer, dp_Res1 is a success flag. + */ + { + QUAD pos = position, prev = 0; + + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_SEEK64, + fh->fh_Arg1, (SIPTR)&pos, mode, (SIPTR)&prev, 0, &err); + if (dos64_PktOK(ret, err)) + return prev; + } + + /* OS4 style pair: query the old position, then reposition */ + old = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_GET_FILE_POSITION64, + fh->fh_Arg1, 0, 0, 0, 0, &err); + if (!dos64_UnsupportedPkt(old, err)) + { + if (old == -1) + return -1; + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_CHANGE_FILE_POSITION64, + fh->fh_Arg1, position, mode, 0, 0, &err); + return ret ? old : -1; + } +#else + old = dos64_SendPkt64OS4(DOS64Base, fh->fh_Type, ACTION_GET_FILE_POSITION64, + fh->fh_Arg1, 0, 0, &err); + if (!dos64_UnsupportedPkt(old, err)) + { + if (old == -1) + return -1; + ret = dos64_SendPkt64OS4(DOS64Base, fh->fh_Type, ACTION_CHANGE_FILE_POSITION64, + fh->fh_Arg1, position, mode, &err); + return ret ? old : -1; + } +#endif + + /* 32-bit delegation */ + if (position > 0x7FFFFFFFLL || position < -0x80000000LL) + { + SetIoErr(ERROR_OBJECT_TOO_LARGE); + return -1; + } + return dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_SEEK, + fh->fh_Arg1, (LONG)position, mode, 0, 0, NULL); +} + +/* + * Seek through a (possibly buffered) filehandle, mirroring the buffer + * handling of dos.library/Seek(). + */ +QUAD dos64_SeekBuffered(struct Dos64Base *DOS64Base, BPTR file, + QUAD position, LONG mode) +{ + struct FileHandle *fh = BADDR(file); + QUAD offset = 0, ret; + + if (fh == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return -1; + } + + /* If the file is in append mode, seeking is not allowed. */ + if (fh->fh_Flags & FHF_APPEND) + return dos64_Seek(DOS64Base, fh, 0, OFFSET_CURRENT); + + if (fh->fh_Flags & FHF_WRITE) + { + /* Write mode: flush pending buffered data first. */ + Flush(file); + } + else + { + /* Read mode: adjust the offset for unconsumed buffered data. */ + if (fh->fh_Pos < fh->fh_End && mode == OFFSET_CURRENT) + offset = (QUAD)(fh->fh_Pos - fh->fh_End); + fh->fh_Pos = fh->fh_End = 0; + } + + ret = dos64_Seek(DOS64Base, fh, position + offset, mode); + return (ret == -1) ? -1 : ret + offset; +} + +/* + * Return the size of the file behind fh, using the 64-bit packet when + * available, then ACTION_EXAMINE_FH, then a seek dance as last resort. + */ +QUAD dos64_GetFileSize(struct Dos64Base *DOS64Base, struct FileHandle *fh) +{ + struct FileInfoBlock *fib; + SIPTR err = 0; + QUAD ret, cur; + +#if (__WORDSIZE == 64) + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_GET_FILE_SIZE64, + fh->fh_Arg1, 0, 0, 0, 0, &err); + if (!dos64_UnsupportedPkt(ret, err)) + return ret; +#else + ret = dos64_SendPkt64OS4(DOS64Base, fh->fh_Type, ACTION_GET_FILE_SIZE64, + fh->fh_Arg1, 0, 0, &err); + if (!dos64_UnsupportedPkt(ret, err)) + return ret; +#endif + + fib = AllocVec(sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR); + if (fib != NULL) + { + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_EXAMINE_FH, + fh->fh_Arg1, (SIPTR)MKBADDR(fib), 0, 0, 0, &err); + cur = (QUAD)(ULONG)fib->fib_Size; + FreeVec(fib); + if (ret) + return cur; + if (!dos64_UnsupportedAction(err)) + return -1; + } + + /* + * Seek dance: ACTION_SEEK returns the previous position, so seeking + * to the end yields the old position, and seeking back to it yields + * the file size. + */ + cur = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_SEEK, + fh->fh_Arg1, 0, OFFSET_END, 0, 0, &err); + if (cur == -1) + return -1; + return dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_SEEK, + fh->fh_Arg1, (SIPTR)cur, OFFSET_BEGINNING, 0, 0, NULL); +} + +/* + * Set the size of the file behind fh. Returns the new size (-1 on + * error); when wantsize is FALSE, 0 is returned on success instead of + * querying the resulting size. + */ +QUAD dos64_SetFileSize(struct Dos64Base *DOS64Base, struct FileHandle *fh, + QUAD offset, LONG mode, BOOL wantsize) +{ + SIPTR err = 0; + QUAD ret; + +#if (__WORDSIZE == 64) + /* MorphOS style: offset and resulting size travel by pointer */ + { + QUAD off = offset, newsize = 0; + + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_SET_FILE_SIZE64, + fh->fh_Arg1, (SIPTR)&off, mode, (SIPTR)&newsize, 0, &err); + if (dos64_PktOK(ret, err)) + return wantsize ? newsize : 0; + } + + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_CHANGE_FILE_SIZE64, + fh->fh_Arg1, offset, mode, 0, 0, &err); +#else + ret = dos64_SendPkt64OS4(DOS64Base, fh->fh_Type, ACTION_CHANGE_FILE_SIZE64, + fh->fh_Arg1, offset, mode, &err); +#endif + if (!dos64_UnsupportedPkt(ret, err)) + { + if (ret == DOSFALSE) + return -1; + return wantsize ? dos64_GetFileSize(DOS64Base, fh) : 0; + } + + /* 32-bit delegation */ + if (offset > 0x7FFFFFFFLL || offset < -0x80000000LL) + { + SetIoErr(ERROR_OBJECT_TOO_LARGE); + return -1; + } + return dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_SET_FILE_SIZE, + fh->fh_Arg1, (LONG)offset, mode, 0, 0, NULL); +} + +/* Local copy helpers: kickstart modules must not drag in the C library */ +static void dos64_bcopy(const void *src, void *dst, ULONG len) +{ + const UBYTE *s = src; + UBYTE *d = dst; + while (len--) + *d++ = *s++; +} + +static void BSTR2CINLINE(char *s) +{ + UBYTE len = s[0]; + dos64_bcopy(s + 1, s, len); /* forward copy is overlap-safe here */ + s[len] = 0; +} + +/* BSTR -> C string conversion, as dos.library does for FileInfoBlocks */ +void dos64_FixFIB64(struct FileInfoBlock *fib) +{ + BSTR2CINLINE((char *)fib->fib_FileName); + BSTR2CINLINE((char *)fib->fib_Comment); +} + +/* + * Prepare a FileInfoBlock for an ACTION_EXAMINE_*64 packet: the sender + * must clear fib_ActExtFlags, and no extensions are requested. + */ +void dos64_PrepFIB64(struct FileInfoBlock *fib) +{ + fib->fib_ActExtFlags = 0; + fib->fib_ReqExtFlags = 0; +} + +/* + * Store a 64-bit size the way the 64-bit examine packets do: fib_Size64 + * holds it, fib_Size is 0 when it does not fit in 31 bits. + */ +void dos64_SetFIBSize(struct FileInfoBlock *fib, UQUAD size) +{ + fib->fib_Size64 = size; + fib->fib_Size = (size > 0x7FFFFFFFULL) ? 0 : (LONG)size; +} + +/* Replace a clamped 32-bit size by the 64-bit size of the open file */ +void dos64_FixSizeFH(struct Dos64Base *DOS64Base, struct FileHandle *fh, + struct FileInfoBlock *fib) +{ + SIPTR err = 0; +#if (__WORDSIZE == 64) + QUAD size = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_GET_FILE_SIZE64, + fh->fh_Arg1, 0, 0, 0, 0, &err); +#else + QUAD size = dos64_SendPkt64OS4(DOS64Base, fh->fh_Type, ACTION_GET_FILE_SIZE64, + fh->fh_Arg1, 0, 0, &err); +#endif + + /* a handler without ACTION_GET_FILE_SIZE64 fails the query: keep the 32-bit size */ + if (size != -1 && err == 0) + dos64_SetFIBSize(fib, (UQUAD)size); + SetIoErr(0); +} + +/* The size of a file entry that may be clamped; a file that cannot be opened keeps it */ +static void dos64_FixSizeEntry(struct Dos64Base *DOS64Base, BPTR obj, + struct FileInfoBlock *fib, LONG action) +{ + struct Process *me = (struct Process *)FindTask(NULL); + BPTR fh; + + if (fib->fib_DirEntryType >= 0 || fib->fib_Size64 < 0x7FFFFFFF || + me->pr_Task.tc_Node.ln_Type != NT_PROCESS) + return; + + if (action == ACTION_EXAMINE_OBJECT) + { + BPTR dup = DupLock(obj); + + if (dup == BNULL) + return; + fh = OpenFromLock(dup); + if (fh == BNULL) + { + UnLock(dup); + return; + } + } + else + { + BPTR old = CurrentDir(obj); + + fh = Open(fib->fib_FileName, MODE_OLDFILE); + CurrentDir(old); + if (fh == BNULL) + return; + } + + dos64_FixSizeFH(DOS64Base, BADDR(fh), fib); + Close(fh); + SetIoErr(0); +} + +/* + * 32-bit delegation for the Examine64 family. The 64-bit fields share + * the FileInfoBlock with the standard ones, so the dos.library call + * fills the caller's block directly; the 64-bit fields are then derived + * from the 32-bit values (which the handler may have clamped). + */ +LONG dos64_Examine32(struct Dos64Base *DOS64Base, BPTR obj, + struct FileInfoBlock *fib, LONG action) +{ + LONG ret = DOSFALSE; + + switch (action) + { + case ACTION_EXAMINE_OBJECT: + ret = Examine(obj, fib); + break; + + case ACTION_EXAMINE_NEXT: + ret = ExNext(obj, fib); + break; + + case ACTION_EXAMINE_FH: + ret = ExamineFH(obj, fib); + break; + } + + if (ret) + { + fib->fib_NumBlocks64 = (UQUAD)(ULONG)fib->fib_NumBlocks; + fib->fib_ActExtFlags = 0; + dos64_SetFIBSize(fib, (UQUAD)(ULONG)fib->fib_Size); + if (action != ACTION_EXAMINE_FH) + dos64_FixSizeEntry(DOS64Base, obj, fib, action); + } + + return ret; +} diff --git a/rom/dos64/examine64.c b/rom/dos64/examine64.c new file mode 100644 index 0000000000..055d37f24c --- /dev/null +++ b/rom/dos64/examine64.c @@ -0,0 +1,81 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Examine a directory entry with 64-bit sizes. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH3(LONG, Examine64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, lock, D1), + AROS_LHA(struct FileInfoBlock *, fib, D2), + AROS_LHA(struct TagItem *, tags, D3), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 13, Dos64) + +/* FUNCTION + Fill a FileInfoBlock with information about the object the + given lock refers to, including the 64-bit fib_Size64 and + fib_NumBlocks64 fields. fib_Size is 0 when the size does not + fit in 31 bits. + + If the filesystem does not support 64-bit examination the + request is delegated to the 32-bit Examine(); the 64-bit fields + then hold what the filesystem reports in 32 bits. + + INPUTS + lock - lock on the object to examine + fib - FileInfoBlock to fill, allocated with + AllocDosObject(DOS_FIB, NULL) or + AllocDosObject64(DOS64_FIB, NULL) + tags - future extensions, pass NULL + + RESULT + Boolean success indicator. On failure IoErr() gives additional + information. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + dos.library/Examine(), ExNext64(), ExamineFH64(), + AllocDosObject64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileLock *fl = BADDR(lock); + SIPTR err = 0; + LONG ret; + + dos64_PrepFIB64(fib); + ret = dos64_SendPkt(DOS64Base, fl ? fl->fl_Task : GetFileSysTask(), + ACTION_EXAMINE_OBJECT64, (SIPTR)lock, + (SIPTR)MKBADDR(fib), 0, 0, 0, &err); + if (ret) + { + dos64_FixFIB64(fib); + return ret; + } + if (!dos64_UnsupportedAction(err)) + return DOSFALSE; + + return dos64_Examine32(DOS64Base, lock, fib, ACTION_EXAMINE_OBJECT); + + AROS_LIBFUNC_EXIT +} /* Examine64 */ diff --git a/rom/dos64/examinefh64.c b/rom/dos64/examinefh64.c new file mode 100644 index 0000000000..15ff66ed3d --- /dev/null +++ b/rom/dos64/examinefh64.c @@ -0,0 +1,89 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Examine an open file with 64-bit sizes. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH3(LONG, ExamineFH64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, fh, D1), + AROS_LHA(struct FileInfoBlock *, fib, D2), + AROS_LHA(struct TagItem *, tags, D3), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 15, Dos64) + +/* FUNCTION + Fill a FileInfoBlock with information about an open file, + including the 64-bit fib_Size64 and fib_NumBlocks64 fields. + fib_Size is 0 when the size does not fit in 31 bits. + + If the filesystem does not support 64-bit examination the + request is delegated to the 32-bit ExamineFH(). In that case + the file size is additionally corrected through the + filesystem's 64-bit size query, when it provides one. + + INPUTS + fh - filehandle to examine + fib - FileInfoBlock to fill, allocated with + AllocDosObject(DOS_FIB, NULL) or + AllocDosObject64(DOS64_FIB, NULL) + tags - future extensions, pass NULL + + RESULT + Boolean success indicator. On failure IoErr() gives additional + information. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + Examine64(), GetFileSize64(), dos.library/ExamineFH() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *handle = BADDR(fh); + SIPTR err = 0; + LONG ret; + + if (handle == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return DOSFALSE; + } + + dos64_PrepFIB64(fib); + ret = dos64_SendPkt(DOS64Base, handle->fh_Type, ACTION_EXAMINE_FH64, + handle->fh_Arg1, (SIPTR)MKBADDR(fib), 0, 0, 0, &err); + if (ret) + { + dos64_FixFIB64(fib); + return ret; + } + if (!dos64_UnsupportedAction(err)) + return DOSFALSE; + + ret = dos64_Examine32(DOS64Base, fh, fib, ACTION_EXAMINE_FH); + if (ret) + dos64_FixSizeFH(DOS64Base, handle, fib); + + return ret; + + AROS_LIBFUNC_EXIT +} /* ExamineFH64 */ diff --git a/rom/dos64/examinename64.c b/rom/dos64/examinename64.c new file mode 100644 index 0000000000..e1f8b5364c --- /dev/null +++ b/rom/dos64/examinename64.c @@ -0,0 +1,141 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Examine an object by name with 64-bit sizes. +*/ + +#include +#include "dos64_intern.h" + +static BOOL dos64_SameName(CONST_STRPTR a, CONST_STRPTR b) +{ + for (;;) + { + UBYTE ca = *a++, cb = *b++; + + if ((ca >= 'a' && ca <= 'z') || (ca >= 0xe0 && ca <= 0xfe && ca != 0xf7)) + ca -= 0x20; + if ((cb >= 'a' && cb <= 'z') || (cb >= 0xe0 && cb <= 0xfe && cb != 0xf7)) + cb -= 0x20; + if (ca != cb) + return FALSE; + if (ca == 0) + return TRUE; + } +} + +/***************************************************************************** + + NAME */ +#include + + AROS_LH3(LONG, ExamineName64, + +/* SYNOPSIS */ + AROS_LHA(CONST_STRPTR, name, D1), + AROS_LHA(struct FileInfoBlock *, fib, D2), + AROS_LHA(struct TagItem *, tags, D3), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 24, Dos64) + +/* FUNCTION + Fill a 64-bit FileInfoBlock with information about the named + object. + + A file that is open for writing cannot be locked. When the lock + fails with ERROR_OBJECT_IN_USE the entry is read from the + directory that contains it, so the size of a file that is being + written is available too. + + INPUTS + name - path of the object, relative to the current directory + fib - FileInfoBlock to fill, allocated with + AllocDosObject64(DOS64_FIB, NULL) + tags - future extensions, pass NULL + + RESULT + Boolean success indicator. On failure IoErr() gives additional + information. + + NOTES + This is an extension of dos64.library; it needs the version that + has it. + + EXAMPLE + + BUGS + + SEE ALSO + Examine64(), ExNext64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + BPTR lock; + LONG ret, err; + CONST_STRPTR file; + STRPTR parent; + LONG len; + BOOL found = FALSE; + + lock = Lock(name, SHARED_LOCK); + if (lock != BNULL) + { + ret = Examine64(lock, fib, tags); + err = IoErr(); + UnLock(lock); + if (!ret) + SetIoErr(err); + return ret; + } + + if (IoErr() != ERROR_OBJECT_IN_USE) + return DOSFALSE; + + /* the entry of the directory that holds the object */ + file = FilePart(name); + if (*file == 0) + { + SetIoErr(ERROR_OBJECT_IN_USE); + return DOSFALSE; + } + len = file - name; + if (len > 1 && name[len - 1] == '/' && name[len - 2] != ':' && name[len - 2] != '/') + len--; + + parent = AllocVec(len + 1, MEMF_PUBLIC); + if (parent == NULL) + { + SetIoErr(ERROR_NO_FREE_STORE); + return DOSFALSE; + } + CopyMem(name, parent, len); + parent[len] = 0; + lock = Lock(parent, SHARED_LOCK); + FreeVec(parent); + if (lock == BNULL) + return DOSFALSE; + + if (Examine64(lock, fib, tags)) + { + while (ExNext64(lock, fib, tags)) + { + if (dos64_SameName(fib->fib_FileName, file)) + { + found = TRUE; + break; + } + } + } + UnLock(lock); + + if (!found) + SetIoErr(ERROR_OBJECT_IN_USE); + return found ? DOSTRUE : DOSFALSE; + + AROS_LIBFUNC_EXIT +} /* ExamineName64 */ diff --git a/rom/dos64/exnext64.c b/rom/dos64/exnext64.c new file mode 100644 index 0000000000..ea910d25ad --- /dev/null +++ b/rom/dos64/exnext64.c @@ -0,0 +1,79 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Examine the next directory entry with 64-bit sizes. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH3(LONG, ExNext64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, lock, D1), + AROS_LHA(struct FileInfoBlock *, fib, D2), + AROS_LHA(struct TagItem *, tags, D3), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 14, Dos64) + +/* FUNCTION + Examine the next entry of a directory, continuing an + enumeration started with Examine64() on the same + FileInfoBlock. The 64-bit fields are filled as by Examine64(). + + If the filesystem does not support 64-bit examination the + request is delegated to the 32-bit ExNext(); the 64-bit fields + then hold what the filesystem reports in 32 bits. + + INPUTS + lock - lock on the directory being enumerated + fib - FileInfoBlock as filled by the previous Examine64() + or ExNext64() call + tags - future extensions, pass NULL + + RESULT + Boolean success indicator. On failure IoErr() gives additional + information; ERROR_NO_MORE_ENTRIES means the enumeration is + complete. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + Examine64(), dos.library/ExNext() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileLock *fl = BADDR(lock); + SIPTR err = 0; + LONG ret; + + dos64_PrepFIB64(fib); + ret = dos64_SendPkt(DOS64Base, fl ? fl->fl_Task : GetFileSysTask(), + ACTION_EXAMINE_NEXT64, (SIPTR)lock, + (SIPTR)MKBADDR(fib), 0, 0, 0, &err); + if (ret) + { + dos64_FixFIB64(fib); + return ret; + } + if (!dos64_UnsupportedAction(err)) + return DOSFALSE; + + return dos64_Examine32(DOS64Base, lock, fib, ACTION_EXAMINE_NEXT); + + AROS_LIBFUNC_EXIT +} /* ExNext64 */ diff --git a/rom/dos64/freedosobject64.c b/rom/dos64/freedosobject64.c new file mode 100644 index 0000000000..4071463a5d --- /dev/null +++ b/rom/dos64/freedosobject64.c @@ -0,0 +1,61 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Free 64-bit dos objects. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2(void, FreeDosObject64, + +/* SYNOPSIS */ + AROS_LHA(ULONG, type, D1), + AROS_LHA(APTR, ptr, D2), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 22, Dos64) + +/* FUNCTION + Frees an object allocated with AllocDosObject64(). + + INPUTS + type - object type the object was allocated with + ptr - pointer to the object; may be NULL + + RESULT + None. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + AllocDosObject64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + switch (type) + { + case DOS64_FIB: + case DOS64_INFODATA: + case DOS64_RECORDLOCK: + FreeVec(ptr); + break; + default: + break; + } + + AROS_LIBFUNC_EXIT +} /* FreeDosObject64 */ diff --git a/rom/dos64/getfileposition64.c b/rom/dos64/getfileposition64.c new file mode 100644 index 0000000000..cb07e26dd7 --- /dev/null +++ b/rom/dos64/getfileposition64.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Read the current 64-bit position in a file. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH1(QUAD, GetFilePosition64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 7, Dos64) + +/* FUNCTION + Read the current read/write position in a file with full + 64-bit range, without changing it. Buffered data on the + filehandle is taken into account. + + INPUTS + file - filehandle + + RESULT + Current absolute position in bytes, or -1 if an error + happened. IoErr() will give additional information in that + case. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + Seek64(), GetFileSize64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fh = BADDR(file); + QUAD pos; + + if (fh == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return -1; + } + + pos = dos64_Seek(DOS64Base, fh, 0, OFFSET_CURRENT); + if (pos == -1) + return -1; + + /* Account for buffered data not yet seen by the filesystem */ + if (fh->fh_Flags & FHF_WRITE) + pos += fh->fh_Pos; + else + pos -= fh->fh_End - fh->fh_Pos; + + return pos; + + AROS_LIBFUNC_EXIT +} /* GetFilePosition64 */ diff --git a/rom/dos64/getfilesize64.c b/rom/dos64/getfilesize64.c new file mode 100644 index 0000000000..acda50ea94 --- /dev/null +++ b/rom/dos64/getfilesize64.c @@ -0,0 +1,66 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Read the 64-bit size of a file. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH1(QUAD, GetFileSize64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 8, Dos64) + +/* FUNCTION + Read the size of an open file with full 64-bit range. + + If the filesystem does not support 64-bit operations the size + is obtained via ExamineFH() or, as a last resort, by seeking. + + INPUTS + file - filehandle + + RESULT + Size of the file in bytes, or -1 if an error happened. IoErr() + will give additional information in that case. + + NOTES + Pending buffered writes on the filehandle are flushed first. + + EXAMPLE + + BUGS + + SEE ALSO + SetFileSize64(), GetFilePosition64(), ExamineFH64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fh = BADDR(file); + + if (fh == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return -1; + } + + if (fh->fh_Flags & FHF_WRITE) + Flush(file); + + return dos64_GetFileSize(DOS64Base, fh); + + AROS_LIBFUNC_EXIT +} /* GetFileSize64 */ diff --git a/rom/dos64/info64.c b/rom/dos64/info64.c new file mode 100644 index 0000000000..6cedcc4127 --- /dev/null +++ b/rom/dos64/info64.c @@ -0,0 +1,103 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Get 64-bit information about a volume. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2(LONG, Info64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, lock, D1), + AROS_LHA(struct InfoData64 *, parameterBlock, D2), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 16, Dos64) + +/* FUNCTION + Get information about a volume in the system, with 64-bit + block counts. + + The block starts with a standard InfoData; the 64-bit block + counts are in id_NumBlocks64 and id_NumBlocksUsed64. + + If the filesystem does not support the 64-bit query the + request is delegated to the 32-bit Info(), and the 64-bit + counts are taken from ACTION_QUERY_ATTR (FQA_NumBlocks, + FQA_NumBlocksUsed) when the filesystem answers it, otherwise + from the 32-bit counts. + + INPUTS + lock - a lock on any file on the volume for which + information should be supplied, or 0 for the + volume of GetFileSysTask() + parameterBlock - pointer to a longword-aligned InfoData64 + structure + + RESULT + Boolean indicating success or failure. If TRUE (success) the + 'parameterBlock' is filled with information on the volume. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + dos.library/Info(), + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileLock *fl = BADDR(lock); + struct MsgPort *port = fl ? fl->fl_Task : GetFileSysTask(); + SIPTR err = 0; + QUAD count; + LONG ret; + +#if (__WORDSIZE == 64) + ret = dos64_SendPkt(DOS64Base, port, ACTION_INFO64, (SIPTR)lock, + (SIPTR)MKBADDR(parameterBlock), 0, 0, 0, &err); + if (ret) + return ret; + if (!dos64_UnsupportedAction(err)) + return DOSFALSE; +#endif + + /* The block starts with a standard InfoData, so Info() can fill it */ + ret = Info(lock, (struct InfoData *)parameterBlock); + if (ret) + { + parameterBlock->id_NumBlocks64 = (UQUAD)(ULONG)parameterBlock->id_NumBlocks; + parameterBlock->id_NumBlocksUsed64 = (UQUAD)(ULONG)parameterBlock->id_NumBlocksUsed; + + /* + * Filesystems that exceed the 32-bit block counts report the full + * counts through the MorphOS style attribute query. + */ + count = 0; + if (dos64_PktOK(dos64_SendPkt(DOS64Base, port, ACTION_QUERY_ATTR, FQA_NumBlocks, + (SIPTR)&count, sizeof(count), 0, 0, &err), err)) + parameterBlock->id_NumBlocks64 = (UQUAD)count; + count = 0; + if (dos64_PktOK(dos64_SendPkt(DOS64Base, port, ACTION_QUERY_ATTR, FQA_NumBlocksUsed, + (SIPTR)&count, sizeof(count), 0, 0, &err), err)) + parameterBlock->id_NumBlocksUsed64 = (UQUAD)count; + SetIoErr(0); + } + + return ret; + + AROS_LIBFUNC_EXIT +} /* Info64 */ diff --git a/rom/dos64/isfilesystem64.c b/rom/dos64/isfilesystem64.c new file mode 100644 index 0000000000..86f93a2aa3 --- /dev/null +++ b/rom/dos64/isfilesystem64.c @@ -0,0 +1,87 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Query whether a filesystem supports 64-bit packets. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH1(LONG, IsFileSystem64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 23, Dos64) + +/* FUNCTION + Query whether the filesystem behind an open file understands + 64-bit packets, i.e. whether the 64-bit dos64.library + operations on it are handled natively rather than through + 32-bit delegation. + + Applications may use this to cache the capability per file and + skip 64-bit attempts on filesystems that cannot service them. + + INPUTS + file - filehandle to query + + RESULT + DOSTRUE when the filesystem handles 64-bit packets, DOSFALSE + otherwise. + + NOTES + The query is answered with (position-neutral) probe packets; + no file state is modified. + + EXAMPLE + + BUGS + + SEE ALSO + Seek64(), GetFilePosition64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fh = BADDR(file); + SIPTR err = 0; + QUAD ret; + + if (fh == NULL || fh->fh_Type == BNULL) + return DOSFALSE; + +#if (__WORDSIZE == 64) + /* MorphOS style: a null seek, positions travel by pointer */ + { + QUAD pos = 0, prev = 0; + + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_SEEK64, + fh->fh_Arg1, (SIPTR)&pos, OFFSET_CURRENT, (SIPTR)&prev, 0, &err); + if (dos64_PktOK(ret, err)) + return DOSTRUE; + } + + /* AmigaOS 4 style position query */ + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_GET_FILE_POSITION64, + fh->fh_Arg1, 0, 0, 0, 0, &err); +#else + ret = dos64_SendPkt64OS4(DOS64Base, fh->fh_Type, ACTION_GET_FILE_POSITION64, + fh->fh_Arg1, 0, 0, &err); +#endif + if (!dos64_UnsupportedPkt(ret, err)) + return DOSTRUE; + + return DOSFALSE; + + AROS_LIBFUNC_EXIT +} /* IsFileSystem64 */ diff --git a/rom/dos64/lockrecord64.c b/rom/dos64/lockrecord64.c new file mode 100644 index 0000000000..46ce5646b1 --- /dev/null +++ b/rom/dos64/lockrecord64.c @@ -0,0 +1,97 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Lock a portion of a file, 64-bit version. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2(BOOL, LockRecord64, + +/* SYNOPSIS */ + AROS_LHA(struct RecordLock64 *, rec, D1), + AROS_LHA(ULONG, timeout, D2), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 17, Dos64) + +/* FUNCTION + Lock a portion of a file for exclusive access, with 64-bit + offsets. The record is described by a RecordLock64 structure + holding the filehandle, offset, length and locking mode. A + timeout may be specified which is the maximum amount of time + to wait for the record to become available. + + If the filesystem does not support 64-bit record locking the + request is delegated to the 32-bit LockRecord(), provided the + record lies within the first 4GB of the file. + + INPUTS + rec - the record to lock (rec_FH, rec_Offset, rec_Length + and rec_Mode must be filled in) + timeout - timeout interval measured in ticks (may be 0) + + RESULT + Success/failure indicator. On failure IoErr() gives additional + information; ERROR_OBJECT_TOO_LARGE indicates the record is + not representable on the filesystem. + + NOTES + Record locks are cooperative, meaning that they only affect + other calls to LockRecord()/LockRecord64(). + + EXAMPLE + + BUGS + + SEE ALSO + LockRecords64(), UnLockRecord64(), dos.library/LockRecord() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fileH; + + if (rec == NULL || (fileH = BADDR(rec->rec_FH)) == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return DOSFALSE; + } + +#if (__WORDSIZE == 64) + { + /* MorphOS style: offset and length travel by pointer */ + UQUAD offset = rec->rec_Offset, length = rec->rec_Length; + SIPTR err = 0; + LONG ret; + + ret = dos64_SendPkt(DOS64Base, fileH->fh_Type, ACTION_LOCK_RECORD64, + fileH->fh_Arg1, (SIPTR)&offset, (SIPTR)&length, + rec->rec_Mode, timeout, &err); + if (!(ret == DOSFALSE && dos64_UnsupportedAction(err))) + return ret; + } +#endif + + /* 32-bit delegation */ + if (rec->rec_Offset > 0xFFFFFFFFULL || rec->rec_Length > 0xFFFFFFFFULL + || rec->rec_Offset + rec->rec_Length > 0xFFFFFFFFULL) + { + SetIoErr(ERROR_OBJECT_TOO_LARGE); + return DOSFALSE; + } + + return LockRecord(rec->rec_FH, (ULONG)rec->rec_Offset, + (ULONG)rec->rec_Length, rec->rec_Mode, timeout); + + AROS_LIBFUNC_EXIT +} /* LockRecord64 */ diff --git a/rom/dos64/lockrecords64.c b/rom/dos64/lockrecords64.c new file mode 100644 index 0000000000..ad4da59d11 --- /dev/null +++ b/rom/dos64/lockrecords64.c @@ -0,0 +1,76 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Lock several records of files, 64-bit version. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2(BOOL, LockRecords64, + +/* SYNOPSIS */ + AROS_LHA(struct RecordLock64 *, recArray, D1), + AROS_LHA(ULONG, timeout, D2), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 18, Dos64) + +/* FUNCTION + Lock several records of files for exclusive access, with + 64-bit offsets. The array is terminated by an entry with + rec_FH set to NULL. If any lock in the array fails, all + already obtained locks are released again. + + INPUTS + recArray - array of RecordLock64 entries to lock + timeout - timeout interval measured in ticks (may be 0), + applied to each record + + RESULT + Success/failure indicator. On failure IoErr() gives additional + information. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + LockRecord64(), UnLockRecords64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct RecordLock64 *rLock = recArray; + + while (BADDR(recArray->rec_FH) != NULL) + { + BPTR temp; + + if (!LockRecord64(recArray, timeout)) + { + temp = recArray->rec_FH; + recArray->rec_FH = BNULL; + UnLockRecords64(rLock); + recArray->rec_FH = temp; + + return DOSFALSE; + } + + recArray++; + } + + return DOSTRUE; + + AROS_LIBFUNC_EXIT +} /* LockRecords64 */ diff --git a/rom/dos64/mmakefile.src b/rom/dos64/mmakefile.src new file mode 100644 index 0000000000..9a51742f41 --- /dev/null +++ b/rom/dos64/mmakefile.src @@ -0,0 +1,31 @@ +# +# Makefile for building dos64.library +# + +include $(SRCDIR)/config/aros.cfg + +#MM- core-linklibs : linklibs-dos64 + +FUNCS := seek64 setfilesize64 getfileposition64 getfilesize64 \ + changefileposition64 changefilesize64 read64 write64 \ + examine64 exnext64 examinefh64 info64 \ + lockrecord64 lockrecords64 unlockrecord64 unlockrecords64 \ + allocdosobject64 freedosobject64 isfilesystem64 examinename64 + +FILES := dos64_packet dos64_support + +USER_INCLUDES := -I$(SRCDIR)/rom/dos +USER_CFLAGS := $(CFLAGS_NO_BUILTIN) +USER_CPPFLAGS := \ + -DNO_INLINE_STDARG \ + -DUSE_EXEC_DEBUG +USER_LDFLAGS := -static + +#MM kernel-dos64 : includes +#MM kernel-dos64-includes : \ +#MM kernel-exec-includes \ +#MM kernel-dos-includes + +%build_module mmake=kernel-dos64 \ + modname=dos64 modtype=library \ + files="dos64_init $(FUNCS) $(FILES)" diff --git a/rom/dos64/read64.c b/rom/dos64/read64.c new file mode 100644 index 0000000000..1f55a02510 --- /dev/null +++ b/rom/dos64/read64.c @@ -0,0 +1,95 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Read up to 64 bits worth of bytes from a file. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2QUAD1(QUAD, Read64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + AROS_LHA(APTR, buffer, D2), + AROS_LHAQUAD(QUAD, length, D3, D4), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 11, Dos64) + +/* FUNCTION + Read some data from a given file with a 64-bit length. The + request is passed to the filesystem in chunks the 32-bit + ACTION_READ packet can carry, so it works with every + filesystem - no buffering is involved. + + INPUTS + file - filehandle + buffer - pointer to buffer for the data + length - number of bytes to read. The filesystem is advised + to try to fulfill the request as well as possible. + + RESULT + The number of bytes actually read, 0 if the end of the file + was reached, -1 if an error happened. If an error occurs after + some data has already been transferred, the number of bytes + read so far is returned and IoErr() gives the error. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + dos.library/Read(), Write64(), Seek64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fh = BADDR(file); + QUAD done = 0; + + if (fh == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return -1; + } + + if (length < 0) + { + SetIoErr(ERROR_BAD_NUMBER); + return -1; + } + + if (fh->fh_Type == BNULL) + return 0; + + while (done < length) + { + LONG chunk = (length - done > DOS64_IOCHUNK) + ? DOS64_IOCHUNK : (LONG)(length - done); + SIPTR ret; + + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_READ, + fh->fh_Arg1, (SIPTR)((UBYTE *)buffer + done), + chunk, 0, 0, NULL); + if (ret < 0) + return done ? done : -1; + done += ret; + if (ret < chunk) + break; + } + + return done; + + AROS_LIBFUNC_EXIT +} /* Read64 */ diff --git a/rom/dos64/seek64.c b/rom/dos64/seek64.c new file mode 100644 index 0000000000..b0e7cc7dfe --- /dev/null +++ b/rom/dos64/seek64.c @@ -0,0 +1,64 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Change the current 64-bit read/write position in a file. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2QUAD1(QUAD, Seek64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + AROS_LHA(LONG, mode, D2), + AROS_LHAQUAD(QUAD, position, D3, D4), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 5, Dos64) + +/* FUNCTION + Changes the current read/write position in a file with full + 64-bit range, and/or reads the current position, e.g. to get + the current position do a Seek64(file, 0, OFFSET_CURRENT). + + If the filesystem does not support 64-bit operations the + request is delegated to the 32-bit Seek(), provided the + position is representable in 32 bits. + + INPUTS + file - filehandle + mode - Where to count from. Either OFFSET_BEGINNING, + OFFSET_CURRENT or OFFSET_END. + position - relative offset in bytes (positive, negative or 0). + + RESULT + Absolute position in bytes before the Seek64(), -1 if an error + happened. IoErr() will give additional information in that + case. If the position is not representable on the filesystem, + IoErr() returns ERROR_OBJECT_TOO_LARGE. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + dos.library/Seek(), SetFileSize64(), GetFilePosition64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + return dos64_SeekBuffered(DOS64Base, file, position, mode); + + AROS_LIBFUNC_EXIT +} /* Seek64 */ diff --git a/rom/dos64/setfilesize64.c b/rom/dos64/setfilesize64.c new file mode 100644 index 0000000000..627669e899 --- /dev/null +++ b/rom/dos64/setfilesize64.c @@ -0,0 +1,69 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Change the size of a file, 64-bit version. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2QUAD1(QUAD, SetFileSize64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + AROS_LHA(LONG, mode, D2), + AROS_LHAQUAD(QUAD, offset, D3, D4), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 6, Dos64) + +/* FUNCTION + Change the size of a file with full 64-bit range. + + If the filesystem does not support 64-bit operations the + request is delegated to the 32-bit SetFileSize(), provided the + offset is representable in 32 bits. + + INPUTS + file - filehandle + mode - OFFSET_BEGINNING, OFFSET_CURRENT or OFFSET_END + offset - relative size + + RESULT + New size of the file or -1 in case of an error. + IoErr() gives additional information in that case. If the size + is not representable on the filesystem, IoErr() returns + ERROR_OBJECT_TOO_LARGE. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + dos.library/SetFileSize(), Seek64(), GetFileSize64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fh = BADDR(file); + + if (fh == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return -1; + } + + return dos64_SetFileSize(DOS64Base, fh, offset, mode, TRUE); + + AROS_LIBFUNC_EXIT +} /* SetFileSize64 */ diff --git a/rom/dos64/unlockrecord64.c b/rom/dos64/unlockrecord64.c new file mode 100644 index 0000000000..d6f2c298ee --- /dev/null +++ b/rom/dos64/unlockrecord64.c @@ -0,0 +1,85 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Unlock a record of a file, 64-bit version. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH1(BOOL, UnLockRecord64, + +/* SYNOPSIS */ + AROS_LHA(struct RecordLock64 *, rec, D1), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 19, Dos64) + +/* FUNCTION + Release a record lock obtained with LockRecord64(). The + rec_FH, rec_Offset, rec_Length values must match the lock + request exactly. + + INPUTS + rec - the record to unlock + + RESULT + Success/failure indicator. On failure IoErr() gives additional + information. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + LockRecord64(), UnLockRecords64(), dos.library/UnLockRecord() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fileH; + + if (rec == NULL || (fileH = BADDR(rec->rec_FH)) == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return DOSFALSE; + } + +#if (__WORDSIZE == 64) + { + /* MorphOS style: offset and length travel by pointer */ + UQUAD offset = rec->rec_Offset, length = rec->rec_Length; + SIPTR err = 0; + LONG ret; + + ret = dos64_SendPkt(DOS64Base, fileH->fh_Type, ACTION_FREE_RECORD64, + fileH->fh_Arg1, (SIPTR)&offset, (SIPTR)&length, + 0, 0, &err); + if (!(ret == DOSFALSE && dos64_UnsupportedAction(err))) + return ret; + } +#endif + + /* 32-bit delegation */ + if (rec->rec_Offset > 0xFFFFFFFFULL || rec->rec_Length > 0xFFFFFFFFULL + || rec->rec_Offset + rec->rec_Length > 0xFFFFFFFFULL) + { + SetIoErr(ERROR_OBJECT_TOO_LARGE); + return DOSFALSE; + } + + return UnLockRecord(rec->rec_FH, (ULONG)rec->rec_Offset, + (ULONG)rec->rec_Length); + + AROS_LIBFUNC_EXIT +} /* UnLockRecord64 */ diff --git a/rom/dos64/unlockrecords64.c b/rom/dos64/unlockrecords64.c new file mode 100644 index 0000000000..b1e059b575 --- /dev/null +++ b/rom/dos64/unlockrecords64.c @@ -0,0 +1,64 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Unlock several records of files, 64-bit version. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH1(BOOL, UnLockRecords64, + +/* SYNOPSIS */ + AROS_LHA(struct RecordLock64 *, recArray, D1), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 20, Dos64) + +/* FUNCTION + Release the record locks obtained with LockRecords64(). The + array is terminated by an entry with rec_FH set to NULL. + + INPUTS + recArray - array of RecordLock64 entries to unlock, as passed + to LockRecords64() + + RESULT + Success/failure indicator. Unlocking continues over failing + entries; the result of the last failing unlock is returned and + IoErr() gives additional information. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + LockRecords64(), UnLockRecord64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + BOOL ret = DOSTRUE; + + while (BADDR(recArray->rec_FH) != NULL) + { + if (!UnLockRecord64(recArray)) + ret = DOSFALSE; + + recArray++; + } + + return ret; + + AROS_LIBFUNC_EXIT +} /* UnLockRecords64 */ diff --git a/rom/dos64/write64.c b/rom/dos64/write64.c new file mode 100644 index 0000000000..581855af6c --- /dev/null +++ b/rom/dos64/write64.c @@ -0,0 +1,94 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Desc: Write up to 64 bits worth of bytes to a file. +*/ + +#include +#include "dos64_intern.h" + +/***************************************************************************** + + NAME */ +#include + + AROS_LH2QUAD1(QUAD, Write64, + +/* SYNOPSIS */ + AROS_LHA(BPTR, file, D1), + AROS_LHA(CONST_APTR, buffer, D2), + AROS_LHAQUAD(QUAD, length, D3, D4), + +/* LOCATION */ + struct Dos64Base *, DOS64Base, 12, Dos64) + +/* FUNCTION + Write some data to a given file with a 64-bit length. The + request is passed to the filesystem in chunks the 32-bit + ACTION_WRITE packet can carry, so it works with every + filesystem - no buffering is involved. + + INPUTS + file - filehandle + buffer - pointer to the data to write + length - number of bytes to write. + + RESULT + The number of bytes actually written, -1 if an error happened. + If an error occurs after some data has already been + transferred, the number of bytes written so far is returned + and IoErr() gives the error. + + NOTES + + EXAMPLE + + BUGS + + SEE ALSO + dos.library/Write(), Read64(), Seek64() + + INTERNALS + +*****************************************************************************/ +{ + AROS_LIBFUNC_INIT + + struct FileHandle *fh = BADDR(file); + QUAD done = 0; + + if (fh == NULL) + { + SetIoErr(ERROR_INVALID_LOCK); + return -1; + } + + if (length < 0) + { + SetIoErr(ERROR_BAD_NUMBER); + return -1; + } + + if (fh->fh_Type == BNULL) + return length; + + while (done < length) + { + LONG chunk = (length - done > DOS64_IOCHUNK) + ? DOS64_IOCHUNK : (LONG)(length - done); + SIPTR ret; + + ret = dos64_SendPkt(DOS64Base, fh->fh_Type, ACTION_WRITE, + fh->fh_Arg1, (SIPTR)((CONST UBYTE *)buffer + done), + chunk, 0, 0, NULL); + if (ret < 0) + return done ? done : -1; + done += ret; + if (ret < chunk) + break; + } + + return done; + + AROS_LIBFUNC_EXIT +} /* Write64 */ diff --git a/rom/mmakefile.src b/rom/mmakefile.src index 73a0e82cf7..d379677509 100644 --- a/rom/mmakefile.src +++ b/rom/mmakefile.src @@ -6,6 +6,7 @@ include $(SRCDIR)/config/aros.cfg #MM kernel-aros \ #MM kernel-disk \ #MM kernel-dos \ +#MM kernel-dos64 \ #MM kernel-debug \ #MM kernel-fs-con \ #MM kernel-graphics \ @@ -36,6 +37,7 @@ include $(SRCDIR)/config/aros.cfg #MM kernel-ata-includes \ #MM kernel-cia-includes \ #MM kernel-dos-includes \ +#MM kernel-dos64-includes \ #MM kernel-bootloader-includes \ #MM kernel-debug-includes \ #MM kernel-efi-includes \ @@ -77,6 +79,7 @@ include $(SRCDIR)/config/aros.cfg #MM kernel-aros \ #MM kernel-bootloader \ #MM kernel-dos \ +#MM kernel-dos64 \ #MM kernel-debug \ #MM kernel-dosboot \ #MM kernel-filesystem \ @@ -105,6 +108,7 @@ include $(SRCDIR)/config/aros.cfg #MM kernel-aros \ #MM kernel-bootloader \ #MM kernel-dos \ +#MM kernel-dos64 \ #MM kernel-dosboot \ #MM kernel-debug \ #MM kernel-filesystem \ @@ -132,7 +136,7 @@ include $(SRCDIR)/config/aros.cfg BASE_DEVICES := console input gameport keyboard BASE_HANDLERS := ram con BASE_HIDD := hiddclass gfx keyboard mouse -BASE_LIBS := aros debug dos graphics intuition keymap layers oop utility +BASE_LIBS := aros debug dos dos64 graphics intuition keymap layers oop utility BASE_RSRCS := bootloader dosboot FileSystem lddemon %make_package mmake=kernel-package-base file=$(AROS_BOOT)/aros-base.pkg \ From 780006c522ade747b2fc97c35a6916c26540fcee Mon Sep 17 00:00:00 2001 From: terminills Date: Wed, 28 Oct 2026 11:34:19 -0500 Subject: [PATCH 05/12] dos: MatchFirst()/MatchNext() with a zero current directory (#1875) * dos: MatchFirst()/MatchNext() with a zero current directory A process whose current directory is the zero lock (the root of the boot volume) is legal, but MatchNext() took DupLock() of it returning zero as a failure and returned IoErr(), which is 0 when nothing has failed: MatchFirst() on a wildcard in a missing directory then reported success with no match, and every MatchNext() after it did the same. Directory Opus 5 loops forever on that while scanning dopus5:groups/. Only a non-zero current directory that cannot be duplicated is an error. Checked with MatchFirst("RAM:x/nodir/#?.info") after CurrentDir(NULL): ERROR_OBJECT_NOT_FOUND, as with a current directory. * dos: ExNext() on a zero lock A zero lock stands for the root of the boot volume. Examine() already sends its packet to GetFileSysTask() for it, but ExNext() dereferenced the lock unconditionally, so MatchFirst("#?") after CurrentDir(NULL), whose base AChain keeps an_Lock 0, page-faulted on fl->fl_Task. ExNext() now falls back to GetFileSysTask() the same way. Checked with MatchFirst("#?") after CurrentDir(NULL): it returns 0, MatchNext() walks the boot volume root and ends with ERROR_NO_MORE_ENTRIES. --- rom/dos/exnext.c | 2 +- rom/dos/matchnext.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rom/dos/exnext.c b/rom/dos/exnext.c index 209d13529f..9bdd14bf6e 100644 --- a/rom/dos/exnext.c +++ b/rom/dos/exnext.c @@ -73,7 +73,7 @@ ASSERT_VALID_FILELOCK(lock); D(bug("[ExNext] lock=%x fib=%x\n", fl, fileInfoBlock)); - ret = dopacket2(DOSBase, NULL, fl->fl_Task, ACTION_EXAMINE_NEXT, lock, MKBADDR(fileInfoBlock)); + ret = dopacket2(DOSBase, NULL, fl ? fl->fl_Task : GetFileSysTask(), ACTION_EXAMINE_NEXT, lock, MKBADDR(fileInfoBlock)); if (ret) { fixfib(fileInfoBlock); D(bug("[ExNext] '%s'\n", fileInfoBlock->fib_FileName)); diff --git a/rom/dos/matchnext.c b/rom/dos/matchnext.c index 66c5162b81..ac9e2b18d7 100644 --- a/rom/dos/matchnext.c +++ b/rom/dos/matchnext.c @@ -156,7 +156,7 @@ { ac->an_Lock = DupLock(origdir); - if (!ac->an_Lock) + if (!ac->an_Lock && origdir) { error = IoErr(); goto done; From 67f98d3a0e25297dd3f958681efea9d3a3909e9c Mon Sep 17 00:00:00 2001 From: Nicolas Ramz Date: Wed, 30 Sep 2026 15:19:55 +0200 Subject: [PATCH 06/12] dos: move large FRead()/FWrite() requests without the file buffer FRead() always went through the handle buffer, so a large read cost one ACTION_READ packet per buffer: 100 packets for 100 KiB with the 1 KiB m68k-amiga buffer. FWrite() copied every byte into the buffer and flushed it in pieces the same way. Once the buffer is empty, a read at least one buffer long now goes straight into the caller's memory with a single Read(). A fully buffered write of at least one buffer flushes what is pending and is sent with a single Write(); line-buffered handles keep flushing at each newline, and append-mode handles still seek to the end first. --- rom/dos/fread.c | 37 ++++++++++++++++++++++++++++++++++++- rom/dos/fwrite.c | 7 +++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/rom/dos/fread.c b/rom/dos/fread.c index a9b457d497..6e6bd2252f 100644 --- a/rom/dos/fread.c +++ b/rom/dos/fread.c @@ -11,6 +11,8 @@ #define FETCHERR (-2) +static LONG direct_fetch(BPTR file, UBYTE *buffer, ULONG fetchsize, struct DosLibrary *DOSBase); + /***************************************************************************** NAME */ @@ -71,7 +73,9 @@ while(fetchsize > 0) { - res = vbuf_fetch(fh, ptr, fetchsize, DOSBase); + res = direct_fetch(fh, ptr, fetchsize, DOSBase); + if (res == 0) + res = vbuf_fetch(fh, ptr, fetchsize, DOSBase); if (res < 0) break; ptr += res; @@ -121,6 +125,37 @@ static LONG handle_write_mode(BPTR file, struct DosLibrary * DOSBase) return 0; } +/* + * A request at least one buffer long gains nothing from the buffer: once + * it is empty, read straight into the caller's memory with one packet. + * Returns 0 when the buffered path must be used instead, otherwise the + * same values as vbuf_fetch(). + */ +static LONG direct_fetch(BPTR file, UBYTE *buffer, ULONG fetchsize, struct DosLibrary *DOSBase) +{ + struct FileHandle *fh = (struct FileHandle *)BADDR(file); + ULONG bufsize; + LONG size; + + /* Buffered characters, a pushed back EOF, or a pending write */ + if (fh == NULL || fh->fh_Pos != fh->fh_End || (fh->fh_Flags & FHF_WRITE)) + return 0; + + if (fh->fh_Buf == BNULL) + bufsize = IOBUFSIZE; + else if (fh->fh_Buf != fh->fh_OrigBuf) + bufsize = 208; + else + bufsize = fh->fh_BufSize; + if (fetchsize < bufsize) + return 0; + + size = Read(file, buffer, fetchsize); + fh->fh_Pos = fh->fh_End = 0; + + return (size > 0) ? size : EOF; +} + /* Fetches up to remaining buffer content from file buffer * Return values: * (-2) on error diff --git a/rom/dos/fwrite.c b/rom/dos/fwrite.c index c7770444bc..e32384a2f3 100644 --- a/rom/dos/fwrite.c +++ b/rom/dos/fwrite.c @@ -147,6 +147,13 @@ FWriteChars(BPTR file, CONST UBYTE* buffer, ULONG length, struct DosLibrary *DOS written = Write(file, buffer, length); } } + else if (!(fh->fh_Flags & FHF_LINEBUF) && length >= (ULONG)fh->fh_End) + { + /* At least a buffer's worth: write it with one packet. Flush() + * also moves an append-mode handle to the end of the file. */ + if ((fh->fh_Pos == 0 && !(fh->fh_Flags & FHF_APPEND)) || Flush(file)) + written = Write(file, buffer, length); + } else { for (written = 0; written < length; ++written) From a757744d80c83fcc608a5f71e1bae248210c09ae Mon Sep 17 00:00:00 2001 From: Nicolas Ramz Date: Sat, 3 Oct 2026 00:26:17 +0200 Subject: [PATCH 07/12] dos: preserve pushback and complete direct buffered I/O requests Seed the read buffer with the last successful direct-read byte so both UnGetC forms continue to work, and allocate it before consuming input. Clamp individual Read requests to the signed LONG limit. Retry short direct writes, stop on zero progress, and batch FWrite blocks with overflow-safe signed-length chunks so byte-block calls use the fast path. Keep append, pending-output and line-buffer behavior. Expand DOS regression tests for direct-read pushback, mixed-read seek positions and pending buffered append writes. Add sanitized host tests for oversized requests, partial/error writes, replaced buffers and packet batching. Update copyright years and dos.library revision to 50.82. --- developer/debug/test/dos/buffered_io_mock.py | 146 +++++++++++++++++++ developer/debug/test/dos/fread.c | 84 +++++++++++ rom/dos/fread.c | 25 +++- rom/dos/fwrite.c | 66 ++++++++- 4 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 developer/debug/test/dos/buffered_io_mock.py diff --git a/developer/debug/test/dos/buffered_io_mock.py b/developer/debug/test/dos/buffered_io_mock.py new file mode 100644 index 0000000000..5e9946f79b --- /dev/null +++ b/developer/debug/test/dos/buffered_io_mock.py @@ -0,0 +1,146 @@ +# Copyright (C) 2026, The AROS Development Team. All rights reserved. +"""Host tests for DOS buffering, with controlled handler results. + +Run with Python 3 and a C compiler supporting AddressSanitizer and UBSan. +The actual FRead/FWrite/UnGetC/FGetC function bodies are compiled against +mock I/O callbacks to cover oversized requests and short/failed writes. +""" +from pathlib import Path +import re +import shutil +import subprocess +import tempfile + +root = Path(__file__).resolve().parents[4] +header=r''' +#include +#include +#include +#include +#include +typedef uint8_t UBYTE; +typedef uint32_t ULONG; +typedef int32_t LONG; +typedef uintptr_t BPTR; +typedef intptr_t SIPTR; +typedef void *APTR; +typedef const void *CONST_APTR; +#define CONST const +#define TRUE 1 +#define FALSE 0 +#define BNULL 0 +#define BADDR(x) ((void *)(uintptr_t)(x)) +#define MKBADDR(x) ((BPTR)(uintptr_t)(x)) +#define IOBUFSIZE 256 +#define OFFSET_CURRENT 0 +#define OFFSET_END 1 +#define ERROR_NO_FREE_STORE 103 +#define ERROR_SEEK_ERROR 219 +#define AROS_LIBFUNC_INIT +#define AROS_LIBFUNC_EXIT +#define AROS_LHA(t,n,r) t n +#define AROS_LH1(t,n,a,bt,bn,l,m) t Dos_##n(a,bt bn) +#define AROS_LH2(t,n,a,b,bt,bn,l,m) t Dos_##n(a,b,bt bn) +#define AROS_LH4(t,n,a,b,c,d,bt,bn,l,m) t Dos_##n(a,b,c,d,bt bn) +#define ASSERT(x) assert(x) +#define ASSERT_VALID_PTR(x) assert(x) +#define ASSERT_VALID_PROCESS(x) assert(x) +#define D(x) +struct DosLibrary {int unused;}; +struct Process {SIPTR pr_Result2;}; +struct FileHandle {LONG fh_Pos,fh_End;ULONG fh_Flags,fh_BufSize;BPTR fh_Buf,fh_OrigBuf;}; +#include "DOS_FHFLAGS_PATH" +struct Stream {struct FileHandle fh;UBYTE data[131072];ULONG pos,len;int reads,writes,flushes,shortwrite,zero_write,fail_write,fail_after,force_eof;LONG read_request,write_request;}; +static struct DosLibrary base; +static struct Process process; +static int fail_alloc; +static void *FindTask(void *x) {return &process;} +static void SetIoErr(LONG x) {process.pr_Result2=x;} +static LONG IoErr(void) {return process.pr_Result2;} +static void CopyMem(const void *src,void *dst,ULONG n) {memcpy(dst,src,n);} +static void *vbuf_alloc(struct FileHandle *f,char *buf,ULONG n) { + if(fail_alloc)return NULL; + if(n<208)n=208; + if(!buf){buf=malloc(n);f->fh_OrigBuf=MKBADDR(buf);f->fh_Flags|=FHF_OWNBUF;} + f->fh_Buf=MKBADDR(buf);f->fh_BufSize=n;f->fh_Flags|=FHF_BUF;f->fh_Pos=0;f->fh_End=(f->fh_Flags&FHF_WRITE)?n:0;return buf; +} +static LONG Read(BPTR file,void *b,LONG n) { + struct Stream *s=BADDR(file);assert(n>=0);s->reads++;s->read_request=n; + if(s->force_eof)return 0; + ULONG k=(ULONG)n;if(k>s->len-s->pos)k=s->len-s->pos; + memcpy(b,s->data+s->pos,k);s->pos+=k;return k; +} +static LONG Write(BPTR file,const void *b,LONG n) { + struct Stream *s=BADDR(file);assert(n>=0);s->writes++;s->write_request=n; + if(s->fail_write || (s->fail_after && s->writes>s->fail_after)){SetIoErr(222);return -1;} + if(s->zero_write)return 0; + ULONG k=(ULONG)n;if(s->shortwrite && k>(ULONG)s->shortwrite)k=s->shortwrite; + assert(s->pos+k<=sizeof(s->data));memcpy(s->data+s->pos,b,k);s->pos+=k;if(s->pos>s->len)s->len=s->pos;return k; +} +static LONG Flush(BPTR file) { + struct Stream *s=BADDR(file);struct FileHandle *f=&s->fh;s->flushes++; + if(f->fh_Flags&FHF_WRITE){ + if(f->fh_Flags&FHF_APPEND)s->pos=s->len; + ULONG done=0; + while(done<(ULONG)f->fh_Pos){LONG n=Write(file,(UBYTE*)BADDR(f->fh_Buf)+done,f->fh_Pos-done);if(n<=0)return 0;done+=n;} + f->fh_Pos=0; + }else if(f->fh_Posfh_End){s->pos-=f->fh_End-f->fh_Pos;f->fh_Pos=f->fh_End=0;} + return 1; +} +static LONG Seek(BPTR file,LONG n,LONG mode) { + struct Stream *s=BADDR(file);struct FileHandle *f=&s->fh; + if(f->fh_Flags&FHF_WRITE)assert(Flush(file)); + LONG old=s->pos-(f->fh_End-f->fh_Pos);f->fh_Pos=f->fh_End=0; + s->pos=mode==OFFSET_END?s->len+n:old+n;return old; +} +LONG vbuf_fetch(BPTR,UBYTE*,ULONG,struct DosLibrary*); +LONG FWriteChars(BPTR,const UBYTE*,ULONG,struct DosLibrary*); +static void init(struct Stream *s) {memset(s,0,sizeof(*s));fail_alloc=0;SetIoErr(0);} +static void end(struct Stream *s) {free(BADDR(s->fh.fh_Buf));s->fh.fh_Buf=0;} +''' +sources='' +for name in ('fread.c','fwrite.c','ungetc.c','fgetc.c'): + s=(root/'rom/dos'/name).read_text();sources+=re.sub(r'^#include[^\n]*\n','',s,flags=re.M)+'\n' +footer=r''' +int main(void) { + static struct Stream s;static UBYTE buf[65536],pattern[65536];BPTR f=MKBADDR(&s);int tests=0; + for(unsigned i=0;i1 && s.len==1000 && !memcmp(s.data,pattern,1000));end(&s);tests++; + init(&s);s.zero_write=1;assert(Dos_FWrite(f,pattern,1,1024,&base)==EOF && s.writes==1);end(&s);tests++; + init(&s);s.fail_write=1;assert(Dos_FWrite(f,pattern,0x80000000U,1,&base)==EOF && s.write_request==INT32_MAX && IoErr()==222);end(&s);tests++; + init(&s);s.fail_write=1;assert(Dos_FWrite(f,pattern,65536,65536,&base)==EOF && s.write_request==2147418112);end(&s);tests++; + init(&s);memcpy(s.data,"start",5);s.len=5;s.fh.fh_Flags=FHF_APPEND; + assert(Dos_FWrite(f,"pending",1,7,&base)==7 && s.fh.fh_Pos==7 && s.len==5); + assert(Dos_FWrite(f,pattern,1,8192,&base)==8192 && s.len==8204 && !memcmp(s.data,"startpending",12) && !memcmp(s.data+12,pattern,8192));end(&s);tests++; + init(&s);s.fh.fh_Flags=FHF_LINEBUF;assert(Dos_FWrite(f,pattern,1,1024,&base)==1024);assert(Flush(f));assert(s.writes>1 && s.len==1024 && !memcmp(s.data,pattern,1024));end(&s);tests++; + init(&s);s.fh.fh_Flags=FHF_NOBUF;s.shortwrite=13;assert(Dos_FWrite(f,pattern,1,1024,&base)==1024 && s.len==1024 && !memcmp(s.data,pattern,1024));end(&s);tests++; + init(&s);s.shortwrite=7;s.fail_after=2;assert(Dos_FWrite(f,pattern,1,1024,&base)==EOF && s.writes==3 && s.len==14 && IoErr()==222);end(&s);tests++; + printf("%d buffered-I/O cases PASS\n",tests);return 0; +} +''' +header = header.replace("DOS_FHFLAGS_PATH", + str(root / "rom/dos/dos_fhflags.h")) +compiler = shutil.which("clang") or shutil.which("cc") +if compiler is None: + raise SystemExit("A C compiler is required") +with tempfile.TemporaryDirectory(prefix="aros-buffered-io-") as directory: + p = Path(directory) + fixture = p / "buffered-io-mock.c" + fixture.write_text(header + sources + footer) + subprocess.run([compiler, "-std=c11", "-Wall", "-Wextra", "-Werror", + "-Wno-unused-parameter", "-Wno-sign-compare", + "-fsanitize=address,undefined", str(fixture), + "-o", str(p / "buffered-io-mock")], check=True) + subprocess.run([str(p / "buffered-io-mock")], check=True) diff --git a/developer/debug/test/dos/fread.c b/developer/debug/test/dos/fread.c index 90e1e3906a..430913622b 100644 --- a/developer/debug/test/dos/fread.c +++ b/developer/debug/test/dos/fread.c @@ -1,14 +1,28 @@ /* +<<<<<<< HEAD Copyright © 1995-2014, The AROS Development Team. All rights reserved. $Id$ +======= + Copyright (C) 1995-2026, The AROS Development Team. All rights reserved. +>>>>>>> ba40ca031a (dos: preserve pushback and complete direct buffered I/O requests) */ #include +#include +#include +#include +#include #include +#include +#include "../../../../rom/dos/dos_fhflags.h" #include "test.h" BPTR fh = BNULL; +static UBYTE *data = NULL; +static UBYTE *readbuf = NULL; +#define DATA_SIZE 65536 +#define LARGE_READ 8192 static void closehandles() { @@ -20,6 +34,7 @@ int main() LONG result = 0; LONG ioerr = 0; TEXT buffer[16]; + ULONG i; fh = Open("T:a", MODE_NEWFILE); @@ -30,6 +45,71 @@ int main() TEST((result == 0)); TEST((ioerr == 0)); + closehandles(); + data = AllocVec(DATA_SIZE, MEMF_ANY); + readbuf = AllocVec(DATA_SIZE, MEMF_ANY); + TEST(data != NULL && readbuf != NULL); + for (i = 0; i < DATA_SIZE; i++) + data[i] = i & 0xff; + fh = Open("T:a", MODE_NEWFILE); + TEST(fh != BNULL); + TEST(Write(fh, data, DATA_SIZE) == DATA_SIZE); + closehandles(); + + /* Direct reads must preserve the last byte for either UnGetC form. */ + fh = Open("T:a", MODE_OLDFILE); + TEST(fh != BNULL); + TEST(FRead(fh, readbuf, 1, LARGE_READ) == LARGE_READ); + TEST(memcmp(readbuf, data, LARGE_READ) == 0); + TEST(UnGetC(fh, -1) != 0); + TEST(FGetC(fh) == data[LARGE_READ - 1]); + TEST(FGetC(fh) == data[LARGE_READ]); + closehandles(); + + fh = Open("T:a", MODE_OLDFILE); + TEST(fh != BNULL); + TEST(FRead(fh, readbuf, 1, LARGE_READ) == LARGE_READ); + TEST(UnGetC(fh, 'X') != 0); + TEST(FGetC(fh) == 'X'); + TEST(FGetC(fh) == data[LARGE_READ]); + closehandles(); + + /* Unread buffered data and direct reads must agree on file position. */ + fh = Open("T:a", MODE_OLDFILE); + TEST(fh != BNULL); + TEST(FRead(fh, readbuf, 1, 17) == 17); + TEST(FRead(fh, readbuf + 17, 1, LARGE_READ) == LARGE_READ); + TEST(memcmp(readbuf, data, LARGE_READ + 17) == 0); + TEST(Seek(fh, 0, OFFSET_CURRENT) == LARGE_READ + 17); + TEST(FRead(fh, readbuf, 1, 23) == 23); + TEST(memcmp(readbuf, data + LARGE_READ + 17, 23) == 0); + TEST(Seek(fh, 0, OFFSET_CURRENT) == LARGE_READ + 40); + TEST(FRead(fh, readbuf, 1, LARGE_READ) == LARGE_READ); + TEST(memcmp(readbuf, data + LARGE_READ + 40, LARGE_READ) == 0); + TEST(Seek(fh, 0, OFFSET_CURRENT) == 2 * LARGE_READ + 40); + closehandles(); + + /* Append pending buffered bytes before a large byte-block write. */ + fh = Open("T:a", MODE_NEWFILE); + TEST(fh != BNULL); + TEST(Write(fh, "start", 5) == 5); + closehandles(); + fh = Open("T:a", MODE_READWRITE); + TEST(fh != BNULL); + TEST(SetVBuf(fh, NULL, BUF_FULL, 256) == 0); + ((struct FileHandle *)BADDR(fh))->fh_Flags |= FHF_APPEND; + TEST(FWrite(fh, "pending", 1, 7) == 7); + TEST(((struct FileHandle *)BADDR(fh))->fh_Pos == 7); + TEST(FWrite(fh, data, 1, LARGE_READ) == LARGE_READ); + TEST(Flush(fh) != 0); + closehandles(); + fh = Open("T:a", MODE_OLDFILE); + TEST(fh != BNULL); + TEST(Read(fh, readbuf, 12 + LARGE_READ) == 12 + LARGE_READ); + TEST(memcmp(readbuf, "startpending", 12) == 0); + TEST(memcmp(readbuf + 12, data, LARGE_READ) == 0); + TEST(Read(fh, buffer, 1) == 0); + /* EOF */ SetIoErr(0); result = FRead(fh, buffer, 1, 1); @@ -52,4 +132,8 @@ int main() void cleanup() { closehandles(); + if (data) FreeVec(data); + if (readbuf) FreeVec(readbuf); + data = readbuf = NULL; + DeleteFile("T:a"); } diff --git a/rom/dos/fread.c b/rom/dos/fread.c index 6e6bd2252f..0dcc026645 100644 --- a/rom/dos/fread.c +++ b/rom/dos/fread.c @@ -1,6 +1,10 @@ /* +<<<<<<< HEAD Copyright © 1995-2014, The AROS Development Team. All rights reserved. $Id$ +======= + Copyright (C) 1995-2026, The AROS Development Team. All rights reserved. +>>>>>>> ba40ca031a (dos: preserve pushback and complete direct buffered I/O requests) Desc: Lang: english @@ -150,8 +154,27 @@ static LONG direct_fetch(BPTR file, UBYTE *buffer, ULONG fetchsize, struct DosLi if (fetchsize < bufsize) return 0; + /* Keep room for the last character so UnGetC() remains valid. Allocate + * before reading, so allocation failure cannot consume input. + */ + if (fh->fh_Buf == BNULL && vbuf_alloc(fh, NULL, bufsize) == NULL) + { + SetIoErr(ERROR_NO_FREE_STORE); + return FETCHERR; + } + + /* Read() takes a signed 32-bit length, including on 64-bit targets. */ + if (fetchsize > 0x7FFFFFFFUL) + fetchsize = 0x7FFFFFFFUL; + size = Read(file, buffer, fetchsize); - fh->fh_Pos = fh->fh_End = 0; + if (size > 0) + { + ((UBYTE *)BADDR(fh->fh_Buf))[0] = buffer[size - 1]; + fh->fh_Pos = fh->fh_End = 1; + } + else + fh->fh_Pos = fh->fh_End = 0; return (size > 0) ? size : EOF; } diff --git a/rom/dos/fwrite.c b/rom/dos/fwrite.c index e32384a2f3..d9b99e0218 100644 --- a/rom/dos/fwrite.c +++ b/rom/dos/fwrite.c @@ -1,6 +1,10 @@ /* +<<<<<<< HEAD Copyright © 1995-2013, The AROS Development Team. All rights reserved. $Id$ +======= + Copyright (C) 1995-2026, The AROS Development Team. All rights reserved. +>>>>>>> ba40ca031a (dos: preserve pushback and complete direct buffered I/O requests) Lang: english */ @@ -8,6 +12,9 @@ #include +static LONG write_direct(BPTR file, CONST UBYTE *buffer, ULONG length, + struct DosLibrary *DOSBase); + /***************************************************************************** @@ -62,23 +69,46 @@ ASSERT(blocklen > 0); ASSERT(numblocks > 0); - ULONG written; + ULONG written = 0; const UBYTE *ptr; ptr = block; SetIoErr(0); - for(written = 0; written < numblocks; written++) + if (blocklen == 0 || numblocks == 0) + return 0; + + while (written < numblocks) { - if (FWriteChars(fh, ptr, blocklen, DOSBase) != blocklen) + ULONG blocks = numblocks - written; + ULONG length; + + /* Batch blocks without overflowing the product or the signed byte + * count. A single oversized block is split into smaller writes. + */ + if (blocklen <= 0x7FFFFFFFUL) { - return(EOF); + ULONG maxblocks = 0x7FFFFFFFUL / blocklen; + if (blocks > maxblocks) + blocks = maxblocks; + length = blocks * blocklen; } else { - ptr += blocklen; + blocks = 1; + length = blocklen; + } + + while (length > 0) + { + ULONG chunk = length > 0x7FFFFFFFUL ? 0x7FFFFFFFUL : length; + if (FWriteChars(fh, ptr, chunk, DOSBase) != (LONG)chunk) + return EOF; + ptr += chunk; + length -= chunk; } + written += blocks; } return written; @@ -144,7 +174,7 @@ FWriteChars(BPTR file, CONST UBYTE* buffer, ULONG length, struct DosLibrary *DOS if (goOn) { - written = Write(file, buffer, length); + written = write_direct(file, buffer, length, DOSBase); } } else if (!(fh->fh_Flags & FHF_LINEBUF) && length >= (ULONG)fh->fh_End) @@ -152,7 +182,7 @@ FWriteChars(BPTR file, CONST UBYTE* buffer, ULONG length, struct DosLibrary *DOS /* At least a buffer's worth: write it with one packet. Flush() * also moves an append-mode handle to the end of the file. */ if ((fh->fh_Pos == 0 && !(fh->fh_Flags & FHF_APPEND)) || Flush(file)) - written = Write(file, buffer, length); + written = write_direct(file, buffer, length, DOSBase); } else { @@ -186,3 +216,25 @@ FWriteChars(BPTR file, CONST UBYTE* buffer, ULONG length, struct DosLibrary *DOS return(written); } + +static LONG write_direct(BPTR file, CONST UBYTE *buffer, ULONG length, + struct DosLibrary *DOSBase) +{ + ULONG written = 0; + + while (written < length) + { + ULONG chunk = length - written; + LONG size; + + if (chunk > 0x7FFFFFFFUL) + chunk = 0x7FFFFFFFUL; + size = Write(file, buffer + written, chunk); + /* A zero-length result makes no progress; do not loop forever. */ + if (size <= 0) + return EOF; + written += size; + } + + return written; +} From ce906f7a631742b2acf1b03131a49d6225d83349 Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 08/12] dos: a seek back from above 2G is not an error Seek returns the old position, which is negative as a LONG above 2G. FWrite and Flush after a read took that for a failure. --- rom/dos/flush.c | 2 +- rom/dos/fwrite.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rom/dos/flush.c b/rom/dos/flush.c index 9d08e50f54..40eec37258 100644 --- a/rom/dos/flush.c +++ b/rom/dos/flush.c @@ -78,7 +78,7 @@ fh->fh_Pos = fh->fh_End = 0; /* Read mode. Try to seek back to the current position. */ - if( InternalSeek( fh, offset, OFFSET_CURRENT, DOSBase ) < 0 ) + if( InternalSeek( fh, offset, OFFSET_CURRENT, DOSBase ) == -1 ) { return FALSE; } diff --git a/rom/dos/fwrite.c b/rom/dos/fwrite.c index d9b99e0218..fa87aa2e2c 100644 --- a/rom/dos/fwrite.c +++ b/rom/dos/fwrite.c @@ -135,7 +135,7 @@ FWriteChars(BPTR file, CONST UBYTE* buffer, ULONG length, struct DosLibrary *DOS if (fh->fh_Pos < fh->fh_End) { /* Read mode. Try to seek back to the current position. */ - if (Seek(file, fh->fh_Pos - fh->fh_End, OFFSET_CURRENT) < 0) + if (Seek(file, fh->fh_Pos - fh->fh_End, OFFSET_CURRENT) == -1) { fh->fh_Pos = fh->fh_End = 0; From 86266d6cc7301e74654b9b55238c0c3e3fc39465 Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 09/12] m68k: put dos64.library in the Vampire ROM It goes into the ext bank (E0) after dos.library. --- arch/m68k-amiga/boot/mmakefile.src | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/m68k-amiga/boot/mmakefile.src b/arch/m68k-amiga/boot/mmakefile.src index 82f84577cc..a141ef5989 100644 --- a/arch/m68k-amiga/boot/mmakefile.src +++ b/arch/m68k-amiga/boot/mmakefile.src @@ -32,6 +32,7 @@ include $(SRCDIR)/config/aros.cfg #MM kernel-diag-kobj \ #MM kernel-disk-kobj \ #MM kernel-dos-kobj \ +#MM kernel-dos64-kobj \ #MM kernel-dosboot-kobj \ #MM kernel-expansion-kobj \ #MM kernel-filesystem-kobj \ @@ -165,7 +166,7 @@ AFILES := ext_entry # APOLLOROM = V4 -> Native V4 ifeq ($(APOLLOROM),V4) - KLIBS := keymap graphics layers intuition gadtools workbench mathffp mathieeesingbas freeanim lowlevel setpatch + KLIBS := keymap graphics layers intuition gadtools workbench mathffp mathieeesingbas freeanim lowlevel setpatch dos64 KDEVS := sagasd ata trackdisk KHNDLRS := con KHIDDS := bus storage system From c78a0e6a439c9e075a51cec21938b5566351f875 Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 10/12] crt: use dos64.library for file offsets and sizes fopen, fseek, ftell, fseeko, ftello, lseek, ftruncate, read, write, stat, statfs and getfsstat go through helpers that use dos64.library when it is installed and the 32 bit calls otherwise. A value that does not fit fails with EOVERFLOW. File systems that answer the 64 bit packets are probed once per file. stat64 and fstat64 return the whole st_size, stat and fstat fail with EOVERFLOW for a file above 2G. --- compiler/posixc/__dos64.c | 209 +++++++++++++++++++++++ compiler/posixc/__dos64.h | 40 +++++ compiler/posixc/__fdesc.c | 10 ++ compiler/posixc/__fseeko.c | 215 ++++++------------------ compiler/posixc/__ftello.c | 57 +++++-- compiler/posixc/__optionallibs.c | 28 +++ compiler/posixc/__optionallibs.h | 11 ++ compiler/posixc/__posixc_intbase.h | 3 + compiler/posixc/__stat.c | 88 +++++----- compiler/posixc/fgetpos64.c | 4 +- compiler/posixc/fseek.c | 108 +----------- compiler/posixc/fsetpos64.c | 4 +- compiler/posixc/ftell.c | 12 +- compiler/posixc/ftruncate.c | 36 ++-- compiler/posixc/getfsstat.c | 16 +- compiler/posixc/lseek.c | 43 +++-- compiler/posixc/lseek64.c | 45 +++-- compiler/posixc/mmakefile.src | 2 + compiler/posixc/read.c | 3 +- compiler/posixc/statfs.c | 12 +- compiler/posixc/write.c | 3 +- compiler/stdc/__stdcio_dos64.c | 85 ++++++++++ compiler/stdc/__stdcio_dos64.h | 24 +++ compiler/stdc/__stdcio_intbase.h | 3 + compiler/stdc/__stdio.h | 1 + compiler/stdc/fopen.c | 4 + compiler/stdc/fseek.c | 6 +- compiler/stdc/ftell.c | 12 +- compiler/stdc/include/aros/stdc/errno.h | 1 + compiler/stdc/mmakefile.src | 1 + 30 files changed, 700 insertions(+), 386 deletions(-) create mode 100644 compiler/posixc/__dos64.c create mode 100644 compiler/posixc/__dos64.h create mode 100644 compiler/posixc/__optionallibs.c create mode 100644 compiler/posixc/__optionallibs.h create mode 100644 compiler/stdc/__stdcio_dos64.c create mode 100644 compiler/stdc/__stdcio_dos64.h diff --git a/compiler/posixc/__dos64.c b/compiler/posixc/__dos64.c new file mode 100644 index 0000000000..95ac5d8e7d --- /dev/null +++ b/compiler/posixc/__dos64.c @@ -0,0 +1,209 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Internal 64-bit file access helpers for posixc.library: use + dos64.library when available, otherwise delegate to the 32-bit + dos.library calls, widening/narrowing as needed. +*/ + +#include + +#include +#include + +#define __NOBLIBBASE__ + +#include "__posixc_intbase.h" +#include "__optionallibs.h" +#include "__dos64.h" + +#include + +/* Returns the dos64.library base, or NULL when it is not available */ +static struct Library *__dos64_base(void) +{ + struct PosixCIntBase *PosixCBase = + (struct PosixCIntBase *)__aros_getbase_PosixCBase(); + + if (__dos64_available(PosixCBase)) + return PosixCBase->PosixCDOS64Base; + + return NULL; +} + +/* The dos64.library base when the fcb's filesystem handles 64-bit + packets, NULL otherwise (32-bit path) */ +static struct Library *__dos64_base_for(fcb *fcb) +{ + if (!(fcb->privflags & _FCB_FS64)) + return NULL; + + return __dos64_base(); +} + +void __dos64_probe(fcb *fcb) +{ + struct Library *DOS64Base = __dos64_base(); + + if (DOS64Base != NULL && fcb->handle != BNULL + && IsFileSystem64(fcb->handle)) + fcb->privflags |= _FCB_FS64; +} + +QUAD __dos64_seek(fcb *fcb, QUAD position, LONG mode) +{ + struct Library *DOS64Base = __dos64_base_for(fcb); + BPTR fh = fcb->handle; + + if (DOS64Base != NULL) + return Seek64(fh, mode, position); + + if (position != (QUAD)(LONG)position) + { + SetIoErr(ERROR_OBJECT_TOO_LARGE); + return -1; + } + return Seek(fh, (LONG)position, mode); +} + +QUAD __dos64_getpos(fcb *fcb) +{ + struct Library *DOS64Base = __dos64_base_for(fcb); + BPTR fh = fcb->handle; + + if (DOS64Base != NULL) + return GetFilePosition64(fh); + + return Seek(fh, 0, OFFSET_CURRENT); +} + +QUAD __dos64_getsize(fcb *fcb) +{ + struct Library *DOS64Base = __dos64_base_for(fcb); + BPTR fh = fcb->handle; + + if (DOS64Base != NULL) + return GetFileSize64(fh); + + /* + * Seek() returns the previous position: seek to the end to learn + * nothing yet, then back to where we were - that second call + * reports the end position, i.e. the size. + */ + QUAD pos = Seek(fh, 0, OFFSET_END); + if (pos == -1) + return -1; + return Seek(fh, (LONG)pos, OFFSET_BEGINNING); +} + +QUAD __dos64_setfilesize(fcb *fcb, QUAD size, LONG mode) +{ + struct Library *DOS64Base = __dos64_base_for(fcb); + BPTR fh = fcb->handle; + + if (DOS64Base != NULL) + return SetFileSize64(fh, mode, size); + + if (size != (QUAD)(LONG)size) + { + SetIoErr(ERROR_OBJECT_TOO_LARGE); + return -1; + } + return SetFileSize(fh, (LONG)size, mode); +} + +QUAD __dos64_read(fcb *fcb, APTR buf, QUAD len) +{ + struct Library *DOS64Base = __dos64_base_for(fcb); + BPTR fh = fcb->handle; + + if (DOS64Base != NULL) + return Read64(fh, buf, len); + + /* Partial transfers are permitted, so simply clamp */ + if (len > 0x7FFFF000LL) + len = 0x7FFFF000LL; + return Read(fh, buf, (LONG)len); +} + +QUAD __dos64_write(fcb *fcb, CONST_APTR buf, QUAD len) +{ + struct Library *DOS64Base = __dos64_base_for(fcb); + BPTR fh = fcb->handle; + + if (DOS64Base != NULL) + return Write64(fh, buf, len); + + if (len > 0x7FFFF000LL) + len = 0x7FFFF000LL; + return Write(fh, buf, (LONG)len); +} + +/* Derive the 64-bit fields of a FileInfoBlock filled by a 32-bit examine */ +static void __dos64_fib32to64(struct FileInfoBlock *fib) +{ + UQUAD size = (UQUAD)(ULONG)fib->fib_Size; + + fib->fib_Size64 = size; + fib->fib_NumBlocks64 = (UQUAD)(ULONG)fib->fib_NumBlocks; + fib->fib_ActExtFlags = 0; + if (size > 0x7FFFFFFFULL) + fib->fib_Size = 0; +} + +LONG __dos64_examine(BPTR obj, struct FileInfoBlock *fib, int what) +{ + struct Library *DOS64Base = __dos64_base(); + LONG ret = DOSFALSE; + + if (DOS64Base != NULL) + { + switch (what) + { + case __DOS64_EXAMINE: + return Examine64(obj, fib, NULL); + case __DOS64_EXAMINE_FH: + return ExamineFH64(obj, fib, NULL); + case __DOS64_EXAMINE_NEXT: + return ExNext64(obj, fib, NULL); + } + return DOSFALSE; + } + + /* The 64-bit fields share the block, so examine into it directly */ + switch (what) + { + case __DOS64_EXAMINE: + ret = Examine(obj, fib); + break; + case __DOS64_EXAMINE_FH: + ret = ExamineFH(obj, fib); + break; + case __DOS64_EXAMINE_NEXT: + ret = ExNext(obj, fib); + break; + } + + if (ret) + __dos64_fib32to64(fib); + + return ret; +} + +LONG __dos64_info(BPTR lock, struct InfoData64 *id) +{ + struct Library *DOS64Base = __dos64_base(); + LONG ret; + + if (DOS64Base != NULL) + return Info64(lock, id); + + /* InfoData64 starts with a standard InfoData */ + ret = Info(lock, (struct InfoData *)id); + if (ret) + { + id->id_NumBlocks64 = (UQUAD)(ULONG)id->id_NumBlocks; + id->id_NumBlocksUsed64 = (UQUAD)(ULONG)id->id_NumBlocksUsed; + } + return ret; +} diff --git a/compiler/posixc/__dos64.h b/compiler/posixc/__dos64.h new file mode 100644 index 0000000000..ab077f5cf3 --- /dev/null +++ b/compiler/posixc/__dos64.h @@ -0,0 +1,40 @@ +#ifndef ___DOS64_H +#define ___DOS64_H + +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Internal 64-bit file access helpers for posixc.library. They use + dos64.library when it is available and transparently fall back to + the 32-bit dos.library calls when it is not, so posixc keeps + working on systems without dos64.library. Values the 32-bit + fallback cannot express fail with IoErr() == ERROR_OBJECT_TOO_LARGE + (mapped to EOVERFLOW by the callers). +*/ + +#include +#include + +#include "__fdesc.h" + +/* Detect 64-bit filesystem support for an open fcb and cache it in + the fcb's _FCB_FS64 privflag; the helpers below then pick the + 64-bit or 32-bit path directly, without per-call probing. */ +void __dos64_probe(fcb *fcb); + +QUAD __dos64_seek(fcb *fcb, QUAD position, LONG mode); +QUAD __dos64_getpos(fcb *fcb); +QUAD __dos64_getsize(fcb *fcb); +QUAD __dos64_setfilesize(fcb *fcb, QUAD size, LONG mode); +QUAD __dos64_read(fcb *fcb, APTR buf, QUAD len); +QUAD __dos64_write(fcb *fcb, CONST_APTR buf, QUAD len); + +/* obj is a filehandle for __DOS64_EXAMINE_FH, otherwise a lock */ +#define __DOS64_EXAMINE 0 +#define __DOS64_EXAMINE_FH 1 +#define __DOS64_EXAMINE_NEXT 2 +LONG __dos64_examine(BPTR obj, struct FileInfoBlock *fib, int what); + +LONG __dos64_info(BPTR lock, struct InfoData64 *id); + +#endif /* ___DOS64_H */ diff --git a/compiler/posixc/__fdesc.c b/compiler/posixc/__fdesc.c index 35d004671b..cae61fae79 100644 --- a/compiler/posixc/__fdesc.c +++ b/compiler/posixc/__fdesc.c @@ -24,6 +24,7 @@ #include #include #include "__fdesc.h" +#include "__dos64.h" #include "__upath.h" /* TODO: Add locking to make filedesc usage thread safe @@ -352,6 +353,10 @@ int __open(int wanted_fd, const char *pathname, int flags, int mode) currdesc->fcb->flags = flags; currdesc->fcb->opencount = 1; + /* Detect 64-bit filesystem support once, and cache it in the fcb */ + if (!(currdesc->fcb->privflags & _FCB_ISDIR)) + __dos64_probe(currdesc->fcb); + __setfdesc(wanted_fd, currdesc); D(bug("__open: exiting fd=%d\n", wanted_fd)); @@ -476,6 +481,11 @@ int __init_stdfiles(struct PosixCIntBase *PosixCBase) BADDR(me->pr_CES), BADDR(errfcb->handle) )); + /* Std streams may be redirected to files; detect 64-bit support */ + __dos64_probe(infcb); + __dos64_probe(outfcb); + __dos64_probe(errfcb); + PosixCBase->fd_array[STDIN_FILENO] = indesc; PosixCBase->fd_array[STDOUT_FILENO] = outdesc; PosixCBase->fd_array[STDERR_FILENO] = errdesc; diff --git a/compiler/posixc/__fseeko.c b/compiler/posixc/__fseeko.c index 1681b7175f..50056194ad 100644 --- a/compiler/posixc/__fseeko.c +++ b/compiler/posixc/__fseeko.c @@ -16,151 +16,36 @@ #include "__stdio.h" #include "__fdesc.h" +#include "__dos64.h" #include -#if (__WORDSIZE < 64) - /* - * 32bit version of fseeko. only handles <=2GB files. + * fseeko engine. Positions are handled in 64 bits throughout; the + * __dos64 helpers use dos64.library when it is available and fall + * back to the 32-bit dos.library calls (failing with + * ERROR_OBJECT_TOO_LARGE for unrepresentable positions) when not. */ - -int __fseeko ( - FILE * stream, - off_t offset, - int whence) +int __fseeko64 ( + FILE * stream, + off64_t offset, + int whence) { - off_t cnt = 0; - off_t finalseekposition = 0; - off_t eofposition = 0; - struct FileInfoBlock *fib = NULL; + QUAD cnt = 0; + QUAD finalseekposition = 0; + QUAD eofposition = 0; BPTR fh = BNULL; fdesc *fdesc = __getfdesc(stream->fd); if (!fdesc) { - errno = EBADF; - return -1; - } - - fh = fdesc->fcb->handle; - - /* This is buffered IO, flush the buffer before any Seek */ - Flush (fh); - - /* Handling for fseeko specific behaviour (not all cases handled) */ - /* Get current position */ - cnt = Seek (fh, 0, OFFSET_CURRENT); - if (cnt == -1) - { - errno = __stdc_ioerr2errno (IoErr ()); - return -1; - } - - /* Get file size */ - fib = AllocDosObject(DOS_FIB, NULL); - if (!fib) - { - errno = __stdc_ioerr2errno(IoErr()); - return -1; - } - - if (ExamineFH(fh, fib)) - eofposition = fib->fib_Size; - else - { - /* Does not happen on sfs/affs */ - FreeDosObject(DOS_FIB, fib); - fib = NULL; errno = EBADF; return -1; } - FreeDosObject(DOS_FIB, fib); - fib = NULL; - - switch(whence) - { - case SEEK_SET: finalseekposition = offset; break; - case SEEK_CUR: finalseekposition = cnt + offset; break; - case SEEK_END: finalseekposition = eofposition + offset; break; - default: - errno = EINVAL; - return -1; - } - - /* Check conditions */ - /* Seek before beginning of file */ - if (finalseekposition < 0) + if (fdesc->fcb->privflags & _FCB_ISDIR) { - errno = EINVAL; - return -1; - } - - /* Seek beyond end of file and in write mode */ - if (finalseekposition > eofposition) - { - if (fdesc->fcb->flags & O_WRITE) - { - /* Write '0' to fill up to requested size - * compatible fseeko does not write but allows write */ - int bytestowrite = finalseekposition - eofposition; - int chunkcount = (bytestowrite)/128; - int remainder = bytestowrite - (chunkcount * 128); - char zeroarray[128] = {0}; - - Seek (fh, 0, OFFSET_END); - if (chunkcount > 0) - FWrite (fh, zeroarray, 128, chunkcount); - if (remainder > 0) - FWrite (fh, zeroarray, remainder, 1); - Flush (fh); - } - } - - cnt = Seek (fh, finalseekposition, OFFSET_BEGINNING); - - if (cnt == -1) - errno = __stdc_ioerr2errno (IoErr ()); - else - { - /* It's specified that upon success fseeko should clear EOF flag - so here we go. - */ - stream->flags &= ~(__POSIXC_STDIO_EOF); - cnt = 0; - } - - return cnt; -} /* __fseeko */ -#endif - -/* - * 64bit version of fseeko. Must be able to hanlde both 32bit and 64bit filesystems ! - */ - -int __fseeko64 ( - FILE * stream, - off64_t offset, - int whence) -{ - off_t cnt = 0; - off_t finalseekposition = 0; - off_t eofposition = 0; - struct FileInfoBlock *fib = NULL; - BPTR fh = BNULL; - fdesc *fdesc = __getfdesc(stream->fd); - - if (!fdesc) - { - errno = EBADF; - return -1; - } - - if (((offset <= LONG_MIN) || (offset >= LONG_MAX)) && !(fdesc->fcb->privflags & _FCB_FS64)) - { - /* asked to seek too far on a 32bit filesystem.. */ - errno = EBADF; + errno = EISDIR; return -1; } @@ -171,7 +56,7 @@ int __fseeko64 ( /* Handling for fseeko specific behaviour (not all cases handled) */ /* Get current position */ - cnt = Seek (fh, 0, OFFSET_CURRENT); + cnt = __dos64_getpos (fdesc->fcb); if (cnt == -1) { errno = __stdc_ioerr2errno (IoErr ()); @@ -179,35 +64,22 @@ int __fseeko64 ( } /* Get file size */ - fib = AllocDosObject(DOS_FIB, NULL); - if (!fib) - { - errno = __stdc_ioerr2errno(IoErr()); - return -1; - } - - if (ExamineFH(fh, fib)) - eofposition = fib->fib_Size; - else + eofposition = __dos64_getsize (fdesc->fcb); + if (eofposition == -1) { /* Does not happen on sfs/affs */ - FreeDosObject(DOS_FIB, fib); - fib = NULL; errno = EBADF; return -1; } - FreeDosObject(DOS_FIB, fib); - fib = NULL; - switch(whence) { case SEEK_SET: finalseekposition = offset; break; case SEEK_CUR: finalseekposition = cnt + offset; break; case SEEK_END: finalseekposition = eofposition + offset; break; default: - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } /* Check conditions */ @@ -225,37 +97,54 @@ int __fseeko64 ( { /* Write '0' to fill up to requested size * compatible fseeko does not write but allows write */ - int bytestowrite = finalseekposition - eofposition; - int chunkcount = (bytestowrite)/128; - int remainder = bytestowrite - (chunkcount * 128); + QUAD bytestowrite = finalseekposition - eofposition; + QUAD chunkcount = bytestowrite / 128; + LONG remainder = bytestowrite - (chunkcount * 128); char zeroarray[128] = {0}; - Seek (fh, 0, OFFSET_END); - if (chunkcount > 0) - FWrite (fh, zeroarray, 128, chunkcount); + __dos64_seek (fdesc->fcb, 0, OFFSET_END); + while (chunkcount > 0) + { + LONG n = (chunkcount > 0x100000) ? 0x100000 : (LONG)chunkcount; + FWrite (fh, zeroarray, 128, n); + chunkcount -= n; + } if (remainder > 0) FWrite (fh, zeroarray, remainder, 1); Flush (fh); } } - cnt = Seek (fh, finalseekposition, OFFSET_BEGINNING); + cnt = __dos64_seek (fdesc->fcb, finalseekposition, OFFSET_BEGINNING); if (cnt == -1) - errno = __stdc_ioerr2errno (IoErr ()); - else { - /* It's specified that upon success fseeko should clear EOF flag - so here we go. - */ - stream->flags &= ~(__POSIXC_STDIO_EOF); - cnt = 0; + LONG ioerr = IoErr (); + errno = (ioerr == ERROR_OBJECT_TOO_LARGE) + ? EOVERFLOW : __stdc_ioerr2errno (ioerr); + return -1; } - return cnt; + /* It's specified that upon success fseeko should clear EOF flag + so here we go. + */ + stream->flags &= ~(__POSIXC_STDIO_EOF); + + return 0; } /* __fseeko64 */ -#if (__WORDSIZE==64) +#if (__WORDSIZE < 64) +/* + * 32-bit off_t variant: same engine, the offset simply widens. + */ +int __fseeko ( + FILE * stream, + off_t offset, + int whence) +{ + return __fseeko64 (stream, (off64_t)offset, whence); +} /* __fseeko */ +#else /* * on 64bit fseeko is an alias of fseeko64 */ diff --git a/compiler/posixc/__ftello.c b/compiler/posixc/__ftello.c index 23b751bc21..d82261727b 100644 --- a/compiler/posixc/__ftello.c +++ b/compiler/posixc/__ftello.c @@ -3,34 +3,65 @@ $Id$ */ +#include #include +#include + #define POSIXC_NOSTDIO_DECL #include "__stdio.h" - -#if (__WORDSIZE < 64) +#include "__fdesc.h" +#include "__dos64.h" /* - * 32bit version of ftello. only handles <=2GB files. + * ftello engine: full 64-bit position via the __dos64 helpers. */ - -off_t __ftello(FILE *stream) +off64_t __ftello64(FILE *stream) { - return ftell(stream); + QUAD cnt; + BPTR fh; + fdesc *fdesc = __getfdesc(stream->fd); + + if (!fdesc) + { + errno = EBADF; + return -1; + } + + if (fdesc->fcb->privflags & _FCB_ISDIR) + { + errno = EISDIR; + return -1; + } + + fh = fdesc->fcb->handle; + + Flush (fh); + cnt = __dos64_getpos (fdesc->fcb); + + if (cnt == -1) + errno = __stdc_ioerr2errno (IoErr ()); + + return cnt; } -#endif +#if (__WORDSIZE < 64) /* - * 64bit version of ftello. Must be able to hanlde both 32bit and 64bit filesystems ! + * 32-bit off_t variant: positions beyond off_t range report EOVERFLOW. */ - -off64_t __ftello64(FILE *stream) +off_t __ftello(FILE *stream) { - return ftell(stream); -} + QUAD cnt = __ftello64(stream); -#if (__WORDSIZE==64) + if (cnt != (QUAD)(off_t)cnt) + { + errno = EOVERFLOW; + return (off_t)-1; + } + return (off_t)cnt; +} +#else /* * on 64bit ftello is an alias of ftello64 */ diff --git a/compiler/posixc/__optionallibs.c b/compiler/posixc/__optionallibs.c new file mode 100644 index 0000000000..b30eda9553 --- /dev/null +++ b/compiler/posixc/__optionallibs.c @@ -0,0 +1,28 @@ +/* + Copyright (C) 2025-2026, The AROS Development Team. All rights reserved. +*/ + +#include +#include + +#include "__posixc_intbase.h" +#include "__optionallibs.h" + +int __dos64_available(struct PosixCIntBase *PosixCBase) +{ + if (PosixCBase->PosixCDOS64Base == NULL) + PosixCBase->PosixCDOS64Base = OpenLibrary("dos64.library", 50); + + return PosixCBase->PosixCDOS64Base != NULL; +} + +/* Close the optional libraries opened by this base */ +static void __optionallibs_close(struct PosixCIntBase *PosixCBase) +{ + if (PosixCBase->PosixCDOS64Base) { + CloseLibrary(PosixCBase->PosixCDOS64Base); + PosixCBase->PosixCDOS64Base = NULL; + } +} + +ADD2CLOSELIB(__optionallibs_close, 0) diff --git a/compiler/posixc/__optionallibs.h b/compiler/posixc/__optionallibs.h new file mode 100644 index 0000000000..39ebe45797 --- /dev/null +++ b/compiler/posixc/__optionallibs.h @@ -0,0 +1,11 @@ +/* + Copyright (C) 2025-2026, The AROS Development Team. All rights reserved. +*/ + +/* Functions in this include should be used in rest of posixc.library to check + if an optional library is available; the library is opened on first use + and closed when posixc.library is closed. */ + +struct PosixCIntBase; + +int __dos64_available(struct PosixCIntBase *PosixCBase); diff --git a/compiler/posixc/__posixc_intbase.h b/compiler/posixc/__posixc_intbase.h index 5a264c2690..b4ff10bc66 100644 --- a/compiler/posixc/__posixc_intbase.h +++ b/compiler/posixc/__posixc_intbase.h @@ -31,6 +31,9 @@ struct PosixCIntBase { struct PosixCBase PosixCBase; + /* __optionallibs.c */ + struct Library *PosixCDOS64Base; /* dos64.library, for 64-bit file I/O */ + /* common */ APTR internalpool; int32_t flags; diff --git a/compiler/posixc/__stat.c b/compiler/posixc/__stat.c index 1d5678a611..04d60c0cda 100644 --- a/compiler/posixc/__stat.c +++ b/compiler/posixc/__stat.c @@ -13,6 +13,7 @@ #include #include +#include "__dos64.h" #include "__stat.h" #include @@ -29,7 +30,7 @@ static mode_t __prot_a2u(ULONG protect); static uid_t __id_a2u(UWORD id); static void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb); -static void __fill_statbuffer( +static int __fill_statbuffer( struct stat *sb, char *buffer, struct FileInfoBlock *fib, @@ -45,12 +46,13 @@ static void __fill_stat64buffer( int __stat(BPTR lock, struct stat *sb, BOOL filehandle) { struct FileInfoBlock *fib; + int res; UBYTE *buffer; int buffersize = 256; int fallback_to_defaults = 0; BOOL Examined; - fib = AllocDosObject(DOS_FIB, NULL); + fib = AllocVec(sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR); if (!fib) { @@ -60,8 +62,8 @@ int __stat(BPTR lock, struct stat *sb, BOOL filehandle) } Examined = filehandle - ? ExamineFH(lock, fib) - : Examine(lock, fib); + ? __dos64_examine(lock, fib, __DOS64_EXAMINE_FH) + : __dos64_examine(lock, fib, __DOS64_EXAMINE); if (!Examined) { if(IoErr() == ERROR_NOT_IMPLEMENTED || @@ -72,7 +74,7 @@ int __stat(BPTR lock, struct stat *sb, BOOL filehandle) else { errno = __stdc_ioerr2errno(IoErr()); - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); return -1; } } @@ -86,7 +88,7 @@ int __stat(BPTR lock, struct stat *sb, BOOL filehandle) if(!(buffer = AllocVec(buffersize, MEMF_ANY))) { errno = ENOMEM; - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); return -1; } @@ -109,7 +111,7 @@ int __stat(BPTR lock, struct stat *sb, BOOL filehandle) else if(IoErr() != ERROR_LINE_TOO_LONG) { errno = __stdc_ioerr2errno(IoErr()); - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); FreeVec(buffer); return -1; } @@ -123,18 +125,18 @@ int __stat(BPTR lock, struct stat *sb, BOOL filehandle) if (filehandle) { BPTR filelock = DupLockFromFH(lock); - __fill_statbuffer(sb, (char*) buffer, fib, fallback_to_defaults, filelock); + res = __fill_statbuffer(sb, (char*) buffer, fib, fallback_to_defaults, filelock); UnLock(filelock); } else { - __fill_statbuffer(sb, (char*) buffer, fib, fallback_to_defaults, lock); + res = __fill_statbuffer(sb, (char*) buffer, fib, fallback_to_defaults, lock); } FreeVec(buffer); - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); - return 0; + return res; } int __stat64(BPTR lock, struct stat64 *sb, BOOL filehandle) @@ -145,7 +147,7 @@ int __stat64(BPTR lock, struct stat64 *sb, BOOL filehandle) int fallback_to_defaults = 0; BOOL Examined; - fib = AllocDosObject(DOS_FIB, NULL); + fib = AllocVec(sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR); if (!fib) { @@ -155,8 +157,8 @@ int __stat64(BPTR lock, struct stat64 *sb, BOOL filehandle) } Examined = filehandle - ? ExamineFH(lock, fib) - : Examine(lock, fib); + ? __dos64_examine(lock, fib, __DOS64_EXAMINE_FH) + : __dos64_examine(lock, fib, __DOS64_EXAMINE); if (!Examined) { if(IoErr() == ERROR_NOT_IMPLEMENTED || @@ -167,7 +169,7 @@ int __stat64(BPTR lock, struct stat64 *sb, BOOL filehandle) else { errno = __stdc_ioerr2errno(IoErr()); - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); return -1; } } @@ -181,7 +183,7 @@ int __stat64(BPTR lock, struct stat64 *sb, BOOL filehandle) if(!(buffer = AllocVec(buffersize, MEMF_ANY))) { errno = ENOMEM; - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); return -1; } @@ -204,7 +206,7 @@ int __stat64(BPTR lock, struct stat64 *sb, BOOL filehandle) else if(IoErr() != ERROR_LINE_TOO_LONG) { errno = __stdc_ioerr2errno(IoErr()); - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); FreeVec(buffer); return -1; } @@ -227,7 +229,7 @@ int __stat64(BPTR lock, struct stat64 *sb, BOOL filehandle) } FreeVec(buffer); - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); return 0; } @@ -313,7 +315,7 @@ int __stat_from_path(const char *path, struct stat *sb) strcpy(filepart, split); *split = '\0'; - if ( !(fib = AllocDosObject(DOS_FIB, NULL)) + if ( !(fib = AllocVec(sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR)) || !(lock = Lock(abspath, SHARED_LOCK))) { errno = __stdc_ioerr2errno(IoErr()); @@ -321,7 +323,7 @@ int __stat_from_path(const char *path, struct stat *sb) } /* examine parent directory of object to stat */ - if (!Examine(lock, fib)) + if (!__dos64_examine(lock, fib, __DOS64_EXAMINE)) { if (IoErr() == ERROR_NOT_IMPLEMENTED || IoErr() == ERROR_ACTION_NOT_KNOWN) @@ -339,14 +341,13 @@ int __stat_from_path(const char *path, struct stat *sb) /* examine entries of parent directory until we find the object to stat */ do { - loop = ExNext(lock, fib); + loop = __dos64_examine(lock, fib, __DOS64_EXAMINE_NEXT); if (loop) { if (stricmp(fib->fib_FileName, filepart) == 0) { - __fill_statbuffer(sb, abspath, fib, 0, lock); - res = 0; + res = __fill_statbuffer(sb, abspath, fib, 0, lock); break; } @@ -373,7 +374,7 @@ int __stat_from_path(const char *path, struct stat *sb) FreeVec(filepart); if (fib) - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); return res; } @@ -459,7 +460,7 @@ int __stat64_from_path(const char *path, struct stat64 *sb) strcpy(filepart, split); *split = '\0'; - if ( !(fib = AllocDosObject(DOS_FIB, NULL)) + if ( !(fib = AllocVec(sizeof(struct FileInfoBlock), MEMF_PUBLIC | MEMF_CLEAR)) || !(lock = Lock(abspath, SHARED_LOCK))) { errno = __stdc_ioerr2errno(IoErr()); @@ -467,7 +468,7 @@ int __stat64_from_path(const char *path, struct stat64 *sb) } /* examine parent directory of object to stat */ - if (!Examine(lock, fib)) + if (!__dos64_examine(lock, fib, __DOS64_EXAMINE)) { if (IoErr() == ERROR_NOT_IMPLEMENTED || IoErr() == ERROR_ACTION_NOT_KNOWN) @@ -485,7 +486,7 @@ int __stat64_from_path(const char *path, struct stat64 *sb) /* examine entries of parent directory until we find the object to stat */ do { - loop = ExNext(lock, fib); + loop = __dos64_examine(lock, fib, __DOS64_EXAMINE_NEXT); if (loop) { @@ -519,7 +520,7 @@ int __stat64_from_path(const char *path, struct stat64 *sb) FreeVec(filepart); if (fib) - FreeDosObject(DOS_FIB, fib); + FreeVec(fib); return res; } @@ -795,7 +796,7 @@ static void hashlittle2( *pc=c; *pb=b; } -static void __fill_statbuffer( +static int __fill_statbuffer( struct stat *sb, char *buffer, struct FileInfoBlock *fib, @@ -805,14 +806,21 @@ static void __fill_statbuffer( uint64_t hash; uint32_t pc = 1, pb = 1; /* initial hash values */ + /* The size does not fit the 32 bit st_size */ + if (!fallback_to_defaults && fib->fib_Size64 > 0x7FFFFFFF) + { + errno = EOVERFLOW; + return -1; + } + hashlittle2(buffer, strlen((char*) buffer), &pc, &pb); hash = pc + (((uint64_t)pb)<<32); if(fallback_to_defaults) { /* Empty file, not protected, as old as it can be... */ - fib->fib_Size = 0; - fib->fib_NumBlocks = 0; + fib->fib_Size64 = 0; + fib->fib_NumBlocks64 = 0; fib->fib_Date.ds_Days = 0; fib->fib_Date.ds_Minute = 0; fib->fib_Date.ds_Tick = 0; @@ -826,7 +834,7 @@ static void __fill_statbuffer( sb->st_dev = (dev_t) (lock ? ((struct FileLock *)BADDR(lock))->fl_Volume : BNULL); sb->st_ino = hash; /* hash value will be truncated if st_ino size is smaller than uint64_t, but it's ok */ - sb->st_size = (off_t)fib->fib_Size; + sb->st_size = (off_t)fib->fib_Size64; /* FIXME: Update to properly handle the struct timespec fields st_atim, st_mtim and st_ctim */ sb->st_atime = @@ -851,9 +859,9 @@ static void __fill_statbuffer( sb->st_blksize = 1024; } } - if(fib->fib_Size > 0 && sb->st_blksize > 0) + if(fib->fib_Size64 > 0 && sb->st_blksize > 0) sb->st_blocks = - (1 + ((long) fib->fib_Size - 1) / sb->st_blksize) * + (1 + ((QUAD) fib->fib_Size64 - 1) / sb->st_blksize) * (sb->st_blksize / 512); else sb->st_blocks = 0; @@ -883,6 +891,8 @@ static void __fill_statbuffer( sb->st_nlink = 1; sb->st_mode |= S_IFREG; } + + return 0; } static void __fill_stat64buffer( @@ -901,8 +911,8 @@ static void __fill_stat64buffer( if(fallback_to_defaults) { /* Empty file, not protected, as old as it can be... */ - fib->fib_Size = 0; - fib->fib_NumBlocks = 0; + fib->fib_Size64 = 0; + fib->fib_NumBlocks64 = 0; fib->fib_Date.ds_Days = 0; fib->fib_Date.ds_Minute = 0; fib->fib_Date.ds_Tick = 0; @@ -916,7 +926,7 @@ static void __fill_stat64buffer( sb->st_dev = (dev_t) (lock ? ((struct FileLock *)BADDR(lock))->fl_Volume : BNULL); sb->st_ino = hash; /* hash value will be truncated if st_ino size is smaller than uint64_t, but it's ok */ - sb->st_size = (off_t)fib->fib_Size; + sb->st_size = (off64_t)fib->fib_Size64; /* FIXME: Update to properly handle the struct timespec fields st_atim, st_mtim and st_ctim */ sb->st_atime = @@ -941,9 +951,9 @@ static void __fill_stat64buffer( sb->st_blksize = 1024; } } - if(fib->fib_Size > 0 && sb->st_blksize > 0) + if(fib->fib_Size64 > 0 && sb->st_blksize > 0) sb->st_blocks = - (1 + ((long) fib->fib_Size - 1) / sb->st_blksize) * + (1 + ((QUAD) fib->fib_Size64 - 1) / sb->st_blksize) * (sb->st_blksize / 512); else sb->st_blocks = 0; diff --git a/compiler/posixc/fgetpos64.c b/compiler/posixc/fgetpos64.c index 53e3471faf..4c921e9109 100644 --- a/compiler/posixc/fgetpos64.c +++ b/compiler/posixc/fgetpos64.c @@ -12,6 +12,8 @@ NAME */ #include +#include "__stdio.h" + int fgetpos64 ( /* SYNOPSIS */ @@ -51,7 +53,7 @@ return -1; } - *pos = ftell (stream); + *pos = __ftello64 (stream); if ( *pos < 0L ) { diff --git a/compiler/posixc/fseek.c b/compiler/posixc/fseek.c index df822336cd..768681a144 100644 --- a/compiler/posixc/fseek.c +++ b/compiler/posixc/fseek.c @@ -60,110 +60,6 @@ ******************************************************************************/ { - int cnt = 0; - int finalseekposition = 0; - int eofposition = 0; - struct FileInfoBlock *fib = NULL; - BPTR fh = BNULL; - fdesc *fdesc = __getfdesc(stream->fd); - - if (!fdesc) - { - errno = EBADF; - return -1; - } - - if (fdesc->fcb->privflags & _FCB_ISDIR) - { - errno = EISDIR; - return -1; - } - - fh = fdesc->fcb->handle; - - /* This is buffered IO, flush the buffer before any Seek */ - Flush (fh); - - /* Handling for fseek specific behaviour (not all cases handled) */ - /* Get current position */ - cnt = Seek (fh, 0, OFFSET_CURRENT); - if (cnt == -1) - { - errno = __stdc_ioerr2errno (IoErr ()); - return -1; - } - - /* Get file size */ - fib = AllocDosObject(DOS_FIB, NULL); - if (!fib) - { - errno = __stdc_ioerr2errno(IoErr()); - return -1; - } - - if (ExamineFH(fh, fib)) - eofposition = fib->fib_Size; - else - { - /* Does not happen on sfs/affs */ - FreeDosObject(DOS_FIB, fib); - fib = NULL; - errno = EBADF; - return -1; - } - - FreeDosObject(DOS_FIB, fib); - fib = NULL; - - switch(whence) - { - case SEEK_SET: finalseekposition = offset; break; - case SEEK_CUR: finalseekposition = cnt + offset; break; - case SEEK_END: finalseekposition = eofposition + offset; break; - default: - errno = EINVAL; - return -1; - } - - /* Check conditions */ - /* Seek before beginning of file */ - if (finalseekposition < 0) - { - errno = EINVAL; - return -1; - } - - /* Seek beyond end of file and in write mode */ - if (finalseekposition > eofposition) - { - if (fdesc->fcb->flags & O_WRITE) - { - /* Write '0' to fill up to requested size - compatible fseek does not write but allows write */ - int i = 0; - int bytestowrite = finalseekposition - eofposition; - int chunkcount = (bytestowrite)/128; - char zeroarray[128] = {0}; - - Seek (fh, 0, OFFSET_END); - for (i = 0; i < chunkcount; i++) - FWrite(fh, (STRPTR)zeroarray, 128, 1); - FWrite(fh, (STRPTR)zeroarray, bytestowrite - (chunkcount * 128), 1); - Flush (fh); - } - } - - cnt = Seek (fh, finalseekposition, OFFSET_BEGINNING); - - if (cnt == -1) - errno = __stdc_ioerr2errno (IoErr ()); - else - { - /* It's specified that upon success fseek should clear EOF flag - so here we go. - */ - stream->flags &= ~(__POSIXC_STDIO_EOF); - cnt = 0; - } - - return cnt; + /* fseek is fseeko with a narrower offset; the engine handles 64-bit positions */ + return __fseeko64 (stream, (off64_t)offset, whence); } /* fseek */ diff --git a/compiler/posixc/fsetpos64.c b/compiler/posixc/fsetpos64.c index 7695639174..5f8c4f0dd1 100644 --- a/compiler/posixc/fsetpos64.c +++ b/compiler/posixc/fsetpos64.c @@ -12,6 +12,8 @@ NAME */ #include +#include "__stdio.h" + int fsetpos64 ( /* SYNOPSIS */ @@ -53,7 +55,7 @@ return -1; } - retval = fseek (stream, *pos, SEEK_SET); + retval = __fseeko64 (stream, (off64_t)*pos, SEEK_SET); return retval; } /* fsetpos64 */ diff --git a/compiler/posixc/ftell.c b/compiler/posixc/ftell.c index 415fcf1c72..375a7c8292 100644 --- a/compiler/posixc/ftell.c +++ b/compiler/posixc/ftell.c @@ -10,6 +10,7 @@ #include #include "__stdio.h" #include "__fdesc.h" +#include "__dos64.h" /***************************************************************************** @@ -44,7 +45,7 @@ ******************************************************************************/ { - long cnt; + QUAD cnt; BPTR fh; fdesc *fdesc = __getfdesc(stream->fd); @@ -57,10 +58,15 @@ fh = fdesc->fcb->handle; Flush (fh); - cnt = Seek (fh, 0, OFFSET_CURRENT); + cnt = __dos64_getpos (fdesc->fcb); if (cnt == -1) errno = __stdc_ioerr2errno (IoErr ()); + else if (cnt != (QUAD)(long)cnt) + { + errno = EOVERFLOW; + cnt = -1; + } - return cnt; + return (long)cnt; } /* ftell */ diff --git a/compiler/posixc/ftruncate.c b/compiler/posixc/ftruncate.c index 5018936f21..0f1c9f4f59 100644 --- a/compiler/posixc/ftruncate.c +++ b/compiler/posixc/ftruncate.c @@ -10,6 +10,7 @@ #include #include #include "__fdesc.h" +#include "__dos64.h" /***************************************************************************** @@ -52,8 +53,8 @@ ******************************************************************************/ { - ULONG oldpos; - size_t size; + QUAD oldpos; + QUAD size; fdesc *fdesc = __getfdesc(fd); @@ -75,35 +76,38 @@ return -1; } - oldpos = Seek(fdesc->fcb->handle, 0, OFFSET_END); - size = Seek(fdesc->fcb->handle, 0, OFFSET_CURRENT); - Seek(fdesc->fcb->handle, oldpos, OFFSET_BEGINNING); + oldpos = __dos64_getpos(fdesc->fcb); + size = __dos64_getsize(fdesc->fcb); - if ((length = SetFileSize(fdesc->fcb->handle, length, OFFSET_BEGINNING)) == -1) + if (__dos64_setfilesize(fdesc->fcb, length, OFFSET_BEGINNING) == -1) { - errno = __stdc_ioerr2errno(IoErr()); + LONG ioerr = IoErr(); + errno = (ioerr == ERROR_OBJECT_TOO_LARGE) + ? EFBIG : __stdc_ioerr2errno(ioerr); return -1; } else - if (size < length) + if (size != -1 && size < length) { char buf[16]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + QUAD left = length - size; - length -= size; + __dos64_seek(fdesc->fcb, size, OFFSET_BEGINNING); - oldpos = Seek(fdesc->fcb->handle, size, OFFSET_BEGINNING); - - while (length >= 16) + while (left >= 16) { FWrite(fdesc->fcb->handle, buf, 16, 1); - length -= 16; + left -= 16; } - if (length) - FWrite(fdesc->fcb->handle, buf, length, 1); + if (left) + FWrite(fdesc->fcb->handle, buf, left, 1); Flush(fdesc->fcb->handle); - Seek(fdesc->fcb->handle, oldpos, OFFSET_BEGINNING); } + /* Restore the original position */ + if (oldpos != -1) + __dos64_seek(fdesc->fcb, oldpos, OFFSET_BEGINNING); + return 0; } diff --git a/compiler/posixc/getfsstat.c b/compiler/posixc/getfsstat.c index f561ce5f4b..44c7c37b74 100644 --- a/compiler/posixc/getfsstat.c +++ b/compiler/posixc/getfsstat.c @@ -9,6 +9,8 @@ #include #include #include + +#include "__dos64.h" #include #include #include "__upath.h" @@ -75,7 +77,7 @@ short getnixfilesystemtype(LONG id_DiskType) STRPTR name; BPTR lock; struct DosList *dlist; - struct InfoData data; + struct InfoData64 data; int fscount = 0; /* number of filesystems */ LONG ioerr = 0; @@ -112,7 +114,7 @@ short getnixfilesystemtype(LONG id_DiskType) /* Get filesystem data from lock */ if((lock = Lock(name, SHARED_LOCK))) { - if(Info(lock, &data)) + if(__dos64_info(lock, &data)) { /* Fill statfs structure */ buf[fscount - 1].f_type = getnixfilesystemtype( @@ -120,11 +122,11 @@ short getnixfilesystemtype(LONG id_DiskType) buf[fscount - 1].f_flags = 0; buf[fscount - 1].f_fsize = data.id_BytesPerBlock; buf[fscount - 1].f_bsize = data.id_BytesPerBlock; - buf[fscount - 1].f_blocks = data.id_NumBlocks; - buf[fscount - 1].f_bfree = data.id_NumBlocks - - data.id_NumBlocksUsed; - buf[fscount - 1].f_bavail = data.id_NumBlocks - - data.id_NumBlocksUsed; + buf[fscount - 1].f_blocks = data.id_NumBlocks64; + buf[fscount - 1].f_bfree = data.id_NumBlocks64 - + data.id_NumBlocksUsed64; + buf[fscount - 1].f_bavail = data.id_NumBlocks64 - + data.id_NumBlocksUsed64; buf[fscount - 1].f_files = 0; buf[fscount - 1].f_ffree = 0; buf[fscount - 1].f_fsid.val[0] = 0; diff --git a/compiler/posixc/lseek.c b/compiler/posixc/lseek.c index a6771ad3c5..0c6534cd6d 100644 --- a/compiler/posixc/lseek.c +++ b/compiler/posixc/lseek.c @@ -11,6 +11,7 @@ #include #include #include "__fdesc.h" +#include "__dos64.h" /***************************************************************************** @@ -61,7 +62,7 @@ ******************************************************************************/ { - int cnt; + QUAD cnt; fdesc *fdesc = __getfdesc(filedes); if (!fdesc) @@ -89,7 +90,7 @@ return -1; } - cnt = Seek (fdesc->fcb->handle, offset, whence); + cnt = __dos64_seek (fdesc->fcb, offset, whence); if (cnt == -1) { @@ -102,40 +103,45 @@ is written there. Since implementing it would be rather difficult, we simply extend the file by writing zeros and hope for the best. */ - LONG abs_cur_pos = Seek(fdesc->fcb->handle, 0, OFFSET_CURRENT); + QUAD abs_cur_pos = __dos64_getpos(fdesc->fcb); if(abs_cur_pos == -1) goto error; - LONG file_size = Seek(fdesc->fcb->handle, 0, OFFSET_END); + QUAD file_size = __dos64_getsize(fdesc->fcb); if(file_size == -1) goto error; /* Now compute how much we have to extend the file */ - LONG abs_new_pos = 0; + QUAD abs_new_pos = 0; switch(whence) { case OFFSET_BEGINNING: abs_new_pos = offset; break; case OFFSET_CURRENT: abs_new_pos = abs_cur_pos + offset; break; case OFFSET_END: abs_new_pos = file_size + offset; break; } - if(abs_new_pos > abs_cur_pos) + if(abs_new_pos > file_size) { ULONG bufsize = 4096; APTR zeros = AllocMem(bufsize, MEMF_ANY | MEMF_CLEAR); if(!zeros) { /* Restore previous position */ - Seek(fdesc->fcb->handle, abs_cur_pos, OFFSET_BEGINNING); + __dos64_seek(fdesc->fcb, abs_cur_pos, OFFSET_BEGINNING); errno = ENOMEM; return -1; } - - LONG towrite = abs_new_pos - abs_cur_pos; + + if(__dos64_seek(fdesc->fcb, 0, OFFSET_END) == -1) + { + FreeMem(zeros, bufsize); + goto error; + } + QUAD towrite = abs_new_pos - file_size; do { Write(fdesc->fcb->handle, zeros, MIN(towrite, bufsize)); towrite -= bufsize; } while(towrite > 0); - + FreeMem(zeros, bufsize); } else @@ -150,8 +156,21 @@ goto error; } - return Seek(fdesc->fcb->handle, 0, OFFSET_CURRENT); + cnt = __dos64_getpos(fdesc->fcb); + if (cnt == -1) + goto error; + if (cnt != (QUAD)(off_t)cnt) + { + errno = EOVERFLOW; + return (off_t) -1; + } + + return (off_t) cnt; error: - errno = __stdc_ioerr2errno (IoErr ()); + { + LONG ioerr = IoErr (); + errno = (ioerr == ERROR_OBJECT_TOO_LARGE) + ? EOVERFLOW : __stdc_ioerr2errno (ioerr); + } return (off_t) -1; } /* __posixc_lseek */ diff --git a/compiler/posixc/lseek64.c b/compiler/posixc/lseek64.c index cd67b0c12e..de44af377a 100644 --- a/compiler/posixc/lseek64.c +++ b/compiler/posixc/lseek64.c @@ -11,6 +11,7 @@ #include #include #include "__fdesc.h" +#include "__dos64.h" /***************************************************************************** @@ -61,7 +62,7 @@ ******************************************************************************/ { - int cnt; + QUAD cnt; fdesc *fdesc = __getfdesc(filedes); if (!fdesc) @@ -89,7 +90,7 @@ return -1; } - cnt = Seek (fdesc->fcb->handle, offset, whence); + cnt = __dos64_seek (fdesc->fcb, offset, whence); if (cnt == -1) { @@ -102,40 +103,45 @@ is written there. Since implementing it would be rather difficult, we simply extend the file by writing zeros and hope for the best. */ - LONG abs_cur_pos = Seek(fdesc->fcb->handle, 0, OFFSET_CURRENT); + QUAD abs_cur_pos = __dos64_getpos(fdesc->fcb); if(abs_cur_pos == -1) goto error; - LONG file_size = Seek(fdesc->fcb->handle, 0, OFFSET_END); + QUAD file_size = __dos64_getsize(fdesc->fcb); if(file_size == -1) goto error; /* Now compute how much we have to extend the file */ - LONG abs_new_pos = 0; + QUAD abs_new_pos = 0; switch(whence) { case OFFSET_BEGINNING: abs_new_pos = offset; break; case OFFSET_CURRENT: abs_new_pos = abs_cur_pos + offset; break; case OFFSET_END: abs_new_pos = file_size + offset; break; } - if(abs_new_pos > abs_cur_pos) + if(abs_new_pos > file_size) { ULONG bufsize = 4096; APTR zeros = AllocMem(bufsize, MEMF_ANY | MEMF_CLEAR); if(!zeros) { /* Restore previous position */ - Seek(fdesc->fcb->handle, abs_cur_pos, OFFSET_BEGINNING); + __dos64_seek(fdesc->fcb, abs_cur_pos, OFFSET_BEGINNING); errno = ENOMEM; return -1; } - - LONG towrite = abs_new_pos - abs_cur_pos; + + if(__dos64_seek(fdesc->fcb, 0, OFFSET_END) == -1) + { + FreeMem(zeros, bufsize); + goto error; + } + QUAD towrite = abs_new_pos - file_size; do { Write(fdesc->fcb->handle, zeros, MIN(towrite, bufsize)); towrite -= bufsize; } while(towrite > 0); - + FreeMem(zeros, bufsize); } else @@ -150,8 +156,21 @@ goto error; } - return Seek(fdesc->fcb->handle, 0, OFFSET_CURRENT); + cnt = __dos64_getpos(fdesc->fcb); + if (cnt == -1) + goto error; + if (cnt != (QUAD)(__off64_t)cnt) + { + errno = EOVERFLOW; + return (__off64_t) -1; + } + + return (__off64_t) cnt; error: - errno = __stdc_ioerr2errno (IoErr ()); - return (off_t) -1; + { + LONG ioerr = IoErr (); + errno = (ioerr == ERROR_OBJECT_TOO_LARGE) + ? EOVERFLOW : __stdc_ioerr2errno (ioerr); + } + return (__off64_t) -1; } /* lseek64 */ diff --git a/compiler/posixc/mmakefile.src b/compiler/posixc/mmakefile.src index b1d30e2eab..57187349e1 100644 --- a/compiler/posixc/mmakefile.src +++ b/compiler/posixc/mmakefile.src @@ -3,12 +3,14 @@ include $(SRCDIR)/config/aros.cfg #MM- AROS : compiler-posixc POSIXC := \ + __dos64 \ __env \ __exec \ __fdesc \ __fopen \ __fseeko \ __ftello \ + __optionallibs \ __posixc_assert \ __posixc_environ \ __posixc_init \ diff --git a/compiler/posixc/read.c b/compiler/posixc/read.c index 53547441b9..36903902ea 100644 --- a/compiler/posixc/read.c +++ b/compiler/posixc/read.c @@ -11,6 +11,7 @@ #include #include #include "__fdesc.h" +#include "__dos64.h" /***************************************************************************** @@ -64,7 +65,7 @@ return -1; } - cnt = Read (fdesc->fcb->handle, buf, count); + cnt = __dos64_read (fdesc->fcb, buf, count); if (cnt == -1) errno = __stdc_ioerr2errno (IoErr ()); diff --git a/compiler/posixc/statfs.c b/compiler/posixc/statfs.c index 532b1c4125..be99c4aff5 100644 --- a/compiler/posixc/statfs.c +++ b/compiler/posixc/statfs.c @@ -8,6 +8,8 @@ #include #include #include + +#include "__dos64.h" #include #include "__upath.h" @@ -51,7 +53,7 @@ short getnixfilesystemtype(LONG id_DiskType); { BPTR lock; LONG ioerr = 0; - struct InfoData data; + struct InfoData64 data; const char *apath; if (path == NULL) @@ -70,16 +72,16 @@ short getnixfilesystemtype(LONG id_DiskType); /* Get filesystem data from lock */ if(((lock = Lock(apath, SHARED_LOCK)))) { - if(Info(lock, &data)) + if(__dos64_info(lock, &data)) { /* Fill statfs structure */ buf->f_type = getnixfilesystemtype(data.id_DiskType); buf->f_flags = 0; buf->f_fsize = data.id_BytesPerBlock; buf->f_bsize = data.id_BytesPerBlock; - buf->f_blocks = data.id_NumBlocks; - buf->f_bfree = data.id_NumBlocks - data.id_NumBlocksUsed; - buf->f_bavail = data.id_NumBlocks - data.id_NumBlocksUsed; + buf->f_blocks = data.id_NumBlocks64; + buf->f_bfree = data.id_NumBlocks64 - data.id_NumBlocksUsed64; + buf->f_bavail = data.id_NumBlocks64 - data.id_NumBlocksUsed64; buf->f_files = 0; buf->f_ffree = 0; buf->f_fsid.val[0] = 0; diff --git a/compiler/posixc/write.c b/compiler/posixc/write.c index 94c28ac389..c8cff053cf 100644 --- a/compiler/posixc/write.c +++ b/compiler/posixc/write.c @@ -11,6 +11,7 @@ #include #include #include "__fdesc.h" +#include "__dos64.h" /***************************************************************************** @@ -56,7 +57,7 @@ return -1; } - cnt = Write (fdesc->fcb->handle, (void *)buf, count); + cnt = __dos64_write (fdesc->fcb, (void *)buf, count); if (cnt == -1) errno = __stdc_ioerr2errno (IoErr ()); diff --git a/compiler/stdc/__stdcio_dos64.c b/compiler/stdc/__stdcio_dos64.c new file mode 100644 index 0000000000..666fee4a4c --- /dev/null +++ b/compiler/stdc/__stdcio_dos64.c @@ -0,0 +1,85 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Internal 64-bit seek helpers for stdcio.library: use dos64.library + when it is available, otherwise fall back to the 32-bit + dos.library calls. Positions the fallback cannot express fail with + IoErr() == ERROR_OBJECT_TOO_LARGE. +*/ + +#include + +#include +#include + +#include "__stdcio_intbase.h" +#include "__stdio.h" +#include "__stdcio_dos64.h" + +#include + +static struct Library *__stdcio_dos64base(void) +{ + struct StdCIOIntBase *StdCIOBase = + (struct StdCIOIntBase *)__aros_getbase_StdCIOBase(); + + if (StdCIOBase->StdCIODOS64Base == NULL) + StdCIOBase->StdCIODOS64Base = OpenLibrary("dos64.library", 50); + + return StdCIOBase->StdCIODOS64Base; +} + +/* Detect 64-bit filesystem support once per stream and cache it */ +void __stdcio_probe64(FILE *stream) +{ + struct Library *DOS64Base = __stdcio_dos64base(); + + if (DOS64Base != NULL && stream->fh != BNULL + && IsFileSystem64(stream->fh)) + stream->flags |= __STDCIO_STDIO_FS64; +} + +static struct Library *__stdcio_dos64base_for(FILE *stream) +{ + if (!(stream->flags & __STDCIO_STDIO_FS64)) + return NULL; + + return __stdcio_dos64base(); +} + +QUAD __stdcio_seek64(FILE *stream, QUAD position, LONG mode) +{ + struct Library *DOS64Base = __stdcio_dos64base_for(stream); + + if (DOS64Base != NULL) + return Seek64(stream->fh, mode, position); + + if (position != (QUAD)(LONG)position) + { + SetIoErr(ERROR_OBJECT_TOO_LARGE); + return -1; + } + return Seek(stream->fh, (LONG)position, mode); +} + +QUAD __stdcio_getpos64(FILE *stream) +{ + struct Library *DOS64Base = __stdcio_dos64base_for(stream); + + if (DOS64Base != NULL) + return GetFilePosition64(stream->fh); + + return Seek(stream->fh, 0, OFFSET_CURRENT); +} + +static int __close_stdcio_dos64(struct StdCIOIntBase *StdCIOBase) +{ + if (StdCIOBase->StdCIODOS64Base != NULL) + { + CloseLibrary(StdCIOBase->StdCIODOS64Base); + StdCIOBase->StdCIODOS64Base = NULL; + } + return 1; +} + +ADD2CLOSELIB(__close_stdcio_dos64, 0) diff --git a/compiler/stdc/__stdcio_dos64.h b/compiler/stdc/__stdcio_dos64.h new file mode 100644 index 0000000000..26caa2e1a0 --- /dev/null +++ b/compiler/stdc/__stdcio_dos64.h @@ -0,0 +1,24 @@ +#ifndef ___STDCIO_DOS64_H +#define ___STDCIO_DOS64_H + +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + Internal 64-bit seek helpers for stdcio.library (dos64.library when + available, 32-bit dos.library fallback otherwise). +*/ + +#include +#include + +#include + +/* Detect 64-bit filesystem support for a freshly opened stream and + cache it in the stream flags (__STDCIO_STDIO_FS64); the helpers + below then pick the 64-bit or 32-bit path directly. */ +void __stdcio_probe64(FILE *stream); + +QUAD __stdcio_seek64(FILE *stream, QUAD position, LONG mode); +QUAD __stdcio_getpos64(FILE *stream); + +#endif /* ___STDCIO_DOS64_H */ diff --git a/compiler/stdc/__stdcio_intbase.h b/compiler/stdc/__stdcio_intbase.h index 9e66af0e19..356a92b1f6 100644 --- a/compiler/stdc/__stdcio_intbase.h +++ b/compiler/stdc/__stdcio_intbase.h @@ -18,6 +18,9 @@ struct StdCIOIntBase { struct StdCIOBase StdCIOBase; + /* __stdcio_dos64.c: optional dos64.library, for 64-bit file I/O */ + struct Library *StdCIODOS64Base; + /* getenv.c */ LONG varsize; char *envvar; diff --git a/compiler/stdc/__stdio.h b/compiler/stdc/__stdio.h index 3f5fa29f50..8e5c0e1549 100644 --- a/compiler/stdc/__stdio.h +++ b/compiler/stdc/__stdio.h @@ -28,6 +28,7 @@ struct __sFILE #define __STDCIO_STDIO_DONTCLOSE 0x0040L #define __STDCIO_STDIO_DONTFREE 0x0080L #define __STDCIO_STDIO_FLUSHONREAD 0x0100L +#define __STDCIO_STDIO_FS64 0x0200L /* Filesystem handles 64-bit packets */ #define __STDCIO_STDIO_RDWR __STDCIO_STDIO_WRITE | __STDCIO_STDIO_READ #endif /* ___STDIO_H */ diff --git a/compiler/stdc/fopen.c b/compiler/stdc/fopen.c index f71da1c972..ea6b3da528 100644 --- a/compiler/stdc/fopen.c +++ b/compiler/stdc/fopen.c @@ -12,6 +12,7 @@ #include #include "__stdio.h" +#include "__stdcio_dos64.h" #include "__stdcio_intbase.h" /***************************************************************************** @@ -125,6 +126,9 @@ if (!file->fh) goto error; + /* Detect 64-bit filesystem support once, and cache it */ + __stdcio_probe64(file); + if (file->flags & __STDCIO_STDIO_APPEND) { if (Seek(file->fh, 0, OFFSET_END) < 0) diff --git a/compiler/stdc/fseek.c b/compiler/stdc/fseek.c index 7357e1616c..6da0cc8416 100644 --- a/compiler/stdc/fseek.c +++ b/compiler/stdc/fseek.c @@ -9,6 +9,7 @@ #include #include "__stdio.h" +#include "__stdcio_dos64.h" #define DEBUG 0 #include @@ -61,7 +62,6 @@ ******************************************************************************/ { LONG mode; - BPTR fh = stream->fh; D(bug("[stdcio/fseek()] Entering stream=0x%x, offset=%d, whence=%d\n", stream, offset, whence @@ -86,11 +86,13 @@ return -1; } - if (Seek(fh, offset, mode) < 0) + if (__stdcio_seek64(stream, (QUAD)offset, mode) < 0) { D(bug("[stdcio/fseek()] Failed (IoErr()=%d)\n", IoErr())); if (IoErr() == ERROR_UNKNOWN) errno = EINVAL; + else if (IoErr() == ERROR_OBJECT_TOO_LARGE) + errno = EOVERFLOW; else errno = __stdc_ioerr2errno(IoErr()); return -1; diff --git a/compiler/stdc/ftell.c b/compiler/stdc/ftell.c index f13cc700f3..e687d67fcc 100644 --- a/compiler/stdc/ftell.c +++ b/compiler/stdc/ftell.c @@ -9,6 +9,7 @@ #include #include "__stdio.h" +#include "__stdcio_dos64.h" #define DEBUG 0 #include @@ -46,18 +47,23 @@ ******************************************************************************/ { - LONG cnt; + QUAD cnt; BPTR fh = stream->fh; D(bug("[stdcio/ftell()] Entering\n")); Flush (fh); - cnt = Seek (fh, 0, OFFSET_CURRENT); + cnt = __stdcio_getpos64 (stream); if (cnt == -1) errno = __stdc_ioerr2errno (IoErr ()); + else if (cnt != (QUAD)(long)cnt) + { + errno = EOVERFLOW; + cnt = -1; + } - D(bug("[stdcio/ftell()] Leaving cnt=%d\n", cnt)); + D(bug("[stdcio/ftell()] Leaving cnt=%ld\n", (long)cnt)); return (long int)cnt; } /* ftell */ diff --git a/compiler/stdc/include/aros/stdc/errno.h b/compiler/stdc/include/aros/stdc/errno.h index 485c00219a..8f72646eae 100644 --- a/compiler/stdc/include/aros/stdc/errno.h +++ b/compiler/stdc/include/aros/stdc/errno.h @@ -57,6 +57,7 @@ /* Codes used for error conversion of DOS error codes */ #define EACCES 13 /* Permission denied */ +#define EOVERFLOW 84 /* Value too large to be stored in data type */ #define ENOTBLK 15 /* Not a Block device */ #define EBUSY 16 /* Device busy */ #define EEXIST 17 /* File exists */ diff --git a/compiler/stdc/mmakefile.src b/compiler/stdc/mmakefile.src index cce9336161..e4c908265d 100644 --- a/compiler/stdc/mmakefile.src +++ b/compiler/stdc/mmakefile.src @@ -469,6 +469,7 @@ STDC_COMMON := \ STDCIO := \ __stdcio_assert \ + __stdcio_dos64 \ __stdcio_init \ __stdio \ clearerr \ From 9cf65e8304a555807cf5273302006a41204d8c64 Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 11/12] List: show the full size of files above 4G A size that fills 32 bits is asked again with ExamineName64 when dos64.library is installed, also for a file that is open for writing, which cannot be locked. The size is no longer sign extended, and the total of blocks is printed as 32 bits. --- workbench/c/List.c | 54 ++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/workbench/c/List.c b/workbench/c/List.c index c88885f3bf..5a222d6085 100644 --- a/workbench/c/List.c +++ b/workbench/c/List.c @@ -139,7 +139,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -545,6 +547,27 @@ int printLformat(STRPTR format, struct lfstruct *lf) } +/* dos64.library, NULL when it is not installed */ +struct Library *DOS64Base; + +/* The size of a file whose 32 bit size was clamped */ +static UQUAD fileSize64(CONST_STRPTR name, UQUAD size) +{ + if (DOS64Base != NULL) + { + struct FileInfoBlock *fib = AllocDosObject64(DOS64_FIB, NULL); + + if (fib != NULL) + { + if (ExamineName64(name, fib, NULL)) + size = fib->fib_Size64; + FreeDosObject64(DOS64_FIB, fib); + } + } + + return size; +} + int printFileData(struct AnchorPath *ap, BOOL showFiles, BOOL showDirs, STRPTR parsedPattern, ULONG *files, ULONG *dirs, ULONG *nBlocks, STRPTR lFormat, @@ -557,7 +580,7 @@ int printFileData(struct AnchorPath *ap, BOOL isDir = (ap->ap_Info.fib_DirEntryType >= 0); struct DateStamp *ds = &ap->ap_Info.fib_Date; ULONG protection = ap->ap_Info.fib_Protection; - UQUAD size = ap->ap_Info.fib_Size; + UQUAD size = (ULONG)ap->ap_Info.fib_Size; STRPTR filenote = ap->ap_Info.fib_Comment; ULONG diskKey = ap->ap_Info.fib_DiskKey; @@ -569,23 +592,9 @@ int printFileData(struct AnchorPath *ap, struct DateTime dt; -#if defined(ACTION_GET_FILE_SIZE64) - if (ap->ap_Info.fib_Size >= 0x7FFFFFFF) - { - BPTR flock = BNULL; - flock = Lock(filename, ACCESS_READ); - - if (flock) - { - UQUAD *size_ptr = (UQUAD *)DoPkt(((struct FileLock *)flock)->fl_Task, ACTION_GET_FILE_SIZE64, (IPTR)flock, 0, 0, 0, 0); - if (size_ptr) - { - size = *size_ptr; - } - UnLock(flock); - } - } -#endif + /* A size that fills 32 bits may be clamped: ask for the full one */ + if (!isDir && size >= 0x7FFFFFFF) + size = fileSize64(filename, size); /* Do the file match the time interval we are looking for? (ARG_SINCE and ARG_UPTO) -- any combination of these may be specified */ @@ -997,6 +1006,8 @@ int main(void) Statistics stats = { 0, 0, 0 }; + DOS64Base = OpenLibrary("dos64.library", 51); + rda = ReadArgs(ARG_TEMPLATE, args, NULL); if (rda != NULL) @@ -1186,7 +1197,7 @@ int main(void) (stats.nFiles || stats.nDirs)) { Printf("\nTOTAL: %ld files - %ld directories - %ld blocks used\n", - stats.nFiles, stats.nDirs, stats.nBlocks); + stats.nFiles, stats.nDirs, (ULONG)stats.nBlocks); } @@ -1218,5 +1229,10 @@ int main(void) Close(SelectOutput(oldOutput)); } + if (DOS64Base != NULL) + { + CloseLibrary(DOS64Base); + } + return result; } From e8db6c9dd7df40b34a8f710921ec9eb8e58e27aa Mon Sep 17 00:00:00 2001 From: Jaroslav Pulchart Date: Thu, 5 Nov 2026 19:27:11 +0100 Subject: [PATCH 12/12] GUI: show sizes above 4G in requesters, Wanderer and Info ASL, reqtools, MUI Dirlist, find, the Wanderer icon list, status bar, copy and the Info tool read the 32 bit size as unsigned and keep sizes and totals in 64 bits. A file whose 32 bit size is 4G-1 is asked again with ExamineName64 when dos64.library is installed, also when it is open for writing. Sorting by size is unsigned and the volume percentage of the reqtools requester no longer overflows. --- workbench/libs/asl/asl_init.c | 18 +++ workbench/libs/asl/asl_intern.h | 2 +- workbench/libs/asl/basicfuncs.c | 36 ++++-- workbench/libs/asl/filereqsupport.c | 34 +++++- workbench/libs/asl/layout.h | 2 +- workbench/libs/muimaster/classes/dirlist.c | 108 +++++++++++++++++- .../libs/muimaster/classes/dirlist_private.h | 5 +- workbench/libs/reqtools/filereq.h | 3 + workbench/libs/reqtools/filereqextra.c | 60 +++++++++- workbench/libs/reqtools/filereqmain.c | 40 ++++++- workbench/libs/reqtools/globalvars.h | 1 + workbench/libs/reqtools/rtfuncs.c | 5 + workbench/system/Wanderer/Classes/iconlist.c | 80 ++++++++++--- workbench/system/Wanderer/Classes/iconlist.h | 1 + workbench/system/Wanderer/Tools/Info/main.c | 77 ++++++++++--- workbench/system/Wanderer/filesystems.c | 38 ++++-- workbench/system/Wanderer/filesystems.h | 6 +- workbench/system/Wanderer/main.c | 8 ++ workbench/system/Wanderer/panel_statusbar.c | 26 ++--- workbench/system/find/findgroup_class.c | 47 +++++++- workbench/system/find/main.c | 7 ++ 21 files changed, 518 insertions(+), 86 deletions(-) diff --git a/workbench/libs/asl/asl_init.c b/workbench/libs/asl/asl_init.c index 0a7239b91b..4afe433d8e 100644 --- a/workbench/libs/asl/asl_init.c +++ b/workbench/libs/asl/asl_init.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "asl_intern.h" #include LC_LIBDEFS_FILE @@ -165,6 +166,9 @@ const struct IntFontReq def_fontreq = }; +/* dos64.library, NULL when it is not installed */ +struct Library *DOS64Base; + /* coolimages may fail to open */ LONG CoolImagesBase_version = -1; @@ -184,12 +188,26 @@ static int InitBase(LIBBASETYPEPTR LIBBASE) InitReqInfo(LIBBASE); + DOS64Base = OpenLibrary("dos64.library", 51); + + return TRUE; +} + +static int ExpungeBase(LIBBASETYPEPTR LIBBASE) +{ + if (DOS64Base != NULL) + { + CloseLibrary(DOS64Base); + DOS64Base = NULL; + } + return TRUE; } /*****************************************************************************************/ ADD2INITLIB(InitBase, 0); +ADD2EXPUNGELIB(ExpungeBase, 0); /*****************************************************************************************/ diff --git a/workbench/libs/asl/asl_intern.h b/workbench/libs/asl/asl_intern.h index 155e1c8752..385a7ab0b6 100644 --- a/workbench/libs/asl/asl_intern.h +++ b/workbench/libs/asl/asl_intern.h @@ -318,7 +318,7 @@ char *PooledCloneStringLen(const char *name1, ULONG len1, const char *name2, ULO char *VecCloneString(const char *name1, const char *name2, struct AslBase_intern *AslBase); char *VecPooledCloneString(const char *name1, const char *name2, APTR pool, struct AslBase_intern *AslBase); -char *PooledUIntegerToString(IPTR value, APTR pool, struct AslBase_intern *AslBase); +char *PooledUIntegerToString(UQUAD value, APTR pool, struct AslBase_intern *AslBase); void CloseWindowSafely(struct Window *window, struct AslBase_intern *AslBase); AROS_UFP3(ULONG, StringEditFunc, diff --git a/workbench/libs/asl/basicfuncs.c b/workbench/libs/asl/basicfuncs.c index f5b2aee4a5..6fc847a58f 100644 --- a/workbench/libs/asl/basicfuncs.c +++ b/workbench/libs/asl/basicfuncs.c @@ -1042,25 +1042,41 @@ AROS_UFH2 (void, puttostr, /*****************************************************************************************/ -/* This is used for printing out fib_Size, which is why - * is takes a IPTR instead of a ULONG - */ -char *PooledUIntegerToString(IPTR value, APTR pool, struct AslBase_intern *AslBase) +/* Decimal string of a 64 bit value, cloned into the pool */ +char *PooledUIntegerToString(UQUAD value, APTR pool, struct AslBase_intern *AslBase) { - char buffer[30]; - char *str = buffer; + char buffer[24]; + char *str = buffer + sizeof(buffer) - 1; char *clone; WORD len; - /* Create the text */ + *str = '\0'; + + /* 32 bit division while the value fits, 64 bit only above 4 GiB */ + if ((ULONG)(value >> 32) == 0) + { + ULONG lo = (ULONG)value; - RawDoFmt("%iu", (RAWARG)&value, (VOID_FUNC)AROS_ASMSYMNAME(puttostr), &str); + do + { + *--str = '0' + (char)(lo % 10); + lo /= 10; + } while (lo); + } + else + { + do + { + *--str = '0' + (char)(value % 10); + value /= 10; + } while (value); + } - len = strlen(buffer) + 1; + len = strlen(str) + 1; if ((clone = AllocPooled(pool, len))) { - CopyMem(buffer, clone, len); + CopyMem(str, clone, len); } return clone; diff --git a/workbench/libs/asl/filereqsupport.c b/workbench/libs/asl/filereqsupport.c index 16965809e1..d291c53c83 100644 --- a/workbench/libs/asl/filereqsupport.c +++ b/workbench/libs/asl/filereqsupport.c @@ -9,11 +9,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -41,6 +43,29 @@ static WORD FRCompareDirectoryNodes(struct IntFileReq *ifreq, struct ASLLVFileRe struct ASLLVFileReqNode *node2, struct AslBase_intern *AslBase); +/*****************************************************************************************/ + +/* The real size of a file whose 32 bit size was clamped, name is relative to dirlock */ +static UQUAD FRFileSize64(BPTR dirlock, CONST_STRPTR name, UQUAD size) +{ + if (DOS64Base != NULL) + { + struct FileInfoBlock *fib64 = AllocDosObject64(DOS64_FIB, NULL); + + if (fib64 != NULL) + { + BPTR oldcd = CurrentDir(dirlock); + + if (ExamineName64(name, fib64, NULL)) + size = fib64->fib_Size64; + CurrentDir(oldcd); + FreeDosObject64(DOS64_FIB, fib64); + } + } + + return size; +} + /*****************************************************************************************/ static void fixpath(char *pathstring) @@ -517,6 +542,11 @@ BOOL FRGetDirectory(STRPTR path, struct LayoutData *ld, struct AslBase_intern *A struct DateTime dt; char datebuffer[LEN_DATSTRING]; char timebuffer[LEN_DATSTRING]; + UQUAD size = (ULONG)fib->fib_Size; + + /* a clamped size of a file: ask dos64.library for the real one */ + if (fib->fib_DirEntryType <= 0 && size == 0xFFFFFFFF) + size = FRFileSize64(lock, fib->fib_FileName, size); if (fib->fib_FileName[0]) { @@ -531,7 +561,7 @@ BOOL FRGetDirectory(STRPTR path, struct LayoutData *ld, struct AslBase_intern *A node->text[1] = GetString(MSG_FILEREQ_LV_DRAWER, GetIR(ifreq)->ir_Catalog, AslBase); node->dontfreetext |= (1 << 1); } else { - node->text[1] = PooledUIntegerToString(fib->fib_Size, + node->text[1] = PooledUIntegerToString(size, ld->ld_IntReq->ir_MemPool, AslBase); @@ -561,7 +591,7 @@ BOOL FRGetDirectory(STRPTR path, struct LayoutData *ld, struct AslBase_intern *A node->userdata = ld; node->date = fib->fib_Date; - node->filesize = fib->fib_Size; + node->filesize = size; node->type = ASLLV_FRNTYPE_DIRECTORY; node->subtype = fib->fib_DirEntryType; diff --git a/workbench/libs/asl/layout.h b/workbench/libs/asl/layout.h index 4fec74933c..70928238a7 100644 --- a/workbench/libs/asl/layout.h +++ b/workbench/libs/asl/layout.h @@ -194,7 +194,7 @@ struct ASLLVFileReqNode char *text[ASLLV_MAXCOLUMNS]; struct DateStamp date; APTR userdata; - ULONG filesize; + UQUAD filesize; LONG type; LONG subtype; UWORD dontfreetext; diff --git a/workbench/libs/muimaster/classes/dirlist.c b/workbench/libs/muimaster/classes/dirlist.c index 5af61c4658..3d9b0b6348 100644 --- a/workbench/libs/muimaster/classes/dirlist.c +++ b/workbench/libs/muimaster/classes/dirlist.c @@ -8,13 +8,17 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include + #include #include @@ -27,6 +31,90 @@ extern struct Library *MUIMasterBase; +/* dos64.library, NULL when it is not installed */ +struct Library *DOS64Base; + +static int Dirlist_OpenDOS64(void) +{ + DOS64Base = OpenLibrary("dos64.library", 51); + + return TRUE; +} + +static void Dirlist_CloseDOS64(void) +{ + if (DOS64Base != NULL) + CloseLibrary(DOS64Base); + DOS64Base = NULL; +} + +ADD2INIT(Dirlist_OpenDOS64, 0); +ADD2EXIT(Dirlist_CloseDOS64, 0); + +/* Decimal string of a UQUAD, end-aligned in the buffer */ +static UBYTE *UQUAD2string(UQUAD value, UBYTE *buffer, int buflen) +{ + UWORD w[4]; + BOOL more; + + /* long division by 10 on 16 bit words, no 64 bit divide (libgcc) */ + w[0] = (UWORD)(value >> 48); + w[1] = (UWORD)(value >> 32); + w[2] = (UWORD)(value >> 16); + w[3] = (UWORD)value; + + buffer[--buflen] = '\0'; + + do + { + ULONG rem = 0; + int i; + + more = FALSE; + for (i = 0; i < 4; i++) + { + ULONG cur = (rem << 16) | w[i]; + + w[i] = (UWORD)(cur / 10); + rem = cur % 10; + if (w[i] != 0) + more = TRUE; + } + buffer[--buflen] = '0' + (UBYTE)rem; + } while (more); + + return buffer + buflen; +} + +/* The saturated NumBytes attribute value */ +static IPTR NumBytesAttr(UQUAD numbytes) +{ + return (numbytes > (IPTR)-1) ? (IPTR)-1 : (IPTR)numbytes; +} + +/* The size of a file; a clamped 32 bit size is asked again from dos64 */ +static UQUAD FileSize(BPTR dirlock, struct FileInfoBlock *fib) +{ + UQUAD size = (ULONG)fib->fib_Size; + + if (size == 0xFFFFFFFF && DOS64Base != NULL) + { + struct FileInfoBlock *fib64 = AllocDosObject64(DOS64_FIB, NULL); + + if (fib64 != NULL) + { + BPTR olddir = CurrentDir(dirlock); + + if (ExamineName64(fib->fib_FileName, fib64, NULL)) + size = fib64->fib_Size64; + CurrentDir(olddir); + FreeDosObject64(DOS64_FIB, fib64); + } + } + + return size; +} + AROS_UFH3S(APTR, construct_func, AROS_UFHA(struct Hook *, hook, A0), AROS_UFHA(APTR, pool, A2), @@ -79,9 +167,8 @@ AROS_UFH3S(LONG, display_func, } else { - snprintf(data->size_string, sizeof(data->size_string), "%ld", - (long)entry->fib.fib_Size); - *array++ = data->size_string; + *array++ = UQUAD2string(entry->size, data->size_string, + sizeof(data->size_string)); } dt.dat_Stamp = entry->fib.fib_Date; @@ -178,6 +265,8 @@ static void ReadDirectory(Object *obj, struct Dirlist_DATA *data) struct FileInfoBlock *fib; BPTR lock; + data->numbytes = 0; + if ((fib = AllocDosObject(DOS_FIB, NULL))) { if ((lock = Lock(data->directory, SHARED_LOCK))) @@ -222,6 +311,8 @@ static void ReadDirectory(Object *obj, struct Dirlist_DATA *data) } else { + struct Dirlist_Entry entry; + if (isdir && data->filesonly) continue; if (!isdir && data->drawersonly) @@ -256,6 +347,9 @@ static void ReadDirectory(Object *obj, struct Dirlist_DATA *data) } } + entry.fib = *fib; + entry.size = 0; + if (isdir) { set(obj, MUIA_Dirlist_NumDrawers, @@ -263,13 +357,15 @@ static void ReadDirectory(Object *obj, struct Dirlist_DATA *data) } else { + entry.size = FileSize(lock, fib); + data->numbytes += entry.size; set(obj, MUIA_Dirlist_NumFiles, ++data->numfiles); set(obj, MUIA_Dirlist_NumBytes, - data->numbytes + fib->fib_Size); + NumBytesAttr(data->numbytes)); } - DoMethod(obj, MUIM_List_InsertSingle, (IPTR) fib, + DoMethod(obj, MUIM_List_InsertSingle, (IPTR) &entry, MUIV_List_Insert_Bottom); } /* no filterhook */ @@ -418,7 +514,7 @@ IPTR Dirlist__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg) return 1; case MUIA_Dirlist_NumBytes: - STORE = data->numbytes; + STORE = NumBytesAttr(data->numbytes); return 1; case MUIA_Dirlist_NumFiles: diff --git a/workbench/libs/muimaster/classes/dirlist_private.h b/workbench/libs/muimaster/classes/dirlist_private.h index 05c700c91c..1502953224 100644 --- a/workbench/libs/muimaster/classes/dirlist_private.h +++ b/workbench/libs/muimaster/classes/dirlist_private.h @@ -14,7 +14,7 @@ struct Dirlist_DATA STRPTR acceptpattern; STRPTR rejectpattern; STRPTR directory; - IPTR numbytes; + UQUAD numbytes; ULONG numdrawers; ULONG numfiles; BOOL drawersonly; @@ -26,7 +26,7 @@ struct Dirlist_DATA BYTE sortdirs; BYTE sorttype; BYTE status; - UBYTE size_string[20]; + UBYTE size_string[24]; UBYTE date_string[20]; UBYTE time_string[20]; UBYTE prot_string[8]; @@ -36,6 +36,7 @@ struct Dirlist_DATA struct Dirlist_Entry { struct FileInfoBlock fib; + UQUAD size; }; #endif /* _DIRLIST_PRIVATE_H_ */ diff --git a/workbench/libs/reqtools/filereq.h b/workbench/libs/reqtools/filereq.h index 5e7d9a4ba1..717e42d830 100644 --- a/workbench/libs/reqtools/filereq.h +++ b/workbench/libs/reqtools/filereq.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -133,6 +135,7 @@ struct ReqEntry { struct Node re_Node; LONG re_Size; + ULONG re_SizeHi; /* upper 32 bits of a file size */ UBYTE re_Flags, re_Style; UBYTE re_SizeLenPix, diff --git a/workbench/libs/reqtools/filereqextra.c b/workbench/libs/reqtools/filereqextra.c index ed1db19825..aed1be0a0b 100644 --- a/workbench/libs/reqtools/filereqextra.c +++ b/workbench/libs/reqtools/filereqextra.c @@ -167,12 +167,42 @@ static void REGARGS Ghost (struct RastPort *rp, UWORD pen, UWORD x, UWORD y, UWO /****************************************************************************************/ +/* Decimal string of a 64 bit value, end aligned in buf */ +static char *UQuadToStr (UQUAD value, char *buf, int buflen) +{ + buf[--buflen] = '\0'; + + /* 32 bit division while the value fits, 64 bit only above 4 GiB */ + if ((ULONG)(value >> 32) == 0) + { + ULONG lo = (ULONG)value; + + do + { + buf[--buflen] = '0' + (char)(lo % 10); + lo /= 10; + } while (lo); + } + else + { + do + { + buf[--buflen] = '0' + (char)(value % 10); + value /= 10; + } while (value); + } + + return (buf + buflen); +} + +/****************************************************************************************/ + void REGARGS PrintEntry (GlobData *glob, int i) { struct TextExtent extent; struct ReqEntry *entry; struct RastPort *reqrp = glob->reqrp; - char sizestr[16], tempstr[108], *volname = NULL, *str; + char sizestr[24], tempstr[108], *volname = NULL, *str; int apen = 0, bpen = 0, top, len = 0, sizelen = 0, sizelenpix = 0, type, rectpen, left, entrytop; LONG size; @@ -198,7 +228,17 @@ void REGARGS PrintEntry (GlobData *glob, int i) /* FIXME: AROS LocaleLibrary does not yet patch RawDoFmt. So "%lD" (uppercase D) does not work yet here! */ useLocFmt = FALSE; #endif - DofmtArgs (sizestr, useLocFmt ? " %lD" : " %ld", size); + if (type == glob->file_id) + { + /* RawDoFmt cannot print 64 bit */ + char numstr[24]; + + sizestr[0] = ' '; + strcpy (sizestr + 1, UQuadToStr (((UQUAD)entry->re_SizeHi << 32) | (ULONG)size, + numstr, sizeof (numstr))); + } + else + DofmtArgs (sizestr, useLocFmt ? " %lD" : " %ld", size); if (type == FONT) { @@ -442,6 +482,7 @@ struct ReqEntry *REGARGS AddEntry (GlobData *glob, struct BufferData *buff, if( ctype <= MAX_FILE_DIRECTORY ) { lastname->re_Size = size; + lastname->re_SizeHi = 0; return( lastname ); } @@ -461,6 +502,7 @@ struct ReqEntry *REGARGS AddEntry (GlobData *glob, struct BufferData *buff, newentry->re_Name = str; newentry->re_Size = size; + newentry->re_SizeHi = 0; newentry->re_Type = ctype; newentry->re_Next = lastname->re_Next; lastname->re_Next = ( struct Node * ) newentry; @@ -785,9 +827,17 @@ AddDisk( if( deventry->task && DoPkt1( deventry->task, ACTION_DISK_INFO, (SIPTR)MKBADDR( infodata ) ) ) { - size = ( infodata->id_NumBlocksUsed * 100 + - infodata->id_NumBlocks / 2 ) / - infodata->id_NumBlocks; + ULONG used = infodata->id_NumBlocksUsed; + ULONG total = infodata->id_NumBlocks; + + /* scale down so that used * 100 fits 32 bits */ + while( total > 40000000 ) + { + used >>= 1; + total >>= 1; + } + + size = ( used * 100 + total / 2 ) / total; } } diff --git a/workbench/libs/reqtools/filereqmain.c b/workbench/libs/reqtools/filereqmain.c index e36c61f698..b01da9627f 100644 --- a/workbench/libs/reqtools/filereqmain.c +++ b/workbench/libs/reqtools/filereqmain.c @@ -96,6 +96,33 @@ ExpandLink( GlobData *glob ) /****************************************************************************************/ +/* The real size of the current fib file, size is the clamped 32 bit one */ +static UQUAD FileSize64( GlobData *glob, UQUAD size ) +{ + if( DOS64Base != NULL ) + { + struct FileInfoBlock *fib64 = AllocDosObject64( DOS64_FIB, NULL ); + + *glob->winaddr = ( APTR ) -1; + + if( fib64 ) + { + BPTR oldcd = CurrentDir( glob->lock ); + + if( ExamineName64( glob->fib.fib_FileName, fib64, NULL ) ) + size = fib64->fib_Size64; + CurrentDir( oldcd ); + FreeDosObject64( DOS64_FIB, fib64 ); + } + + *glob->winaddr = glob->reqwin; + } + + return( size ); +} + +/****************************************************************************************/ + IPTR ASM SAVEDS PropReqHandler ( REGPARAM(a1, struct RealHandlerInfo *, glob), REGPARAM(d0, ULONG, sigs), @@ -506,14 +533,15 @@ IPTR ASM SAVEDS PropReqHandler ( { if ((glob->exnext = ExNext (glob->lock, &glob->fib))) { - ULONG size = glob->fib.fib_Size; + UQUAD size = ( ULONG ) glob->fib.fib_Size; + struct ReqEntry *newentry; ctype = glob->fib.fib_EntryType; /* Try to examine links */ if( ( glob->fib.fib_EntryType == ST_SOFTLINK ) && ExpandLink( glob ) ) { - size = glob->linkfib.fib_Size; + size = ( ULONG ) glob->linkfib.fib_Size; ctype = glob->linkfib.fib_EntryType; } @@ -541,7 +569,13 @@ IPTR ASM SAVEDS PropReqHandler ( ctype = ( ctype > 0 ) ? glob->directory_id : glob->file_id; - if( !AddEntry( glob, buff, glob->fib.fib_FileName, size, ctype ) ) + /* a clamped size of a file: ask dos64.library for the real one */ + if( ctype == glob->file_id && size == 0xFFFFFFFF ) + size = FileSize64( glob, size ); + + if( ( newentry = AddEntry( glob, buff, glob->fib.fib_FileName, ( ULONG ) size, ctype ) ) ) + newentry->re_SizeHi = ( ULONG )( size >> 32 ); + else glob->exnext = FALSE; skipfile: diff --git a/workbench/libs/reqtools/globalvars.h b/workbench/libs/reqtools/globalvars.h index de56958b50..0635100521 100644 --- a/workbench/libs/reqtools/globalvars.h +++ b/workbench/libs/reqtools/globalvars.h @@ -5,6 +5,7 @@ extern struct ReqToolsBase *ReqToolsBase; extern struct Device *ConsoleDevice; extern struct IOStdReq iorequest; extern Class *ButtonImgClass; +extern struct Library *DOS64Base; /* NULL when not installed */ /* On AROS don't define the libbases because that will prevent autoinit */ #if !defined(__RT_DEFINEVARS) || !defined(__AROS__) diff --git a/workbench/libs/reqtools/rtfuncs.c b/workbench/libs/reqtools/rtfuncs.c index 6598683d8d..c15c792b21 100644 --- a/workbench/libs/reqtools/rtfuncs.c +++ b/workbench/libs/reqtools/rtfuncs.c @@ -205,6 +205,10 @@ SAVEDS ASM struct ReqToolsBase *RTFuncs_Open(REGPARAM(a6, struct ReqToolsBase *, if(LocaleBase == NULL) return NULL; + /* optional */ + if(DOS64Base == NULL) + DOS64Base = OpenLibrary("dos64.library", 51); + D(bug("reqtools.library: Inside libopen func. Libraries opened successfully.\n")); if (ConsoleDevice == NULL) @@ -308,6 +312,7 @@ SAVEDS ASM BPTR RTFuncs_Expunge(REGPARAM(a6, struct ReqToolsBase *, RTBase)) CloseLibrary((struct Library *)LocaleBase); CloseLibrary(GadToolsBase); CloseLibrary(LayersBase); + if (DOS64Base) CloseLibrary(DOS64Base); D(bug("reqtools.library: Inside libexpunge func. Freeing libbase.\n")); diff --git a/workbench/system/Wanderer/Classes/iconlist.c b/workbench/system/Wanderer/Classes/iconlist.c index b4a933c034..451f2aec45 100644 --- a/workbench/system/Wanderer/Classes/iconlist.c +++ b/workbench/system/Wanderer/Classes/iconlist.c @@ -58,6 +58,9 @@ #include #include #include +#include +#include +#include #include #if defined(__AROS__) @@ -110,6 +113,9 @@ extern struct Library *MUIMasterBase; +/* dos64.library, NULL when it is not installed */ +struct Library *DOS64Base; + static struct Hook __iconlist_UpdateLabels_hook; // N.B: We Handle frame/background rendering so make sure icon.library doesnt do it .. @@ -348,8 +354,48 @@ const UBYTE MSG_MEM_M[] = "MB"; const UBYTE MSG_MEM_K[] = "KB"; const UBYTE MSG_MEM_B[] = "Bytes"; +///IconList__FileSize64() +/* The size of a file whose 32 bit size was clamped */ +static UQUAD IconList__FileSize64(CONST_STRPTR name, UQUAD size) +{ + if (DOS64Base != NULL) + { + struct FileInfoBlock *fib64 = AllocDosObject64(DOS64_FIB, NULL); + + if (fib64 != NULL) + { + if (ExamineName64(name, fib64, NULL)) + size = fib64->fib_Size64; + FreeDosObject64(DOS64_FIB, fib64); + } + } + + return size; +} + +/* Open and close the optional dos64.library with the class */ +static int IconList__OpenDOS64(struct Library *lh) +{ + DOS64Base = OpenLibrary("dos64.library", 51); + return TRUE; +} + +static int IconList__CloseDOS64(struct Library *lh) +{ + if (DOS64Base != NULL) + { + CloseLibrary(DOS64Base); + DOS64Base = NULL; + } + return TRUE; +} + +ADD2INITLIB(IconList__OpenDOS64, 0) +ADD2EXPUNGELIB(IconList__CloseDOS64, 0) +/// + ///FmtSizeToString() -static void FmtSizeToString(UBYTE *buf, ULONG num) +static void FmtSizeToString(UBYTE *buf, UQUAD num) { UQUAD d; const UBYTE *ch; @@ -359,38 +405,38 @@ static void FmtSizeToString(UBYTE *buf, ULONG num) ULONG dec; } array = { - num, + (ULONG)num, 0 }; if (num >= 1073741824) { //Gigabytes - array.val = num >> 30; - d = ((UQUAD)num * 10 + 536870912) / 1073741824; - array.dec = d % 10; + array.val = (ULONG)(num >> 30); + d = (num * 10 + 536870912) / 1073741824; + array.dec = (ULONG)(d % 10); ch = MSG_MEM_G; } else if (num >= 1048576) { //Megabytes - array.val = num >> 20; - d = ((UQUAD)num * 10 + 524288) / 1048576; - array.dec = d % 10; + array.val = (ULONG)(num >> 20); + d = (num * 10 + 524288) / 1048576; + array.dec = (ULONG)(d % 10); ch = MSG_MEM_M; } else if (num >= 1024) { //Kilobytes - array.val = num >> 10; + array.val = (ULONG)(num >> 10); d = (num * 10 + 512) / 1024; - array.dec = d % 10; + array.dec = (ULONG)(d % 10); ch = MSG_MEM_K; } else { //Bytes - array.val = num; + array.val = (ULONG)num; array.dec = 0; d = 0; ch = MSG_MEM_B; @@ -4421,13 +4467,18 @@ IPTR IconList__MUIM_IconList_CreateEntry(struct IClass *CLASS, Object *obj, stru { CopyMem(message->fib, entry->ie_FileInfoBlock, sizeof(struct FileInfoBlock)); + entry->ie_FileSize64 = (ULONG)entry->ie_FileInfoBlock->fib_Size; + if (entry->ie_FileInfoBlock->fib_DirEntryType > 0) { strcpy(entry->ie_TxtBuf_SIZE, "Drawer"); } else { - FmtSizeToString(entry->ie_TxtBuf_SIZE, entry->ie_FileInfoBlock->fib_Size); + /* 0xFFFFFFFF is the clamp, ask dos64 for the real size */ + if (entry->ie_FileSize64 == 0xFFFFFFFF) + entry->ie_FileSize64 = IconList__FileSize64(message->filename, entry->ie_FileSize64); + FmtSizeToString(entry->ie_TxtBuf_SIZE, entry->ie_FileSize64); } dt.dat_Stamp = entry->ie_FileInfoBlock->fib_Date; @@ -7509,7 +7560,10 @@ IPTR IconList__MUIM_IconList_Sort(struct IClass *CLASS, Object *obj, struct MUIP else if (data->icld_SortFlags & MUIV_IconList_Sort_BySize) { /* Sort by Size .. */ - i = entry->ie_FileInfoBlock->fib_Size - icon1->ie_FileInfoBlock->fib_Size; + if (entry->ie_FileSize64 > icon1->ie_FileSize64) + i = 1; + else if (entry->ie_FileSize64 < icon1->ie_FileSize64) + i = -1; } else if ((data->icld_SortFlags & MUIV_IconList_Sort_ByType) && ((entry->ie_IconListEntry.type == ST_FILE) || (entry->ie_IconListEntry.type == ST_USERDIR))) { diff --git a/workbench/system/Wanderer/Classes/iconlist.h b/workbench/system/Wanderer/Classes/iconlist.h index 5da4059135..9e7573c113 100644 --- a/workbench/system/Wanderer/Classes/iconlist.h +++ b/workbench/system/Wanderer/Classes/iconlist.h @@ -106,6 +106,7 @@ struct IconEntry struct DiskObject *ie_DiskObj; /* The icons disk objects */ struct FileInfoBlock *ie_FileInfoBlock; + UQUAD ie_FileSize64; /* Full file size, FIB size is clamped to 32 bits */ LONG ie_IconX, /* Top Left Co-ords of Icons "AREA" */ ie_IconY, diff --git a/workbench/system/Wanderer/Tools/Info/main.c b/workbench/system/Wanderer/Tools/Info/main.c index 3fea56e450..a83b85aeb8 100644 --- a/workbench/system/Wanderer/Tools/Info/main.c +++ b/workbench/system/Wanderer/Tools/Info/main.c @@ -13,11 +13,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -85,6 +87,47 @@ BOOL file_altered = FALSE; BOOL icon_altered = FALSE; char loadedcomment[MAXCOMMENTLENGTH]; +/* dos64.library, NULL when it is not installed */ +struct Library *DOS64Base; + +/* The size of a file whose 32 bit size was clamped */ +static UQUAD fileSize64(CONST_STRPTR name, UQUAD size) +{ + if (DOS64Base != NULL) + { + struct FileInfoBlock *fib = AllocDosObject64(DOS64_FIB, NULL); + + if (fib != NULL) + { + if (ExamineName64(name, fib, NULL)) + size = fib->fib_Size64; + FreeDosObject64(DOS64_FIB, fib); + } + } + + return size; +} + +/* The size of a directory entry, the real one when the 32 bit size was clamped */ +static UQUAD entrySize64(CONST_STRPTR directory, CONST_STRPTR name, UQUAD size) +{ + if ((size == 0xFFFFFFFF) && (DOS64Base != NULL)) + { + ULONG pathlen = strlen(directory) + strlen(name) + 2; + STRPTR path = AllocVec(pathlen, MEMF_CLEAR); + + if (path != NULL) + { + strcpy(path, directory); + AddPart(path, name, pathlen); + size = fileSize64(path, size); + FreeVec(path); + } + } + + return size; +} + void getReadableSize(UBYTE *buf, UQUAD size, BOOL accurate) { UQUAD d; @@ -99,31 +142,23 @@ void getReadableSize(UBYTE *buf, UQUAD size, BOOL accurate) 0 }; - /*if (size >= (1024 * 1024 * 1024 * 1024 * 1024 * 1024)) - { - //Exabytes - array.val = size >> 60; - d = (size * 10 + ((1024 * 1024 * 1024 * 1024 * 1024 * 1024) / 2)) / (1024 * 1024 * 1024 * 1024 * 1024 * 1024); - array.dec = d % 10; - ch = "EiB"; - } - else if (size >= (1024 * 1024 * 1024 * 1024 * 1024)) + if (size >= ((UQUAD)1 << 50)) { //Petabytes array.val = size >> 50; - d = (size * 10 + ((1024 * 1024 * 1024 * 1024 * 1024) / 2)) / (1024 * 1024 * 1024 * 1024 * 1024); + d = (size * 10 + (((UQUAD)1 << 50) / 2)) / ((UQUAD)1 << 50); array.dec = d % 10; ch = "PiB"; } - else if (size >= (1024 * 1024 * 1024 * 1024)) + else if (size >= ((UQUAD)1 << 40)) { //Terabytes array.val = size >> 40; - d = (size * 10 + ((1024 * 1024 * 1024 * 1024) / 2)) / (1024 * 1024 * 1024 * 1024); + d = (size * 10 + (((UQUAD)1 << 40) / 2)) / ((UQUAD)1 << 40); array.dec = d % 10; ch = "TiB"; - }*/ - if (size >= (1024 * 1024 * 1024)) + } + else if (size >= (1024 * 1024 * 1024)) { //Gigabytes array.val = size >> 30; @@ -215,7 +250,7 @@ D(bug("[WBInfo] calculateDirectorySize('%s')\n", directory)); { if (ead->ed_Type == ST_FILE) { - directorySize += ead->ed_Size; + directorySize += entrySize64(directory, (CONST_STRPTR)ead->ed_Name, ead->ed_Size); /* Refresh size only every 25% grow */ if ((((base + directorySize) * 100) / (*lastrefreshsize)) > 125) /* 25 % */ { @@ -720,6 +755,7 @@ int main(int argc, char **argv) char stack[16]; char deftool[MAX_PATH_LEN]; char size[64]; + UQUAD fsize; char date[LEN_DATSTRING]; char time[LEN_DATSTRING]; char dow[LEN_DATSTRING]; @@ -743,7 +779,9 @@ int main(int argc, char **argv) char pathname[1024]; int retval = RETURN_OK; - + + DOS64Base = OpenLibrary("dos64.library", 51); + if (argc != 0) { /* start from wanderer only */ @@ -844,7 +882,10 @@ D(bug("[WBInfo] scan file\n")); sprintf(datetime, "%s %s", time, date); /* fill size */ - getReadableSize(size, ap->ap_Info.fib_Size, TRUE); + fsize = (ULONG)ap->ap_Info.fib_Size; + if (fsize == 0xFFFFFFFF) + fsize = fileSize64(name, fsize); + getReadableSize(size, fsize, TRUE); /* fill protection */ protection = ap->ap_Info.fib_Protection; @@ -1453,5 +1494,7 @@ D(bug("[WBInfo: Couldn't create app\n")); FreeVec(ap); FreeVec(file); FreeVec(name); + if (DOS64Base != NULL) + CloseLibrary(DOS64Base); return retval; } diff --git a/workbench/system/Wanderer/filesystems.c b/workbench/system/Wanderer/filesystems.c index b161b2bfbe..f106e9eecf 100644 --- a/workbench/system/Wanderer/filesystems.c +++ b/workbench/system/Wanderer/filesystems.c @@ -402,6 +402,28 @@ static BOOL deleteFile(char *file) } /// +///fileSize64() +/* The size of a file, the real one when the 32 bit size was clamped */ +static UQUAD fileSize64(CONST_STRPTR name, ULONG size) +{ + UQUAD full = size; + + if ((size == 0xFFFFFFFF) && (DOS64Base != NULL)) + { + struct FileInfoBlock *fib64 = AllocDosObject64(DOS64_FIB, NULL); + + if (fib64 != NULL) + { + if (ExamineName64(name, fib64, NULL)) + full = fib64->fib_Size64; + FreeDosObject64(DOS64_FIB, fib64); + } + } + + return full; +} +/// + ///copyFile() static BOOL copyFile(APTR pool, char *file, char *destpath, struct FileInfoBlock *fileinfo, struct Hook *displayHook, @@ -411,7 +433,7 @@ static BOOL copyFile(APTR pool, char *file, char *destpath, char *to; LONG clen, wlen; LONG bufferlen = COPYLEN; - LONG filelen = 0; + UQUAD filelen = 0; BOOL quit = TRUE; BPTR in, out; BYTE *buffer; @@ -421,8 +443,8 @@ static BOOL copyFile(APTR pool, char *file, char *destpath, if (display != NULL) display->actlen = 0; if (fileinfo) { - filelen = fileinfo->fib_Size; - if (fileinfo->fib_Size <= COPYLEN) bufferlen = fileinfo->fib_Size; + filelen = fileSize64(file, (ULONG) fileinfo->fib_Size); + if (filelen <= COPYLEN) bufferlen = (LONG) filelen; if (bufferlen < 8192) bufferlen = 8192; fib = fileinfo; } @@ -440,8 +462,8 @@ static BOOL copyFile(APTR pool, char *file, char *destpath, return TRUE; } UnLock(nLock); - filelen = fib->fib_Size; - if (fib->fib_Size <= COPYLEN) bufferlen = fib->fib_Size; + filelen = fileSize64(file, (ULONG) fib->fib_Size); + if (filelen <= COPYLEN) bufferlen = (LONG) filelen; if (bufferlen < 8192) bufferlen = 8192; } } @@ -643,7 +665,7 @@ static BOOL actionDir(APTR pool, ULONG flags, char *source, char *dest, askDisplay.spath = FIB->fib_FileName; askDisplay.file = NULL; askDisplay.type = 0; - askDisplay.filelen = FIB->fib_Size; + askDisplay.filelen = (ULONG) FIB->fib_Size; if (dmode != OPMODE_ALL) dmode = CallHook(opModes->askhook, (Object *) &askDisplay, NULL); if ((dmode == OPMODE_ALL) || (dmode == OPMODE_YES)) { @@ -709,7 +731,7 @@ static BOOL actionDir(APTR pool, ULONG flags, char *source, char *dest, if (dHook) { display.file = FIB->fib_FileName; - display.filelen = FIB->fib_Size; + display.filelen = fileSize64(FIB->fib_FileName, (ULONG) FIB->fib_Size); display.spath = source; display.dpath = dest; display.flags = (flags &= ~ACTION_UPDATE); @@ -788,7 +810,7 @@ static BOOL actionDir(APTR pool, ULONG flags, char *source, char *dest, askDisplay.spath = source; askDisplay.file = FIB->fib_FileName; askDisplay.type = 0; - askDisplay.filelen = FIB->fib_Size; + askDisplay.filelen = (ULONG) FIB->fib_Size; if (dmode != OPMODE_ALL) dmode = CallHook(opModes->askhook, (Object *) &askDisplay, NULL); if ((dmode == OPMODE_ALL) || (dmode == OPMODE_YES)) { diff --git a/workbench/system/Wanderer/filesystems.h b/workbench/system/Wanderer/filesystems.h index f221636c59..a18695ed5f 100644 --- a/workbench/system/Wanderer/filesystems.h +++ b/workbench/system/Wanderer/filesystems.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include #if defined(__AMIGA__) && !defined(__PPC__) #define NO_INLINE_STDARG #endif @@ -74,9 +76,9 @@ struct dCopyStruct char *file; APTR userdata; ULONG flags; - ULONG filelen; + UQUAD filelen; ULONG actlen; - ULONG totallen; + UQUAD totallen; UWORD type; unsigned int difftime; }; diff --git a/workbench/system/Wanderer/main.c b/workbench/system/Wanderer/main.c index 8cd8dd27a4..7b62008f68 100644 --- a/workbench/system/Wanderer/main.c +++ b/workbench/system/Wanderer/main.c @@ -88,6 +88,9 @@ struct CyberGfxIFace *ICyberGfx; Object *_WandererIntern_AppObj = NULL; Class *_WandererIntern_CLASS = NULL; +/* dos64.library, NULL when it is not installed */ +struct Library *DOS64Base = NULL; + /* Don't output errors to the console, open requesters instead */ int __forceerrorrequester = 1; @@ -412,6 +415,8 @@ int main(void) return retval; #endif + DOS64Base = OpenLibrary("dos64.library", 51); + D( struct Task *me = (struct Task *)FindTask(NULL); @@ -435,6 +440,9 @@ int main(void) D(bug("[Wanderer] %s: Exiting .. \n", __PRETTY_FUNCTION__)); + if (DOS64Base != NULL) + CloseLibrary(DOS64Base); + #ifndef __AROS__ deInitLibs(); #endif diff --git a/workbench/system/Wanderer/panel_statusbar.c b/workbench/system/Wanderer/panel_statusbar.c index 97e4052245..fc799aebb8 100644 --- a/workbench/system/Wanderer/panel_statusbar.c +++ b/workbench/system/Wanderer/panel_statusbar.c @@ -103,7 +103,7 @@ const UBYTE MSG_MEM_K[] = "KB"; const UBYTE MSG_MEM_B[] = "Bytes"; ///FmtSizeToString() -static void FmtSizeToString(UBYTE *buf, ULONG num) +static void FmtSizeToString(UBYTE *buf, UQUAD num) { UQUAD d; const UBYTE *ch; @@ -113,38 +113,38 @@ static void FmtSizeToString(UBYTE *buf, ULONG num) ULONG dec; } array = { - num, + (ULONG)num, 0 }; if (num >= 1073741824) { //Gigabytes - array.val = num >> 30; - d = ((UQUAD)num * 10 + 536870912) / 1073741824; - array.dec = d % 10; + array.val = (ULONG)(num >> 30); + d = (num * 10 + 536870912) / 1073741824; + array.dec = (ULONG)(d % 10); ch = MSG_MEM_G; } else if (num >= 1048576) { //Megabytes - array.val = num >> 20; - d = ((UQUAD)num * 10 + 524288) / 1048576; - array.dec = d % 10; + array.val = (ULONG)(num >> 20); + d = (num * 10 + 524288) / 1048576; + array.dec = (ULONG)(d % 10); ch = MSG_MEM_M; } else if (num >= 1024) { //Kilobytes - array.val = num >> 10; + array.val = (ULONG)(num >> 10); d = (num * 10 + 512) / 1024; - array.dec = d % 10; + array.dec = (ULONG)(d % 10); ch = MSG_MEM_K; } else { //Bytes - array.val = num; + array.val = (ULONG)num; array.dec = 0; d = 0; ch = MSG_MEM_B; @@ -204,7 +204,7 @@ HOOKPROTO(panelStatusBar__HookFunc_UpdateStatusFunc, void, APTR *obj, APTR param UBYTE size_str[256]; int files = 0, dirs = 0, hidden = 0; - ULONG size = 0; + UQUAD size = 0; GET(data->iwd_IconListObj, MUIA_Family_List, &iconList); if (iconList) @@ -222,7 +222,7 @@ HOOKPROTO(panelStatusBar__HookFunc_UpdateStatusFunc, void, APTR *obj, APTR param files += 1; if (icon->ie_FileInfoBlock) { - size += icon->ie_FileInfoBlock->fib_Size; + size += icon->ie_FileSize64; D(bug("[IW.statusbar] %s: '%s' FIB Size = %d bytes\n", __PRETTY_FUNCTION__, icon->ie_IconNode.ln_Name, icon->ie_FileInfoBlock->fib_Size)); } } diff --git a/workbench/system/find/findgroup_class.c b/workbench/system/find/findgroup_class.c index 8e50684d91..1d10241ca0 100644 --- a/workbench/system/find/findgroup_class.c +++ b/workbench/system/find/findgroup_class.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -19,6 +20,8 @@ #include #include +#include + #include #include "findgroup_class.h" @@ -46,6 +49,7 @@ struct Listentry STRPTR fullname; ULONG namebuflen; struct FileInfoBlock fib; + UQUAD size; }; static struct Hook list_display_hook, list_constr_hook, list_destr_hook, list_compare_hook; @@ -53,6 +57,40 @@ static struct Hook list_display_hook, list_constr_hook, list_destr_hook, list_co // ======================================================================================= +// Decimal string of a UQUAD, end-aligned in the buffer +static TEXT *UQUAD2string(UQUAD value, TEXT *buffer, int buflen) +{ + buffer[--buflen] = '\0'; + + do + { + buffer[--buflen] = '0' + (value % 10); + value /= 10; + } while (value); + + return buffer + buflen; +} + +// The size of a file; a clamped 32 bit size is asked again from dos64 +static UQUAD file_size(CONST_STRPTR name, struct FileInfoBlock *fib) +{ + UQUAD size = (ULONG)fib->fib_Size; + + if (size == 0xFFFFFFFF && DOS64Base != NULL) + { + struct FileInfoBlock *fib64 = AllocDosObject64(DOS64_FIB, NULL); + + if (fib64 != NULL) + { + if (ExamineName64(name, fib64, NULL)) + size = fib64->fib_Size64; + FreeDosObject64(DOS64_FIB, fib64); + } + } + + return size; +} + static void display_doserror(Object *app, ULONG error) { TEXT buffer[255]; @@ -170,6 +208,7 @@ AROS_UFH3(APTR, list_constr_func, CopyMem(li->fullname, newentry->fullname, buflen); } newentry->fib = li->fib; + newentry->size = li->size; } return newentry; @@ -202,9 +241,10 @@ AROS_UFH3S(LONG, list_display_func, if (li) { - static TEXT protbuf[8], sizebuf[20]; + static TEXT protbuf[8], sizebuf[24]; static TEXT datebuf[20], timebuf[20]; struct DateTime dt; + TEXT *sizestr; // Protection bits protbuf[0] = li->fib.fib_Protection & FIBF_SCRIPT ? 's' : '-'; @@ -219,7 +259,7 @@ AROS_UFH3S(LONG, list_display_func, protbuf[7] = '\0'; // Size - snprintf(sizebuf, sizeof sizebuf, "%lu", (long unsigned int)li->fib.fib_Size); + sizestr = UQUAD2string(li->size, sizebuf, sizeof sizebuf); // Date datebuf[0] = '\0'; @@ -233,7 +273,7 @@ AROS_UFH3S(LONG, list_display_func, DateToStr(&dt); *array++ = li->fullname; - *array++ = sizebuf; + *array++ = sizestr; *array++ = protbuf; *array++ = datebuf; *array++ = timebuf; @@ -723,6 +763,7 @@ IPTR FindGroup__MUIM_Process_Process(Class *CLASS, Object *self, struct MUIP_Pro { entry->fullname = StrDup(anchorpath->ap_Buf); CopyMem(&anchorpath->ap_Info, &entry->fib, sizeof (entry->fib)); + entry->size = file_size(anchorpath->ap_Buf, &entry->fib); // we must use PushMethod because we are in a sub process methodid2 = DoMethod(_app(self), MUIM_Application_PushMethod, diff --git a/workbench/system/find/main.c b/workbench/system/find/main.c index 22da5b85f6..2d3d1d122f 100644 --- a/workbench/system/find/main.c +++ b/workbench/system/find/main.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -37,12 +38,17 @@ static struct DiskObject *dobj; static struct RDArgs *rda; static IPTR args[ARG_COUNT]; +// dos64.library, NULL when it is not installed +struct Library *DOS64Base; + int main(int argc, char **argv) { STRPTR path = NULL; STRPTR pattern = NULL; STRPTR contents = NULL; + DOS64Base = OpenLibrary("dos64.library", 51); + dobj = GetDiskObject("PROGDIR:Find"); if (argc) // started from CLI @@ -115,5 +121,6 @@ static void cleanup_exit(CONST_STRPTR str) if (dobj) FreeDiskObject(dobj); if (rda) FreeArgs(rda); + if (DOS64Base) CloseLibrary(DOS64Base); exit(0); }