[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