[Top][All Lists]
[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;