Commit 8dcb6880 authored by Ben Avison's avatar Ben Avison
Browse files

File handling improvements

Detail:
  * Added 64-bit file pointer API support, following the LFS spec v1.5
    (see Docs directory). Internally, now uses 64-bit file pointers
    exclusively. For now, the backend still limits you to 4GB-1 files, but
    clients of the C library won't need recompiling again to support larger
    files than this once they use the new API.
  * Fixed a large number of warnings produced in compilation, assembly and
    linking, many of them new and resulting from the improved checks in the
    latest toolchain.
  * Increased the maximum stream buffer size from 16MB to 1GB.
  * Added Hdr:SDFS and Hdr:SDIO to the list of headers used to build swis.h
    if they are present.
Admin:
  Verified that the new 64-bit file pointer buffering code works using a
  ROM build (since the toolchain makes extensive use of reading, writing
  and seeking internally).

Version 5.64. Tagged as 'RISC_OSLib-5_64'
parent 3f057115
Adding Support for Arbitrary File Sizes to the Single UNIX Specification
Last Update: 20Mar96
----------------------------------------------------------------------------
Table of Contents
Adding Support for Arbitrary File Sizes to the Single UNIX Specification
1.0 Overview
1.1 The Large File Problem
1.2 Requirements
1.3 Importance
1.4 Concepts
1.5 Changes and Additions
1.6 Conformance
2.0 Changes to the Single UNIX Specification
2.1 Changes to CAE Specification System Interface Definitions, Issue 4,
Version 2
2.2 Changes to CAE Specification System Interfaces and Headers, Issue 4,
Version 2
2.2.1 Changes to System Interfaces
2.2.2 Changes to Headers
2.3 Changes to CAE Specification Commands and Utilities, Issue 4, Version 2
3.0 Transitional Extensions to the Single UNIX Specification
3.1 Transitional Extensions to CAE Specification System Interfaces and
Headers, Issue 4, Version 2
3.1.1 Transitional Extensions to System Interfaces
3.1.2 Transitional Extensions to Headers
3.2 Transitional Extensions to the mount Utility
3.3 Accessing the Extensions to the SUS
Appendix A: Rationale and Notes
A.1 Overview
A.1.1 Guiding Principles
A.1.2 Concepts
A.2 Changes to the Single UNIX Specification
A.2.1 Changes to CAE Specification System Interfaces and Headers, Issue 4,
Version 2
A.2.1.1 Changes to System Interfaces
A.2.2 Changes to CAE Specification Commands and Utilities, Issue 4, Version
2
A.3 Transitional Extensions to the Single UNIX Specification
A.3.1 Transitional Extensions to CAE Specification System Interfaces and
Headers, Issue 4, Version 2
A.3.1.1 Transitional Extensions to System Interfaces
A.3.1.2 Transitional Extensions to Headers
A.3.2 Accessing the Transitional Extensions to the SUS
Acknowledgements
Revision Information
23Feb96 Version 1.1
24Feb96 Version 1.2
01Mar96 Version 1.3
05Mar96 Version 1.4
20Mar96 Version 1.5
----------------------------------------------------------------------------
Acknowledgements
Even with the rise of 64-bit systems, the 32-bit operating system will be
with us for a while yet. However, the need for interoperability with 64-bit
systems, large applications, large databases, and cheap disks has created a
market imperative for the UNIX industry: support large files on 32-bit
systems. Most current UNIX systems support file sizes of at most 2^31-1
bytes. This is not enough for today's applications, which include files
containing videos, sounds, images, and large databases. Today's 32-bit
systems are quite capable of handling the computational needs of these
applications, but they need to be able to support maximum file sizes that
are many orders of magnitude larger.
This support must be compatible with the existing Single UNIX Specification,
and provide a path to conformance with following versions. It must allow
system vendors a cost effective approach to adding these features to their
existing products, and provide system vendors, software vendors, and users
with a clear path for future products. The independent software vendors
(ISVs) listed below gathered in a set of meetings with the UNIX systems
vendors to develop a common set of APIs and modifications to the Single UNIX
Specification to allow support for large files. We called these meetings the
Large File Summit. For details of the meetings, how the proposals were
developed, and the ISV requirements document, see
http://www.sas.com/standards/large.file.
This work is being sent to the X/Open Base System Working Group so they can
consider the changes that are suggested for the next generation of the
Single UNIX Specification.
The individuals who participated in the Large File Summit meetings and
on-line discussions were:
Amdahl Corp.: Dennis Chapman, John Haines
Convex Computer Corp.: Mike Carl, Peter Poorman, Tom White
Cray Research, Inc.: Rick Matthews
Data General Corp.: Dean Herington
Digital Equipment Corp.: Fred Glover, Ray Lanza, Peter Smith
Fujitsu: Chris Seabrook
HAL Computer Systems, Inc.: Prashant Dholakia, Howard Gayle,
David H. Yamada
Hewlett-Packard Co.: Larry Dwyer, Hal Prince
IBM Corp.: Bill Baker, Mark Brown
MacNeal-Schwendler Corp.: David Lombard
NCR: Kevin Brasche, Shawn Shealy
NEC Systems Laboratory, Inc.: Jeff Forys
Novell: Bill Cox, John Kiger, Seth Rosenthal
NOVON Research Inc.: Brian Boyle
Oracle: Mark Johnson
Programmed Logic Corp.: Tim Williams, Steve Rago
Pyramid Technology Corporation: Ralph Campbell, Henry Robinson
SAS Institute Inc.: Mark Cates, Leigh Ihnen, Tom Truscott,
Kelly Wyatt
Sequent Computer Systems: Gerrit Huizenga, Mike Spitzer
Siemens Nixdorf Inc.: Ralf Nolting, Klaus Thon
Silicon Graphics: Steve Cobb, Adam Sweeney
Stratus Computer Inc.: Tony Luck
Sun Microsystems, Inc.: Steve Chessin
SunSoft Inc.: Karen Barnes, Don Cragun, Karl Danz, Andy Roach,
Glenn Skinner, Peter Van der Linden,
Srinivasan Viswanathan
Sybase Inc.: Marc Sugiyama
Syncsort Inc.: Asokan
Tandem Computers: David M. VomLehn
The Santa Cruz Operation, Inc.: John Farley, Kurt Gollhardt,
Art Herzog, Danielle Lahmani, Wen-Ling Lu, Dave Prosser
Unisoft: Guy Hadland
Unisys Corp.: Steve Beck, Bruce Jones, Scott Lurndal,
Jim Soddy
UTG Inc.: Michael Dortch, Mark Hatch, Larry Lytle
Veritas: Craig Harmer, Michael Schmitz
Special thanks go to SAS Institute Inc., SunSoft, Silicon Graphics, and
Convex Computer (now HP) for providing meeting rooms and logistics support.
Hal Prince and Don Cragun provided technical guidance and kept us aware of
the details. Mark Brown helped us understand how important it was to comply
with existing standards. Bill Baker and Tom White worked hard typing early
drafts and providing alternative ways to organize the document. Adam Sweeney
and Howard Gayle kept us within reason. David VomLehn and Tom Truscott kept
good notes and provided the minutes. Ray Lanza gave us rousing encouragement
("Just make everything 64 bits!!"). Mark Johnson quipped excellent
summaries. Kelly Wyatt did the final edits and provided an excellent sanity
check during the endgame. And special thanks go to Mark Hatch (now with
Integrated Computer Solutions, Inc.) who organized the first meetings and
got this effort going.
I really enjoyed participating and would like to express my gratitude to the
members of the large file summit. In particular, I enjoyed participating
with people who were so honestly motivated to make the right technical
decisions. This was a great lesson in UNIX file system semantics and how the
Open Systems Process works.
There are a couple of interesting features of this specification. First, it
contains a method of supporting an industry wide transition to full 64-bit
APIs. Second, it specifies a set of changes to the Single UNIX Specification
that will allow unlimited file offsets. The transition includes a way to add
64-bit file indexing without breaking current compliance to standards, and
allow software developers to migrate existing sources and binaries to
systems that support 64-bit file indexing.
This document is the result of a collaborative process that was open to all
participants. The efforts of those who participated will best be rewarded by
having this work accepted and used. I believe that this specification is an
example of how well the industry can work together to solve problems that
affect our ability to produce products that compete in the market.
John Carl Zeigler, jcz@utg.org
VP Technology, UTG Inc.
Cary, NC
----------------------------------------------------------------------------
1.0 Overview
1.1 The Large File Problem
As UNIX systems have become increasingly powerful, a number of system
vendors and UNIX independent software vendors have developed a requirement
to access files that contain more information than can be addressed using a
signed long integer. One possible solution could be to convert every program
using files to a larger size for long integers, including the operating
system. However, the work to do this is undesirable for many vendors. A
number of major system vendors and users have been meeting at the "Large
File Summit" (LFS) for over a year to develop a set of changes to the
existing Single UNIX Specification (SUS) that allow both new and converted
programs to address files of arbitrary sizes. This set of changes will be
provided to X/Open for inclusion into the next version of the SUS. In
addition, a set of transitional extensions intended to permit users to
immediately implement large file support on typical 32-bit UNIX operating
systems is proposed. Both the changes and transitional extensions and the
rationale behind their definition is included in this document.
1.2 Requirements
The LFS has worked to develop a solution to the large file problem meeting
the following requirements:
Be implementable at a reasonable cost
Several of the LFS members are leading efforts to develop and implement
solutions. Results from their experiences have guided our decisions.
Protect existing programs
This proposal allows for protection of existing programs. Many of the
solutions considered would have caused existing programs to fail
unexpectedly and silently. This proposal has been carefully crafted to
reduce this possibility.
Provide access to files much larger than 2 gigabytes on 32-bit operating
systems
This is the requirement that first motivated the LFS activity. The
proposed changes implement a solution that allows file size and related
sizes to be uncoupled from the size of the C language data types chosen
for an operating environment. As a result, systems conforming to the
proposed changes to the SUS can support files of arbitrary sizes.
Be fully compliant to the SUS
Systems modified to support the proposed extensions can be configured
to strictly conform to the existing SUS. These same systems will
normally be configured to fully meet the proposed changes supporting
arbitrary file sizes and remain compliant to the SUS with extensions.
In addition, conforming systems can also support a transitional API
extension designed to substantially reduce the difficulty of conversion
to this proposed standard while remaining compliant to the existing
SUS. This transitional interface is contained in section 3.0
Transitional Extensions to the Single UNIX Specification.
Provide an extension to the SUS
While the LFS would like to see this proposal included in the next
version of the SUS, this specification provides extensions that system
vendors and independent software vendors need to support this
functionality in their current compliant products.
1.3 Importance
As noted earlier, several vendors have already begun or completed
implementation because of substantial market pressures. Independent software
vendors are already writing software dependent on large file functionality.
Rapid inclusion into the SUS is necessary to avoid repeating the existing
situation where over 20 different implementations of asynchronous I/O are
available on various UNIX systems. The LFS has chosen design alternatives to
facilitate the needed rapid process of standardization. We believe the
proposed changes will substantially enhance the value of the next revision
of the SUS if they are included.
1.4 Concepts
The proposed changes are motivated by a consistent implementation of a few
very basic technical concepts.
Mixed sizes of off_t
During a period of transition from existing systems to systems able to
support an arbitrarily large file size, most systems will need to
support binaries with two or more sizes of the off_t data type (and
related data types). This mixed off_t environment may occur on a system
with an ABI that supports different sizes of off_t. It may occur on a
system which has both a 64-bit and a 32-bit ABI. Finally, it may occur
when using a distributed system where clients and servers have
differing sizes of off_t. In effect, the period of transition will not
end until we need 128-bit file sizes, requiring yet another transition!
The proposed changes may also be used as a model for the 64 to 128-bit
file size transition.
Offset maximum
Most, but unfortunately not all, of the numeric values in the SUS are
protected by opaque type definitions. In theory this allows programs to
use these types rather than the underlying C language data types to
avoid issues like overflow. However, most existing code maps these
opaque data types like off_t to long integers that can overflow for the
values needed to represent the offsets possible in large files.
To protect existing binaries from arbitrarily large files, a new value
(offset maximum) will be part of the open file description. An offset
maximum is the largest offset that can be used as a file offset.
Operations attempting to go beyond the offset maximum will return an
error. The offset maximum is normally established as the size of the
off_t "extended signed integral type" used by the program creating the
file description.
The open() function and other interfaces establish the offset maximum
for a file description, returning an error if the file size is larger
than the offset maximum at the time of the call. Returning errors when
the offset maximum is (or is likely to be) exceeded protects existing
binaries effectively.
EOVERFLOW
In a system with binaries compiled to support different sizes of off_t,
operations such as read() or write() can attempt to reach parts of a
large file beyond the range of an off_t or other limit. The existing
SUS does not define an error for this case. EOVERFLOW is an existing
error type that must be added to a number of system interfaces to
communicate the new error condition to applications.
Development models
In addition to supporting environments requiring mixed sizes of off_t,
the LFS also considered the development model. To maintain older
programs that have not been converted to support arbitrary file sizes,
it is necessary to specify the size of off_t and related data types.
Two compilation models and the means to control them are specified in
section 3.3 Accessing the Extensions to the SUS. A new set of
transitional extensions will probably be needed when the next jump to
larger file sizes occurs. The changes specified for the SUS, however,
are size neutral.
Selectable off_t
In this model, the size of off_t is specified at compile time, and
the appropriate set of libraries, headers and data types is chosen
during the compilation and linking process. All existing binaries
default to an off_t the size of a long integer.
Explicit off_t
In this model, the size of off_t is specified during application
design. The system interface specified explicitly uses an off_t of
a particular length. On a 32-bit system, for example, use of
open() implies an off_t of 32 bits and use of open64() implies an
off64_t of 64 bits. While the model is very useful for supporting
incremental conversions and writing system software, it is not
directly supported in the SUS. A proposed set of transitional
extensions is described in section 3.0 Transitional Extensions to
the Single UNIX Specification. These transitional interfaces
support only the 32-bit to 64-bit file offset transition.
1.5 Changes and Additions
The requirements and concepts defined above have been consistently and
completely applied to the SUS to generate the changes and additions
specified in sections 2.0 Changes to the Single UNIX Specification and 3.0
Transitional Extensions to the Single UNIX Specification. The changes are
classified as:
Changes to System Interface Definitions
The terms extended signed integral type, extended unsigned integral
type, offset maximum and saved resource limits have been defined.
Changes to System Interfaces and Headers
EOVERFLOW, EFBIG and EINVAL are added or updated wherever needed.
The open() and fcntl() functions have been changed to support the
offset maximum.
The fseeko() and ftello() functions have been added because the
existing fseek() and ftell() do not use the required opaque types.
Data types, declarations and symbolic constants were added to or
changed in headers.
Changes to Commands and Utilities
Utilities needed to establish a minimally complete system that can
support large files which require conversion are defined. A complete
conversion is both expensive and unnecessary for effective use of large
files.
Transitional Extensions
The proposed transitional extensions including interfaces, macros and
data types have been defined.
1.6 Conformance
A conforming implementation will supply all the interfaces that are
specified in 2.0 Changes to the Single UNIX Specification (except that
implementations need not provide the asynchronous I/O interfaces:
aio_read(), aio_write(), and lio_listio()) and will define _LFS_LARGEFILE to
be 1 (see 3.1.2.12 <unistd.h>).
A conforming implementation that provides asynchronous I/O interfaces and
the extensions to them specified in 2.0 Changes to the Single UNIX
Specification will define _LFS_ASYNCHRONOUS_IO to be 1 (see 3.1.2.12
<unistd.h>).
A conforming implementation that provides the explicit 64-bit interfaces
will provide at least those interfaces specified in 3.1.1.1.3 Other
Interfaces, 3.1.1.2 fcntl(), 3.1.1.3 open(), and 3.1.2 Transitional
Extensions to Headers (except that changes specified in 3.1.2.2 <aio.h> and
3.1.2.6 <stdio.h> need not be supported) and will define _LFS64_LARGEFILE to
be 1 (see 3.1.2.12 <unistd.h>).
A conforming implementation that defines _LFS64_LARGEFILE to be 1 and
provides the explicit 64-bit interfaces for asynchronous I/O specified in
3.1.1.1.1 Asynchronous I/O Interfaces will define _LFS64_ASYNCHRONOUS_IO to
be 1 (see 3.1.2.12 <unistd.h>).
A conforming implementation that defines _LFS64_LARGEFILE to be 1 and
provides the explicit 64-bit STDIO interfaces specified in 3.1.1.1.2 STDIO
Interfaces and 3.1.2.6 <stdio.h> will define _LFS64_STDIO to be 1 (see
3.1.2.12 <unistd.h>).
2.0 Changes to the Single UNIX Specification
2.1 Changes to CAE Specification System Interface Definitions, Issue 4,
Version 2
The following definitions will be added to System Interface Definitions,
Chapter 2, Glossary:
extended signed integral type
a signed integral type or an implementation-specific type with similar
properties.
extended unsigned integral type
an unsigned integral type or an implementation-specific type with
similar properties.
offset maximum
an attribute of an open file description representing the largest value
that can be used as a file offset.
saved resource limits
an attribute of a process that provides some flexibility in the
handling of unrepresentable resource limits, as described in the exec
family of functions and setrlimit().
(Note the attribute "resource limits" as used in the SUS is not
defined.)
2.2 Changes to CAE Specification System Interfaces and Headers, Issue 4,
Version 2
2.2.1 Changes to System Interfaces
The following changes will be made to System Interfaces and Headers, Chapter
3, System Interfaces. The Asynchronous I/O interfaces (aio_read(),
aio_write() and lio_listio()) should be included when POSIX.1b is added in a
future revision to the SUS.
2.2.1.1 aio_read()
DESCRIPTION
For regular files, no data transfer will occur past the offset
maximum established in the open file description associated with
aiocbp->aio_fildes.
ERRORS
The following is an additional condition which may be detected
synchronously or asynchronously:
[EOVERFLOW]
The file is a regular file, aiocbp->aio_nbytes is greater
than 0 and the starting offset in aiocbp->aio_offset is
before the end-of-file and is at or beyond the offset maximum
in the open file description associated with
aiocbp->aio_fildes.
Note: This is a new error condition.
2.2.1.2 aio_write()
DESCRIPTION
For regular files, no data transfer will occur past the offset
maximum established in the open file description associated with
aiocbp->aio_fildes.
ERRORS
The following is an additional condition which may be detected
synchronously or asynchronously:
[EFBIG]
The file is a regular file, aiocbp->aio_nbytes is greater
than 0 and the starting offset in aiocbp->aio_offset is at or
beyond the offset maximum in the open file description
associated with aiocbp->aio_fildes.
Note: This is an additional EFBIG error condition.
2.2.1.3 exec
DESCRIPTION
The saved resource limits in the new process image are set to be a
copy of the process's corresponding hard and soft resource limits.
2.2.1.4 fclose(), fflush(), fputwc(), fputws(), fseek(), putwc(), putwchar()
ERRORS
These functions will fail if:
[EFBIG]
The file is a regular file and an attempt was made to write
at or beyond the offset maximum associated with the
corresponding stream.
Note: This is an additional EFBIG error condition.
2.2.1.5 fcntl()
DESCRIPTION
An unlock (F_UNLCK) request in which l_len is non-zero and the
offset of the last byte of the requested segment is the maximum
value for an object of type off_t, when the process has an
existing lock in which l_len is 0 and which includes the last byte
of the requested segment, will be treated as a request to unlock
from the start of the requested segment with an l_len equal to 0.
Otherwise an unlock (F_UNLCK) request will attempt to unlock only
the requested segment.
ERRORS
The fcntl() function will fail if:
[EOVERFLOW]
One of the values to be returned cannot be represented
correctly.
[EOVERFLOW]
The cmd argument is F_GETLK, F_SETLK or F_SETLKW and the
smallest or, if l_len is non-zero, the largest, offset of any
byte in the requested segment cannot be represented correctly
in an object of type off_t.
Note: These are new error conditions.
2.2.1.6 fdopen()
DESCRIPTION
The fdopen() function will preserve the offset maximum previously
set for the open file description corresponding to fildes.
2.2.1.7 fgetc(), fgets(), fgetwc(), fgetws(), fread(), fscanf(), getc(),
getchar(), gets(), getw(), getwc(), getwchar(), scanf()
ERRORS
These functions will fail if data needs to be read and:
[EOVERFLOW]
The file is a regular file and an attempt was made to read at
or beyond the offset maximum associated with the
corresponding stream.
Note: This is a new error condition.
2.2.1.8 fgetpos()
ERRORS
The fgetpos() function will fail if:
[EOVERFLOW]
The current value of the file position cannot be represented
correctly in an object of type fpos_t.
Note: This is a new error condition.
2.2.1.9 fopen(), freopen(), tmpfile()
DESCRIPTION
The largest value that can be represented correctly in an object
of type off_t will be established as the offset maximum in the
open file description.
ERRORS
The fopen() and freopen() functions will fail if:
[EOVERFLOW]
The named file is a regular file and the size of the file
cannot be represented correctly in an object of type off_t.
Note: This is a new error condition.
2.2.1.10 fpathconf() and pathconf()
DESCRIPTION
Variable Value of name Notes
FILESIZEBITS _PC_FILESIZEBITS 3,4
2.2.1.11 fprintf(), fputc(), fputs(), fwrite(), printf(), putc(), putchar(),
puts(), putw(), vfprintf(), vprintf()
ERRORS
These functions will fail if either the stream is unbuffered or
the stream's buffer needed to be flushed and:
[EFBIG]
The file is a regular file and an attempt was made to write
at or beyond the offset maximum.
Note: This is an additional EFBIG error condition.
2.2.1.12 fseek()
ERRORS
The fseek() function will fail if:
[EOVERFLOW]
The resulting file offset would be a value which cannot be
represented correctly in an object of type long.
Note: This is a new error condition.
2.2.1.13 fseeko()
DESCRIPTION
The fseeko() function is identical to the modified fseek() except
that the offset argument is of type off_t and the EOVERFLOW error
is changed as follows:
ERRORS
[EOVERFLOW]
The resulting file offset would be a value which cannot be
represented correctly in an object of type off_t.
Note: This is a new function.
2.2.1.14 fstat(), lstat() and stat()
ERRORS
These functions will fail if:
[EOVERFLOW]
The file size in bytes or the number of blocks allocated to
the file or the file serial number cannot be represented
correctly in the structure pointed to by buf.
Note: This is an additional EOVERFLOW error condition.
2.2.1.15 fstatvfs() and statvfs()
ERRORS
These functions will fail if:
[EOVERFLOW]
One of the values to be returned cannot be represented
correctly in the structure pointed to by buf.
Note: This is a new error condition.
2.2.1.16 ftell()
ERRORS
The ftell() function will fail if:
[EOVERFLOW]
The current file offset cannot be represented correctly in an
object of type long.
Note: This is a new error condition.
2.2.1.17 ftello()
DESCRIPTION
The ftello() function is identical to the modified ftell() except
that the return value is of type off_t and the EOVERFLOW error is
changed as follows:
ERRORS
[EOVERFLOW]
The current file offset cannot be represented correctly in an
object of type off_t.
Note: This is a new function.
2.2.1.18 ftruncate()
ERRORS
The ftruncate() function will fail if:
[EFBIG]
The file is a regular file and length is greater than the
offset maximum established in the open file description
associated with fildes.
Note: This is an additional EFBIG error condition.
2.2.1.19 getrlimit() and setrlimit()
DESCRIPTION
When using the getrlimit() function, if a resource limit can be
represented correctly in an object of type rlim_t then its
representation is returned; otherwise if the value of the resource
limit is equal to that of the corresponding saved hard limit the
value returned is RLIM_SAVED_MAX; otherwise the value returned is
RLIM_SAVED_CUR.
When using the setrlimit() function, if the requested new limit is
RLIM_INFINITY the new limit will be "no limit"; otherwise if the
requested new limit is RLIM_SAVED_MAX the new limit will be the
corresponding saved hard limit; otherwise if the requested new
limit is RLIM_SAVED_CUR the new limit will be the corresponding
saved soft limit; otherwise the new limit will be the requested
value. In addition, if the corresponding saved limit can be
represented correctly in an object of type rlim_t then it will be
overwritten with the new limit.
The result of setting a limit to RLIM_SAVED_MAX or RLIM_SAVED_CUR
is unspecified unless a previous call to getrlimit() returned that
value as the soft or hard limit for the corresponding resource
limit.
The determination of whether a limit can be correctly represented
in an object of type rlim_t is implementation-dependent. For
example, some implementations permit a limit whose value is
greater than RLIM_INFINITY and others do not.
The exec family of functions also cause resource limits to be
saved. (See 2.2.1.3 exec).
2.2.1.20 lio_listio()
DESCRIPTION
For regular files, no data transfer will occur past the offset
maximum established in the open file description associated with
aiocbp->aio_fildes.
ERRORS
The following are additional error codes which may be set for each
aiocb control block:
[EOVERFLOW]
The aiocbp->aio_lio_opcode is LIO_READ, the file is a regular
file, aiocbp->aio_nbytes is greater than 0, and the
aiocbp->aio_offset is before the end-of-file and is greater
than or equal to the offset maximum in the open file
description associated with aiocbp->aio_fildes.
[EFBIG]
The aiocbp->aio_lio_opcode is LIO_WRITE, the file is a
regular file, aiocbp->aio_nbytes is greater than 0, and the
aiocbp->aio_offset is greater than or equal to the offset
maximum in the open file description associated with
aiocbp->aio_fildes.
Note: These are additional EFBIG and EOVERFLOW error conditions.
2.2.1.21 lockf()
DESCRIPTION
An F_ULOCK request in which size is non-zero and the offset of the
last byte of the requested section is the maximum value for an
object of type off_t, when the process has an existing lock in
which size is 0 and which includes the last byte of the requested
section, will be treated as a request to unlock from the start of
the requested section with a size equal to 0. Otherwise an F_ULOCK
request will attempt to unlock only the requested section.
ERRORS
The lockf() function will fail if:
[EINVAL]
The function argument is not one of F_LOCK, F_TLOCK, F_TEST
or F_ULOCK; or size plus the current file offset is less than
0.
[EOVERFLOW]
The offset of the first, or if size is not 0 then the last,
byte in the requested section cannot be represented correctly
in an object of type off_t.
Note: This is a clarification of the EINVAL error condition.
Note: EOVERFLOW is a new error condition.
2.2.1.22 lseek()
ERRORS
The lseek() function will fail if:
[EOVERFLOW]
The resulting file offset would be a value which cannot be
represented correctly in an object of type off_t.
Note: This is a new error condition.
2.2.1.23 mmap()
ERRORS
The mmap() function will fail if:
[EOVERFLOW]
The file is a regular file and the value of off plus len
exceeds the offset maximum established in the open file
description associated with fildes.
Note: This is a new error condition.
2.2.1.24 open()
DESCRIPTION
The largest value that can be represented correctly in an object
of type off_t will be established as the offset maximum in the
open file description.
ERRORS
The open() function will fail if:
[EOVERFLOW]
The named file is a regular file and the size of the file
cannot be represented correctly in an object of type off_t.
Note: This is a new error condition.
2.2.1.25 read() and readv()
DESCRIPTION
For regular files, no data transfer will occur past the offset
maximum established in the open file description associated with
fildes.
ERRORS
The read() and readv() functions will fail if:
[EOVERFLOW]
The file is a regular file, nbyte is greater than 0, the
starting position is before the end-of-file and the starting
position is greater than or equal to the offset maximum
established in the open file description associated with
fildes.
Note: This is a new error condition.
2.2.1.26 readdir()
ERRORS
The readdir() function will fail if:
[EOVERFLOW]
One of the values in the structure to be returned cannot be
represented correctly.
Note: This is a new error condition.
2.2.1.27 write() and writev()
DESCRIPTION
For regular files, no data transfer will occur past the offset
maximum established in the open file description associated with
fildes.
ERRORS
These functions will fail if:
[EFBIG]
The file is a regular file, nbyte is greater than 0 and the
starting position is greater than or equal to the offset
maximum established in the open file description associated
with fildes.
Note: This is an additional EFBIG error condition.
2.2.2 Changes to Headers
The following changes will be made to System Interfaces and Headers, Chapter
4, Headers.
2.2.2.1 <limits.h>
The following symbolic constant is defined as a Pathname Variable Value:
Name Description Acceptable Value
FILESIZEBITS Minimum number of bits *
needed to represent,
as a signed integer
value, the maximum size
of a regular file
allowed in the
specified directory.
2.2.2.2 <stdio.h>
The following are declared as functions and may also be defined as macros:
int fseeko(FILE *stream, off_t offset, int whence);
off_t ftello(FILE *stream);
The type off_t is defined through typedef as described in <sys/types.h>.
2.2.2.3 <sys/resource.h>
The following symbolic constants are defined:
RLIM_SAVED_MAX A value of type rlim_t indicating an
unrepresentable saved hard limit.
RLIM_SAVED_CUR A value of type rlim_t indicating an
unrepresentable saved soft limit.
On implementations where all resource limits are representable in an object
of type rlim_t, RLIM_SAVED_MAX and RLIM_SAVED_CUR need not be distinct from
RLIM_INFINITY.
2.2.2.4 <sys/stat.h>
The type of st_blocks in the stat structure will be changed to:
blkcnt_t st_blocks number of blocks allocated for this
object.
2.2.2.5 <sys/statvfs.h>
The types of the fields below in the statvfs structure will be changed to:
fsblkcnt_t f_blocks total number of blocks in the file
system in units of f_frsize.
fsblkcnt_t f_bfree total number of free blocks.
fsblkcnt_t f_bavail number of free blocks available to
non-privileged process.
fsfilcnt_t f_files total number of file serial numbers.
fsfilcnt_t f_ffree total number of free file serial
numbers.
fsfilcnt_t f_favail number of free file serial numbers
available to non-privileged process.
2.2.2.6 <sys/types.h>
The following data types will be defined:
blkcnt_t Used for file block counts.
fsblkcnt_t Used for file system block counts.
fsfilcnt_t Used for file system file counts.
The types blkcnt_t and off_t are defined as extended signed integral types.
The types fsblkcnt_t, fsfilcnt_t, and ino_t are defined as extended unsigned
integral types.
2.2.2.7 <unistd.h>
The following symbolic constant is defined for pathconf():
_PC_FILESIZEBITS
2.3 Changes to CAE Specification Commands and Utilities, Issue 4, Version 2
The following changes will be made to Commands and Utilities, Chapter 3,
Utilities.
2.3.1 Considerations for Utilities in Support of Files of Arbitrary Size
Note: This is a new section and should be added to Commands and Utilities,
Issue 4, Version 2, Chapter 3 after section 1.2.1, Symbolic Links.
The following utilities will support files of any size up to the maximum
that can be created by the implementation. This support includes correct
writing of file size related values (such as file sizes and offsets, line
numbers, and block counts) and correct interpretation of command line
arguments that contain such values.
basename return non-directory portion of pathname
cat concatenate and print files
cd change working directory
chgrp change file group ownership
chmod change file modes
chown change file ownership
cksum write file checksums and sizes
cmp compare two files
cp copy files
dd convert and copy a file
df report free disk space
dirname return directory portion of pathname
du estimate file space usage
find find files
ln link files
ls list directory contents
mkdir make directories
mv move files
pathchk check pathnames
pwd return working directory name
rm remove directory entries
rmdir remove directories
sh shell, the standard command language interpreter
sum print checksum and block or byte count of a file
test evaluate expression
touch change file access and modification times
ulimit set or report file size limit
Exceptions to the requirement that utilities support files of any size up to
the maximum are:
1. Utilities such as tar and cpio cannot support arbitrary file sizes due
to limitations imposed by fixed file formats.
2. Uses of files as command scripts, or for configuration or control, are
exempt. For example, it is not required that sh be able to read an
arbitrarily large ".profile".
3. Shell input and output redirection are exempt. For example, it is not
required that the redirections sum < file or echo foo > file succeed
for an arbitrarily large existing file.
2.3.2 The sh Utility
DESCRIPTION:
Pathname expansion will not fail due to the size of a file.
Shell input and output redirections will have an
implementation-specific offset maximum that will be established in
the open file description.
2.3.3 The pax Utility
APPLICATION USAGE
The pax utility is not able to handle arbitrary file sizes. There
is currently a proposal in ballot in IEEE Project 1003.2b to
address this issue.
3.0 Transitional Extensions to the Single UNIX Specification
The interfaces, macros and data types in this section are explicitly 64-bit
instances of the corresponding SUS and POSIX.1b interfaces, macros and data
types. The function prototype and semantics of a transitional interface will
be equivalent to those of the SUS version of the call. Version test macros
announcing extensions to the SUS are also defined.
The transitional extensions in this section are intended to be temporary.
While an application using this specification may be using non-POSIX
conforming transitional extensions to operating system functions, this does
not require that system vendors break their POSIX compliance. This
specification is intended to be compatible with the standards. The
transitional extensions are provided so that system vendors may define a
common set of large file capable extensions to their current compliant
systems without violating that compliance.
3.1 Transitional Extensions to CAE Specification System Interfaces and
Headers, Issue 4, Version 2
3.1.1 Transitional Extensions to System Interfaces
3.1.1.1 64-bit Versions of Interfaces
The following interfaces are explicitly 64-bit versions of the corresponding
Single UNIX Specification and POSIX.1b interfaces. There is no functional
difference between these and the corresponding Single UNIX Specification and
POSIX.1b interfaces.
3.1.1.1.1 Asynchronous I/O Interfaces
aio_cancel64() aio_error64()
aio_fsync64() aio_read64()
aio_return64() aio_suspend64()
aio_write64() lio_listio64()
3.1.1.1.2 STDIO Interfaces
fgetpos64() fopen64()
freopen64() fseeko64()
fsetpos64() ftello64()
tmpfile64()
3.1.1.1.3 Other Interfaces
creat64() fstat64()
fstatvfs64() ftruncate64()
ftw64() getrlimit64()
lockf64() lseek64()
lstat64() mmap64()
nftw64() open64()
readdir64() setrlimit64()
stat64() statvfs64()
truncate64()
3.1.1.2 fcntl()
DESCRIPTION
The following additional value may be used in constructing oflag:
O_LARGEFILE
If set, the offset maximum in the open file description will
be the largest value that can be represented correctly in an
object of type off64_t.
The behavior of the following additional values is equivalent to
the corresponding Single UNIX Specification value (FGETLK, FSETLK,
FSETLKW), but they take a struct flock64 argument rather than a
struct flock argument.
FGETLK64
FSETLK64
FSETLKW64
3.1.1.3 open()
DESCRIPTION
The following additional value may be used in constructing oflag:
O_LARGEFILE
If set, the offset maximum in the open file description will
be the largest value that can be represented correctly in an
object of type off64_t.
ERRORS
The open() function will fail if:
[EOVERFLOW]
The named file is a regular file and either O_LARGEFILE is
not set and the size of the file cannot be represented
correctly in an object of type off_t or O_LARGEFILE is set
and the size of the file cannot be represented correctly in
an object of type off64_t.
APPLICATION USAGE
Note that using open64() is equivalent to using open() with
O_LARGEFILE set in oflag.
Note: For the transitional extensions these changes to open() are in place
of the changes described in 2.2.1.24 open() relating to the changes to the
SUS.
3.1.2 Transitional Extensions to Headers
The modifications to the headers in this section are necessary to implement
the transitional extensions as described in 3.0 Transitional Extensions to
the Single UNIX Specification.
3.1.2.1 64-bit Versions of Headers
In summary, the changes to the headers involve the following data types,
structures and symbolic constants:
3.1.2.1.1 Data Types
blkcnt_t fsblkcnt_t
fsfilcnt_t fpos_t
ino_t off_t
rlim_t
3.1.2.1.2 Structures
struct dirent struct flock
struct rlimit struct stat
struct statvfs
3.1.2.1.3 Symbolic Constants
F_GETLK F_SETLK
F_SETLKW RLIM_INFINITY
RLIM_SAVED_MAX RLIM_SAVED_CUR
3.1.2.2 <aio.h>
The aiocb64 structure is defined in the same way as the aiocb structure in
the POSIX.1b with the exception of the following member:
off64_t aio_offset
The following are declared as functions and may be defined as macros.
int aio_read64(struct aiocb64 *aiocbp);
int aio_write64(struct aiocb64 *aiocbp);
int lio_listio64(int mode, struct aiocb64 *const list[],
int nent, struct sigevent *sig);
int aio_error64(const struct aiocb64 *aiocbp);
ssize_t aio_return64(struct aiocb64 *aiocbp);
int aio_cancel64(int fildes, struct aiocb64 *aiocbp);
int aio_suspend64(const struct aiocb64 *const list[],
int nent, const struct timespec *timeout);
int aio_fsync64(int op, struct aiocb64 *aiocbp);
3.1.2.3 <dirent.h>
The dirent64 structure is defined in the same way as the dirent structure in
the Single UNIX Specification with the exception of the following member:
ino64_t d_ino file serial number.
The following is declared as a function and may also be defined as a macro:
struct dirent64 *readdir64(DIR *dirp);
3.1.2.4 <fcntl.h>
The flock64 structure is defined in the same way as the flock structure in
the Single UNIX Specification with the exception of the following members:
off64_t l_start relative offset in bytes.
off64_t l_len size.
Additional values for cmd used by fcntl():
F_GETLK64 Get record locking information using struct
flock64.
F_SETLK64 Establish a record lock using struct flock64.
F_SETLKW64 Establish a record lock, blocking, using struct
flock64.
An additional file status flag, used by open() and fcntl(), is defined:
O_LARGEFILE The offset maximum in the open file description
is the largest value that can be represented
correctly in an object of type off64_t.
The following are declared as functions and may also be defined as macros:
int creat64(const char *path, mode_t mode);
int open64(const char *path, int oflag, ...);
3.1.2.5 <ftw.h>
The following are declared as functions and may also be defined as macros:
int ftw64(const char *path,
int (*fn)(const char *, const struct stat64 *, int),
int ndirs);
int nftw64(const char *path,
int (*fn)(const char *, const struct stat64 *, int,
struct FTW *),
int depth, int flags);
3.1.2.6 <stdio.h>
The following data type is defined through typedef:
fpos64_t Type containing all information needed to specify
uniquely every position within a file in which the
largest offset can be represented in an object of type
off64_t.
The following are declared as functions and may also be defined as macros:
int fgetpos64(FILE *stream, fpos64_t *pos);
FILE *fopen64(const char *filename, const char *mode);
FILE *freopen64(const char *filename, const char *mode,
FILE *stream);
int fseeko64(FILE *stream, off64_t offset, int whence);
int fsetpos64(FILE *stream, const fpos64_t *pos);
off64_t ftello64(FILE *stream);
FILE *tmpfile64(void);
3.1.2.7 <sys/mman.h>
The following is declared as a function and may also be defined as a macro:
void *mmap64(void *addr, size_t len, int prot, int flags,
int fd, off64_t offset);
3.1.2.8 <sys/resource.h>
The following data type is defined through typedef:
rlim64_t type used for limit values.
The type rlim64_t must be an extended unsigned arithmetic type that can
represent correctly any non-negative value of an off64_t.
The following symbolic constants are defined:
RLIM64_INFINITY A value of type rlim64_t indicating no limit.
RLIM64_SAVED_MAX A value of type rlim64_t indicating an
unrepresentable saved hard limit.
RLIM64_SAVED_CUR A value of type rlim64_t indicating an
unrepresentable saved soft limit.
On implementations where all resource limits are representable in an object
of type rlim64_t, RLIM64_SAVED_MAX and RLIM64_SAVED_CUR need not be distinct
from RLIM64_INFINITY.
The rlimit64 structure is defined in the same way as the rlimit structure in
the Single UNIX Specification with the exception of the following members:
rlim64_t rlim_cur the current (soft) limit.
rlim64_t rlim_max the hard limit.
The following are declared as functions and may also be defined as macros:
int getrlimit64(int resource, struct rlimit64 *rlp);
int setrlimit64(int resource, const struct rlimit64 *rlp);
3.1.2.9 <sys/stat.h>
The stat64 structure is defined in the same way as the stat structure in the
Single UNIX Specification with the exception of the following members:
ino64_t st_ino file serial number.
off64_t st_size file size in bytes.
blkcnt64_t st_blocks number of blocks allocated for this
object.
The following are declared as functions and may also be defined as macros:
int fstat64(int fildes, struct stat64 *buf);
int lstat64(const char *, struct stat64 *buf);
int stat64(const char *, struct stat64 *buf);
3.1.2.10 <sys/statvfs.h>
The statvfs64 structure is defined in the same way as the statvfs structure
in the Single UNIX Specification with the exception of the following
members:
fsblkcnt64_t f_blocks total number of blocks in the file
system in units of f_frsize.
fsblkcnt64_t f_bfree total number of free blocks.
fsblkcnt64_t f_bavail number of free blocks available to
non-privileged process.
fsfilcnt64_t f_files total number of file serial numbers.
fsfilcnt64_t f_ffree total number of free file serial
numbers.
fsfilcnt64_t f_favail number of free file serial numbers
available to non-privileged process.
The following are declared as functions and may also be defined as macros:
int statvfs64(const char *path, struct statvfs64 *buf);
int fstatvfs64(int fildes, struct statvfs64 *buf);
3.1.2.11 <sys/types.h>
The following data types are defined through typedef:
blkcnt64_t Used for file block counts.
fsblkcnt64_t Used for file system block counts.
fsfilcnt64_t Used for file system file counts.
ino64_t Used for file serial numbers.
off64_t Used for file sizes.
The types blkcnt64_t and off64_t are defined as extended signed integral
types.
The types fsblkcnt64_t, fsfilcnt64_t, and ino64_t are defined as extended
unsigned integral types.
3.1.2.12 <unistd.h>
The following are declared as functions and may also be defined as macros:
int lockf64(int fildes, int function, off64_t size);
off64_t lseek64(int fildes, off64_t offset, int whence);
int ftruncate64(int fildes, off64_t length);
int truncate64(const char *path, off64_t length);
Version Test Macros:
_LFS_LARGEFILE is defined to be 1 if the implementation
supports the interfaces as specified in
2.2.1 Changes to System Interfaces
except that implementations need not provide
the asynchronous I/O interfaces: aio_read(),
aio_write(), and lio_listio().
_LFS_ASYNCHRONOUS_IO
is defined to be 1 if the implementation
supports the asynchronous IO interfaces:
aio_read(), aio_write(), and lio_listio() as
specified in 2.2.1 Changes to
System Interfaces.
_LFS64_ASYNCHRONOUS_IO
is defined to be 1 if the implementation
supports all the transitional extensions
listed in 3.1.1.1.1 Asynchronous I/O Interfaces
and 3.1.2.2 <aio.h>.
_LFS64_LARGEFILE is defined to be 1 if the implementation
supports all the transitional extensions
listed in 3.1.1.1.3 Other Interfaces,
3.1.1.2 fcntl(), 3.1.1.3 open() and
3.1.2 Transitional Extensions to Headers,
except changes specified in 3.1.2.2 <aio.h>
and 3.1.2.6 <stdio.h> need not be supported.
_LFS64_STDIO is defined to be 1 if the implementation
supports all the transitional extensions
listed in 3.1.1.1.2 STDIO Interfaces
and 3.1.2.6 <stdio.h>.
If _LFS64_STDIO is not defined to be 1 and the
underlying file description associated with
stream has O_LARGEFILE set then the behavior
of the Standard I/O functions is unspecified.
Constants for Functions:
_CS_LFS_CFLAGS for confstr().
_CS_LFS_LDFLAGS for confstr().
_CS_LFS_LIBS for confstr().
_CS_LFS_LINTFLAGS for confstr().
_CS_LFS64_CFLAGS for confstr().
_CS_LFS64_LDFLAGS for confstr().
_CS_LFS64_LIBS for confstr().
_CS_LFS64_LINTFLAGS for confstr().
3.2 Transitional Extensions to the mount Utility
3.2.1 Optional Additional Option for the mount utility
If the -o nolargefiles option is specified and is supported by the file
system, then for the duration of the mount it is guaranteed that all regular
files in the file system have a file size that will fit in the smallest
object of type off_t supported by the system performing the mount. The mount
will fail if there are any files in the file system not meeting this
criterion.
If -o largefiles is specified then there is no such guarantee.
The default behavior is implementation-dependent.
3.3 Accessing the Extensions to the SUS
3.3.1 Compilation Environment - Visibility of Additions to the API
Applications which define the macro _LARGEFILE_SOURCE to be 1 before
inclusion of any header will enable at least the functionality described in
2.0 Changes to the Single UNIX Specification on implementations that support
these features. Implementations that support these features will define
_LFS_LARGEFILE to be 1 in <unistd.h>, as described in 3.1.2.12 <unistd.h>.
3.3.2 Compilation Environment - Visibility of Transitional API
Applications which define the macro _LARGEFILE64_SOURCE to be 1 before
inclusion of any header will enable at least the fseeko(), ftello()
extensions to the SUS (see 2.2.1.13 fseeko(), 2.2.1.17 ftello() and 2.2.2.2
<stdio.h>) and the transitional extensions described in 3.1 Transitional
Extensions to CAE Specification System Interfaces and Headers, Issue 4,
Version 2 on implementations that support these features. Implementations
that support these features will define _LFS64_LARGEFILE,
_LFS64_ASYNCHRONOUS_IO and _LFS64_STDIO to be 1 in <unistd.h>, as described
in 3.1.2.12 <unistd.h>.
3.3.3 Mixed API and Compile Environments Within a Single Process
It is permitted to use both the Single UNIX Specification and the
transitional APIs within the same executable, including within the same
source file, and to use both on the same file descriptor whether in the same
process or in different processes (when an open file descriptor is passed or
inherited).
3.3.4 Utilities: Optional Method for Specifying the Size of an off_t
For programs to take advantage of different environments, it is necessary to
compile them for each particular environment. For programs to make use of
the features described in this section they must be compiled with new
compiler and linker options. The getconf utility called with the new
arguments can be used to generate compiler and linker options.
Example 1:
An example of compiling a program with a "large" off_t and that uses
fseeko() and ftello() and uses yacc:
c89 -D_LARGEFILE_SOURCE -o foo \
$(getconf LFS_CFLAGS) y.tab.c b.o \
$(getconf LFS_LDFLAGS) \
-ly $(getconf LFS_LIBS)
Example 2:
An example of compiling a program with a "large" off_t and that does not use
fseeko() and ftello() and has no application specific libraries:
c89 $(getconf LFS_CFLAGS) a.c \
$(getconf LFS_LDFLAGS) \
$(getconf LFS_LIBS)
Example 3:
An example of compiling a program with a "default" off_t and that uses
fseeko() and ftello():
c89 -D_LARGEFILE_SOURCE a.c
Example 4:
An example of compiling a program using transitional versions of SUS
interfaces such as lseek64() and fopen64():
c89 -D_LARGEFILE64_SOURCE \
$(getconf LFS64_CFLAGS) a.c \
$(getconf LFS64_LDFLAGS) \
$(getconf LFS64_LIBS)
Example 5:
An example of running lint on a program with a "large" off_t:
lint -D_LARGEFILE_SOURCE \
$(getconf LFS_LINTFLAGS) ... \
$(getconf LFS_LIBS)
Example 6: An example of running lint on a program using the transitional
API:
lint -D_LARGEFILE64_SOURCE \
$(getconf LFS64_LINTFLAGS) ... \
$(getconf LFS64_LIBS)
These examples show the need for the additional variables LFS_CFLAGS,
LFS_LDFLAGS, LFS_LIBS, LFS_LINTFLAGS, LFS64_CFLAGS, LFS64_LDFLAGS,
LFS64_LIBS and LFS64_LINTFLAGS to be reported by getconf.
Implementations may permit the linking of object files that are compiled
with differing off_t environments. For example, an object module compiled
with a 32-bit off_t can be linked with an object module compiled with a
64-bit off_t. In such a case, both 32-bit off_t and 64-bit off_t API calls
may be used on the same file descriptor. Implementations may instead
disallow this linking.
Appendix A: Rationale and Notes
In a mixed environment the size of an off_t (and other types) might differ
from program to program, and in a transitional environment (see 3.0
Transitional Extensions to the Single UNIX Specification) it might differ
even from routine to routine within a single program. Each specific use of
an off_t has an invariant size that is determined by the compilation
environment. This is referred to below as the size which is "in use".
A.1 Overview
A.1.1 Guiding Principles
A.1.1.1 "No Lies" Rule
An error will be returned whenever a function cannot return the correct
result of an operation.
Returning a "lie" to allow for common uses of a function (e.g. use of stat()
to determine if a file exists) could inadvertently cause a correctly written
application to operate incorrectly.
It is conceivable that returning a "lie" could keep an incorrectly written
application from malfunctioning in a way that creates a serious problem, but
no such applications are known to exist. (Of course it would be easy to
contrive one.)
PASC Interpretation reference 1003.1-90 #38 completed by the POSIX.1
interpretations committee confirms that POSIX.1 conforming implementations
are not allowed to lie to applications. This interpretation explicitly
states that if the file size will not fit in an object of type off_t,
fstat() must fail. In addition, PASC Interpretation reference 1003.1-90 #75
went on to clarify that EOVERFLOW would be a legal extension to report this
condition.
A.1.1.2 "Open Protection" Rule
An open() will fail if the size of the (regular) file cannot be represented
correctly in an object of type off_t.
The size of file on which a program is able to operate is determined by the
off_t in use for the open(). The open protection rule ensures that old
binaries do not operate on files that are too large to handle correctly, and
prevents the binaries from generating incorrect results or corrupting the
data in the file.
An argument against open protection is that requiring opens to fail will
break some binaries that would have worked perfectly well otherwise. For
example, a cat program does a loop of open(), read()/write() pairs, and
close() for each input file. This program would unnecessarily break due to
open protection. But this "Let it Run" argument is flawed in that there is
no known utility which fails due to open protection but would work
"perfectly well" if only we "let it run". Real versions of the cat program
use fstat() to determine whether the input and output files are the same,
have a -n option (count newlines) which will fail on sufficiently large
files and so on.
Another argument against open protection is that it is unnecessary because
an error will be returned as soon as a function cannot return the correct
result of an operation ("No Lies" rule). However, most programs check for
the success of the open() call, but many do not check for overflow or error
after lseek() and other calls. An audit of the standard utilities uncovered
numerous examples.
An argument for open protection is that it increases the likelihood of an
immediate and informative error message. The error message is likely to
include the name of the file that could not be opened. It is much less
likely that an lseek() error message will be as immediate or as informative.
The delay in, or complete lack of, reporting such errors may result in
"silent failure".
Another argument for open protection is that there are numerous plausible
scenarios in which this rule avoids serious harm. It prevents typical
implementations of the touch utility from truncating large files to 0 length
(see A.2.1.1.4 creat()). It can prevent silent failure, which has been
demonstrated to occur in at least one commercial data management system.
With open protection a commercial backup/restore system will report errors
on files that might otherwise result in a corrupted backup tape. It prevents
typical implementations of dbm/ndbm from returning incorrect results from a
database whose size exceeds the off_t in use for the dbm routines.
A.1.1.3 "Read/Write Limit" Rule
For regular files, no data transfer will occur past the offset maximum
established in the open file description.
There are two separate issues for this rule, which are that there is an
application-dependent limit on read() and write(), and that the limit is
"the offset maximum established in the open file description". The second
issue is deferred to A.1.2.1 Offset Maximum. The first issue, that there be
an application-dependent limit, is considered here.
There are two assertions upon which many applications rely:
1. A file can be read until end-of-file and written until the file system
is full or some other implementation limit is reached.
2. The current file offset can be stored correctly in an object of type
off_t, and any file position that can be reached with read() and write
can also be reached with lseek().
In a mixed off_t environment these assertions are true only for the largest
supported size of off_t. An audit of typical applications revealed that most
check return codes from read() and write() in order to guard against
end-of-file, full file systems, and the like, but that most do not check for
overflow of file offsets or errors returned by lseek(). This suggests that
it is more important to maintain the truth of the second assertion. In order
to maintain the second assertion, read() and write() must not be permitted
to move the file offset past the largest offset representable by the
application's off_t.
The write limit avoids the unintuitive situation in which a program could
create a file too large for it to open (due to open protection). This could
result in a serious problem. "Can you imagine the reaction of someone who
has 1.9G of data, and all of a sudden, the DBMS can no longer open the file?
I wouldn't want to be working in tech support that day."
An argument for the write limit is that it keeps a program from creating a
file too large for it to handle properly. An argument for the read limit is
that it is a simple way to cover the hole where a file grows after it is
opened.
An argument for the read/write limit rule is that generating an error at
this limit provides the earliest possible warning of an incompatibility
problem that could result in lost or corrupted data if the application was
to continue.
An argument against the read/write limit rule is that it results in
unnecessary breakage of binaries that would have worked perfectly well
otherwise. This is the "Let it Run" argument, but as noted earlier few if
any such programs exist.
Another argument against the read/write limit rule is that implementing it
is expensive and complex. But it has already been implemented and found not
to be either expensive or complex (an analysis appears in A.1.2.1 Offset
Maximum).
Another argument against the read/write limit rule is that it can result in
a truncated log file record (hence corrupting the log file). But this
truncation and corruption can also occur due to insufficient disk space or
RLIMIT_FSIZE, and indeed the standards require that this occur.
Another argument against the read/write limit rule is that instead one can
use the existing file size resource limit (RLIMIT_FSIZE). But this is not a
useful defense in a mixed off_t environment because it unnecessarily
restricts the size of files created by programs which support a larger
off_t. The practical effect will be that use of RLIMIT_FSIZE in this way
will inconvenience users and they will unlimit themselves and then there
will be no write limit. So this is a false, although attractive, argument.
Another argument against the read/write limit rule is that instead there can
be a mount option which limits the maximum size of a file created in the
file system. But regardless of other merits for such an option, it does not
provide a useful defense in a mixed off_t environment because it
unnecessarily restricts the size of files created by programs which support
a larger off_t. The practical effect will be that the system administrator
will be pressured into remounting the file system with no limit and then
there will be no write limit. So this is another false, although attractive,
argument.
A.1.1.4 Holes in the Protection Mechanism
The following holes in the protection mechanism are discussed in other
sections of this document:
* While a "small" application has a file open another "large" application
can extend the file (see A.1.2.1 Offset Maximum).
* The fcntl() function may inadvertently clear O_LARGEFILE (see A.3.1.1.1
fcntl()).
* The lseek() failure may result in corruption of log file or database
(see A.2.1.1.6 fgetpos(), fseek(), ftell(), lseek()).
* An open file description with a "large" offset maximum may be inherited
by a "small" application (see A.1.2.2 Inheritance).
A.1.2 Concepts
A.1.2.1 Offset Maximum
The offset maximum is used to implement the read/write limit (see A.1.1.3
"Read/Write Limit" Rule). It is basically a hack to avoid the need to
provide transitional versions of read()/write() and the numerous routines
which call them (getchar(), putchar(), printf(), etc.). For consistency it
also affects the semantics of ftruncate() and mmap().
The offset maximum is an unusual part of this specification as it is
associated with the file description whereas in all other cases the limit is
determined by the size of the type that is used for the call. But
determining the latter for read/write would be extremely difficult in an
environment in which a single process contains calls with differing sizes of
off_t in use (this environment is not part of this section of the
specification, but it is part of the transitional specification). In such an
environment it would be necessary to determine the size of off_t for every
function that might result in a read() or write(). That would include
putchar(), fwrite(), fputs(), fprintf(), puts(), etc. The number of the
routines that might potentially do a read() or write() is too large for such
an implementation to be practical.
It is possible that while a "small" application has a file open another
application with a larger off_t can extend the file beyond the size of the
small application's off_t. This leads to a situation where the small
application has a file descriptor which refers to a file too large for it to
be able to process correctly. That is, open protection has been lost. The
application will still have some protection due to "No Lies" and the
"Read/Write Limit", but these are less effective protections. It is believed
that this case is sufficiently unlikely that it may be safely ignored.
As an added protection, it has been suggested that all file calls should
fail whenever the size of the file cannot be represented correctly in an
object of type off_t. This would defend against the file growth scenario
described above. But checking file size on each read/write might hurt
performance in some cases and also it was not considered an important
defense. It would also have the putchar(), fwrite(), etc. implementation
problem.
It has been suggested that a file should not be permitted to be extended
beyond the size of the smallest offset maximum in any open file description
that refers to the file. It is believed that this is an unnecessary
complication, cannot be enforced for some distributed file systems and
applies only to a situation that it is believed may be safely ignored.
The value of the offset maximum in an open file description will not affect
the semantics of operations related to other open file descriptions or of
operations which create new open file descriptions, including other open
file descriptions which refer to the same file.
An argument against offset maximum is that it is expensive and complex. But
that is not the case. The only implementation that will matter for years is
for 64-bit off_t which
* can be implemented as a open file flag (O_LARGEFILE -- see 3.1.2.4
<fcntl.h>).
* will require about 5 lines in headers (e.g. <sys/fcntl.h>).
* will require about 0 lines to set it during a 64-bit open().
* will require about 5 lines of code to check and enforce it in each of
the kernel implementations of read() and write().
* will require about 2 lines of code to display it in each of the
programs which display file flags (e.g. pstat utility).
Documentation would add a dozen or so lines of text, but this part of the
specification does not require such documentation.
A.1.2.1.1 Offset Maximum and the 2G-1 File Size Limit
On implementations where type off_t is a 32-bit two's complement integer,
the maximum value that can be correctly represented in an object of type
off_t is 2^31-1 (2G-1). Because of this, the maximum file size and maximum
file offset of a small file are 2G-1, but the maximum offset of any byte
contained in a small file is 2G-2. An illustration of the offsets (0, 1,
...) of a file, with the bytes (b, B and L) shown as small boxes and the
offset shown as "^" is:
<- "small" -> | <- "large" >-
---------- -----------------------
| b | b | ::: | b | B | L | L | L | :::
^---^---^- -^---^---^---^---^---^-
0 1 2 2G 2G 2G
-2 -1
Although an lseek() can be done to the 2G-1 offset, a read() or write()
cannot be performed at that position because when B (counting number 2G, but
offset 2G-1) is read or written, the resulting pointer to the next offset
address and the file size itself would overflow.
A.1.2.2 Inheritance
The offset maximum will be inherited via fork(), the exec family of
functions, dup(), and fcntl() called with F_DUPFD, and its value will not be
altered by them. The value of the offset maximum will not affect any
semantics related to inheritance.
An application can inherit, via the exec family of functions, a file
descriptor that is associated with a file whose size exceeds the largest
value that can be represented correctly by the off_t that is in use by the
application. An example is if a shell that was compiled with a 64-bit off_t
does input or output redirection of a 10 gigabyte file and then executes a
program which was compiled with a 32-bit off_t. In such a case the large
file unaware application will function until attempting an operation from
which the results cannot be correctly returned.
Most inherited files are due to shell redirection, the other cases are rare
and typically under the complete control of a single application provider.
The cases that are of primary concern are:
old_binary < large_file
and
old_binary > large_file
In these cases a pre-existing application binary, old_binary, is given a
file descriptor to a file that it would not have been able to open for
itself and would be able to read and write past the limit that would have
been established by the open(). The concern is that the application will do
something destructive or generate incorrect results since it is not
expecting a file to be so large.
In comparison, consider the following cases:
a.out | old_binary
and
old_binary | a.out
There is no limit to the amount of data that may be passed through a pipe.
In the first case the application named a.out may push more data through the
pipe than can be contained in a small file. In the second case a.out may be
willing to read more data than can be contained in a small file. If a
pre-existing application binary has problems with inherited file descriptors
that refer to large files then it is likely to have a pre-existing problem
when using a pipe for large amounts of data. While it is true that the two
sets of cases are not completely equivalent, the above examples show that
pre-existing binaries have had the potential to see data streams larger than
the amount of data that can be contained in a small file.
Another reason it is believed that the inheritance of file descriptors does
not cause problems is that the majority of existing applications do not
perform seek operations on standard input or standard output.
A.1.2.3 Non-Requirements
Open protection and the read/write limit apply only to regular files, and
are not specified to apply to block or character special files such as raw
disk partitions.
A.1.2.4 Non-Changes
The following are to clarify, not to change, existing practice: Different
files may have different maximum permitted sizes even when they are on the
same system, or are on the same type of file system, or are on the same file
system. The maximum permitted file sizes are independent of the offset
maximum. The maximum permitted file sizes do not have specified minimum or
maximum values. Attempts to grow a file via write(), writev(), or truncate()
may fail even when statvfs() reports that space is available.
A.1.2.5 NFS Quality of Implementation Issue
NFS does not fall within the confines of this specification since there are
no relevant NFS interfaces. However, here are some suggestions for NFS
implementations.
The NFS version 2 protocol is effectively a 32-bit application since it
cannot handle file sizes larger than 2^31-1 bytes. Any attempt by an NFS V2
client to access a large file (read(), write(), stat(), etc.) should be
rejected by the server since the server knows the file is large and knows
the application (NFS V2) is not "large file aware". This test is trivial and
requires no more performance penalty than the tests for any other file
system type.
The NFS version 3 protocol is "large file aware" since it can handle file
sizes up to 2^63-1 bytes. An NFS V3 server would handle all requests without
change, even if the request involves a large file. It is up to the NFS V3
client code to determine if the application accessing a file is "large file
aware" or not. This should be handled in the standard fashion in the OS on
the client side machine using the attributes returned by the NFS operation
or the cached file attributes. While this does not provide perfect
protection or immediate detection of files that have grown beyond 2^31-1
bytes since being opened, it is no more broken than the rest of NFS. (See
below for more discussion of cached file attributes).
This does not address the issue of NFS V3 clients that are not prepared to
handle "large files". If they are carefully written and obey the NFS V3
protocol they should realize that files can be larger than 2^31-1 bytes and
handle this condition appropriately, probably by failing the operation (they
would know this when a stat(), read(), write(), etc. operation returned a
file size larger than 2^31). However, there are probably NFS V3 clients that
are not carefully written. We really can't do much about that.
Cached Attributes: with the NFS V3 protocol, clients are not required to
cache the file attributes, and servers are not required to return the file
attributes with each operation. If the file attributes are returned with
each operation, it is easy to determine if the file has grown past the large
file limit. If not, the cached attributes can be consulted.
If the client does not cache attributes, then it will either have to request
the attributes from the server over the wire (adversely affecting
performance) or assume the file has not grown in size since it was opened.
This specification pretty much requires the client code to check the file
size at open.
Because of the stateless nature of NFS, it is difficult to ensure that a
large-file unaware application cannot operate on a file that has grown from
small to large. This is for the same reasons that NFS cannot implement
standard UNIX file semantics. However, it is easy to ensure that a
large-file unaware application does not grow a small file to become large
(since the offset and length of each write are determined at the client, the
client can fail any operation where the offset plus length exceeds the small
file limit). It is also easy to insure that a large-file unaware application
does not read past the small file limit.
A.2 Changes to the Single UNIX Specification
A.2.1 Changes to CAE Specification System Interfaces and Headers, Issue 4,
Version 2
A.2.1.1 Changes to System Interfaces
A.2.1.1.1 Notes on Functions not Modified by this Proposal
The following functions do not require modification to meet the terms of
this proposal:
aio_error(), aio_cancel(), aio_return() and aio_suspend()
No large file implications were identified for these functions.
aio_fsync()
It is possible that an aio_fsync() could try to write out file blocks
that are beyond the offset maximum, just as fsync() could. There is no
compelling reason for either to fail. Clearly, the original write
request had to be within the offset maximum for the file description
used. The aio_fsync() function will not enforce the offset maximum on
the blocks which it writes out.
glob() and wordexp()
The subroutines that expand file name wild cards need to be large file
capable.
A.2.1.1.2 aio_read()
The aio_read() function enforces the offset maximum rules for consistency
with read() and readv().
A.2.1.1.3 aio_write()
The aio_write() function enforces the offset maximum rules for consistency
with write() and writev().
A.2.1.1.4 creat()
The creat() function will fail if the named file is a regular file and the
size of the file cannot be represented correctly in an object of type off_t
(see 2.2.1.24 open()). This offers protection from the following coding
style:
if (stat(path, ...) < 0) {
/* assume file does not exist, so create it */
if ((fd = creat(path, ...)) < 0) {
/* print out error text */
}
}
In this example the stat() function is being used to determine the existence
of a file. But if the file size cannot be represented correctly in an object
of type off_t then stat() will fail (see 2.2.1.14 fstat(), lstat() and
stat()) and if creat() did not then fail it would have the unintended effect
of truncating the file to 0 length. Many applications and standard utilities
have code similar to this example, including typical implementations of the
touch utility.
A.2.1.1.5 fcntl() and lockf()
Unlock requests are sometimes "rounded to infinity" so that a process can
create a whole-file lock and then successfully issue a request to clip off
the beginning of the lock without leaving behind an unrepresentable lock.
This is to avoid breaking any existing 32-bit applications which might
happen to do this.
Several existing implementations of fcntl() permit locking the byte whose
offset is the maximum value that can be represented correctly in a object of
type off_t, even though write() cannot write to that offset. This
specification permits that behavior.
The fcntl() function will fail if the cmd argument is F_GETLK and the first
lock which blocks the lock description has a starting offset or length which
cannot be represented correctly in an object of type off_t. Information
about such a lock cannot be correctly returned.
Discussion of the semantics of fcntl() locks that cross the off_t boundary
resulted in six competing proposals:
1. An unlock request fails if it would create an unrepresentable lock.
2. If any lock request includes the byte whose offset is the maximum value
that fits in an off_t, then the request is equivalent to a request
where l_len is 0 and l_start refers to the first byte of the affected
area.
3. (proposal was dropped)
4. If l_len is 0 then the lock is through and including the maximum value
of off_t (and not beyond).
5. Just no lies.
6. If an unlock request includes the byte whose offset is the maximum
value that fits in an off_t, and there is an existing lock with l_len
equal to 0 which also includes that byte, then the request is
equivalent to a request where l_len is 0 and l_start refers to the
first byte of the affected area.
An advantage of 2, 4, and 6 is that they do not change existing behavior of
a 32-bit application.
Proposals 1 and 5 can result in a new type of failure in the case where the
program creates a lock with l_len equal to 0 and then clips off the
beginning leaving behind an unrepresentable lock.
Proposal 4 precludes truly "whole file" locking.
Proposal 6 was adopted because as it preserves existing 32-bit behavior and
is less disruptive than proposal 2 (which extends lock requests in addition
to unlock requests).
The fcntl() and lockf() functions will fail if the offset of the first byte
in the region, or if l_len (size) is non-zero then the offset of last byte
in the region, exceeds the largest possible value in an object of type
off_t. Otherwise the process could create a lock which would be "beyond" the
ability of the program to represent.
A.2.1.1.6 fgetpos(), fseek(), ftell(), lseek()
These functions will fail if the resulting file offset would exceed the
largest value that can be represented correctly in the related type which is
in use for the call, and will set errno to EOVERFLOW (permitted by PASC
Interpretation 1003.1-90 #75).
Programs typically, but incorrectly, fail to check the return value of these
functions, which renders the error return less useful. On the other hand,
returning an incorrect offset can result in serious malfunction as well.
An lseek() to the end of a file using
lseek(fd, 0, SEEK_END);
is quite common. It is unfortunate that these fail on a too-large file since
the return value is usually ignored. One alternative that was considered was
for lseek() to move the file offset for all valid requests and then return
an error if the resulting offset is too large. That is, the call would
succeed for applications that do not check the return code, but also fail
for applications that do check. This option was deemed too bizarre to adopt.
For example, it might be difficult to implement using a remote procedure
call system that was constructed to return either results or an error, but
not both. In addition, the POSIX 1003.1 standard requires the file offset to
remain unchanged if an error is returned by lseek(). It was felt that the
open protection (see A.1.1.2 "Open Protection" Rule) and the read/write
limit (see A.1.1.3 "Read/Write Limit" Rule) are more effective defenses
against this problem.
Another potentially serious consequence of ignoring the return value of
lseek() is that programs which extend data files by attempting to seek
beyond the end-of-file and then writing may instead overwrite existing data.
For example, typical implementations of the dbm and ndbm libraries contain
code such as:
(void) lseek(db->dbm_pagf, blkno*PBLKSIZ, L_SET);
if (write(db->dbm_pagf, pagebuf, PBLKSIZ) != PBLKSIZ)
... error handling ...
The problem is that the return code of lseek() is not checked and so if
"blkno*PBLKSIZ" overflows the lseek() will fail (or will seek to an
unintended offset) and the data will be written to an unintended offset.
A.2.1.1.7 fpathconf() and pathconf()
The reference "See Note 3,4" refers to notes in the X/Open specification for
fpathconf() and pathconf(). These notes indicate that this option
(_PC_FILESIZEBITS) is valid only for a directory, and the results are for
files that exist or may be created in that directory.
The _PC_FILESIZEBITS option makes it possible for a process to determine how
large a file can be created in a given directory. It takes into account
implementation limitations in the file system (e.g. due to the size of file
size and block count variables), and it takes into account long term policy
limitations (e.g. due to the mount utility's -o nolargefiles option). It
does not take into account dynamic restrictions such as the RLIM_FSIZE
resource limit or the number of available file blocks, so the process must
perform appropriate checks.
When the current directory is on a typical large file capable file system
and is mounted with the -o nolargefiles option,
pathconf(".", _PC_FILESIZEBITS);
will return 32. In general, if the maximum size file that could ever exist
on the mounted file system is maxsize then the returned value is 2 plus the
floor of the base 2 logarithm of maxsize.
A.2.1.1.8 fseeko() and ftello()
These functions are needed because fseek() and ftell() are limited by the
long offset type required by ISO C. The fsetpos() and fgetpos() functions,
although they do use an opaque offset type, are not complete replacements
for fseek() and ftell() because they do not allow relative seeks or
arithmetic on fpos_t values.
A.2.1.1.9 fsetpos()
Since fsetpos() sets an absolute file position, which is always legal
regardless of the implementation-supported sizes of off_t, there are no new
error returns or other new semantics.
A.2.1.1.10 fstatvfs() and statvfs()
These functions will fail if the total, or free, or available number of
blocks or files cannot be represented correctly in the structure to be
returned (f_blocks, f_bfree, f_bavail, f_files, f_ffree, f_favail).
A.2.1.1.11 ftruncate(), truncate(), unlink()
These functions are used only on pre-existing files and so do not have the
potential programming hazard as does creat() (see A.2.1.1.4 creat()).
When ftruncate() is used to increase the size of a file, the semantics are
similar to a write() of zeroes to the file. For consistency with write(),
the ftruncate() function will fail when the request is beyond the offset
maximum (even if the effect of the request would be to shorten the file).
A.2.1.1.12 ftw() and nftw()
The ftw() and nftw() functions may fail if a stat() in the underlying
implementation fails with EOVERFLOW. This is unfortunate because "small"
binaries using these functions cannot reasonably be used on file trees
containing "large" files. Some systems have a non-standard extension to
nftw() which permits it to continue when stat() fails (typical failures also
include ESTALE and ELOOP).
A.2.1.1.13 getrlimit() and setrlimit()
These functions map limits that they cannot represent correctly to and from
RLIM_SAVED_MAX and RLIM_SAVED_CUR. These values do not require any special
handling by programs. They may be thought of as tokens that the kernel hands
out to programs that can't handle the real answer, and that remind the
kernel, when the tokens come back from the user, of what value is really
meant.
If setrlimit() fails for any reason (for example, EPERM), the resource
limits and saved resource limits remain unchanged.
This proposal does not specify any particular value for RLIM_INFINITY,
RLIM_SAVED_MAX or RLIM_SAVED_CUR. Typical current implementations use the
value 0x7FFFFFFF for RLIM_INFINITY, and it is recommended that
RLIM_SAVED_MAX and RLIM_SAVED_CUR have similar large values.
Few, if any, programs will need to refer explicitly to RLIM_SAVED_MAX or
RLIM_SAVED_CUR. Those that do should not use them in C-language switch cases
since they may have the same value in some implementations (see 2.2.2.3
<sys/resource.h>).
A limit that can be represented correctly in an object of type rlim_t is
either "no limit", which is represented with RLIM_INFINITY, or has a value
not equal to any of RLIM_INFINITY or RLIM_SAVED_MAX or RLIM_SAVED_CUR and
which can be represented correctly in an object of type rlim_t and which
meets any additional implementation-specific criteria for correct
representation.
A rejected alternative proposal was to map limits that could not be
represented to and from RLIM_INFINITY. This would avoid the need for the new
symbols RLIM_SAVED_MAX and RLIM_SAVED_CUR. But such mapping would arguably
be a lie, and the resulting information loss would cause unintuitive program
behavior, especially in programs running with appropriate privileges needed
to raise hard limits.
A rejected alternative proposal was that if getrlimit() could not correctly
return a current limit then it should instead return -1 and set errno to
EOVERFLOW. But that would result in unnecessary breakage of programs. (Note
that this breakage occurs even when no large files are present.) It would
also result in malfunction of programs that assume that they are calling
getrlimit() properly and so failure "cannot happen". For example, in the 4.4
BSD-Lite distribution, there are at least 15 unchecked calls to getrlimit().
When the 4.4 BSD csh limit function is used to report the current limits,
there is no check of the return code and so the reported results can be
entirely incorrect. Also, non-superuser programs typically unlimit
themselves with:
getrlimit(RLIMIT_STACK, &rl);
rl.rlim_cur = rl.rlim_max;
setrlimit(RLIMIT_STACK, &rl);
If the getrlimit() fails then garbage is passed to setrlimit() which may
result in an unwanted and extremely restricted limit. Several utilities that
are part of the GNU C compiler have this problem.
A.2.1.1.14 lio_listio()
The lio_list() function enforces the offset maximum rules since they are
logically equivalent to aio_read() and aio_write() which enforce it.
A.2.1.1.15 mmap()
For consistency with read() and write(), the mmap() function will fail when
the request extends beyond the offset maximum.
A.2.1.1.16 open()
The open() function called with O_TRUNC set will fail without truncation if
the named file is a regular file and the size of the file cannot be
represented correctly in an object of type off_t. (See A.2.1.1.4 creat()).
A.2.1.1.17 read(), readv(), write() and writev()
These functions may do a "partial read or write" due to the offset maximum.
That is, the value returned may be less than nbyte if the number of bytes
remaining which may be transferred is less than nbyte.
A.2.1.1.18 ulimit()
The ulimit() function will return an unspecified result if the result cannot
be represented correctly in an object of type long. As this function is
already obsolescent, the use of getrlimit() and setrlimit() is recommended
for getting and setting process limits.
A.2.2 Changes to CAE Specification Commands and Utilities, Issue 4, Version
2
A.2.2.1 General Porting Suggestions
When porting a program to be large file capable, general areas of concern in
addition to the issues mentioned in A.1.1.4 Holes in the Protection
Mechanism include:
* command line arguments
* API conversion
* type conversion
* output formatting
* fixed format media issues
* other languages
A.2.2.1.1 Command Line Arguments
Numeric arguments which are file size related, such as a file offset or
block count, need to be handled as an appropriately large type. Converting
arguments into an off_t that is larger than a long may need to be
accomplished with non-standard scanf() formats, if available, or with
portable user-written functions that convert ASCII to a large off_t
analogous to the strtol() function.
A.2.2.1.2 API Conversion
The program should be recompiled in a large off_t environment or,
alternatively, should be converted to use the transitional API. In either
case the source must be scanned for the functions listed in 3.1.1.1 64-bit
Versions of Interfaces and the data types listed in 3.1.2.1 64-bit Versions
of Headers to ensure that all types are properly converted.
A.2.2.1.3 Type Conversion
Whenever a new 64-bit function is used, the argument types and function
result will need to be converted as appropriate. Whenever a variable's type
is converted (whether via the large off_t compilation environment or the
transitional API), all uses of the variable must be checked to determine if
further type conversions are warranted. For example, wherever there is a
struct stat, all uses of st_size must be checked. If the st_size value is
assigned or compared with a variable "v" the variable "v" must be converted
if necessary and all uses of "v" must in turn be checked. This is also true
of type conversions required for command line arguments.
In addition, the program needs to be checked for file size related variables
such as offsets, line numbers, and block counts that must be converted to a
large off_t or related type. These variables typically appear inside loops
that are performing input and/or output.
A.2.2.1.4 Output Formatting
Output of types that have been converted will probably involve using a
different printf() format or using a revised user-written conversion
routine. Since there is a larger range of values which take up more space,
revision of the output layout may be required.
A.2.2.1.5 Fixed Format Media Issues
Current implementations of the tar and cpio utilities are defective in their
support of arbitrarily large files. The pax utility is also equally
defective, but is the subject of a proposal in ballot. (See 2.3.3 The pax
Utility for discussion of this topic.)
Vendor and third-party backup software is also unable to support large files
and will require modification in order to do so.
A.2.2.1.6 Other Languages
This specification is for the C language only. Other languages have
different support requirements. For example, the Fortran I/O API has a limit
on the number of records, not bytes.
A.2.2.2 Considerations for Utilities in Support of Files of Arbitrary Size
The utilities listed in 2.3.1 Considerations for Utilities in Support of
Files of Arbitrary Size are utilities which are used to perform
administrative tasks such as to create, move, copy, remove, change the
permissions, or measure the resources of a file. They are useful both as
end-user tools and as utilities invoked by applications during software
installation and operation.
Typical core utilities must be compiled in a "large" off_t compilation
environment or must use the transitional APIs. Using the compilation
environment reduces the number of editing changes required to port a
program, but it does not reduce the effort required to ensure the
correctness of the port.
The chgrp, chmod, chown, ln, and rm utilities probably require use of large
file capable versions of stat(), lstat(), ftw(), and the stat structure.
The cat, cksum, cmp, cp, dd, mv, sum, and touch utilities probably require
use of large file capable versions of creat(), open(), and fopen().
The cat, cksum, cmp, dd, df, du, ls, and sum utilities may require writing
large integer values. For example,
* The cat utility might have a -n option which counts newlines.
* The cksum and ls utilities report file sizes.
* The cmp utility reports the line number at which the first difference
occurs, and also has a -l option which reports file offsets.
* The dd, df, du, ls, and sum utilities report block counts.
The dd, find and test utilities may need to interpret command arguments that
contain 64-bit values. For dd the arguments include skip=n, seek=n, and
count=n. For find the arguments include -size n. For test the arguments are
those associated with algebraic comparisons.
The df utility might need to access large file systems with statvfs().
The ulimit utility will need to use large file capable versions of
getrlimit() and setrlimit() and be able to read and write large integer
values.
Conversion between off_t (or other derived types) and ASCII is unspecified,
which is a significant practical deficiency. This is being considered by
other groups. For example, see:
ftp://ftp.dmk.com/DMK/sc22wg14/c9x/extended-integers/
A.2.2.3 Additional Requirements for the sh Utility - Porting Recommendations
Pathname expansion (e.g. expanding */foo.c to a/foo.c b/foo.c c/foo.c) and
pathname completion might in some cases use the stat() function which would
need to be large file capable.
The offset maximum used for shell input and output redirections is
implementation-specific. Some vendors prefer to use the smallest supported
off_t, others prefer the largest.
A.3 Transitional Extensions to the Single UNIX Specification
A.3.1 Transitional Extensions to CAE Specification System Interfaces and
Headers, Issue 4, Version 2
Prior experience with transitional access is reported by SGI, Convex,
(http://www.sas.com/standards/large.file/background) and Programmed Logic
Corporation
(http://www.sas.com/standards/large.file/proposals).
A.3.1.1 Transitional Extensions to System Interfaces
A.3.1.1.1 fcntl()
The O_LARGEFILE flag may be set or cleared with F_SETFL. An incorrectly
written program may inadvertently clear this flag. For example, some
programs put a file into append mode with:
fcntl(fd, F_SETFL, O_APPEND);
This is incorrect because it turns off all the other open flags, including
O_LARGEFILE. Instead, to turn on append mode one should first use F_GETFL to
get the current flags:
int oflag = fcntl(fd, F_GETFL, 0);
then include O_APPEND in the flags:
oflag |= O_APPEND;
and then set the new flags:
fcntl(fd, F_SETFL, oflag);
A more complete example would also check for fcntl() failures.
A.3.1.1.2 No fcntl64()
A rejected alternative to extending fcntl() with F_GETLK64 (and so on) would
be to specify fcntl64() with F_GETLK (and so on). The former has prior art
and less functional redundancy, whereas the latter is more consistent with
other transitional functions. This specification does not preclude vendors
from supplying an fcntl64().
A.3.1.2 Transitional Extensions to Headers
A.3.1.2.1 <aio.h>
The aio control block has an embedded offset which is of type off_t. A large
file enabled aio control block needs a 64-bit offset. For consistency with
the other transitional interfaces, a new control block with a 64-bit offset
is defined. The offset is of the type off64_t.
Since a new control block is needed, new interfaces are required for all of
the existing aio interfaces since every one takes a pointer to the control
block as an argument.
A.3.1.2.2 <sys/resource.h>
This proposal does not specify any particular value for RLIM64_INFINITY,
RLIM64_SAVED_MAX or RLIM64_SAVED_CUR. Typical implementations should use the
value 0x7FFFFFFFFFFFFFFF or 0xFFFFFFFFFFFFFFFF for RLIM_INFINITY, and it is
recommended that RLIM64_SAVED_MAX and RLIM64_SAVED_CUR have similar large
values. Even though all limit values will be represented in 64-bit types for
a few years, specifying them as distinct values now will reduce
compatibility problems in the future when the next transition to a still
larger type occurs.
A.3.1.2.3 <sys/types.h>
It is not required that ino64_t be a 64-bit type. However, the NFS version 3
protocol allows for 64-bit file serial numbers. For NFS interoperability
with systems making use of 64-bit file serial numbers, 64-bit ino_t support
is necessary. DCE also may make use of 64-bit file serial numbers.
A.3.2 Accessing the Transitional Extensions to the SUS
A.3.2.1 Compilation Environment - Visibility of Additions to the API
Applications which use the fseeko() and ftello() interfaces should define
_LARGEFILE_SOURCE to be 1, then include <unistd.h> and then test that
_LFS_LARGEFILE is 1 to determine if the additional functionality is indeed
available. This additional functionality may be available even when
_LARGEFILE_SOURCE is not defined, but it will not be available to strictly
conforming X/Open programs.
This macro does not affect the size of off_t (see 3.3.3 Mixed API and
Compile Environments Within a Single Process).
A.3.2.2 Visibility of Transitional API
Applications which wish to use this transitional functionality should define
_LARGEFILE64_SOURCE to be 1, then include <unistd.h>, and then test that
_LFS64_LARGEFILE, _LFS64_ASYNCHRONOUS_IO and _LFS64_STDIO are set to 1 to
determine if the corresponding transitional functionality is indeed
available. This transitional functionality may be available even when
_LARGEFILE64_SOURCE is not defined, but it will not be available to strictly
conforming X/Open programs.
This macro does not affect the size of off_t (see 3.3.3 Utilities: Optional
Method for Specifying the Size of an off_t).
If _LARGEFILE64_SOURCE is defined then _LARGEFILE_SOURCE is implied so it
need not also be defined (see 3.3.1 Compilation Environment - Visibility of
Additions to the API). Similarly, if _LFS64_LARGEFILE is defined then
_LFS_LARGEFILE will be defined so it need not also be tested.
A.3.2.3 Mixed API and Compile Environments within a Single Process
Mixing objects from differing compile environments can be dangerous, since
some types have different sizes in the differing environments. The types
might be used in a way where the size difference causes problems. A system
may disallow this mixing. To avoid these problems, don't mix such objects in
the same executable, or at least ensure that data shared between files
compiled differently does not use any of the types whose meaning may change.
Mixing the standard and transitional APIs is relatively safe, since data
types have the same meaning in every file. This mixing permits a smoother
and faster migration to a larger off_t environment, because it permits
asynchronous upgrades. For example, it permits libraries to be made large
file aware without requiring large file awareness in all the programs which
use the library or in all the libraries which the library uses. (This is
true both for static and for shared libraries.) This is particularly
beneficial for situations in which the system vendor, one or more
third-party suppliers, and the end user may all be supplying libraries or
other objects that are components of a complete program.
A.3.2.4 Utilities: Optional Method for Specifying the Size an off_t
The LFS_CFLAGS variable is used to obtain implementation- specific compiler
options, such as flags and preprocessor variable definitions, so that the
compiled program will be using a "large" off_t. Similarly the LFS_LDFLAGS
variable supplies link editor options, the LFS_LIBS variable supplies link
library names, and the LFS_LINTFLAGS variable supplies lint options.
If the size of off_t is controlled by a preprocessor macro variable then it
is recommended that the macro be named _FILE_OFFSET_BITS and be supported as
follows:
* If this symbol is not defined then an implementation-defined default
size will be used.
* Otherwise, if this symbol has a decimal value equal to the number of
bits in one of the implementation-supported sizes of off_t then that
size of off_t will be used.
* Otherwise, an error message will be written to the standard error and
compilation will terminate with a non-zero status.
For POSIX compatibility this method must not be affected by the #undef
preprocessor or directive. For example:
#undef lseek
must not alter the size of type off_t in use for a call to lseek().
The functions that might be affected by this option are listed in 3.1.1.1
64-bit Versions of Interfaces.
The types, structures and symbolic constants that might be affected by this
option are listed in 3.1.2.1 64-bit Versions of Headers.
It has been argued that there should be a new mode bit (or "magic number")
on executable images to indicate whether or not the application is large
file aware. This is not precluded by this specification. However, an
argument against it is that it requires significant work. Specifically,
kernel, compiler, loader, and library changes are needed. It is unclear how
the mode bit would support a large file aware application that makes calls
to a non-aware shared library.
----------------------------------------------------------------------------
Revision Information
23Feb96 Version 1.1
The 23Feb96 changes include:
1. Unix changed to UNIX throughout
2. Section 1.5 (Changes and Additions) second bullet (Changes to System
Interfaces and Headers) added EFBIG
3. Section 2.2.1 (Changes to System Interfaces) changed "as a future" to
"in a future".
4. Section 2.2.1.1 (aio_read), 2.2.1.1 (aio_write) and 2.2.1.20
(lio_listio) changed nbyte to aiocbp->aio_nbytes; added "is before the
end-of-file and" before "is at or beyond" in the EOVERFLOW error.
5. Section 2.2.1.1 (aio_read), 2.2.1.1 (aio_write) and 2.2.1.20
(lio_listio) changed "greater than or equal to" to "greater than".
6. Section 2.2.1.4 (fclose, etc.), 2.2.1.7 (fgetc, etc.) and 2.2.1.11
(fprintf, etc.) changed "write beyond" to "write at or beyond".
7. Section 2.2.1.20 (lio_listio) prefixed lio_opcode with aiocbp->;
changed order of phrases in EOVERFLOW and EFBIG (moved "the
aiocbp->aio_lio_opcode is LIO_READ" to the front of the sentences);
removed "before EOF" in the EOVERFLOW error condition; added "is before
the end-of-file and" before "is greater than or equal to the offset
maximum".
8. Section 2.2.2.6 (sys/types.h) and 3.1.2.11 (sys/types.h) changed "must
be" to "are defined as" in the sentences starting "The types..".
9. Section 3.1.1.1 (64-bit Versions of SUS Interfaces) changed title of
section to "64-bit Versions of Interfaces". Changed titles in
references to match.
10. Section A.1.1.4.1 (fcntl) moved into A.3.1.1.1 (fcntl).
11. Section A.1.1.4 (Holes in the Protection Mechanism) body added.
12. Section A.1.2.1.1 (Offset Maximum and the 2G-1 File Size Limit)
boldfaced "B" in "byte line"; changed "a lseek" to "an lseek"; changed
"the resulting pointer to the next offset address will overflow" to
"the resulting pointer to the next offset address and the file size
itself would overflow"; changed title from "Offset Maximum - 2G-1 File
Size Limit" to "Offset Maximum and the 2G-1 File Size Limit"; changed
"cannot be performed because" to "cannot be performed at that position
because" in the last paragraph.
13. Section A.2.1.1.4 (creat) changed sample code from if (creat(path, ...)
< 0) { to if ((fd = creat(path, ...)) < 0) {.
14. Section A.2.1.1.6 (fgetpos, etc.) changed "this function" to "these
functions" in second paragraph; added paragraph beginning "Another
potentially serious..." and all that follows to the end of the section.
15. Section A.3.1.1 (Transitional Extensions...) changed "B.3.1.1.2" to
"A.3.1.1.2" in subsection.
16. Section A.3.1.1.1 (fcntl) Merged sentence "The O_LARGEFILE flag may be
set..." with the sentence "The O_LARGEFILE flag can expose..." moved in
from A.1.1.4.1 (fcntl).
17. Section A.3.2.2 (Visibility of Transitional API) changed "Note that if"
to "If" in fourth paragraph.
18. Section A.3.2.4 (Utilities:...) corrected reference to 3.1.2 in the
second to the last paragraph to 3.1.2.1 64-bit Version of Headers.
19. Table of Contents corrected A.3 and A.3.1 heading titles.
24Feb96 Version 1.2
The 24Feb96 changes include:
1. Added link to Foreword and section.
2. Section 1.6 (Conformance) removed list, added text for section.
3. Section 2.2.1.11 (fprintf) changed "needs" to "needed" in the error
text.
4. Section 3.1.2.12 (unistd.h) added LFS_ASYNCHRONOUS_IO version test
macro.
01Mar96 Version 1.3
The 01Mar96 changes include:
1. Changed "Foreword" to "Acknowledgements".
2. Added body of Acknowledgements.
3. Section 1.6 (Conformance) 1st paragraph changed "may fail to" to "need
not".
4. Section 3.3.4, Example 2 changed "had" to "has".
5. Section A.1.2.1.1 (Offset Maximum...) swapped "-" and ">" in top line.
6. Section A.2.1.1.4 (creat) corrected reference for fstat.
7. Section 3.3.3 (Utilities:...) corrected reference for Compilation
Environment...
05Mar96 Version 1.4
The 05Mar96 changes include:
1. Changed Version 1.2 in 01Mar96 revision section to Version 1.3
2. Added additional contributors in the Acknowledgements.
20Mar96 Version 1.5
The 20Mar96 changes include:
1. Back by popular demand.... Larger fonts in the PostScript Version!
2. Section 1.2 (Requirements) In the text for "Be fully compliant to the
SUS" changed "conversion to the proposed standard" to "conversion to
this proposed standard" in the second from the last paragraph.
3. Section 1.4 (Concepts) Changed "file is larger" to "file size is
larger" and changed "only support" to "support only".
4. Section 1.6 (Conformance) LOTS of changes. In summary: each statement
of conformance ("A conforming implementation...") was separated into
individual paragraph and in each the phrases "described in" and "listed
in" were changed to "specified in"; the version test macro required for
each statement of conformance was added along with a reference to the
section where the changes to the interfaces and/or headers is
described; in the first statement of conformance parenthesis were added
around "except...lio_listio()" for clarity. Also deleted the last
paragraph (beginning "Implementations which provide...").
5. Section 2.2.1.7 (fgetc) Removed extra period at end of EOVERFLOW
description.
6. Section 2.2.1.19 (getrlimit) Changed commas before "otherwise" to
semicolons in first and second paragraphs; changed "permit" to "might
permit" and "do not" to "might not" in the fourth paragraph.
7. Section 3.0 (Transitional Extensions...) first paragraph: Added
sentence beginning "Version test macros..." after the first sentence
("The interfaces...").
8. Section 3.1.2.8 (sys/resource.h) Added period after description of
RLIM64_INFINITY.
9. Section 3.1.2.12 (unistd.h) In Version Test Macros section added to
description of _LFS_ASYNCHRONOUS_IO beginning with "as specified
in..."; added "and 3.1.2.2..." to description of
_LFS64_ASYNCHRONOUS_IO; added "3.1.1.2 fcntl()..." to description of
_LFS64_LARGEFILE; added "and 3.1.2.6..." to description of
_LFS64_STDIO. The last paragraph of A.3.2.2 ("If _LFS64_STDIO...") was
moved to 3.1.2.12 as a new paragraph in the description of
_LFS64_STDIO. In the description of _LFS_LARGEFILE the phrase "the
fseeko() and ftello()" was removed and the text beginning with "as
specified in..." through the end of the sentence was added.
10. Section 3.2.1 (Optional Additional...) Changed criteria to criterion
(last word of first paragraph).
11. Section A.1.1.2 (Open Protection...) Removed comma before "and so on"
in the third paragraph.
12. Section A.1.2.1 (Offset Maximum) Added "it" between "that" and "is
believed" in last sentence of the fifth paragraph. Also in the fifth
paragraph, changed "only applies" to "applies only".
13. Section A.2.1.1.13 (getrlimit()...) Added text beginning "These values
do not..." through "...is really meant." to the end of the first
paragraph.
14. Section A.2.2.1 (General Porting...) In the first paragraph removed the
phrase "there are four" and added "include" at then end of the
sentence.
15. Section A.2.2.3 (Type Conversion...) Removed the last sentence of the
last paragraph ("Utilities not directly...").
16. Section A.3.2.2 (Visibility of...) Second paragraph: added missing
parenthesis at end of the sentence. Also moved last paragraph ("If
_LFS64_STDIO is not defined...") to section 3.1.2.12 (unistd.h) as an
additional paragraph in the _LFS64_STDIO description.
17. Acknowledgements first paragraph: changed "files sizes" to "file sizes"
in two places and changed "at least 2**32-1" to "at most 2^31-1". In
the list of contributors changed "Hewlett-Packard Inc." to
"Hewlett-Packard Co."; changed "Sun Microsystems Corp." to "Sun
Microsystems, Inc."; changed "Srimivasam" to "Srinivasan"; removed Art
Herzog from Novell list; removed Carl Zeigler from SAS list; added The
Santa Cruz Operation, Inc. contributors. Added "(now with Integrated
Computer Solutions, Inc.)" after "Mark Hatch".
18. General: Changed "define[s,d] XXX as 1" to "define[s,d] XXX to be 1".
...@@ -63,7 +63,7 @@ DIFF = gnu.diff -df >null: ...@@ -63,7 +63,7 @@ DIFF = gnu.diff -df >null:
AFLAGS = -depend !Depend AFLAGS = -depend !Depend
# The zz switch stops library static data being placed in a zero-init area # The zz switch stops library static data being placed in a zero-init area
CFLAGS = -c -depend !Depend ${INCLUDES} -DDDE -fK -zz10000000 CFLAGS = -c -depend !Depend ${INCLUDES} -DDDE -fK -zz10000000 -jC:
CPFLAGS = ~cfr~v CPFLAGS = ~cfr~v
WFLAGS = ~c~r~v WFLAGS = ~c~r~v
......
...@@ -60,6 +60,8 @@ IfThere Hdr:ScrBlank Then Echo <32> GET Hdr:ScrBlank { >> s.swioptions } ...@@ -60,6 +60,8 @@ IfThere Hdr:ScrBlank Then Echo <32> GET Hdr:ScrBlank { >> s.swioptions }
IfThere Hdr:ScrModes Then Echo <32> GET Hdr:ScrModes { >> s.swioptions } IfThere Hdr:ScrModes Then Echo <32> GET Hdr:ScrModes { >> s.swioptions }
IfThere Hdr:SCSI Then Echo <32> GET Hdr:SCSI { >> s.swioptions } IfThere Hdr:SCSI Then Echo <32> GET Hdr:SCSI { >> s.swioptions }
IfThere Hdr:SCSIFS Then Echo <32> GET Hdr:SCSIFS { >> s.swioptions } IfThere Hdr:SCSIFS Then Echo <32> GET Hdr:SCSIFS { >> s.swioptions }
IfThere Hdr:SDFS Then Echo <32> GET Hdr:SDFS { >> s.swioptions }
IfThere Hdr:SDIO Then Echo <32> GET Hdr:SDIO { >> s.swioptions }
IfThere Hdr:SharedCLib Then Echo <32> GET Hdr:SharedCLib { >> s.swioptions } IfThere Hdr:SharedCLib Then Echo <32> GET Hdr:SharedCLib { >> s.swioptions }
IfThere Hdr:Shell Then Echo <32> GET Hdr:Shell { >> s.swioptions } IfThere Hdr:Shell Then Echo <32> GET Hdr:Shell { >> s.swioptions }
IfThere Hdr:Sound Then Echo <32> GET Hdr:Sound { >> s.swioptions } IfThere Hdr:Sound Then Echo <32> GET Hdr:Sound { >> s.swioptions }
......
...@@ -11,13 +11,13 @@ ...@@ -11,13 +11,13 @@
GBLS Module_HelpVersion GBLS Module_HelpVersion
GBLS Module_ComponentName GBLS Module_ComponentName
GBLS Module_ComponentPath GBLS Module_ComponentPath
Module_MajorVersion SETS "5.63" Module_MajorVersion SETS "5.64"
Module_Version SETA 563 Module_Version SETA 564
Module_MinorVersion SETS "" Module_MinorVersion SETS ""
Module_Date SETS "28 Oct 2011" Module_Date SETS "28 Oct 2011"
Module_ApplicationDate SETS "28-Oct-11" Module_ApplicationDate SETS "28-Oct-11"
Module_ComponentName SETS "RISC_OSLib" Module_ComponentName SETS "RISC_OSLib"
Module_ComponentPath SETS "castle/RiscOS/Sources/Lib/RISC_OSLib" Module_ComponentPath SETS "castle/RiscOS/Sources/Lib/RISC_OSLib"
Module_FullVersion SETS "5.63" Module_FullVersion SETS "5.64"
Module_HelpVersion SETS "5.63 (28 Oct 2011)" Module_HelpVersion SETS "5.64 (28 Oct 2011)"
END END
/* (5.63) /* (5.64)
* *
* This file is automatically maintained by srccommit, do not edit manually. * This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1. * Last processed by srccommit version: 1.1.
* *
*/ */
#define Module_MajorVersion_CMHG 5.63 #define Module_MajorVersion_CMHG 5.64
#define Module_MinorVersion_CMHG #define Module_MinorVersion_CMHG
#define Module_Date_CMHG 28 Oct 2011 #define Module_Date_CMHG 28 Oct 2011
#define Module_MajorVersion "5.63" #define Module_MajorVersion "5.64"
#define Module_Version 563 #define Module_Version 564
#define Module_MinorVersion "" #define Module_MinorVersion ""
#define Module_Date "28 Oct 2011" #define Module_Date "28 Oct 2011"
...@@ -18,6 +18,6 @@ ...@@ -18,6 +18,6 @@
#define Module_ComponentName "RISC_OSLib" #define Module_ComponentName "RISC_OSLib"
#define Module_ComponentPath "castle/RiscOS/Sources/Lib/RISC_OSLib" #define Module_ComponentPath "castle/RiscOS/Sources/Lib/RISC_OSLib"
#define Module_FullVersion "5.63" #define Module_FullVersion "5.64"
#define Module_HelpVersion "5.63 (28 Oct 2011)" #define Module_HelpVersion "5.64 (28 Oct 2011)"
#define Module_LibraryVersionInfo "5:63" #define Module_LibraryVersionInfo "5:64"
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
/* version 11 */ /* version 11 */
#define __system_io 1 /* to get at flag bits */ #define __system_io 1 /* to get at flag bits */
#define _LARGEFILE64_SOURCE /* define 64-bit file pointer stuff in stdio.h */
#include "VersionNum" #include "VersionNum"
...@@ -80,13 +81,13 @@ struct bbctime {unsigned int l,h;}; ...@@ -80,13 +81,13 @@ struct bbctime {unsigned int l,h;};
static clock_t _time0; static clock_t _time0;
static clock_t _clock() static clock_t _clock(void)
{ struct bbctime bt; { struct bbctime bt;
_bbctime(&bt); _bbctime(&bt);
return bt.l; return bt.l;
} }
static void _clock_init() /* private - for initialisation */ static void _clock_init(void) /* private - for initialisation */
{ _time0 = _clock(); { _time0 = _clock();
} }
...@@ -97,7 +98,7 @@ static void _clock_ignore(clock_t t) ...@@ -97,7 +98,7 @@ static void _clock_ignore(clock_t t)
/* Exported... */ /* Exported... */
clock_t clock() clock_t clock(void)
{ return _clock() - _time0; /* clock runs even if date not set */ { return _clock() - _time0; /* clock runs even if date not set */
} }
...@@ -106,7 +107,7 @@ clock_t clock() ...@@ -106,7 +107,7 @@ clock_t clock()
time_t time(time_t *timer) time_t time(time_t *timer)
/* this version gives the UNIX result of secs since 1-Jan-1970 */ /* this version gives the UNIX result of secs since 1-Jan-1970 */
{ time_t result; { time_t result;
int mctype; /*int mctype;*/
struct bbctime bt, w, w2; struct bbctime bt, w, w2;
unsigned v; unsigned v;
_kernel_swi_regs r; _kernel_swi_regs r;
...@@ -159,7 +160,7 @@ time_t time(time_t *timer) ...@@ -159,7 +160,7 @@ time_t time(time_t *timer)
* and Wimp_ReadSysInfo 3 says we're in the desktop, and Wimp_ReadSysInfo 5 gives us a * and Wimp_ReadSysInfo 3 says we're in the desktop, and Wimp_ReadSysInfo 5 gives us a
* task handle. * task handle.
*/ */
int _desktop_task() int _desktop_task(void)
{ {
_kernel_swi_regs r; _kernel_swi_regs r;
if (_kernel_processor_mode() & 0xF) return 0; if (_kernel_processor_mode() & 0xF) return 0;
...@@ -381,20 +382,49 @@ int _sys_istty(FILE *stream) ...@@ -381,20 +382,49 @@ int _sys_istty(FILE *stream)
return istty(stream->__file); return istty(stream->__file);
} }
int _sys_seek(FILEHANDLE fh, long pos) int _sys_seek(FILEHANDLE fh, off64_t pos)
{ {
if istty(fh) return 0; if istty(fh) return 0;
#if 1
/* Can't use _kernel_osargs, even for 32-bit file pointers, because it can't handle files of size 4G-2 .*/
/* Use _kernel_swi instead so that _kernel_last_oserror is set up on failure like it always was. */
_kernel_swi_regs r;
r.r[0] = 1;
r.r[1] = fh;
r.r[2] = (unsigned int) pos;
if (_kernel_swi(OS_Args, &r, &r) != NULL)
{
errno = -1;
return _kernel_ERROR;
}
return 0;
#else
{ int rc = _kernel_osargs(1, fh, (int)pos); { int rc = _kernel_osargs(1, fh, (int)pos);
if (rc == _kernel_ERROR) errno = -1; if (rc == _kernel_ERROR) errno = -1;
return rc; return rc;
} }
#endif
} }
long _sys_flen(FILEHANDLE fh) off64_t _sys_flen(FILEHANDLE fh)
{ {
#if 1
/* Can't use _kernel_osargs, even for 32-bit file pointers, because it can't handle files of size 4G-2 .*/
/* Use _kernel_swi instead so that _kernel_last_oserror is set up on failure like it always was. */
_kernel_swi_regs r;
r.r[0] = 2;
r.r[1] = fh;
if (_kernel_swi(OS_Args, &r, &r) != NULL)
{
errno = -1;
return _kernel_ERROR;
}
return (unsigned int) r.r[2];
#else
int rc = _kernel_osargs(2, fh, 0); int rc = _kernel_osargs(2, fh, 0);
if (rc == _kernel_ERROR) errno = -1; if (rc == _kernel_ERROR) errno = -1;
return rc; return rc;
#endif
} }
int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode) int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode)
...@@ -698,6 +728,7 @@ void _armsys_lib_init(void) ...@@ -698,6 +728,7 @@ void _armsys_lib_init(void)
{ char *stdinfile = TTYFILENAME, { char *stdinfile = TTYFILENAME,
*stdoutfile = TTYFILENAME, *stdoutfile = TTYFILENAME,
*stderrfile = TTYFILENAME; *stderrfile = TTYFILENAME;
(void) unused;
_getenv_value = NULL; _getenv_value = NULL;
_error_recursion = 0; _error_recursion = 0;
_ctype_init(); /* C locale */ _ctype_init(); /* C locale */
......
...@@ -320,7 +320,7 @@ void _set_ctype(int territory) ...@@ -320,7 +320,7 @@ void _set_ctype(int territory)
} }
} }
void _ctype_init() void _ctype_init(void)
{ {
__ctype[-1] = IL; /* for ctype(EOF) */ __ctype[-1] = IL; /* for ctype(EOF) */
_set_ctype(0); _set_ctype(0);
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
extern int _sprintf_lf(char *buff, const char *fmt, ...); extern int _sprintf_lf(char *buff, const char *fmt, ...);
extern int __locales[5];
int __locales[5] = {0, 0, 0, 0, 0}; int __locales[5] = {0, 0, 0, 0, 0};
/* lc initialised to C for default */ /* lc initialised to C for default */
......
...@@ -962,11 +962,13 @@ float modff(float value, float *iptr) ...@@ -962,11 +962,13 @@ float modff(float value, float *iptr)
double nan(const char *s) double nan(const char *s)
{ {
(void) s;
return (double) NAN; return (double) NAN;
} }
float nanf(const char *s) float nanf(const char *s)
{ {
(void) s;
return NAN; return NAN;
} }
......
...@@ -117,7 +117,7 @@ static int printf_display(FILE *p, int flags, int ch, int precision, int width, ...@@ -117,7 +117,7 @@ static int printf_display(FILE *p, int flags, int ch, int precision, int width,
} }
break; break;
case 'o': while(v!=0) case 'o': while(v!=0)
{ buff[len++] = '0' + (v & 07); { buff[len++] = '0' + (char)(v & 07);
v = v >> 3; v = v >> 3;
} }
break; break;
...@@ -125,7 +125,7 @@ static int printf_display(FILE *p, int flags, int ch, int precision, int width, ...@@ -125,7 +125,7 @@ static int printf_display(FILE *p, int flags, int ch, int precision, int width,
case 'i': case 'i':
case 'd': while (v != 0) case 'd': while (v != 0)
{ unsigned long long vDiv10 = v / 10U; { unsigned long long vDiv10 = v / 10U;
buff[len++] = '0' + v - vDiv10 * 10U; buff[len++] = '0' + (char)(v - vDiv10 * 10U);
v = vDiv10; v = vDiv10;
} }
break; break;
......
...@@ -842,6 +842,10 @@ typedef struct __extradata { ...@@ -842,6 +842,10 @@ typedef struct __extradata {
int __d; int __d;
int __e; int __e;
int __f; int __f;
#ifdef SUPPORT_WIDE
int __g;
mbstate_t __h;
#endif
} _extradata, *_extradatap; } _extradata, *_extradatap;
int vsscanf(const char *buff, const char *fmt, va_list a) int vsscanf(const char *buff, const char *fmt, va_list a)
......
...@@ -49,7 +49,7 @@ extern void __ignore_signal_handler(int sig) ...@@ -49,7 +49,7 @@ extern void __ignore_signal_handler(int sig)
static void _real_default_signal_handler(int sig) static void _real_default_signal_handler(int sig)
{ {
char *s, v[128]; char *s = NULL, v[128];
_kernel_oserror *e = _kernel_peek_last_oserror(); _kernel_oserror *e = _kernel_peek_last_oserror();
if (((sig == SIGSEGV || sig == SIGILL) && _SignalNumber(e->errnum) == sig) || if (((sig == SIGSEGV || sig == SIGILL) && _SignalNumber(e->errnum) == sig) ||
...@@ -179,7 +179,7 @@ void (*signal(int sig, void (*func)(int)))(int) ...@@ -179,7 +179,7 @@ void (*signal(int sig, void (*func)(int)))(int)
return oldf; return oldf;
} }
void _signal_init() void _signal_init(void)
{ {
int i; int i;
/* do the following initialisation explicitly so code restartable */ /* do the following initialisation explicitly so code restartable */
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
*/ */
#define __system_io 1 /* makes stdio.h declare more */ #define __system_io 1 /* makes stdio.h declare more */
#define _LARGEFILE64_SOURCE /* define 64-bit file pointer stuff in stdio.h */
#include "hostsys.h" /* _sys_alloc() etc */ #include "hostsys.h" /* _sys_alloc() etc */
#include <stdio.h> /* macros for putc, getc, putchar, getchar */ #include <stdio.h> /* macros for putc, getc, putchar, getchar */
...@@ -62,6 +63,20 @@ int __backspace(FILE *stream); /* strict right inverse of getc() */ ...@@ -62,6 +63,20 @@ int __backspace(FILE *stream); /* strict right inverse of getc() */
#define NO_DEBUG #define NO_DEBUG
/* Maximum allowable file pointers for the 32 and 64-bit APIs. */
#define OFF32_MAX (0x7fffffffL)
#if 1 /* change this once FileSwitch has a 64-bit API */
#define OFF64_MAX (0x00000000ffffffffLL)
#else
#define OFF64_MAX (0x7fffffffffffffffLL)
#endif
/* The maximum buffer size to permit via setvbuf().
* Previous limit of 16MB-1 was maybe a bit stingy, given the amount of
* RAM in machines these days.
*/
#define MAX_BUF_SIZE (1u<<30)
/* This macro is part of the fwrite performance improvement. It selects /* This macro is part of the fwrite performance improvement. It selects
* which strategy is being used for large block writes. If this macro * which strategy is being used for large block writes. If this macro
* is defined, then _writebuf is asked to write n*buffersize bytes in one * is defined, then _writebuf is asked to write n*buffersize bytes in one
...@@ -86,8 +101,9 @@ typedef struct __extradata { ...@@ -86,8 +101,9 @@ typedef struct __extradata {
* it, alter sscanf's view of it. * it, alter sscanf's view of it.
*/ */
unsigned char __lilbuf[2]; /* single byte buffer for them that want it */ unsigned char __lilbuf[2]; /* single byte buffer for them that want it */
/* plus an unget char is put in __lilbuf[1] */ /* plus an unget char is put in __lilbuf[1] */
long _lspos; /* what __pos should be (set after lazy seek) */ off64_t __pos; /* position in file corresponding to start of buffer */
off64_t _lspos; /* what __pos should be (set after lazy seek)*/
unsigned char *__extent; /* extent of writes into the current buffer */ unsigned char *__extent; /* extent of writes into the current buffer */
int __buflim; /* used size of buffer */ int __buflim; /* used size of buffer */
int __savedicnt; /* after unget contains old icnt */ int __savedicnt; /* after unget contains old icnt */
...@@ -203,8 +219,9 @@ static FILE *_getFILE(void) ...@@ -203,8 +219,9 @@ static FILE *_getFILE(void)
#define _IOUSERFILE 0x00200000 /* set if should be closed by user */ #define _IOUSERFILE 0x00200000 /* set if should be closed by user */
/* terminateio in a module */ /* terminateio in a module */
#define _IOACTIVE 0x00400000 /* some IO operation already performed*/ #define _IOACTIVE 0x00400000 /* some IO operation already performed*/
#define _IODEL 0xad800000 /* for safety check 9 bits */ #define _IO64 0x00800000 /* stream ok for 64-bit file pointers */
#define _IODELMSK 0xff800000 #define _IODEL 0xad000000 /* for safety check 8 bits */
#define _IODELMSK 0xff000000
/* first functions for macros in <stdio.h> */ /* first functions for macros in <stdio.h> */
int (fgetc)(FILE *stream) { return getc(stream); } int (fgetc)(FILE *stream) { return getc(stream); }
...@@ -217,15 +234,15 @@ int (feof)(FILE *stream) { return feof(stream); } ...@@ -217,15 +234,15 @@ int (feof)(FILE *stream) { return feof(stream); }
int (ferror)(FILE *stream) { return ferror(stream); } int (ferror)(FILE *stream) { return ferror(stream); }
#define STDOUT stderr #define STDOUT stderr
#ifdef DEBUG #ifdef DEBUG
#define dbmsg(m, m2) if (stream > STDOUT || stream == stdin) {int last=0 ;int iw; char v[128]; \ #define dbmsg(m, ...) if (stream > STDOUT || stream == stdin) {int last=0 ;int iw; char v[128]; \
sprintf(v, m, m2); \ sprintf(v, m, __VA_ARGS__); \
for(iw=0;v[iw];_kernel_oswrch(last=v[iw++])); \ for(iw=0;v[iw];_kernel_oswrch(last=v[iw++])); \
if (last == 10)_kernel_oswrch(13);} if (last == 10)_kernel_oswrch(13);}
#define dbmsg_noNL(m, m2) if (stream > STDOUT || stream == stdin) {int last=0 ;int iw; char v[128]; \ #define dbmsg_noNL(m, m2) if (stream > STDOUT || stream == stdin) {int last=0 ;int iw; char v[128]; \
sprintf(v, m, m2); \ sprintf(v, m, m2); \
for(iw=0;v[iw];_kernel_oswrch(last=v[iw++]));} for(iw=0;v[iw];_kernel_oswrch(last=v[iw++]));}
#else #else
#define dbmsg(m, m2) #define dbmsg(m, ...)
#define dbmsg_noNL(m, m2) #define dbmsg_noNL(m, m2)
#endif #endif
/* put this here too */ /* put this here too */
...@@ -251,7 +268,7 @@ int setvbuf(FILE *stream, char *buf, int type, size_t size) ...@@ -251,7 +268,7 @@ int setvbuf(FILE *stream, char *buf, int type, size_t size)
break; break;
case _IOLBF: case _IOLBF:
case _IOFBF: case _IOFBF:
if (size-1 >= 0xffffff) return 1; /* unsigned! */ if (size-1 >= MAX_BUF_SIZE) return 1; /* unsigned! */
break; break;
} }
stream->__ptr = stream->__base = ubuf; stream->__ptr = stream->__base = ubuf;
...@@ -289,37 +306,54 @@ int ungetc(int c,FILE *stream) ...@@ -289,37 +306,54 @@ int ungetc(int c,FILE *stream)
return c; return c;
} }
static int _writebuf(unsigned char *buf, int len, FILE *stream) static int _writebuf(unsigned char *buf, unsigned int len, FILE *stream)
{ int w; { int w;
FILEHANDLE fh = stream->__file; FILEHANDLE fh = stream->__file;
off64_t over_limit;
int flag = stream->__flag; int flag = stream->__flag;
if (flag & _IOSHARED) /* this is really gross */ if (flag & _IOSHARED) /* this is really gross */
{ flag |= _IOSEEK; { flag |= _IOSEEK;
stream->__pos = _sys_flen(fh); stream->__extrap->__pos = _sys_flen(fh);
dbmsg("_IOSHARED so zoom to end %d\n", (int)stream->__pos); dbmsg("_IOSHARED so zoom to end %lld\n", stream->__extrap->__pos);
} }
if (flag & _IOSEEK+_IOBUFREAD) if (flag & _IOSEEK+_IOBUFREAD)
{ {
dbmsg("_writebuf seeking to %d\n", (int)stream->__pos); dbmsg("_writebuf seeking to %lld\n", stream->__extrap->__pos);
if (_sys_seek(fh, stream->__pos) < 0) if (_sys_seek(fh, stream->__extrap->__pos) < 0)
{ seterr(stream); { seterr(stream);
return EOF; return EOF;
} }
stream->__flag = (flag &= ~(_IOSEEK+_IOBUFREAD)); stream->__flag = (flag &= ~(_IOSEEK+_IOBUFREAD));
} }
dbmsg_noNL("_writebuf pop goes the stoat %i, ", fh); dbmsg_noNL("_writebuf pop goes the stoat %i, ", fh);
dbmsg_noNL("%X, ", buf); dbmsg_noNL("%X, ", (int)buf);
dbmsg_noNL("%d, ", len); dbmsg_noNL("%d, ", len);
dbmsg("%X\n", flag); dbmsg("%X\n", flag);
w = _sys_write(fh, buf, len, flag); over_limit = stream->__extrap->__pos + len - ((stream->__flag & _IO64) ? OFF64_MAX : OFF32_MAX);
stream->__flag |= _IOADFSBUG; if (over_limit < 0) over_limit = 0;
dbmsg("over_limit %lld\n", over_limit);
len -= (unsigned int) over_limit;
if (len == 0)
w = 0;
else
{
w = _sys_write(fh, buf, len, flag);
stream->__flag |= _IOADFSBUG;
dbmsg("_sys_write_ returned %d\n", w); dbmsg("_sys_write_ returned %d\n", w);
stream->__pos += len - (w & 0x7fffffffL); }
if (w < (unsigned int) _kernel_ERROR)
stream->__extrap->__pos += (off64_t) len - (w & 0x7fffffffLL);
if (w!=0) /* AM: was (w<0) but trap unwritten chars as error too */ if (w!=0) /* AM: was (w<0) but trap unwritten chars as error too */
{ seterr(stream); { seterr(stream);
return(EOF); return(EOF);
} }
dbmsg("filelen = %d\n",_sys_flen(fh)); /* length of this file */ if (over_limit)
{
seterr(stream);
errno = EFBIG;
return(EOF);
}
dbmsg("filelen = %lld\n",_sys_flen(fh)); /* length of this file */
return 0; return 0;
} }
...@@ -358,7 +392,7 @@ else dbmsg("%s\n", "not a dirty buffer"); ...@@ -358,7 +392,7 @@ else dbmsg("%s\n", "not a dirty buffer");
stream->__flag = stream->__flag & ~(_IOEOF|_IONOWRITES|_IOREADS|_IOPEOF) stream->__flag = stream->__flag & ~(_IOEOF|_IONOWRITES|_IOREADS|_IOPEOF)
|_IOSEEK; |_IOSEEK;
stream->__icnt = stream->__ocnt = 0; stream->__icnt = stream->__ocnt = 0;
stream->__pos += (extent - buff); stream->__extrap->__pos += (extent - buff);
stream->__ptr = buff; stream->__ptr = buff;
} }
*/ */
...@@ -368,15 +402,15 @@ else dbmsg("%s\n", "not a dirty buffer"); ...@@ -368,15 +402,15 @@ else dbmsg("%s\n", "not a dirty buffer");
static void _deferredlazyseek(FILE *stream) static void _deferredlazyseek(FILE *stream)
{ {
dbmsg("deferredlazyseek to %d\n", (int)stream->__extrap->_lspos); dbmsg("deferredlazyseek to %lld\n", stream->__extrap->_lspos);
/* only here because of a seek */ /* only here because of a seek */
stream->__flag &= ~_IOLAZY; stream->__flag &= ~_IOLAZY;
if (stream->__pos != stream->__extrap->_lspos) { if (stream->__extrap->__pos != stream->__extrap->_lspos) {
_fflush(stream); _fflush(stream);
/* clear EOF condition */ /* clear EOF condition */
dbmsg("%s\n", "clear IODIRTIED"); dbmsg("%s\n", "clear IODIRTIED");
stream->__flag = stream->__flag & ~(_IONOWRITES | _IONOREADS) | _IOSEEK; stream->__flag = stream->__flag & ~(_IONOWRITES | _IONOREADS) | _IOSEEK;
stream->__pos = stream->__extrap->_lspos; stream->__extrap->__pos = stream->__extrap->_lspos;
stream->__ptr = stream->__extrap->__extent = stream->__base; stream->__ptr = stream->__extrap->__extent = stream->__base;
} }
else dbmsg("%s\n", ".....already there"); else dbmsg("%s\n", ".....already there");
...@@ -421,7 +455,7 @@ dbmsg("%s\n", "!= _IOWRITE"); ...@@ -421,7 +455,7 @@ dbmsg("%s\n", "!= _IOWRITE");
/* Will somebody please help ACN remember/understand what was going on here!*/ /* Will somebody please help ACN remember/understand what was going on here!*/
{ /* first write to APPEND file after FFLUSH, but not FSEEK nor */ { /* first write to APPEND file after FFLUSH, but not FSEEK nor */
/* fopen (does its own FSEEK) */ /* fopen (does its own FSEEK) */
fseek(stream, 0L, SEEK_END); fseeko64(stream, 0LL, SEEK_END);
if (stream->__flag & _IOLAZY) _deferredlazyseek(stream); if (stream->__flag & _IOLAZY) _deferredlazyseek(stream);
flag = stream->__flag; flag = stream->__flag;
} }
...@@ -441,7 +475,7 @@ dbmsg("%s\n", "set IODIRTIED"); ...@@ -441,7 +475,7 @@ dbmsg("%s\n", "set IODIRTIED");
} }
if (flag & _IOFBF) /* system or user buffer */ if (flag & _IOFBF) /* system or user buffer */
{ unsigned char *buff = stream->__base; { unsigned char *buff = stream->__base;
int count = EXTENT(stream) - buff; unsigned int count = EXTENT(stream) - buff;
if (count != 0) { if (count != 0) {
if (_writebuf(buff, count, stream)) return EOF; if (_writebuf(buff, count, stream)) return EOF;
} }
...@@ -452,7 +486,7 @@ dbmsg("%s\n", "set IODIRTIED"); ...@@ -452,7 +486,7 @@ dbmsg("%s\n", "set IODIRTIED");
} }
else /* no buffer (i.e. 1 char private one) or line buffer */ else /* no buffer (i.e. 1 char private one) or line buffer */
{ unsigned char *buff = stream->__base; { unsigned char *buff = stream->__base;
int count; unsigned int count;
*stream->__ptr++ = ch; /* always room */ *stream->__ptr++ = ch; /* always room */
count = EXTENT(stream) - buff; count = EXTENT(stream) - buff;
stream->__extrap->__buflim = stream->__bufsiz; stream->__extrap->__buflim = stream->__bufsiz;
...@@ -470,7 +504,8 @@ extern int __filbuf(FILE *stream) ...@@ -470,7 +504,8 @@ extern int __filbuf(FILE *stream)
{ int w; { int w;
unsigned char *buff; unsigned char *buff;
FILEHANDLE fh; FILEHANDLE fh;
int request; off64_t over_limit;
unsigned int request;
dbmsg("%s\n", "__filbuf"); dbmsg("%s\n", "__filbuf");
stream->__flag |= _IOACTIVE; stream->__flag |= _IOACTIVE;
if (stream->__flag & _IOUNGET) { if (stream->__flag & _IOUNGET) {
...@@ -514,12 +549,12 @@ dbmsg("fillbuf negative icnt = %d\n", stream->__icnt); ...@@ -514,12 +549,12 @@ dbmsg("fillbuf negative icnt = %d\n", stream->__icnt);
if (stream->__flag & _IOSEEK) { if (stream->__flag & _IOSEEK) {
if (stream->__flag & _IODIRTIED) _fflush(stream); if (stream->__flag & _IODIRTIED) _fflush(stream);
else { else {
dbmsg("fillbuf seeking to %d\n", (int)stream->__pos); dbmsg("fillbuf seeking to %lld\n", stream->__extrap->__pos);
if (stream->__flag & _IOADFSBUG) { if (stream->__flag & _IOADFSBUG) {
_sys_ensure(fh); _sys_ensure(fh);
stream->__flag &= ~_IOADFSBUG; stream->__flag &= ~_IOADFSBUG;
} }
if (_sys_seek(fh, stream->__pos) < 0) if (_sys_seek(fh, stream->__extrap->__pos) < 0)
{ seterr(stream); { seterr(stream);
return EOF; return EOF;
} }
...@@ -529,7 +564,7 @@ dbmsg("fillbuf seeking to %d\n", (int)stream->__pos); ...@@ -529,7 +564,7 @@ dbmsg("fillbuf seeking to %d\n", (int)stream->__pos);
stream->__flag |= _IONOWRITES; /* we are reading */ stream->__flag |= _IONOWRITES; /* we are reading */
if (stream->__flag & _IODIRTIED) { if (stream->__flag & _IODIRTIED) {
int extent = (int) (EXTENT(stream) - stream->__base); unsigned int extent = (int) (EXTENT(stream) - stream->__base);
request = stream->__bufsiz - extent; request = stream->__bufsiz - extent;
if (request == 0) { if (request == 0) {
_fflush(stream); _fflush(stream);
...@@ -537,12 +572,12 @@ dbmsg("fillbuf seeking to %d\n", (int)stream->__pos); ...@@ -537,12 +572,12 @@ dbmsg("fillbuf seeking to %d\n", (int)stream->__pos);
} else { } else {
dbmsg("fillbuf flag %X\n", stream->__flag); dbmsg("fillbuf flag %X\n", stream->__flag);
if ((stream->__flag & (_IOBUFREAD+_IOSEEK)) == 0) { if ((stream->__flag & (_IOBUFREAD+_IOSEEK)) == 0) {
dbmsg("fillbuf dirty buffer, read into end,seeking to %d\n",(int) stream->__pos+extent); dbmsg("fillbuf dirty buffer, read into end,seeking to %lld\n", stream->__extrap->__pos+extent);
if (stream->__flag & _IOADFSBUG) { if (stream->__flag & _IOADFSBUG) {
_sys_ensure(fh); _sys_ensure(fh);
stream->__flag &= ~_IOADFSBUG; stream->__flag &= ~_IOADFSBUG;
} }
if (_sys_seek(fh, stream->__pos + extent) < 0) if (_sys_seek(fh, stream->__extrap->__pos + extent) < 0)
{ seterr(stream); { seterr(stream);
return EOF; return EOF;
} else stream->__flag |= _IOBUFREAD; } else stream->__flag |= _IOBUFREAD;
...@@ -554,19 +589,41 @@ dbmsg("at buff %X\n", (int)buff); ...@@ -554,19 +589,41 @@ dbmsg("at buff %X\n", (int)buff);
} else { } else {
request = stream->__bufsiz; request = stream->__bufsiz;
buff = stream->__base; buff = stream->__base;
stream->__pos += stream->__ptr - buff; /* add buf size for ftell() */ stream->__extrap->__pos += stream->__ptr - buff; /* add buf size for ftell() */
} }
stream->__flag &= ~_IOSEEK; stream->__flag &= ~_IOSEEK;
/* At this point, we are attempting to fill the buffer with data read from the
* file, with no knowledge of where EOF might be. If the file pointer
* corresponding to the start of the read is already at the maximum file pointer,
* it's time to report EOVERFLOW. Since RISC OS is treated as a 'late' eof OS,
* we can't detect EOF coinciding with the maximum file pointer - at least, not
* without extending the armsys.c API, since polling the EOF flag requires a
* separate OS_Args call which it would not be desirable to do on every call to
* _sys_read(). If the file pointer corresponding to the end of the read lies
* beyond the maximum file pointer, we need to truncate the read so as not to
* cause FileSwitch to exceed the limit. If the C library client uses up this
* truncated buffer, __filbuf will be called again, and we can report EOVERFLOW
* at that time.
*/
over_limit = stream->__extrap->__pos + stream->__bufsiz - request - ((stream->__flag & _IO64) ? OFF64_MAX : OFF32_MAX);
if (over_limit >= 0) /* shouldn't actually ever be > 0, but just in case */
{
seterr(stream);
errno = EOVERFLOW;
return EOF;
}
else if (request > -over_limit)
request = (unsigned int) -over_limit;
dbmsg("READING FROM FILE REQUEST = %d\n", request); dbmsg("READING FROM FILE REQUEST = %d\n", request);
dbmsg("filelen = %d\n",_sys_flen(fh)); /* length of this file */ dbmsg("filelen = %lld\n",_sys_flen(fh)); /* length of this file */
stream->__icnt = 0; stream->__icnt = 0;
w = _sys_read(fh, buff, request, stream->__flag); w = _sys_read(fh, buff, request, stream->__flag);
stream->__flag &= ~_IOADFSBUG; stream->__flag &= ~_IOADFSBUG;
dbmsg("_sys_read_ returned %d\n", w); dbmsg("_sys_read_ returned %d\n", w);
if (w<0) { if (w<0) {
if (w == _kernel_ERROR) { seterr(stream); return EOF; } if (w >= (unsigned int) _kernel_ERROR) { seterr(stream); return EOF; }
/* this deals with operating systems with 'early' eof */ /* this deals with operating systems with 'early' eof */
stream->__flag |= _IOPEOF; stream->__flag |= _IOPEOF;
w = w & 0x7fffffff; w = w & 0x7fffffff;
...@@ -645,7 +702,7 @@ int fclose(FILE *stream) ...@@ -645,7 +702,7 @@ int fclose(FILE *stream)
return res; return res;
} }
FILE *freopen(const char *name, const char *mode, FILE *iob) static FILE *freopen_common(const char *name, const char *mode, FILE *iob, int flag64, off64_t limit)
{ {
/* The use of modes "r+", "w+" and "a+" is not fully thought out */ /* The use of modes "r+", "w+" and "a+" is not fully thought out */
/* yet, in that calls to __flsbuf may write back stuff that was */ /* yet, in that calls to __flsbuf may write back stuff that was */
...@@ -674,14 +731,31 @@ FILE *freopen(const char *name, const char *mode, FILE *iob) ...@@ -674,14 +731,31 @@ FILE *freopen(const char *name, const char *mode, FILE *iob)
break; break;
} }
if ((fh = _sys_open(name, openmode)) == NONHANDLE) return NULL; if ((fh = _sys_open(name, openmode)) == NONHANDLE) return NULL;
if (_sys_flen(fh) > limit)
{
errno = EOVERFLOW;
_sys_close(fh);
return NULL;
}
flag |= flag64;
if (_kernel_client_is_module()) flag |= _IOUSERFILE; if (_kernel_client_is_module()) flag |= _IOUSERFILE;
iob->__ptr = iob->__base = NULL; iob->__bufsiz = BUFSIZ; iob->__ptr = iob->__base = NULL; iob->__bufsiz = BUFSIZ;
iob->__flag = flag; iob->__flag = flag;
iob->__file = fh; iob->__file = fh;
if (openmode & OPEN_A) fseek(iob, 0L, SEEK_END); /* a or a+ */ if (openmode & OPEN_A) fseeko64(iob, 0LL, SEEK_END); /* a or a+ */
return iob; return iob;
} }
FILE *freopen(const char *name, const char *mode, FILE *iob)
{
return freopen_common(name, mode, iob, 0, OFF32_MAX);
}
FILE *freopen64(const char *name, const char *mode, FILE *iob)
{
return freopen_common(name, mode, iob, _IO64, OFF64_MAX);
}
FILE *fopen(const char *name, const char *mode) FILE *fopen(const char *name, const char *mode)
{ FILE *stream = _getFILE(); { FILE *stream = _getFILE();
if (stream) if (stream)
...@@ -689,6 +763,13 @@ FILE *fopen(const char *name, const char *mode) ...@@ -689,6 +763,13 @@ FILE *fopen(const char *name, const char *mode)
return 0; /* no more i/o channels allowed for */ return 0; /* no more i/o channels allowed for */
} }
FILE *fopen64(const char *name, const char *mode)
{ FILE *stream = _getFILE();
if (stream)
return (freopen64(name, mode, stream));
return 0; /* no more i/o channels allowed for */
}
FILEHANDLE __dup(int new, int old) FILEHANDLE __dup(int new, int old)
{ FILE *s_new, *s_old; { FILE *s_new, *s_old;
(void) fclose(&__iob[new]); (void) fclose(&__iob[new]);
...@@ -701,6 +782,7 @@ FILEHANDLE __dup(int new, int old) ...@@ -701,6 +782,7 @@ FILEHANDLE __dup(int new, int old)
return s_new->__file; return s_new->__file;
} }
#if 0
FILE *_fopen_string_file(const char *data, int length) FILE *_fopen_string_file(const char *data, int length)
{ {
/* open a file that will read data from the given string argument */ /* open a file that will read data from the given string argument */
...@@ -717,6 +799,7 @@ FILE *_fopen_string_file(const char *data, int length) ...@@ -717,6 +799,7 @@ FILE *_fopen_string_file(const char *data, int length)
} }
return 0; /* no more i/o channels allowed for */ return 0; /* no more i/o channels allowed for */
} }
#endif
int _fisatty(FILE *stream) /* not in ANSI, but related needed for ML */ int _fisatty(FILE *stream) /* not in ANSI, but related needed for ML */
{ if ((stream->__flag & _IOREAD) && _sys_istty(stream)) return 1; { if ((stream->__flag & _IOREAD) && _sys_istty(stream)) return 1;
...@@ -830,7 +913,7 @@ int puts(const char *s) ...@@ -830,7 +913,7 @@ int puts(const char *s)
} }
/* _read improved to use __filbuf and block moves. Optimisation /* _read improved to use __filbuf and block moves. Optimisation
to memcpy too if word move. Still possible improvments avoiding copy to memcpy too if word move. Still possible improvements avoiding copy
but I don't want to do these yet because of interactions but I don't want to do these yet because of interactions
(e.g. __pos of a file). N.B. _read is not far from unix 'read' */ (e.g. __pos of a file). N.B. _read is not far from unix 'read' */
static int _read(char *ptr, int nbytes, FILE *stream) static int _read(char *ptr, int nbytes, FILE *stream)
...@@ -876,15 +959,15 @@ dbmsg("fread %d\n", count); ...@@ -876,15 +959,15 @@ dbmsg("fread %d\n", count);
: _read(ptr, itemsize*count, stream) / itemsize; : _read(ptr, itemsize*count, stream) / itemsize;
} }
static int _write(const char *ptr, int nbytes, FILE *stream) static int _write(const char *ptr, unsigned int nbytes, FILE *stream)
{ int i; { unsigned int i;
if (_sys_istty(stream) || (stream->__flag & _IONBF)) { if (_sys_istty(stream) || (stream->__flag & _IONBF)) {
for(i=0; i<nbytes; i++) for(i=0; i<nbytes; i++)
if (putc(*ptr++, stream) == EOF) return 0; if (putc(*ptr++, stream) == EOF) return 0;
/* H&S say 0 on error */ /* H&S say 0 on error */
} }
else if (nbytes > 0) { else if (nbytes > 0) {
int so_far = 0; unsigned int so_far = 0;
if (stream->__ocnt < 0) { if (stream->__ocnt < 0) {
/* Not ready for writes, so do one putc to force it into a nice state. */ /* Not ready for writes, so do one putc to force it into a nice state. */
...@@ -914,7 +997,7 @@ static int _write(const char *ptr, int nbytes, FILE *stream) ...@@ -914,7 +997,7 @@ static int _write(const char *ptr, int nbytes, FILE *stream)
* OR non-existant. We need to write (nbytes - so_far) bytes, at ptr to 'stream'. * OR non-existant. We need to write (nbytes - so_far) bytes, at ptr to 'stream'.
* Buffer does exist if __ocnt is zero. Thus the call to __flsbuf will flush any * Buffer does exist if __ocnt is zero. Thus the call to __flsbuf will flush any
* filled buffers AND/OR initialise the data structures to accept written data, * filled buffers AND/OR initialise the data structures to accept written data,
* so we can legally check __ocnt, __flags and __bufsiz.  This call to __flsbuf is * so we can legally check __ocnt, __flags and __bufsiz. This call to __flsbuf is
* basically simulating putc, so it MUST always decrement __ocnt before the call. * basically simulating putc, so it MUST always decrement __ocnt before the call.
*/ */
--stream->__ocnt; --stream->__ocnt;
...@@ -926,8 +1009,8 @@ static int _write(const char *ptr, int nbytes, FILE *stream) ...@@ -926,8 +1009,8 @@ static int _write(const char *ptr, int nbytes, FILE *stream)
*/ */
if (stream->__ocnt > 0 && (stream->__flag & _IOFBF) && stream->__bufsiz > 0) { if (stream->__ocnt > 0 && (stream->__flag & _IOFBF) && stream->__bufsiz > 0) {
/* Looks like it is worth attempting a direct write to the file */ /* Looks like it is worth attempting a direct write to the file */
int nblocks, count, loop; unsigned int nblocks, count, loop;
nblocks = (nbytes - so_far - 1) / stream->__bufsiz; nblocks = (nbytes == so_far) ? 0 : (nbytes - so_far - 1) / stream->__bufsiz;
if (nblocks > 0) { if (nblocks > 0) {
/* There cannot be any _IOLAZY pending as __flsbuf will have taken care of it. /* There cannot be any _IOLAZY pending as __flsbuf will have taken care of it.
* We want _writebuf to simply pass this data directly to _sys_write (and under * We want _writebuf to simply pass this data directly to _sys_write (and under
...@@ -990,22 +1073,37 @@ dbmsg("itemsize %d (decimal)\n", itemsize); ...@@ -990,22 +1073,37 @@ dbmsg("itemsize %d (decimal)\n", itemsize);
#define _ftell(stream) ( (stream)->__flag & _IOLAZY \ #define _ftell(stream) ( (stream)->__flag & _IOLAZY \
? (stream)->__extrap->_lspos \ ? (stream)->__extrap->_lspos \
: (stream)->__pos + (stream)->__ptr - (stream)->__base) : (stream)->__extrap->__pos + (stream)->__ptr - (stream)->__base)
long int ftell(FILE *stream) static off64_t ftell_common(FILE * stream, off64_t limit)
{ long pos; { off64_t pos;
if (!(stream->__flag & _IOREAD+_IOWRITE)) /* already closed */ if (!(stream->__flag & _IOREAD+_IOWRITE)) /* already closed */
{ errno = EDOM; { errno = EDOM;
return -1L; return -1LL;
} }
pos = _ftell(stream); pos = _ftell(stream);
if (stream->__flag & _IOUNGET && pos > 0) --pos; if (stream->__flag & _IOUNGET && pos > 0) --pos;
if ((unsigned long long) pos > limit)
{
errno = EOVERFLOW;
return -1LL;
}
return pos; return pos;
} }
long int ftell(FILE *stream)
{
return (long int) ftell_common(stream, OFF32_MAX);
}
off64_t ftello64(FILE * stream)
{
return ftell_common(stream, OFF64_MAX);
}
/* The treatment of files that can be written to seems complicated in fseek */ /* The treatment of files that can be written to seems complicated in fseek */
int fseek(FILE *stream, long int offset, int whence) static int fseek_common(FILE *stream, off64_t offset, int whence, off64_t limit)
{ {
FILEHANDLE fh = stream->__file; FILEHANDLE fh = stream->__file;
int flag = stream->__flag; int flag = stream->__flag;
...@@ -1019,17 +1117,17 @@ dbmsg_noNL("%s ", "SEEK ENTRY"); ...@@ -1019,17 +1117,17 @@ dbmsg_noNL("%s ", "SEEK ENTRY");
case SEEK_SET: case SEEK_SET:
break; /* relative to file start */ break; /* relative to file start */
case SEEK_CUR: case SEEK_CUR:
offset += ftell(stream); /* relative seek */ offset += ftello64(stream); /* relative seek */
break; break;
case SEEK_END: case SEEK_END:
{ long int filelen, filepos; { off64_t filelen, filepos;
filelen = _sys_flen(fh); /* length of this file */ filelen = _sys_flen(fh); /* length of this file */
dbmsg("filelen in seek = %d\n", (int)filelen); dbmsg("filelen in seek = %lld\n", filelen);
if (filelen<0) /* failed to read length */ if (filelen<0) /* failed to read length */
{ seterr(stream); { seterr(stream);
return 1; return 1;
} }
filepos = stream->__pos + EXTENT(stream) - stream->__base; filepos = stream->__extrap->__pos + EXTENT(stream) - stream->__base;
if (stream->__flag & _IOLAZY && filepos < stream->__extrap->_lspos) if (stream->__flag & _IOLAZY && filepos < stream->__extrap->_lspos)
filepos = stream->__extrap->_lspos; filepos = stream->__extrap->_lspos;
if (filepos>filelen) /* only possible on write */ if (filepos>filelen) /* only possible on write */
...@@ -1044,11 +1142,18 @@ default: ...@@ -1044,11 +1142,18 @@ default:
if (offset < 0) { seterr(stream); return 2; } /* fseek impossible */ if (offset < 0) { seterr(stream); return 2; } /* fseek impossible */
if (offset > limit)
{
seterr(stream);
errno = EOVERFLOW;
return 2;
}
if ((flag & _IONOREADS) && stream->__extrap->__extent < stream->__ptr) if ((flag & _IONOREADS) && stream->__extrap->__extent < stream->__ptr)
stream->__extrap->__extent = stream->__ptr; stream->__extrap->__extent = stream->__ptr;
dbmsg_noNL("%s ", "SEEK"); dbmsg_noNL("%s ", "SEEK");
dbmsg_noNL("__pos %d", (int)stream->__pos); dbmsg_noNL("__pos %lld", stream->__extrap->__pos);
dbmsg_noNL(" offset %d", (int)offset); dbmsg_noNL(" offset %d", (int)offset);
dbmsg_noNL(" buflim %d", stream->__extrap->__buflim); dbmsg_noNL(" buflim %d", stream->__extrap->__buflim);
dbmsg_noNL(" __ptr %X", (int)stream->__ptr); dbmsg_noNL(" __ptr %X", (int)stream->__ptr);
...@@ -1056,9 +1161,9 @@ dbmsg_noNL(" __icnt %d", stream->__icnt); ...@@ -1056,9 +1161,9 @@ dbmsg_noNL(" __icnt %d", stream->__icnt);
dbmsg_noNL(" __ocnt %d", stream->__ocnt); dbmsg_noNL(" __ocnt %d", stream->__ocnt);
dbmsg_noNL(" __base %X", (int)stream->__base); dbmsg_noNL(" __base %X", (int)stream->__base);
if (offset < stream->__pos || if (offset < stream->__extrap->__pos ||
offset > stream->__pos + EXTENT(stream) - stream->__base || offset > stream->__extrap->__pos + EXTENT(stream) - stream->__base ||
offset >= stream->__pos + stream->__extrap->__buflim) offset >= stream->__extrap->__pos + stream->__extrap->__buflim)
{ /* outside buffer */ { /* outside buffer */
dbmsg("%s\n", " outside buffer"); dbmsg("%s\n", " outside buffer");
...@@ -1067,7 +1172,7 @@ dbmsg("%s\n", " outside buffer"); ...@@ -1067,7 +1172,7 @@ dbmsg("%s\n", " outside buffer");
stream->__extrap->_lspos = offset; stream->__extrap->_lspos = offset;
} else { /* inside buffer */ } else { /* inside buffer */
dbmsg("%s\n", " inside buffer"); dbmsg("%s\n", " inside buffer");
offset -= stream->__pos; offset -= stream->__extrap->__pos;
if (flag & _IOWRITE) if (flag & _IOWRITE)
stream->__ocnt = -(stream->__extrap->__buflim - (int)offset); stream->__ocnt = -(stream->__extrap->__buflim - (int)offset);
if (flag & _IOREAD) if (flag & _IOREAD)
...@@ -1083,17 +1188,27 @@ dbmsg(" __ocnt %d\n", stream->__ocnt); ...@@ -1083,17 +1188,27 @@ dbmsg(" __ocnt %d\n", stream->__ocnt);
return 0; return 0;
} }
int fseek(FILE *stream, long int offset, int whence)
{
return fseek_common(stream, offset, whence, OFF32_MAX);
}
int fseeko64(FILE *stream, off64_t offset, int whence)
{
return fseek_common(stream, offset, whence, OFF64_MAX);
}
static int _do_fflush(FILE *stream) static int _do_fflush(FILE *stream)
{ /* ignore the effect of a previous unget on the file position indicator by { /* ignore the effect of a previous unget on the file position indicator by
using _ftell rather than ftell */ using _ftell rather than ftell */
if (stream->__flag & _IOREAD+_IOWRITE) /* not open */ if (stream->__flag & _IOREAD+_IOWRITE) /* not open */
{ long offset = _ftell(stream); { off64_t offset = _ftell(stream);
int res; int res;
dbmsg("%s\n", "fflush"); dbmsg("%s\n", "fflush");
if (stream->__flag & _IOLAZY) _deferredlazyseek(stream); if (stream->__flag & _IOLAZY) _deferredlazyseek(stream);
stream->__flag &= ~(_IONOREADS+_IONOWRITES); stream->__flag &= ~(_IONOREADS+_IONOWRITES);
res =_fflush(stream); res =_fflush(stream);
fseek(stream, offset, SEEK_SET); fseeko64(stream, offset, SEEK_SET);
return res; return res;
} else return 0; } else return 0;
} }
...@@ -1117,18 +1232,29 @@ int fflush(FILE *stream) ...@@ -1117,18 +1232,29 @@ int fflush(FILE *stream)
void rewind(FILE *stream) void rewind(FILE *stream)
{ {
fseek(stream, 0L, SEEK_SET); fseeko64(stream, 0LL, SEEK_SET);
clearerr(stream); clearerr(stream);
} }
/* the following routines need to become the main entry I suppose */ /* the following routines need to become the main entry I suppose */
int fgetpos(FILE *stream, fpos_t *pos) int fgetpos(FILE *stream, fpos_t *pos)
{ pos->__lo = ftell(stream); { *pos = ftell(stream);
return 0;
}
int fgetpos64(FILE *stream, fpos64_t *pos)
{ *pos = ftello64(stream);
return 0; return 0;
} }
int fsetpos(FILE *stream, const fpos_t *pos) int fsetpos(FILE *stream, const fpos_t *pos)
{ int res = fseek(stream, pos->__lo, SEEK_SET); { int res = fseek(stream, *pos, SEEK_SET);
if (res) errno = EDOM;
return res;
}
int fsetpos64(FILE *stream, const fpos64_t *pos)
{ int res = fseeko64(stream, *pos, SEEK_SET);
if (res) errno = EDOM; if (res) errno = EDOM;
return res; return res;
} }
...@@ -1157,6 +1283,7 @@ char *tmpnam(char *a) ...@@ -1157,6 +1283,7 @@ char *tmpnam(char *a)
return a; return a;
} }
extern char *__old_tmpnam(char *a);
char *__old_tmpnam(char *a) char *__old_tmpnam(char *a)
{ {
return tmpnam(a); return tmpnam(a);
...@@ -1174,6 +1301,18 @@ FILE *tmpfile(void) ...@@ -1174,6 +1301,18 @@ FILE *tmpfile(void)
return f; return f;
} }
FILE *tmpfile64(void)
{
char name[L_tmpnam];
FILE *f;
f = fopen64(tmpnam(name), "w+b");
if (f)
{ f->__flag |= _IODEL;
f->__signature = _tmp_file_sig;
}
return f;
}
void perror(const char *s) void perror(const char *s)
{ char b[256]; { char b[256];
if (s != 0 && *s != 0) fprintf(stderr, "%s: ", s); if (s != 0 && *s != 0) fprintf(stderr, "%s: ", s);
......
...@@ -536,6 +536,12 @@ char *_strerror(int n, char *v) ...@@ -536,6 +536,12 @@ char *_strerror(int n, char *v)
return _kernel_getmessage2("ERANGE - function result not representable", "C37", v, 80); return _kernel_getmessage2("ERANGE - function result not representable", "C37", v, 80);
case ESIGNUM: case ESIGNUM:
return _kernel_getmessage2("ESIGNUM - illegal signal number to signal() or raise()", "C66", v, 80); return _kernel_getmessage2("ESIGNUM - illegal signal number to signal() or raise()", "C66", v, 80);
case EILSEQ:
return _kernel_getmessage2("EILSEQ - character encoding error", "C74", v, 80);
case EOVERFLOW:
return _kernel_getmessage2("EOVERFLOW - too large for data structure", "C75", v, 80);
case EFBIG:
return _kernel_getmessage2("EFBIG - data written to file lost due to exceeding file size limit", "C76", v, 80);
default: default:
return _hostos_error_string(n, v); return _hostos_error_string(n, v);
} }
......
No preview for this file type
...@@ -57,6 +57,7 @@ extern volatile int errno; ...@@ -57,6 +57,7 @@ extern volatile int errno;
* acquires the value of the macro EDOM and HUGE_VAL is returned. EDOM may * acquires the value of the macro EDOM and HUGE_VAL is returned. EDOM may
* be used by non-mathematical functions. * be used by non-mathematical functions.
*/ */
#define ERANGE 2 #define ERANGE 2
/* /*
* a range error occurs if the result of a function can not be represented * a range error occurs if the result of a function can not be represented
...@@ -70,7 +71,33 @@ extern volatile int errno; ...@@ -70,7 +71,33 @@ extern volatile int errno;
* integer expression errno acquires the value of the macro ERANGE. ERANGE * integer expression errno acquires the value of the macro ERANGE. ERANGE
* may be used by non-mathematical functions. * may be used by non-mathematical functions.
*/ */
#define ESIGNUM 3 #define ESIGNUM 3
/*
* a signal number error occurs if an unrecognised signal number is passed
* to signal() or raise().
*/
#define EILSEQ 4
/*
* an illegal sequence error indicates that a multibyte character encoding
* error has been detected.
*/
#define EOVERFLOW 5
/*
* an overflow error occurs if one or more fields of a data structure is
* not large enough to hold the values required - for example, if you
* attempt to open a file with fopen() whose size cannot be expressed using
* an object of type off_t.
*/
#define EFBIG 6
/*
* a big file error occurs if a file is unbuffered or the file's buffer
* needs to be flushed, and this would have resulted in a write occurring
* at or beyond the maximum file pointer for this file descriptor.
*/
#endif #endif
......
...@@ -44,14 +44,45 @@ typedef char *__va_list[1]; /* keep in step with <stdarg.h> */ ...@@ -44,14 +44,45 @@ typedef char *__va_list[1]; /* keep in step with <stdarg.h> */
# define NULL 0 /* see <stddef.h> */ # define NULL 0 /* see <stddef.h> */
#endif #endif
typedef struct __fpos_t_struct typedef long int _off_t;
{ unsigned long __lo; /* add hi one day */ #ifdef __STDC__
} fpos_t; typedef long long int _off64_t;
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 32
#endif
#if defined(__STDC__) && _FILE_OFFSET_BITS == 64
typedef _off64_t fpos_t;
#elif _FILE_OFFSET_BITS == 32
typedef _off_t fpos_t;
#else
#error Unsupported _FILE_OFFSET_BITS value
#endif
/* /*
* fpos_t is an object capable of recording all information needed to * fpos_t is an object capable of recording all information needed to
* specify uniquely every position within a file. * specify uniquely every position within a file.
*/ */
#if defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)
typedef fpos_t off_t;
#endif
/*
* off_t is an object capable of recording the offset from any position
* within a file to any other position within that file, and is used by
* the LFS extension functions fseeko() and fello().
*/
#if defined(__STDC__) && defined(_LARGEFILE64_SOURCE)
typedef _off64_t fpos64_t, off64_t;
#endif
/*
* fpos64_t and of64_t are the equivalent of fpos_t and off_t respectively,
* and are used in their place when an application explicitly uses the
* 64-bit LFS extension functions fgetpo64(), fseeko64(), fsetpos64() and
* ftello64().
*/
typedef struct __FILE_struct typedef struct __FILE_struct
{ unsigned char *__ptr; { unsigned char *__ptr;
int __icnt; /* two separate _cnt fields so we can police ... */ int __icnt; /* two separate _cnt fields so we can police ... */
...@@ -61,7 +92,7 @@ typedef struct __FILE_struct ...@@ -61,7 +92,7 @@ typedef struct __FILE_struct
/* are invisible in an ANSI-conforming program. */ /* are invisible in an ANSI-conforming program. */
unsigned char *__base; /* buffer base */ unsigned char *__base; /* buffer base */
int __file; /* RISCOS/Arthur/Brazil file handle */ int __file; /* RISCOS/Arthur/Brazil file handle */
long __pos; /* position in file */ long __unused; /* used to contain 32-bit file pointer */
int __bufsiz; /* maximum buffer size */ int __bufsiz; /* maximum buffer size */
int __signature; /* used with temporary files */ int __signature; /* used with temporary files */
struct __extradata *__extrap; /* pointer to information about stream */ struct __extradata *__extrap; /* pointer to information about stream */
...@@ -172,6 +203,15 @@ int rename(const char * /*old*/, const char * /*new*/); ...@@ -172,6 +203,15 @@ int rename(const char * /*old*/, const char * /*new*/);
* original name. * original name.
*/ */
FILE *tmpfile(void); FILE *tmpfile(void);
#ifdef __STDC__
FILE *_tmpfile64(void);
#if _FILE_OFFSET_BITS == 64
#define tmpfile _tmpfile64
#endif
#ifdef _LARGEFILE64_SOURCE
#define tmpfile64 _tmpfile64
#endif
#endif
/* /*
* creates a temporary binary file that will be automatically removed when * creates a temporary binary file that will be automatically removed when
* it is closed or at program termination. The file is opened for update. * it is closed or at program termination. The file is opened for update.
...@@ -222,6 +262,16 @@ int fflush(FILE * /*stream*/); ...@@ -222,6 +262,16 @@ int fflush(FILE * /*stream*/);
*/ */
FILE *fopen(const char * restrict /*filename*/, FILE *fopen(const char * restrict /*filename*/,
const char * restrict /*mode*/); const char * restrict /*mode*/);
#ifdef __STDC__
FILE *_fopen64(const char * restrict /*filename*/,
const char * restrict /*mode*/);
#if _FILE_OFFSET_BITS == 64
#define fopen _fopen64
#endif
#ifdef _LARGEFILE64_SOURCE
#define fopen64 _fopen64
#endif
#endif
/* /*
* opens the file whose name is the string pointed to by filename, and * opens the file whose name is the string pointed to by filename, and
* associates a stream with it. * associates a stream with it.
...@@ -267,6 +317,17 @@ FILE *fopen(const char * restrict /*filename*/, ...@@ -267,6 +317,17 @@ FILE *fopen(const char * restrict /*filename*/,
FILE *freopen(const char * restrict /*filename*/, FILE *freopen(const char * restrict /*filename*/,
const char * restrict /*mode*/, const char * restrict /*mode*/,
FILE * restrict /*stream*/); FILE * restrict /*stream*/);
#ifdef __STDC__
FILE *_freopen64(const char * restrict /*filename*/,
const char * restrict /*mode*/,
FILE * restrict /*stream*/);
#if _FILE_OFFSET_BITS == 64
#define freopen _freopen64
#endif
#ifdef _LARGEFILE64_SOURCE
#define freopen64 _freopen64
#endif
#endif
/* /*
* opens the file whose name is the string pointed to by filename and * opens the file whose name is the string pointed to by filename and
* associates the stream pointed to by stream with it. The mode argument is * associates the stream pointed to by stream with it. The mode argument is
...@@ -659,7 +720,16 @@ size_t fwrite(const void * restrict /*ptr*/, ...@@ -659,7 +720,16 @@ size_t fwrite(const void * restrict /*ptr*/,
* than nmemb only if a write error is encountered. * than nmemb only if a write error is encountered.
*/ */
int fgetpos(FILE * restrict /*stream*/, fpos_t * restrict /*pos*/); int fgetpos(FILE * restrict /*stream*/, _off_t * restrict /*pos*/);
#ifdef __STDC__
int _fgetpos64(FILE * restrict /*stream*/, _off64_t * restrict /*pos*/);
#if _FILE_OFFSET_BITS == 64
#define fgetpos _fgetpos64
#endif
#ifdef _LARGEFILE64_SOURCE
#define fgetpos64 _fgetpos64
#endif
#endif
/* /*
* stores the current value of the file position indicator for the stream * stores the current value of the file position indicator for the stream
* pointed to by stream in the object pointed to by pos. The value stored * pointed to by stream in the object pointed to by pos. The value stored
...@@ -671,6 +741,20 @@ int fgetpos(FILE * restrict /*stream*/, fpos_t * restrict /*pos*/); ...@@ -671,6 +741,20 @@ int fgetpos(FILE * restrict /*stream*/, fpos_t * restrict /*pos*/);
* nonzero value (under RISCOS/Arthur/Brazil fgetpos cannot fail). * nonzero value (under RISCOS/Arthur/Brazil fgetpos cannot fail).
*/ */
int fseek(FILE * /*stream*/, long int /*offset*/, int /*whence*/); int fseek(FILE * /*stream*/, long int /*offset*/, int /*whence*/);
int _fseeko(FILE * /*stream*/, _off_t /*offset*/, int /*whence*/);
#if defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)
#if _FILE_OFFSET_BITS == 64
#define fseeko _fseeko64
#else
#define fseeko _fseeko
#endif
#endif
#ifdef __STDC__
int _fseeko64(FILE * /*stream*/, _off64_t /*offset*/, int /*whence*/);
#ifdef _LARGEFILE64_SOURCE
#define fseeko64 _fseeko64
#endif
#endif
/* /*
* sets the file position indicator for the stream pointed to by stream. * sets the file position indicator for the stream pointed to by stream.
* For a binary stream, the new position is at the signed number of * For a binary stream, the new position is at the signed number of
...@@ -687,7 +771,16 @@ int fseek(FILE * /*stream*/, long int /*offset*/, int /*whence*/); ...@@ -687,7 +771,16 @@ int fseek(FILE * /*stream*/, long int /*offset*/, int /*whence*/);
* the next operation on an update stream may be either input or output. * the next operation on an update stream may be either input or output.
* Returns: nonzero only for a request that cannot be satisfied. * Returns: nonzero only for a request that cannot be satisfied.
*/ */
int fsetpos(FILE * /*stream*/, const fpos_t * /*pos*/); int fsetpos(FILE * /*stream*/, const _off_t * /*pos*/);
#ifdef __STDC__
int _fsetpos64(FILE * /*stream*/, const _off64_t * /*pos*/);
#if _FILE_OFFSET_BITS == 64
#define fsetpos _fsetpos64
#endif
#ifdef _LARGEFILE64_SOURCE
#define fsetpos64 _fsetpos64
#endif
#endif
/* /*
* sets the file position indicator for the stream pointed to by stream * sets the file position indicator for the stream pointed to by stream
* according to the value of the object pointed to by pos, which shall be a * according to the value of the object pointed to by pos, which shall be a
...@@ -702,6 +795,20 @@ int fsetpos(FILE * /*stream*/, const fpos_t * /*pos*/); ...@@ -702,6 +795,20 @@ int fsetpos(FILE * /*stream*/, const fpos_t * /*pos*/);
* in math.h). * in math.h).
*/ */
long int ftell(FILE * /*stream*/); long int ftell(FILE * /*stream*/);
_off_t _ftello(FILE * /*stream*/);
#if defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)
#if _FILE_OFFSET_BITS == 64
#define ftello _ftello64
#else
#define ftello _ftello
#endif
#endif
#ifdef __STDC__
_off64_t _ftello64(FILE * /*stream*/);
#ifdef _LARGEFILE64_SOURCE
#define ftello64 _ftello64
#endif
#endif
/* /*
* obtains the current value of the file position indicator for the stream * obtains the current value of the file position indicator for the stream
* pointed to by stream. For a binary stream, the value is the number of * pointed to by stream. For a binary stream, the value is the number of
......
...@@ -255,6 +255,10 @@ char *strerror(int /*errnum*/); ...@@ -255,6 +255,10 @@ char *strerror(int /*errnum*/);
* EDOM "EDOM - function argument out of range" * EDOM "EDOM - function argument out of range"
* ERANGE "ERANGE - function result not representable" * ERANGE "ERANGE - function result not representable"
* ESIGNUM "ESIGNUM - illegal signal number to signal() or raise()" * ESIGNUM "ESIGNUM - illegal signal number to signal() or raise()"
* EILSEQ "EILSEQ - character encoding error"
* EOVERFLOW "EOVERFLOW - too large for data structure"
* EFBIG "EFBIG - data written to file lost due to exceeding
* file size limit"
* -1 Error message from _kernel_lastoserror(), if any, * -1 Error message from _kernel_lastoserror(), if any,
* else "unspecified error" * else "unspecified error"
* others "unknown error" * others "unknown error"
......
...@@ -150,12 +150,12 @@ $Label ...@@ -150,12 +150,12 @@ $Label
EXPORT |_ldfp| EXPORT |_ldfp|
EXPORT |_stfp| EXPORT |_stfp|
EXPORT |__fpclassifyf| EXPORT |__fpclassifyf| [FPREGARGS]
EXPORT |__fpclassifyd| EXPORT |__fpclassifyd| [FPREGARGS]
EXPORT |__signbitf| EXPORT |__signbitf| [FPREGARGS]
EXPORT |__signbitd| EXPORT |__signbitd| [FPREGARGS]
EXPORT |__copysignf| EXPORT |__copysignf| [FPREGARGS]
EXPORT |__copysignd| EXPORT |__copysignd| [FPREGARGS]
EXPORT copysign EXPORT copysign
EXPORT copysignf EXPORT copysignf
EXPORT nextafter EXPORT nextafter
...@@ -237,7 +237,7 @@ $Label ...@@ -237,7 +237,7 @@ $Label
BL |_lib_shutdown| BL |_lib_shutdown|
MOV a1, #0 MOV a1, #0
BL |_exit| BL |_exit|
LDMFD sp!, {r1} ; free the RMA block addressed by LDR r1, [sp], #4 ; free the RMA block addressed by
MOV r0, #Module_Free ; our private word. MOV r0, #Module_Free ; our private word.
LDR r2, [r1] LDR r2, [r1]
MOV r3, #0 MOV r3, #0
...@@ -267,9 +267,9 @@ EventHandler Keep ...@@ -267,9 +267,9 @@ EventHandler Keep
MOV a1, #SIGINT MOV a1, #SIGINT
STRNE a1, [ip, #O__saved_interrupt] STRNE a1, [ip, #O__saved_interrupt]
BNE %FT01 BNE %FT01
STMFD sp!, {r14} STR r14, [sp, #-4]!
BL raise BL raise
LDMFD sp!, {r14} LDR r14, [sp], #4
01 MOV a1, #1 ; we wish to handle it, but not just yet 01 MOV a1, #1 ; we wish to handle it, but not just yet
Return ,LinkNotStacked Return ,LinkNotStacked
...@@ -284,9 +284,9 @@ UnhandledEventHandler Keep ...@@ -284,9 +284,9 @@ UnhandledEventHandler Keep
MOV a1, #SIGINT MOV a1, #SIGINT
STRNE a1, [ip, #O__saved_interrupt] STRNE a1, [ip, #O__saved_interrupt]
BNE %FT02 BNE %FT02
STMFD sp!, {r14} STR r14, [sp, #-4]!
BL raise BL raise
LDMFD sp!, {r14} LDR r14, [sp], #4
02 MOV a1, #1 ; we wish to handle it, but not just yet 02 MOV a1, #1 ; we wish to handle it, but not just yet
Return ,LinkNotStacked Return ,LinkNotStacked
...@@ -343,7 +343,7 @@ TrapHandler Keep ...@@ -343,7 +343,7 @@ TrapHandler Keep
MOV a4, a1 MOV a4, a1
STMFD sp!, {a2, a4, r14} STMFD sp!, {a2, a4, r14}
BL SignalNumber BL SignalNumber
STMFD sp!, {a1} STR a1, [sp, #-4]!
BL |_signal_real_handler| BL |_signal_real_handler|
CMP a1, #0 CMP a1, #0
LDMFD sp!, {a1, a2, a4, r14} LDMFD sp!, {a1, a2, a4, r14}
...@@ -403,7 +403,7 @@ llabs ...@@ -403,7 +403,7 @@ llabs
; test for division by zero (used when division is voided) ; test for division by zero (used when division is voided)
TEQS a1, #0 TEQS a1, #0
Return ,LinkNotStacked, NE Return ,LinkNotStacked, NE
STMFD sp!, {r0} STR r0, [sp, #-4]!
ADR r0, E_DivideByZero ADR r0, E_DivideByZero
B |_kernel_fault| B |_kernel_fault|
...@@ -482,14 +482,14 @@ llabs ...@@ -482,14 +482,14 @@ llabs
Return ,,CC Return ,,CC
; and drop into writefail ; and drop into writefail
writefail writefail
LDMFD sp!, {lr} LDR lr, [sp], #4
STMFD sp!, {r0} STR r0, [sp, #-4]!
ADR r0, E_WriteFail ADR r0, E_WriteFail
B |_kernel_fault| B |_kernel_fault|
readfail readfail
LDMFD sp!, {lr} LDR lr, [sp], #4
STMFD sp!, {r0} STR r0, [sp, #-4]!
ADR r0, E_ReadFail ADR r0, E_ReadFail
B |_kernel_fault| B |_kernel_fault|
...@@ -523,8 +523,8 @@ readfail ...@@ -523,8 +523,8 @@ readfail
Return "v1" Return "v1"
NOOP NOOP
LDMIA a2!, {a4} LDR a4, [a2], #4
STMIA a1!, {a4} STR a4, [a1], #4
Return "v1" Return "v1"
; Note that the number of instructions is critical for the SUBLT ; Note that the number of instructions is critical for the SUBLT
...@@ -545,7 +545,7 @@ readfail ...@@ -545,7 +545,7 @@ readfail
STMIA a1!, {a2, a4} STMIA a1!, {a2, a4}
Return Return
STMIA a1!, {a4} STR a4, [a1], #4
Return Return
mesg DCB "mesg" mesg DCB "mesg"
...@@ -598,7 +598,7 @@ postmortem1 ...@@ -598,7 +598,7 @@ postmortem1
postmortem2 postmortem2
LDMFD sp!, {r0-r5} LDMFD sp!, {r0-r5}
BL |_kernel_fpavailable| BL |_kernel_fpavailable|
LDMFD sp!, {r14} LDR r14, [sp], #4
CMP a1, #0 CMP a1, #0
MOV ip, sp MOV ip, sp
SUBEQ sp, sp, #12*4 SUBEQ sp, sp, #12*4
...@@ -731,7 +731,13 @@ sj_f7 # 3*4 ...@@ -731,7 +731,13 @@ sj_f7 # 3*4
STMIA a1, {sl, lr} STMIA a1, {sl, lr}
SUB v1, a1, #sj_sl SUB v1, a1, #sj_sl
| |
[ {FALSE} ; this instruction is now deprecated
STMIA a1, {v1-v6, sl, fp, sp, lr} STMIA a1, {v1-v6, sl, fp, sp, lr}
|
STMIA a1!, {v1-v6, sl, fp}
STR lr, [a1, #sj_pc - sj_sp]
STR sp, [a1], #-sj_sp
]
MOV v1, a1 MOV v1, a1
] ]
MOV v2, lr MOV v2, lr
...@@ -775,7 +781,13 @@ sj_f7 # 3*4 ...@@ -775,7 +781,13 @@ sj_f7 # 3*4
LDMFD sp, {sl, fp, sp} LDMFD sp, {sl, fp, sp}
| |
LFMNE f4, 4, [v1, #sj_f4-sj_f4] LFMNE f4, 4, [v1, #sj_f4-sj_f4]
[ {FALSE} ; this instruction is now deprecated
LDMDB v1!, {sl, fp, sp, lr} LDMDB v1!, {sl, fp, sp, lr}
|
LDR lr, [v1, #sj_pc - sj_f4]!
LDR sp, [v1, #sj_sp - sj_pc]!
LDMDB v1!, {sl, fp}
]
MOV v5, lr MOV v5, lr
] ]
...@@ -829,12 +841,12 @@ chunks_deallocated ...@@ -829,12 +841,12 @@ chunks_deallocated
|_osgbpb| |_osgbpb|
STMFD sp!, {a3, a4, v1, v2, v3} ; v1-v3 just to reserve space STMFD sp!, {a3, a4, v1, v2, v3} ; v1-v3 just to reserve space
STMFD sp!, {r14} STR r14, [sp, #-4]!
ADD a3, sp, #4 ADD a3, sp, #4
BL |_kernel_osgbpb| BL |_kernel_osgbpb|
CMP a1, #-2 CMP a1, #-2
LDRNE a1, [sp, #8] ; new value of len LDRNE a1, [sp, #8] ; new value of len
LDMFD sp!, {r14} LDR r14, [sp], #4
ADD sp, sp, #5*4 ADD sp, sp, #5*4
Return ,LinkNotStacked Return ,LinkNotStacked
...@@ -852,10 +864,10 @@ chunks_deallocated ...@@ -852,10 +864,10 @@ chunks_deallocated
|_osfile| |_osfile|
STMFD sp!, {a3, a4, v1, v2} ; v1,v2 just to reserve space STMFD sp!, {a3, a4, v1, v2} ; v1,v2 just to reserve space
STMFD sp!, {r14} STR r14, [sp, #-4]!
ADD a3, sp, #4 ADD a3, sp, #4
BL |_kernel_osfile| BL |_kernel_osfile|
LDMFD sp!, {r14} LDR r14, [sp], #4
ADD sp, sp, #4*4 ADD sp, sp, #4*4
Return ,LinkNotStacked Return ,LinkNotStacked
...@@ -1199,7 +1211,7 @@ fmax ...@@ -1199,7 +1211,7 @@ fmax
BVS fcmpnan BVS fcmpnan
Return ,LinkNotStacked,NE Return ,LinkNotStacked,NE
; Values are equal. Anding the sign bits will give nice behaviour ; Values are equal. Anding the sign bits will give nice behaviour
; for fmax(0, 0). ; for fmax(0, 0).
[ FloatingPointArgsInRegs [ FloatingPointArgsInRegs
STFD f1, [sp, #-8]! STFD f1, [sp, #-8]!
STFD f0, [sp, #-8]! STFD f0, [sp, #-8]!
...@@ -1252,7 +1264,7 @@ fmin ...@@ -1252,7 +1264,7 @@ fmin
BVS fcmpnan BVS fcmpnan
Return ,LinkNotStacked,NE Return ,LinkNotStacked,NE
; Values are equal. Oring the sign bits will give nice behaviour ; Values are equal. Oring the sign bits will give nice behaviour
; for fmin(0, 0). ; for fmin(0, 0).
[ FloatingPointArgsInRegs [ FloatingPointArgsInRegs
STFD f1, [sp, #-8]! STFD f1, [sp, #-8]!
STFD f0, [sp, #-8]! STFD f0, [sp, #-8]!
......
...@@ -142,9 +142,9 @@ ...@@ -142,9 +142,9 @@
Entry fread, imported , , , 4 Entry fread, imported , , , 4
Entry fwrite, imported , , , 4 Entry fwrite, imported , , , 4
Entry fgetpos, imported , , , 2 Entry fgetpos, imported , , , 2
Entry fseek, imported , , , 3 Entry2 fseek, imported , , , 3, , _fseeko
Entry fsetpos, imported , , , 2 Entry fsetpos, imported , , , 2
Entry ftell, imported , , , 1 Entry2 ftell, imported , , , 1, , _ftello
Entry rewind, imported , , , 1 Entry rewind, imported , , , 1
Entry clearerr, imported , , , 1 Entry clearerr, imported , , , 1
Entry feof, imported , , , 1 Entry feof, imported , , , 1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment