-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
gnulib ftruncate.c has code using fcntl F_CHSIZE and F_FREESP, which
might be possibilities if we've got other systems without ftruncate. */
-#if HAVE_CHSIZE && ! HAVE_FTRUNCATE
+#if defined HAVE_CHSIZE && ! defined HAVE_FTRUNCATE
# define ftruncate(fd, size) chsize (fd, size)
-#undef HAVE_FTRUNCATE
-#define HAVE_FTRUNCATE 1
+# undef HAVE_FTRUNCATE
+# define HAVE_FTRUNCATE 1
#endif
#if SIZEOF_OFF_T == SIZEOF_INT
if (SCM_INPUT_PORT_P (port) && read_size > 0)
{
- pt->read_buf = scm_gc_malloc (read_size, "port buffer");
+ pt->read_buf = scm_gc_malloc_pointerless (read_size, "port buffer");
pt->read_pos = pt->read_end = pt->read_buf;
pt->read_buf_size = read_size;
}
if (SCM_OUTPUT_PORT_P (port) && write_size > 0)
{
- pt->write_buf = scm_gc_malloc (write_size, "port buffer");
+ pt->write_buf = scm_gc_malloc_pointerless (write_size, "port buffer");
pt->write_pos = pt->write_buf;
pt->write_buf_size = write_size;
}
if (SCM_FPORTP (port))
{
- scm_t_fport *fp = SCM_FSTREAM (port);
+ scm_t_port *p;
+ scm_t_fport *fp;
+
+ /* XXX: In some cases, we can encounter a port with no associated ptab
+ entry. */
+ p = SCM_PTAB_ENTRY (port);
+ fp = (p != NULL) ? (scm_t_fport *) p->stream : NULL;
- if (fp->fdes == fd)
+ if ((fp != NULL) && (fp->fdes == fd))
{
fp->fdes = dup (fd);
if (fp->fdes == -1)
#define FUNC_NAME s_scm_open_file
{
SCM port;
- int fdes;
- int flags = 0;
- char *file;
- char *md;
- char *ptr;
+ int fdes, flags = 0;
+ unsigned int retries;
+ char *file, *md, *ptr;
scm_dynwind_begin (0);
}
ptr++;
}
- SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
- if (fdes == -1)
+
+ for (retries = 0, fdes = -1;
+ fdes < 0 && retries < 2;
+ retries++)
{
- int en = errno;
+ SCM_SYSCALL (fdes = open_or_open64 (file, flags, 0666));
+ if (fdes == -1)
+ {
+ int en = errno;
- SCM_SYSERROR_MSG ("~A: ~S",
- scm_cons (scm_strerror (scm_from_int (en)),
- scm_cons (filename, SCM_EOL)), en);
+ if (en == EMFILE && retries == 0)
+ /* Run the GC in case it collects open file ports that are no
+ longer referenced. */
+ scm_i_gc (FUNC_NAME);
+ else
+ SCM_SYSERROR_MSG ("~A: ~S",
+ scm_cons (scm_strerror (scm_from_int (en)),
+ scm_cons (filename, SCM_EOL)), en);
+ }
}
+
port = scm_i_fdes_to_port (fdes, scm_i_mode_bits (mode), filename);
scm_dynwind_end ();
pt = SCM_PTAB_ENTRY(port);
{
scm_t_fport *fp
- = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), "file port");
+ = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
+ "file port");
fp->fdes = fdes;
pt->rw_random = SCM_FDES_RANDOM_P (fdes);
scm_syserror ("ftruncate");
}
-/* helper for fport_write: try to write data, using multiple system
- calls if required. */
-#define FUNC_NAME "write_all"
-static void write_all (SCM port, const void *data, size_t remaining)
-{
- int fdes = SCM_FSTREAM (port)->fdes;
-
- while (remaining > 0)
- {
- size_t done;
-
- SCM_SYSCALL (done = write (fdes, data, remaining));
-
- if (done == -1)
- SCM_SYSERROR;
- remaining -= done;
- data = ((const char *) data) + done;
- }
-}
-#undef FUNC_NAME
-
static void
fport_write (SCM port, const void *data, size_t size)
+#define FUNC_NAME "fport_write"
{
/* this procedure tries to minimize the number of writes/flushes. */
scm_t_port *pt = SCM_PTAB_ENTRY (port);
if (pt->write_buf == &pt->shortbuf
|| (pt->write_pos == pt->write_buf && size >= pt->write_buf_size))
{
- /* "unbuffered" port, or
- port with empty buffer and data won't fit in buffer. */
- write_all (port, data, size);
+ /* Unbuffered port, or port with empty buffer and data won't fit in
+ buffer. */
+ if (full_write (SCM_FPORT_FDES (port), data, size) < size)
+ SCM_SYSERROR;
+
return;
}
if (size >= pt->write_buf_size)
{
- write_all (port, ptr, remaining);
+ if (full_write (SCM_FPORT_FDES (port), ptr, remaining)
+ < remaining)
+ SCM_SYSERROR;
return;
}
else
fport_flush (port);
}
}
+#undef FUNC_NAME
/* becomes 1 when process is exiting: normal exception handling won't
work by this time. */