diff --git a/arch/m68k-all/include/gencall.c b/arch/m68k-all/include/gencall.c index 50cb01549c2..5319a3f80f4 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" diff --git a/arch/m68k-amiga/boot/mmakefile.src b/arch/m68k-amiga/boot/mmakefile.src index 82f84577cc3..a141ef59894 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 diff --git a/compiler/include/dos/dos.h b/compiler/include/dos/dos.h index 9fbb80fe511..cbbe3359372 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/dos64.h b/compiler/include/dos/dos64.h new file mode 100644 index 00000000000..14fcf55dec8 --- /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/compiler/include/dos/dosextens.h b/compiler/include/dos/dosextens.h index 1367158e34e..e806f503bc3 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 a12c1b5f70c..10b4398f6f1 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 1099988fe42..a918417d267 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/compiler/posixc/__dos64.c b/compiler/posixc/__dos64.c new file mode 100644 index 00000000000..95ac5d8e7dd --- /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 00000000000..ab077f5cf3d --- /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 35d004671b8..cae61fae795 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 1681b7175f1..50056194ad8 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 23b751bc219..d82261727b6 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 00000000000..b30eda95538 --- /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 00000000000..39ebe45797c --- /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 5a264c2690f..b4ff10bc661 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 1d5678a611d..04d60c0cda3 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 53e3471faf1..4c921e91093 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 df822336cd3..768681a144f 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 76956391741..5f8c4f0dd10 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 415fcf1c72a..375a7c8292d 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 5018936f21c..0f1c9f4f59f 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 f561ce5f4b8..44c7c37b740 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 a6771ad3c50..0c6534cd6d2 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 cd67b0c12e2..de44af377ab 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 b1d30e2eabd..57187349e13 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 53547441b93..36903902eaf 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 532b1c4125a..be99c4aff57 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 94c28ac3895..c8cff053cf0 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 00000000000..666fee4a4c2 --- /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 00000000000..26caa2e1a07 --- /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 9e66af0e19f..356a92b1f68 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 3f5fa29f50e..8e5c0e1549f 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 f71da1c9727..ea6b3da5289 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 7357e1616c9..6da0cc8416e 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 f13cc700f3b..e687d67fcc5 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 485c00219a3..8f72646eaed 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 cce93361611..e4c908265df 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 \ 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 00000000000..5e9946f79be --- /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 90e1e3906ac..430913622b0 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/dos_fhflags.h b/rom/dos/dos_fhflags.h new file mode 100644 index 00000000000..6adba9bb019 --- /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 25afd52cd26..fd29408b5a9 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&& \ diff --git a/rom/dos/exall.c b/rom/dos/exall.c index 7e0abfc5eed..7e495f019e7 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/dos/exnext.c b/rom/dos/exnext.c index 209d13529f9..9bdd14bf6e0 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/flush.c b/rom/dos/flush.c index 9d08e50f54f..40eec372580 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/fread.c b/rom/dos/fread.c index a9b457d4973..0dcc0266456 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 @@ -11,6 +15,8 @@ #define FETCHERR (-2) +static LONG direct_fetch(BPTR file, UBYTE *buffer, ULONG fetchsize, struct DosLibrary *DOSBase); + /***************************************************************************** NAME */ @@ -71,7 +77,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 +129,56 @@ 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; + + /* 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); + 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; +} + /* 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 c7770444bc3..fa87aa2e2c5 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; @@ -105,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; @@ -144,9 +174,16 @@ 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) + { + /* 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_direct(file, buffer, length, DOSBase); + } else { for (written = 0; written < length; ++written) @@ -179,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; +} diff --git a/rom/dos/matchnext.c b/rom/dos/matchnext.c index 66c5162b81d..ac9e2b18d74 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; diff --git a/rom/dos64/allocdosobject64.c b/rom/dos64/allocdosobject64.c new file mode 100644 index 00000000000..93cac1701be --- /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 00000000000..d2633c0db28 --- /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 00000000000..84923d3629f --- /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 00000000000..07e094810ac --- /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 00000000000..4df44046ebf --- /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 00000000000..88f1fc76fad --- /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 00000000000..27396fac1ae --- /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 00000000000..0a46450bba4 --- /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 00000000000..055d37f24c7 --- /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 00000000000..15ff66ed3d6 --- /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 00000000000..e1f8b5364c9 --- /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 00000000000..ea910d25ad1 --- /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 00000000000..4071463a5d3 --- /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 00000000000..cb07e26dd74 --- /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 00000000000..acda50ea94e --- /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 00000000000..6cedcc41274 --- /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 00000000000..86f93a2aa30 --- /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 00000000000..46ce5646b1e --- /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 00000000000..ad4da59d11a --- /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 00000000000..9a51742f41b --- /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 00000000000..1f55a025107 --- /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 00000000000..b0e7cc7dfe2 --- /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 00000000000..627669e8991 --- /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 00000000000..d6f2c298eea --- /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 00000000000..b1e059b5753 --- /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 00000000000..581855af6ca --- /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/filesys/afs/filehandles3.c b/rom/filesys/afs/filehandles3.c index dbe589462bd..1e1164e87ec 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 f4d5b6c489f..a1403126070 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 5b53a8187af..6f55b3e9bc8 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/rom/mmakefile.src b/rom/mmakefile.src index 73a0e82cf7c..d3796775095 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 \ diff --git a/workbench/c/List.c b/workbench/c/List.c index c88885f3bfd..5a222d6085e 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; } diff --git a/workbench/libs/asl/asl_init.c b/workbench/libs/asl/asl_init.c index 0a7239b91bd..4afe433d8e8 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 155e1c87525..385a7ab0b62 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 f5b2aee4a57..6fc847a58f4 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 16965809e1a..d291c53c839 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 4fec74933cf..70928238a75 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 5af61c46580..3d9b0b6348e 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 05c700c91c2..1502953224a 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 5e7d9a4ba16..717e42d8304 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 ed1db198257..aed1be0a0b5 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 e36c61f6981..b01da9627f5 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 de56958b50d..06351005213 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 6598683d8db..c15c792b21e 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/network/smbfs/source_code/main.c b/workbench/network/smbfs/source_code/main.c index cb7453f6d02..f882a75ebeb 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; } diff --git a/workbench/system/Wanderer/Classes/iconlist.c b/workbench/system/Wanderer/Classes/iconlist.c index b4a933c034f..451f2aec45e 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 5da4059135e..9e7573c1135 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 3fea56e4506..a83b85aeb8e 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 b161b2bfbe5..f106e9eecfb 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 f221636c590..a18695ed5f7 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 8cd8dd27a4a..7b62008f687 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 97e4052245f..fc799aebb84 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 8e50684d91d..1d10241ca0d 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 22da5b85f63..2d3d1d122fc 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); }