guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

largefile64 on ports


From: Kevin Ryde
Subject: largefile64 on ports
Date: Fri, 08 Sep 2006 09:17:32 +1000
User-agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux)

I'm looking at the addition below to allow ports to access 64-bit
files with the _LARGEFILE64 mechanism.  New scm_t_ptob_descriptor
fields seek64 and truncate64 are off64_t versions of those operations.
They're used by fports, and can also by used by an application.  The
plain seek and truncate fields are unchanged.

Extending scm_t_ptob_descriptor is a slight worry for binary
compatibility, but I think that structure is only ever created by
scm_make_port_type, so applications shouldn't be depending on its size
(only the existing fields).

Actually instantiating a port from a descriptor isn't documented, so
it's possible no applications are using the C port type stuff at all!


Index: ports.h
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/ports.h,v
retrieving revision 1.98.2.2
diff -u -r1.98.2.2 ports.h
--- ports.h     30 May 2006 01:36:35 -0000      1.98.2.2
+++ ports.h     7 Sep 2006 23:06:52 -0000
@@ -184,6 +184,17 @@
   off_t (*seek) (SCM port, off_t OFFSET, int WHENCE);
   void (*truncate) (SCM port, off_t length);
 
+#if SCM_HAVE_LARGEFILE64 && defined (_LARGEFILE64_SOURCE)
+  /* if Guile has been configured with these fields, and if the user has
+     asked for off64_t stuff */
+  off64_t (*seek64) (SCM port, off64_t OFFSET, int WHENCE);
+  void (*truncate64) (SCM port, off64_t length);
+#else
+  /* otherwise dummy fields to keep the struct size constant */
+  off_t (*dummy_seek64) (SCM port, off_t OFFSET, int WHENCE);
+  void (*dummy_truncate64) (SCM port, off_t length);
+#endif
+
 } scm_t_ptob_descriptor;
 
 #define SCM_TC2PTOBNUM(x) (0x0ff & ((x) >> 8))
@@ -226,6 +237,16 @@
 SCM_API void scm_set_port_truncate (scm_t_bits tc,
                                    void (*truncate) (SCM port,
                                                      off_t length));
+#if SCM_HAVE_LARGEFILE64 && defined (_LARGEFILE64_SOURCE)
+/* only give prototypes if user has asked for off64_t stuff */
+SCM_API void scm_set_port_seek64 (scm_t_bits tc,
+                                  off64_t (*seek64) (SCM port,
+                                                     off64_t OFFSET,
+                                                     int WHENCE));
+SCM_API void scm_set_port_truncate64 (scm_t_bits tc,
+                                      void (*truncate64) (SCM port,
+                                                          off64_t length));
+#endif
 SCM_API void scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) 
(SCM));
 SCM_API SCM scm_char_ready_p (SCM port);
 size_t scm_take_from_input_buffers (SCM port, char *dest, size_t read_len);
Index: ports.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/ports.c,v
retrieving revision 1.204.2.6
diff -u -r1.204.2.6 ports.c
--- ports.c     1 Sep 2006 01:39:52 -0000       1.204.2.6
+++ ports.c     7 Sep 2006 23:06:56 -0000
@@ -149,6 +149,10 @@
 
       scm_ptobs[scm_numptob].seek = 0;
       scm_ptobs[scm_numptob].truncate = 0;
+#if SCM_HAVE_LARGEFILE64
+      scm_ptobs[scm_numptob].seek64 = 0;
+      scm_ptobs[scm_numptob].truncate64 = 0;
+#endif
 
       scm_numptob++;
     }
@@ -215,12 +219,30 @@
   scm_ptobs[SCM_TC2PTOBNUM (tc)].seek = seek;
 }
 
+#if SCM_HAVE_LARGEFILE64
+void
+scm_set_port_seek64 (scm_t_bits tc, off64_t (*seek64) (SCM port,
+                                          off64_t OFFSET,
+                                          int WHENCE))
+{
+  scm_ptobs[SCM_TC2PTOBNUM (tc)].seek64 = seek64;
+}
+#endif
+
 void
 scm_set_port_truncate (scm_t_bits tc, void (*truncate) (SCM port, off_t 
length))
 {
   scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate = truncate;
 }
 
+#if SCM_HAVE_LARGEFILE64
+void
+scm_set_port_truncate64 (scm_t_bits tc, void (*truncate64) (SCM port, off64_t 
length))
+{
+  scm_ptobs[SCM_TC2PTOBNUM (tc)].truncate64 = truncate64;
+}
+#endif
+
 void
 scm_set_port_input_waiting (scm_t_bits tc, int (*input_waiting) (SCM))
 {
@@ -1385,15 +1407,25 @@
   if (SCM_OPPORTP (fd_port))
     {
       scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (fd_port);
-      off_t off = scm_to_off_t (offset);
-      off_t rv;
 
-      if (!ptob->seek)
-       SCM_MISC_ERROR ("port is not seekable", 
+      if (!ptob->seek
+#if SCM_HAVE_LARGEFILE64
+          && !ptob->seek64
+#endif
+          )
+        SCM_MISC_ERROR ("port is not seekable", 
                         scm_cons (fd_port, SCM_EOL));
+
+#if SCM_HAVE_LARGEFILE64
+      if (ptob->seek64)
+        return scm_from_off64_t (ptob->seek64 (fd_port,
+                                               scm_to_off64_t (offset),
+                                               how));
       else
-       rv = ptob->seek (fd_port, off, how);
-      return scm_from_off_t (rv);
+#endif
+        return scm_from_off_t (ptob->seek (fd_port,
+                                           scm_to_off_t (offset),
+                                           how));
     }
   else /* file descriptor?.  */
     {
@@ -1457,18 +1489,27 @@
     }
   else if (SCM_OPOUTPORTP (object))
     {
-      off_t c_length = scm_to_off_t (length);
       scm_t_port *pt = SCM_PTAB_ENTRY (object);
       scm_t_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (object);
       
-      if (!ptob->truncate)
+      if (!ptob->truncate
+#if SCM_HAVE_LARGEFILE64
+          && !ptob->truncate64
+#endif
+          )
        SCM_MISC_ERROR ("port is not truncatable", SCM_EOL);
+
       if (pt->rw_active == SCM_PORT_READ)
        scm_end_input (object);
       else if (pt->rw_active == SCM_PORT_WRITE)
        ptob->flush (object);
       
-      ptob->truncate (object, c_length);
+#if SCM_HAVE_LARGEFILE64
+      if (ptob->truncate64)
+        ptob->truncate64 (object, scm_to_int64 (length));
+      else
+#endif
+        ptob->truncate (object, scm_to_off_t (length));
       rv = 0;
     }
   else
Index: fports.c
===================================================================
RCS file: /cvsroot/guile/guile/guile-core/libguile/fports.c,v
retrieving revision 1.137.2.4
diff -u -r1.137.2.4 fports.c
--- fports.c    26 May 2006 00:24:03 -0000      1.137.2.4
+++ fports.c    7 Sep 2006 23:06:57 -0000
@@ -17,6 +17,8 @@
 
 
 
+#define _LARGEFILE64_SOURCE      /* ask for stat64 etc */
+
 #if HAVE_CONFIG_H
 #  include <config.h>
 #endif
@@ -46,6 +48,7 @@
 #endif
 
 #include <errno.h>
+#include <sys/types.h>
 
 #include "libguile/iselect.h"
 
@@ -57,6 +60,19 @@
 #endif /* __MINGW32__ */
 
 
+#if SIZEOF_OFF_T == SIZEOF_INT
+#define OFF_T_MAX  INT_MAX
+#define OFF_T_MIN  INT_MIN
+#elif SIZEOF_OFF_T == SIZEOF_LONG
+#define OFF_T_MAX  LONG_MAX
+#define OFF_T_MIN  LONG_MIN
+#elif SIZEOF_OFF_T == SIZEOF_LONG_LONG
+#define OFF_T_MAX  LONG_LONG_MAX
+#define OFF_T_MIN  LONG_LONG_MIN
+#else
+#error Oops, unknown OFF_T size
+#endif
+
 scm_t_bits scm_tc16_fport;
 
 
@@ -334,7 +350,7 @@
        }
       ptr++;
     }
-  SCM_SYSCALL (fdes = open (file, flags, 0666));
+  SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
   if (fdes == -1)
     {
       int en = errno;
@@ -583,25 +599,39 @@
     }
 }
 
-static off_t
-fport_seek (SCM port, off_t offset, int whence)
+/* fport_seek and fport_seek64.  There's two cases here,
+
+   1. We don't have off64_t.  fport_seek_or_seek64 uses off_t and fport_seek
+      is an alias for that func.  fport_seek64 is NULL.
+
+   2. We do have off64_t.  fport_seek_or_seek64 uses off64_t and
+      fport_seek64 is an alias for that func.  An fport_seek func is created
+      as a range-checking wrapper around fport_seek64.
+
+   It'd be possible to duplicate the code of fport_seek_or_seek64, making
+   one off_t version, and one off64_t version.  But it's a bit big to want
+   to do that, hence the magic off_t or off64_t adaption.  (The truncate and
+   truncate64 funcs below are small so they can be duplicated.)  */
+
+static off_t_or_off64_t
+fport_seek_or_seek64 (SCM port, off_t_or_off64_t offset, int whence)
 {
   scm_t_port *pt = SCM_PTAB_ENTRY (port);
   scm_t_fport *fp = SCM_FSTREAM (port);
-  off_t rv;
-  off_t result;
+  off_t_or_off64_t rv;
+  off_t_or_off64_t result;
 
   if (pt->rw_active == SCM_PORT_WRITE)
     {
       if (offset != 0 || whence != SEEK_CUR)
        {
          fport_flush (port);
-         result = rv = lseek (fp->fdes, offset, whence);
+         result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
        }
       else
        {
          /* read current position without disturbing the buffer.  */
-         rv = lseek (fp->fdes, offset, whence);
+         rv = lseek_or_lseek64 (fp->fdes, offset, whence);
          result = rv + (pt->write_pos - pt->write_buf);
        }
     }
@@ -611,13 +641,13 @@
        {
          /* could expand to avoid a second seek.  */
          scm_end_input (port);
-         result = rv = lseek (fp->fdes, offset, whence);
+         result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
        }
       else
        {
          /* read current position without disturbing the buffer
             (particularly the unread-char buffer).  */
-         rv = lseek (fp->fdes, offset, whence);
+         rv = lseek_or_lseek64 (fp->fdes, offset, whence);
          result = rv - (pt->read_end - pt->read_pos);
 
          if (pt->read_buf == pt->putback_buf)
@@ -626,7 +656,7 @@
     }
   else /* SCM_PORT_NEITHER */
     {
-      result = rv = lseek (fp->fdes, offset, whence);      
+      result = rv = lseek_or_lseek64 (fp->fdes, offset, whence);
     }
 
   if (rv == -1)
@@ -635,6 +665,25 @@
   return result;
 }
 
+#if SCM_HAVE_LARGEFILE64
+static off_t
+fport_seek (SCM port, off_t offset, int whence)
+{
+  off64_t rv = fport_seek_or_seek64 (port, (off64_t) offset, whence);
+  if (rv > OFF_T_MAX || rv < OFF_T_MIN)
+    {
+      errno = EOVERFLOW;
+      scm_syserror ("fport_seek");
+    }
+  return (off_t) rv;
+
+}
+#define fport_seek64 fport_seek_or_seek64
+#else
+#define fport_seek   fport_seek_or_seek64
+#define fport_seek64 NULL
+#endif
+
 static void
 fport_truncate (SCM port, off_t length)
 {
@@ -644,6 +693,20 @@
     scm_syserror ("ftruncate");
 }
 
+#if SCM_HAVE_LARGEFILE64
+static void
+fport_truncate64 (SCM port, off64_t length)
+{
+  scm_t_fport *fp = SCM_FSTREAM (port);
+
+  if (ftruncate64 (fp->fdes, length) == -1)
+    {
+      fprintf (stderr, "ftruncate64: %d %Ld %s\n", fp->fdes, length, strerror 
(errno));
+    scm_syserror ("ftruncate64");
+    }
+}
+#endif
+
 /* helper for fport_write: try to write data, using multiple system
    calls if required.  */
 #define FUNC_NAME "write_all"
@@ -851,6 +914,10 @@
   scm_set_port_close           (tc, fport_close);
   scm_set_port_seek            (tc, fport_seek);
   scm_set_port_truncate        (tc, fport_truncate);
+#if SCM_HAVE_LARGEFILE64
+  scm_set_port_seek64          (tc, fport_seek64);
+  scm_set_port_truncate64      (tc, fport_truncate64);
+#endif
   scm_set_port_input_waiting   (tc, fport_input_waiting);
 
   return tc;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]