Merge "Support _FILE_OFFSET_BITS=64 for most of <stdio.h>." am: 94bb0fab93
am: 1500a65adb
* commit '1500a65adbd7cd18c7bb6d0282947cd44dc76ef6':
Support _FILE_OFFSET_BITS=64 for most of <stdio.h>.
This commit is contained in:
commit
c217342f36
13 changed files with 182 additions and 48 deletions
|
@ -49,7 +49,8 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
typedef off_t fpos_t; /* stdio file position type */
|
||||
typedef off_t fpos_t;
|
||||
typedef off64_t fpos64_t;
|
||||
|
||||
struct __sFILE;
|
||||
typedef struct __sFILE FILE;
|
||||
|
@ -118,8 +119,6 @@ FILE *freopen(const char * __restrict, const char * __restrict,
|
|||
FILE * __restrict);
|
||||
int fscanf(FILE * __restrict, const char * __restrict, ...)
|
||||
__scanflike(2, 3);
|
||||
int fseek(FILE *, long, int);
|
||||
long ftell(FILE *);
|
||||
size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict);
|
||||
int getc(FILE *);
|
||||
int getchar(void);
|
||||
|
@ -166,25 +165,26 @@ char* tempnam(const char*, const char*)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
extern int rename(const char*, const char*);
|
||||
extern int renameat(int, const char*, int, const char*);
|
||||
int rename(const char*, const char*);
|
||||
int renameat(int, const char*, int, const char*);
|
||||
|
||||
int fseek(FILE*, long, int);
|
||||
long ftell(FILE*);
|
||||
#if defined(__USE_FILE_OFFSET64)
|
||||
/* Not possible. */
|
||||
int fgetpos(FILE * __restrict, fpos_t * __restrict)
|
||||
__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
|
||||
int fsetpos(FILE *, const fpos_t *)
|
||||
__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
|
||||
int fseeko(FILE *, off_t, int)
|
||||
__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
|
||||
off_t ftello(FILE *)
|
||||
__attribute__((__error__("not available with _FILE_OFFSET_BITS=64")));
|
||||
int fgetpos(FILE*, fpos_t*) __RENAME(fgetpos64);
|
||||
int fsetpos(FILE*, const fpos_t*) __RENAME(fsetpos64);
|
||||
int fseeko(FILE*, off_t, int) __RENAME(fseeko64);
|
||||
off_t ftello(FILE*) __RENAME(ftello64);
|
||||
#else
|
||||
int fgetpos(FILE * __restrict, fpos_t * __restrict);
|
||||
int fsetpos(FILE *, const fpos_t *);
|
||||
int fseeko(FILE *, off_t, int);
|
||||
off_t ftello(FILE *);
|
||||
int fgetpos(FILE*, fpos_t*);
|
||||
int fsetpos(FILE*, const fpos_t*);
|
||||
int fseeko(FILE*, off_t, int);
|
||||
off_t ftello(FILE*);
|
||||
#endif
|
||||
int fgetpos64(FILE*, fpos64_t*);
|
||||
int fsetpos64(FILE*, const fpos64_t*);
|
||||
int fseeko64(FILE*, off64_t, int);
|
||||
off64_t ftello64(FILE*);
|
||||
|
||||
#if __ISO_C_VISIBLE >= 1999 || __BSD_VISIBLE
|
||||
int snprintf(char * __restrict, size_t, const char * __restrict, ...)
|
||||
|
@ -256,6 +256,7 @@ int fileno_unlocked(FILE*);
|
|||
|
||||
/*
|
||||
* Stdio function-access interface.
|
||||
* TODO: __USE_FILE_OFFSET64
|
||||
*/
|
||||
FILE *funopen(const void *,
|
||||
int (*)(void *, char *, int),
|
||||
|
|
|
@ -1228,8 +1228,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1228,8 +1228,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1152,8 +1152,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1255,8 +1255,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1213,8 +1213,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1213,8 +1213,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1152,8 +1152,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1212,8 +1212,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1212,8 +1212,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -1152,8 +1152,11 @@ LIBC_N {
|
|||
__pwrite_chk;
|
||||
__pwrite64_chk;
|
||||
__write_chk;
|
||||
fgetpos64;
|
||||
fileno_unlocked;
|
||||
freeifaddrs;
|
||||
fseeko64;
|
||||
fsetpos64;
|
||||
getgrgid_r;
|
||||
getgrnam_r;
|
||||
getifaddrs;
|
||||
|
|
|
@ -433,11 +433,10 @@ static off64_t __seek_unlocked(FILE* fp, off64_t offset, int whence) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: _FILE_OFFSET_BITS=64.
|
||||
static off_t __ftello_unlocked(FILE* fp) {
|
||||
static off64_t __ftello64_unlocked(FILE* fp) {
|
||||
// Find offset of underlying I/O object, then adjust for buffered bytes.
|
||||
__sflush(fp); // May adjust seek offset on append stream.
|
||||
fpos_t result = __seek_unlocked(fp, 0, SEEK_CUR);
|
||||
off64_t result = __seek_unlocked(fp, 0, SEEK_CUR);
|
||||
if (result == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -457,29 +456,34 @@ static off_t __ftello_unlocked(FILE* fp) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// TODO: _FILE_OFFSET_BITS=64.
|
||||
int fseeko(FILE* fp, off_t offset, int whence) {
|
||||
int __fseeko64(FILE* fp, off64_t offset, int whence, int off_t_bits) {
|
||||
ScopedFileLock sfl(fp);
|
||||
|
||||
// Change any SEEK_CUR to SEEK_SET, and check `whence` argument.
|
||||
// After this, whence is either SEEK_SET or SEEK_END.
|
||||
if (whence == SEEK_CUR) {
|
||||
fpos_t current_offset = __ftello_unlocked(fp);
|
||||
fpos64_t current_offset = __ftello64_unlocked(fp);
|
||||
if (current_offset == -1) {
|
||||
return EOF;
|
||||
return -1;
|
||||
}
|
||||
offset += current_offset;
|
||||
whence = SEEK_SET;
|
||||
} else if (whence != SEEK_SET && whence != SEEK_END) {
|
||||
errno = EINVAL;
|
||||
return EOF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If our caller has a 32-bit interface, refuse to go past a 32-bit file offset.
|
||||
if (off_t_bits == 32 && offset > LONG_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fp->_bf._base == NULL) __smakebuf(fp);
|
||||
|
||||
// Flush unwritten data and attempt the seek.
|
||||
if (__sflush(fp) || __seek_unlocked(fp, offset, whence) == -1) {
|
||||
return EOF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Success: clear EOF indicator and discard ungetc() data.
|
||||
|
@ -491,34 +495,46 @@ int fseeko(FILE* fp, off_t offset, int whence) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// TODO: _FILE_OFFSET_BITS=64.
|
||||
int fseek(FILE* fp, long offset, int whence) {
|
||||
return fseeko(fp, offset, whence);
|
||||
int fseeko(FILE* fp, off_t offset, int whence) {
|
||||
static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
|
||||
return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
|
||||
}
|
||||
__strong_alias(fseek, fseeko);
|
||||
|
||||
int fseeko64(FILE* fp, off64_t offset, int whence) {
|
||||
return __fseeko64(fp, offset, whence, 8*sizeof(off_t));
|
||||
}
|
||||
|
||||
int fsetpos(FILE* fp, const fpos_t* pos) {
|
||||
return fseeko(fp, *pos, SEEK_SET);
|
||||
}
|
||||
|
||||
int fsetpos64(FILE* fp, const fpos64_t* pos) {
|
||||
return fseeko64(fp, *pos, SEEK_SET);
|
||||
}
|
||||
|
||||
// TODO: _FILE_OFFSET_BITS=64.
|
||||
off_t ftello(FILE* fp) {
|
||||
ScopedFileLock sfl(fp);
|
||||
return __ftello_unlocked(fp);
|
||||
}
|
||||
|
||||
// TODO: _FILE_OFFSET_BITS=64
|
||||
long ftell(FILE* fp) {
|
||||
off_t offset = ftello(fp);
|
||||
if (offset > LONG_MAX) {
|
||||
static_assert(sizeof(off_t) == sizeof(long), "sizeof(off_t) != sizeof(long)");
|
||||
off64_t result = ftello64(fp);
|
||||
if (result > LONG_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
return offset;
|
||||
return result;
|
||||
}
|
||||
__strong_alias(ftell, ftello);
|
||||
|
||||
off64_t ftello64(FILE* fp) {
|
||||
ScopedFileLock sfl(fp);
|
||||
return __ftello64_unlocked(fp);
|
||||
}
|
||||
|
||||
// TODO: _FILE_OFFSET_BITS=64
|
||||
int fgetpos(FILE* fp, fpos_t* pos) {
|
||||
*pos = ftello(fp);
|
||||
return (*pos == -1);
|
||||
}
|
||||
|
||||
// TODO: _FILE_OFFSET_BITS=64
|
||||
int fsetpos(FILE* fp, const fpos_t* pos) {
|
||||
return fseeko(fp, *pos, SEEK_SET);
|
||||
int fgetpos64(FILE* fp, fpos64_t* pos) {
|
||||
*pos = ftello64(fp);
|
||||
return (*pos == -1);
|
||||
}
|
||||
|
|
|
@ -280,7 +280,7 @@ TEST(STDIO_TEST, snprintf_n) {
|
|||
EXPECT_EQ(1234, i);
|
||||
EXPECT_STREQ("a n b", buf);
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
GTEST_LOG_(INFO) << "This test does nothing on glibc.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -831,7 +831,7 @@ TEST(STDIO_TEST, open_memstream_EINVAL) {
|
|||
ASSERT_EQ(nullptr, open_memstream(&p, nullptr));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||
GTEST_LOG_(INFO) << "This test does nothing on glibc.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -962,7 +962,7 @@ static void test_fwrite_after_fread(size_t n) {
|
|||
|
||||
// But hitting EOF doesn't prevent us from writing...
|
||||
errno = 0;
|
||||
ASSERT_EQ(1U, fwrite("2", 1, 1, fp)) << errno;
|
||||
ASSERT_EQ(1U, fwrite("2", 1, 1, fp)) << strerror(errno);
|
||||
|
||||
// And if we rewind, everything's there.
|
||||
rewind(fp);
|
||||
|
@ -1011,7 +1011,7 @@ TEST(STDIO_TEST, fread_after_fseek) {
|
|||
ASSERT_EQ(memcmp(file_data+cur_location, buffer, 8192), 0);
|
||||
|
||||
// Small backwards seek to verify fseek does not reuse the internal buffer.
|
||||
ASSERT_EQ(0, fseek(fp, -22, SEEK_CUR));
|
||||
ASSERT_EQ(0, fseek(fp, -22, SEEK_CUR)) << strerror(errno);
|
||||
cur_location = static_cast<size_t>(ftell(fp));
|
||||
ASSERT_EQ(22U, fread(buffer, 1, 22, fp));
|
||||
ASSERT_EQ(memcmp(file_data+cur_location, buffer, 22), 0);
|
||||
|
@ -1121,3 +1121,90 @@ TEST(STDIO_TEST, lots_of_concurrent_files) {
|
|||
delete tfs[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void AssertFileOffsetAt(FILE* fp, off64_t offset) {
|
||||
EXPECT_EQ(offset, ftell(fp));
|
||||
EXPECT_EQ(offset, ftello(fp));
|
||||
fpos_t pos;
|
||||
fpos64_t pos64;
|
||||
EXPECT_EQ(0, fgetpos(fp, &pos));
|
||||
EXPECT_EQ(0, fgetpos64(fp, &pos64));
|
||||
#if defined(__BIONIC__)
|
||||
EXPECT_EQ(offset, static_cast<off64_t>(pos));
|
||||
EXPECT_EQ(offset, static_cast<off64_t>(pos64));
|
||||
#else
|
||||
GTEST_LOG_(INFO) << "glibc's fpos_t is opaque.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(STDIO_TEST, seek_tell_family_smoke) {
|
||||
TemporaryFile tf;
|
||||
FILE* fp = fdopen(tf.fd, "w+");
|
||||
|
||||
// Initially we should be at 0.
|
||||
AssertFileOffsetAt(fp, 0);
|
||||
|
||||
// Seek to offset 8192.
|
||||
ASSERT_EQ(0, fseek(fp, 8192, SEEK_SET));
|
||||
AssertFileOffsetAt(fp, 8192);
|
||||
fpos_t eight_k_pos;
|
||||
ASSERT_EQ(0, fgetpos(fp, &eight_k_pos));
|
||||
|
||||
// Seek forward another 8192...
|
||||
ASSERT_EQ(0, fseek(fp, 8192, SEEK_CUR));
|
||||
AssertFileOffsetAt(fp, 8192 + 8192);
|
||||
fpos64_t sixteen_k_pos64;
|
||||
ASSERT_EQ(0, fgetpos64(fp, &sixteen_k_pos64));
|
||||
|
||||
// Seek back 8192...
|
||||
ASSERT_EQ(0, fseek(fp, -8192, SEEK_CUR));
|
||||
AssertFileOffsetAt(fp, 8192);
|
||||
|
||||
// Since we haven't written anything, the end is also at 0.
|
||||
ASSERT_EQ(0, fseek(fp, 0, SEEK_END));
|
||||
AssertFileOffsetAt(fp, 0);
|
||||
|
||||
// Check that our fpos64_t from 16KiB works...
|
||||
ASSERT_EQ(0, fsetpos64(fp, &sixteen_k_pos64));
|
||||
AssertFileOffsetAt(fp, 8192 + 8192);
|
||||
// ...as does our fpos_t from 8192.
|
||||
ASSERT_EQ(0, fsetpos(fp, &eight_k_pos));
|
||||
AssertFileOffsetAt(fp, 8192);
|
||||
|
||||
// Do fseeko and fseeko64 work too?
|
||||
ASSERT_EQ(0, fseeko(fp, 1234, SEEK_SET));
|
||||
AssertFileOffsetAt(fp, 1234);
|
||||
ASSERT_EQ(0, fseeko64(fp, 5678, SEEK_SET));
|
||||
AssertFileOffsetAt(fp, 5678);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
TEST(STDIO_TEST, fseek_fseeko_EINVAL) {
|
||||
TemporaryFile tf;
|
||||
FILE* fp = fdopen(tf.fd, "w+");
|
||||
|
||||
// Bad whence.
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, fseek(fp, 0, 123));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, fseeko(fp, 0, 123));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, fseeko64(fp, 0, 123));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
|
||||
// Bad offset.
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, fseek(fp, -1, SEEK_SET));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, fseeko(fp, -1, SEEK_SET));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, fseeko64(fp, -1, SEEK_SET));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue