[Ada] improve handling of files larger than 2GB
Arnaud Charlet
charlet@adacore.com
Mon Jun 22 09:23:00 GMT 2009
Wherever we depend on stat for files larger than 2GB we get failures
or junk values. This impacts all kinds of stuff, for instance in this
TN the customer was seeing errors in Ada Directories.Search.
Here's a example of the problem:
with GNAT.IO; use GNAT.IO;
with GNAT.OS_Lib; use GNAT.OS_Lib;
procedure T is
Name : String := "largefile.tar";
begin
if (Is_Regular_File (Name)) then
Put_Line ("largefile.tar is a regular file.");
else
Put_Line ("largefile.tar is not a regular file.");
end if;
if (Is_Directory (Name)) then
Put_Line ("largefile.tar is a directory.");
else
Put_Line ("largefile.tar is not a directory.");
end if;
Put_Line (Locate_Regular_File (Name, ".").all);
end T;
gingell@nile$ ./t
0
largefile.tar is not a regular file.
largefile.tar is not a directory.
raised CONSTRAINT_ERROR : t.adb:25 access check failed
This patch solves the above problem.
Tested on x86_64-pc-linux-gnu, committed on trunk
2009-06-22 Matthew Gingell <gingell@adacore.com>
* adaint.c, adaint.h, cstreams.c: Call stat64 on platforms where it is
available.
-------------- next part --------------
Index: adaint.c
===================================================================
--- adaint.c (revision 148742)
+++ adaint.c (working copy)
@@ -520,7 +520,7 @@ __gnat_try_lock (char *dir, char *file)
{
char full_path[256];
char temp_file[256];
- struct stat stat_result;
+ STRUCT_STAT stat_result;
int fd;
sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
@@ -775,15 +775,7 @@ __gnat_fopen (char *path, char *mode, in
#elif defined (VMS)
return decc$fopen (path, mode);
#else
-
-#if defined (__GLIBC__) || defined (sun)
- /* GLIBC and Solaris provides fopen64, which allows IO on files
- larger than 2GB on systems that support it. */
- return fopen64 (path, mode);
-#else
- return fopen (path, mode);
-#endif
-
+ return FOPEN (path, mode);
#endif
}
@@ -1027,12 +1019,16 @@ long
__gnat_file_length (int fd)
{
int ret;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- ret = fstat (fd, &statbuf);
+ ret = FSTAT (fd, &statbuf);
if (ret || !S_ISREG (statbuf.st_mode))
return 0;
+ /* st_size may be 32 bits, or 64 bits which is converted to long. We
+ don't return a useful value for files larger than 2 gigabytes in
+ either case. */
+
return (statbuf.st_size);
}
@@ -1042,12 +1038,16 @@ long
__gnat_named_file_length (char *name)
{
int ret;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
ret = __gnat_stat (name, &statbuf);
if (ret || !S_ISREG (statbuf.st_mode))
return 0;
+ /* st_size may be 32 bits, or 64 bits which is converted to long. We
+ don't return a useful value for files larger than 2 gigabytes in
+ either case. */
+
return (statbuf.st_size);
}
@@ -1269,7 +1269,7 @@ __gnat_file_time_name (char *name)
}
return (OS_Time) ret;
#else
- struct stat statbuf;
+ STRUCT_STAT statbuf;
if (__gnat_stat (name, &statbuf) != 0) {
return (OS_Time)-1;
} else {
@@ -1361,9 +1361,9 @@ __gnat_file_time_fd (int fd)
return (OS_Time) ret;
#else
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- if (fstat (fd, &statbuf) != 0) {
+ if (FSTAT (fd, &statbuf) != 0) {
return (OS_Time) -1;
} else {
#ifdef VMS
@@ -1651,7 +1651,7 @@ __gnat_get_libraries_from_registry (void
}
int
-__gnat_stat (char *name, struct stat *statbuf)
+__gnat_stat (char *name, STRUCT_STAT *statbuf)
{
#ifdef __MINGW32__
/* Under Windows the directory name for the stat function must not be
@@ -1683,7 +1683,7 @@ __gnat_stat (char *name, struct stat *st
return _tstat (wname, (struct _stat *)statbuf);
#else
- return stat (name, statbuf);
+ return STAT (name, statbuf);
#endif
}
@@ -1699,7 +1699,7 @@ __gnat_file_exists (char *name)
S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
#else
- struct stat statbuf;
+ STRUCT_STAT statbuf;
return !__gnat_stat (name, &statbuf);
#endif
@@ -1744,7 +1744,7 @@ int
__gnat_is_regular_file (char *name)
{
int ret;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
ret = __gnat_stat (name, &statbuf);
return (!ret && S_ISREG (statbuf.st_mode));
@@ -1754,7 +1754,7 @@ int
__gnat_is_directory (char *name)
{
int ret;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
ret = __gnat_stat (name, &statbuf);
return (!ret && S_ISDIR (statbuf.st_mode));
@@ -1972,9 +1972,9 @@ __gnat_is_readable_file (char *name)
#else
int ret;
int mode;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- ret = stat (name, &statbuf);
+ ret = STAT (name, &statbuf);
mode = statbuf.st_mode & S_IRUSR;
return (!ret && mode);
#endif
@@ -2004,9 +2004,9 @@ __gnat_is_writable_file (char *name)
#else
int ret;
int mode;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- ret = stat (name, &statbuf);
+ ret = STAT (name, &statbuf);
mode = statbuf.st_mode & S_IWUSR;
return (!ret && mode);
#endif
@@ -2031,13 +2031,12 @@ __gnat_is_executable_file (char *name)
else
return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
&& _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4);
-
#else
int ret;
int mode;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- ret = stat (name, &statbuf);
+ ret = STAT (name, &statbuf);
mode = statbuf.st_mode & S_IXUSR;
return (!ret && mode);
#endif
@@ -2057,9 +2056,9 @@ __gnat_set_writable (char *name)
SetFileAttributes
(wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
#elif ! defined (__vxworks) && ! defined(__nucleus__)
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- if (stat (name, &statbuf) == 0)
+ if (STAT (name, &statbuf) == 0)
{
statbuf.st_mode = statbuf.st_mode | S_IWUSR;
chmod (name, statbuf.st_mode);
@@ -2079,9 +2078,9 @@ __gnat_set_executable (char *name)
__gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
#elif ! defined (__vxworks) && ! defined(__nucleus__)
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- if (stat (name, &statbuf) == 0)
+ if (STAT (name, &statbuf) == 0)
{
statbuf.st_mode = statbuf.st_mode | S_IXUSR;
chmod (name, statbuf.st_mode);
@@ -2106,9 +2105,9 @@ __gnat_set_non_writable (char *name)
SetFileAttributes
(wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
#elif ! defined (__vxworks) && ! defined(__nucleus__)
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- if (stat (name, &statbuf) == 0)
+ if (STAT (name, &statbuf) == 0)
{
statbuf.st_mode = statbuf.st_mode & 07577;
chmod (name, statbuf.st_mode);
@@ -2128,9 +2127,9 @@ __gnat_set_readable (char *name)
__gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
#elif ! defined (__vxworks) && ! defined(__nucleus__)
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- if (stat (name, &statbuf) == 0)
+ if (STAT (name, &statbuf) == 0)
{
chmod (name, statbuf.st_mode | S_IREAD);
}
@@ -2149,9 +2148,9 @@ __gnat_set_non_readable (char *name)
__gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
#elif ! defined (__vxworks) && ! defined(__nucleus__)
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- if (stat (name, &statbuf) == 0)
+ if (STAT (name, &statbuf) == 0)
{
chmod (name, statbuf.st_mode & (~S_IREAD));
}
@@ -2166,9 +2165,9 @@ __gnat_is_symbolic_link (char *name ATTR
#elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
int ret;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
- ret = lstat (name, &statbuf);
+ ret = LSTAT (name, &statbuf);
return (!ret && S_ISLNK (statbuf.st_mode));
#else
@@ -3435,10 +3434,10 @@ __gnat_copy_attribs (char *from, char *t
return 0;
#else
- struct stat fbuf;
+ STRUCT_STAT fbuf;
struct utimbuf tbuf;
- if (stat (from, &fbuf) == -1)
+ if (STAT (from, &fbuf) == -1)
{
return -1;
}
Index: adaint.h
===================================================================
--- adaint.h (revision 148742)
+++ adaint.h (working copy)
@@ -43,6 +43,24 @@
#define Encoding_8bits 1 /* Standard 8bits, CP_ACP on Windows. */
#define Encoding_Unspecified 2 /* Based on GNAT_CODE_PAGE env variable. */
+/* Large file support. It is unclear what portable mechanism we can
+ use to determine at compile time what support the system offers for
+ large files. For now we just list the platforms we have manually
+ tested. */
+
+#if defined (__GLIBC__) || defined (sun) || defined (__sgi)
+#define FOPEN fopen64
+#define STAT stat64
+#define FSTAT fstat64
+#define LSTAT lstat64
+#define STRUCT_STAT struct stat64
+#else
+#define FOPEN fopen
+#define STAT stat
+#define FSTAT fstat
+#define STRUCT_STAT struct stat
+#endif
+
typedef long OS_Time; /* Type corresponding to GNAT.OS_Lib.OS_Time */
extern int __gnat_max_path_len;
@@ -70,7 +88,7 @@ extern int __gnat_open_new
extern int __gnat_open_new_temp (char *, int);
extern int __gnat_mkdir (char *);
extern int __gnat_stat (char *,
- struct stat *);
+ STRUCT_STAT *);
extern int __gnat_unlink (char *);
extern int __gnat_rename (char *, char *);
extern int __gnat_chdir (char *);
Index: cstreams.c
===================================================================
--- cstreams.c (revision 148742)
+++ cstreams.c (working copy)
@@ -96,7 +96,7 @@ int
__gnat_is_regular_file_fd (int fd)
{
int ret;
- struct stat statbuf;
+ STRUCT_STAT statbuf;
#ifdef __EMX__
/* Programs using screen I/O may need to reset the FPU after
@@ -107,7 +107,7 @@ __gnat_is_regular_file_fd (int fd)
__gnat_init_float();
#endif
- ret = fstat (fd, &statbuf);
+ ret = FSTAT (fd, &statbuf);
return (!ret && S_ISREG (statbuf.st_mode));
}
More information about the Gcc-patches
mailing list