]> git.donarmstrong.com Git - lilypond.git/blob - guile18/libguile/filesys.c
Import guile-1.8 as multiple upstream tarball component
[lilypond.git] / guile18 / libguile / filesys.c
1 /* Copyright (C) 1996,1997,1998,1999,2000,2001, 2002, 2004, 2006, 2008 Free Software Foundation, Inc.
2  * 
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16  */
17
18
19 \f
20
21 /* See stime.c for comments on why _POSIX_C_SOURCE is not always defined. */
22 #define _LARGEFILE64_SOURCE      /* ask for stat64 etc */
23 #ifdef __hpux
24 #define _POSIX_C_SOURCE 199506L  /* for readdir_r */
25 #endif
26 #if defined(__INTERIX) && !defined(_REENTRANT)
27 # define _REENTRANT   /* ask Interix for readdir_r prototype */
28 #endif
29
30 #ifdef HAVE_CONFIG_H
31 #  include <config.h>
32 #endif
33
34 /* This blob per the Autoconf manual (under "Particular Functions"), updated
35    to match that of Gnulib.  */
36 #ifndef alloca
37 # if HAVE_ALLOCA_H
38 #  include <alloca.h>
39 # elif defined __GNUC__
40 #  define alloca __builtin_alloca
41 # elif defined _AIX
42 #  define alloca __alloca
43 # elif defined _MSC_VER
44 #  include <malloc.h>
45 #  define alloca _alloca
46 # else
47 #  include <stddef.h>
48 #  ifdef  __cplusplus
49 extern "C"
50 #  endif
51 void *alloca (size_t);
52 # endif
53 #endif
54
55 #include <stdio.h>
56 #include <errno.h>
57
58 #include "libguile/_scm.h"
59 #include "libguile/smob.h"
60 #include "libguile/feature.h"
61 #include "libguile/fports.h"
62 #include "libguile/private-gc.h"  /* for SCM_MAX */
63 #include "libguile/iselect.h"
64 #include "libguile/strings.h"
65 #include "libguile/vectors.h"
66 #include "libguile/lang.h"
67 #include "libguile/dynwind.h"
68
69 #include "libguile/validate.h"
70 #include "libguile/filesys.h"
71
72 \f
73 #ifdef HAVE_IO_H
74 #include <io.h>
75 #endif
76
77 #ifdef HAVE_DIRECT_H
78 #include <direct.h>
79 #endif
80
81 #ifdef TIME_WITH_SYS_TIME
82 # include <sys/time.h>
83 # include <time.h>
84 #else
85 # if HAVE_SYS_TIME_H
86 #  include <sys/time.h>
87 # else
88 #  include <time.h>
89 # endif
90 #endif
91
92 #ifdef HAVE_UNISTD_H
93 #include <unistd.h>
94 #endif
95
96 #ifdef LIBC_H_WITH_UNISTD_H
97 #include <libc.h>
98 #endif
99
100 #ifdef HAVE_SYS_SELECT_H
101 #include <sys/select.h>
102 #endif
103
104 #ifdef HAVE_STRING_H
105 #include <string.h>
106 #endif
107
108 #include <sys/types.h>
109 #include <sys/stat.h>
110 #include <fcntl.h>
111
112 #ifdef HAVE_PWD_H
113 #include <pwd.h>
114 #endif
115
116
117 #if defined (__MINGW32__) || defined (_MSC_VER) || defined (__BORLANDC__)
118 # include "win32-dirent.h"
119 # define NAMLEN(dirent) strlen((dirent)->d_name)
120 /* The following bits are per AC_HEADER_DIRENT doco in the autoconf manual */
121 #elif HAVE_DIRENT_H
122 # include <dirent.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 #else
125 # define dirent direct
126 # define NAMLEN(dirent) (dirent)->d_namlen
127 # if HAVE_SYS_NDIR_H
128 #  include <sys/ndir.h>
129 # endif
130 # if HAVE_SYS_DIR_H
131 #  include <sys/dir.h>
132 # endif
133 # if HAVE_NDIR_H
134 #  include <ndir.h>
135 # endif
136 #endif
137
138 /* Ultrix has S_IFSOCK, but no S_ISSOCK.  Ipe!  */
139 #if defined (S_IFSOCK) && ! defined (S_ISSOCK)
140 #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
141 #endif
142
143 /* The MinGW gcc does not define the S_ISSOCK macro. Any other native Windows
144    compiler like BorlandC or MSVC has none of these macros defined. */
145 #ifdef __MINGW32__
146
147 # ifdef _S_IFIFO
148 #  undef _S_IFIFO
149 # endif
150 # ifdef _S_IFCHR
151 #  undef _S_IFCHR
152 # endif
153 # ifdef _S_IFBLK
154 #  undef _S_IFBLK
155 # endif
156 # ifdef _S_IFDIR
157 #  undef _S_IFDIR
158 # endif
159 # ifdef _S_IFREG
160 #  undef _S_IFREG
161 # endif
162 # ifdef _S_IFSOCK
163 #  undef _S_IFSOCK
164 # endif
165
166 # define _S_IFIFO        0x1000  /* FIFO */
167 # define _S_IFCHR        0x2000  /* Character */
168 # define _S_IFBLK        0x3000  /* Block */
169 # define _S_IFDIR        0x4000  /* Directory */
170 # define _S_IFREG        0x8000  /* Regular */
171 # define _S_IFSOCK       0xC000  /* Socket */
172
173 # ifdef S_ISBLK
174 #  undef S_ISBLK
175 # endif
176 # ifdef S_ISFIFO
177 #  undef S_ISFIFO
178 # endif
179 # ifdef S_ISCHR
180 #  undef S_ISCHR
181 # endif
182 # ifdef S_ISDIR
183 #  undef S_ISDIR
184 # endif
185 # ifdef S_ISREG
186 #  undef S_ISREG
187 # endif
188 # ifdef S_ISSOCK
189 #  undef S_ISSOCK
190 # endif
191
192 # define S_ISBLK(mode)  (((mode) & _S_IFMT) == _S_IFBLK)
193 # define S_ISFIFO(mode) (((mode) & _S_IFMT) == _S_IFIFO)
194 # define S_ISCHR(mode)  (((mode) & _S_IFMT) == _S_IFCHR)
195 # define S_ISDIR(mode)  (((mode) & _S_IFMT) == _S_IFDIR)
196 # define S_ISREG(mode)  (((mode) & _S_IFMT) == _S_IFREG)
197 # define S_ISSOCK(mode) (((mode) & _S_IFMT) == _S_IFSOCK)
198
199 #endif /* __MINGW32__ */
200
201 /* Some more definitions for the native Windows port. */
202 #ifdef __MINGW32__
203 # define mkdir(path, mode) mkdir (path)
204 # define fsync(fd) _commit (fd)
205 # define fchmod(fd, mode) (-1)
206 #endif /* __MINGW32__ */
207
208 /* dirfd() returns the file descriptor underlying a "DIR*" directory stream.
209    Found on MacOS X for instance.  The following definition is for Solaris
210    10, it's probably not right elsewhere, but that's ok, it shouldn't be
211    used elsewhere.  Crib note: If we need more then gnulib has a dirfd.m4
212    figuring out how to get the fd (dirfd function, dirfd macro, dd_fd field,
213    or d_fd field).  */
214 #ifndef dirfd
215 #define dirfd(dirstream) ((dirstream)->dd_fd)
216 #endif
217
218 \f
219
220 /* Two helper macros for an often used pattern */
221
222 #define STRING_SYSCALL(str,cstr,code)        \
223   do {                                       \
224     int eno;                                 \
225     char *cstr = scm_to_locale_string (str); \
226     SCM_SYSCALL (code);                      \
227     eno = errno; free (cstr); errno = eno;   \
228   } while (0)
229
230 #define STRING2_SYSCALL(str1,cstr1,str2,cstr2,code)  \
231   do {                                               \
232     int eno;                                         \
233     char *cstr1, *cstr2;                             \
234     scm_dynwind_begin (0);                             \
235     cstr1 = scm_to_locale_string (str1);             \
236     scm_dynwind_free (cstr1);                          \
237     cstr2 = scm_to_locale_string (str2);             \
238     scm_dynwind_free (cstr2);                          \
239     SCM_SYSCALL (code);                              \
240     eno = errno; scm_dynwind_end (); errno = eno;      \
241   } while (0)
242
243 \f
244
245 /* {Permissions}
246  */
247
248 #ifdef HAVE_CHOWN
249 SCM_DEFINE (scm_chown, "chown", 3, 0, 0, 
250             (SCM object, SCM owner, SCM group),
251             "Change the ownership and group of the file referred to by @var{object} to\n"
252             "the integer values @var{owner} and @var{group}.  @var{object} can be\n"
253             "a string containing a file name or, if the platform\n"
254             "supports fchown, a port or integer file descriptor\n"
255             "which is open on the file.  The return value\n"
256             "is unspecified.\n\n"
257             "If @var{object} is a symbolic link, either the\n"
258             "ownership of the link or the ownership of the referenced file will be\n"
259             "changed depending on the operating system (lchown is\n"
260             "unsupported at present).  If @var{owner} or @var{group} is specified\n"
261             "as @code{-1}, then that ID is not changed.")
262 #define FUNC_NAME s_scm_chown
263 {
264   int rv;
265
266   object = SCM_COERCE_OUTPORT (object);
267
268 #ifdef HAVE_FCHOWN
269   if (scm_is_integer (object) || (SCM_OPFPORTP (object)))
270     {
271       int fdes = (SCM_OPFPORTP (object)?
272                   SCM_FPORT_FDES (object) : scm_to_int (object));
273
274       SCM_SYSCALL (rv = fchown (fdes, scm_to_int (owner), scm_to_int (group)));
275     }
276   else
277 #endif
278     {
279       STRING_SYSCALL (object, c_object,
280                       rv = chown (c_object,
281                                   scm_to_int (owner), scm_to_int (group)));
282     }
283   if (rv == -1)
284     SCM_SYSERROR;
285   return SCM_UNSPECIFIED;
286 }
287 #undef FUNC_NAME
288 #endif /* HAVE_CHOWN */
289
290
291 SCM_DEFINE (scm_chmod, "chmod", 2, 0, 0,
292             (SCM object, SCM mode),
293             "Changes the permissions of the file referred to by @var{obj}.\n"
294             "@var{obj} can be a string containing a file name or a port or integer file\n"
295             "descriptor which is open on a file (in which case @code{fchmod} is used\n"
296             "as the underlying system call).\n"
297             "@var{mode} specifies\n"
298             "the new permissions as a decimal number, e.g., @code{(chmod \"foo\" #o755)}.\n"
299             "The return value is unspecified.")
300 #define FUNC_NAME s_scm_chmod
301 {
302   int rv;
303   int fdes;
304
305   object = SCM_COERCE_OUTPORT (object);
306
307   if (scm_is_integer (object) || SCM_OPFPORTP (object))
308     {
309       if (scm_is_integer (object))
310         fdes = scm_to_int (object);
311       else
312         fdes = SCM_FPORT_FDES (object);
313       SCM_SYSCALL (rv = fchmod (fdes, scm_to_int (mode)));
314     }
315   else
316     {
317       STRING_SYSCALL (object, c_object,
318                       rv = chmod (c_object, scm_to_int (mode)));
319     }
320   if (rv == -1)
321     SCM_SYSERROR;
322   return SCM_UNSPECIFIED;
323 }
324 #undef FUNC_NAME
325
326 SCM_DEFINE (scm_umask, "umask", 0, 1, 0, 
327             (SCM mode),
328             "If @var{mode} is omitted, returns a decimal number representing the current\n"
329             "file creation mask.  Otherwise the file creation mask is set to\n"
330             "@var{mode} and the previous value is returned.\n\n"
331             "E.g., @code{(umask #o022)} sets the mask to octal 22, decimal 18.")
332 #define FUNC_NAME s_scm_umask
333 {
334   mode_t mask;
335   if (SCM_UNBNDP (mode))
336     {
337       mask = umask (0);
338       umask (mask);
339     }
340   else
341     {
342       mask = umask (scm_to_uint (mode));
343     }
344   return scm_from_uint (mask);
345 }
346 #undef FUNC_NAME
347
348 \f
349
350 SCM_DEFINE (scm_open_fdes, "open-fdes", 2, 1, 0, 
351             (SCM path, SCM flags, SCM mode),
352             "Similar to @code{open} but return a file descriptor instead of\n"
353             "a port.")
354 #define FUNC_NAME s_scm_open_fdes
355 {
356   int fd;
357   int iflags;
358   int imode;
359
360   iflags = SCM_NUM2INT (2, flags);
361   imode = SCM_NUM2INT_DEF (3, mode, 0666);
362   STRING_SYSCALL (path, c_path, fd = open_or_open64 (c_path, iflags, imode));
363   if (fd == -1)
364     SCM_SYSERROR;
365   return scm_from_int (fd);
366 }
367 #undef FUNC_NAME
368
369 SCM_DEFINE (scm_open, "open", 2, 1, 0, 
370             (SCM path, SCM flags, SCM mode),
371             "Open the file named by @var{path} for reading and/or writing.\n"
372             "@var{flags} is an integer specifying how the file should be opened.\n"
373             "@var{mode} is an integer specifying the permission bits of the file, if\n"
374             "it needs to be created, before the umask is applied.  The default is 666\n"
375             "(Unix itself has no default).\n\n"
376             "@var{flags} can be constructed by combining variables using @code{logior}.\n"
377             "Basic flags are:\n\n"
378             "@defvar O_RDONLY\n"
379             "Open the file read-only.\n"
380             "@end defvar\n"
381             "@defvar O_WRONLY\n"
382             "Open the file write-only.\n"
383             "@end defvar\n"
384             "@defvar O_RDWR\n"
385             "Open the file read/write.\n"
386             "@end defvar\n"
387             "@defvar O_APPEND\n"
388             "Append to the file instead of truncating.\n"
389             "@end defvar\n"
390             "@defvar O_CREAT\n"
391             "Create the file if it does not already exist.\n"
392             "@end defvar\n\n"
393             "See the Unix documentation of the @code{open} system call\n"
394             "for additional flags.")
395 #define FUNC_NAME s_scm_open
396 {
397   SCM newpt;
398   char *port_mode;
399   int fd;
400   int iflags;
401
402   fd = scm_to_int (scm_open_fdes (path, flags, mode));
403   iflags = SCM_NUM2INT (2, flags);
404   if (iflags & O_RDWR)
405     {
406       if (iflags & O_APPEND)
407         port_mode = "a+";
408       else if (iflags & O_CREAT)
409         port_mode = "w+";
410       else
411         port_mode = "r+";
412     }
413   else {
414     if (iflags & O_APPEND)
415       port_mode = "a";
416     else if (iflags & O_WRONLY)
417       port_mode = "w";
418     else
419       port_mode = "r";
420   }
421   newpt = scm_fdes_to_port (fd, port_mode, path);
422   return newpt;
423 }
424 #undef FUNC_NAME
425
426 SCM_DEFINE (scm_close, "close", 1, 0, 0, 
427             (SCM fd_or_port),
428             "Similar to close-port (@pxref{Closing, close-port}),\n"
429             "but also works on file descriptors.  A side\n"
430             "effect of closing a file descriptor is that any ports using that file\n"
431             "descriptor are moved to a different file descriptor and have\n"
432             "their revealed counts set to zero.")
433 #define FUNC_NAME s_scm_close
434 {
435   int rv;
436   int fd;
437
438   fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
439
440   if (SCM_PORTP (fd_or_port))
441     return scm_close_port (fd_or_port);
442   fd = scm_to_int (fd_or_port);
443   scm_evict_ports (fd);         /* see scsh manual.  */
444   SCM_SYSCALL (rv = close (fd));
445   /* following scsh, closing an already closed file descriptor is
446      not an error.  */
447   if (rv < 0 && errno != EBADF)
448     SCM_SYSERROR;
449   return scm_from_bool (rv >= 0);
450 }
451 #undef FUNC_NAME
452
453 SCM_DEFINE (scm_close_fdes, "close-fdes", 1, 0, 0, 
454             (SCM fd),
455             "A simple wrapper for the @code{close} system call.\n"
456             "Close file descriptor @var{fd}, which must be an integer.\n"
457             "Unlike close (@pxref{Ports and File Descriptors, close}),\n"
458             "the file descriptor will be closed even if a port is using it.\n"
459             "The return value is unspecified.")
460 #define FUNC_NAME s_scm_close_fdes
461 {
462   int c_fd;
463   int rv;
464
465   c_fd = scm_to_int (fd);
466   SCM_SYSCALL (rv = close (c_fd));
467   if (rv < 0)
468     SCM_SYSERROR;
469   return SCM_UNSPECIFIED;
470 }
471 #undef FUNC_NAME
472
473 \f
474 /* {Files}
475  */
476
477 SCM_SYMBOL (scm_sym_regular, "regular");
478 SCM_SYMBOL (scm_sym_directory, "directory");
479 #ifdef S_ISLNK
480 SCM_SYMBOL (scm_sym_symlink, "symlink");
481 #endif
482 SCM_SYMBOL (scm_sym_block_special, "block-special");
483 SCM_SYMBOL (scm_sym_char_special, "char-special");
484 SCM_SYMBOL (scm_sym_fifo, "fifo");
485 SCM_SYMBOL (scm_sym_sock, "socket");
486 SCM_SYMBOL (scm_sym_unknown, "unknown");
487
488 static SCM 
489 scm_stat2scm (struct stat_or_stat64 *stat_temp)
490 {
491   SCM ans = scm_c_make_vector (15, SCM_UNSPECIFIED);
492   
493   SCM_SIMPLE_VECTOR_SET(ans, 0, scm_from_ulong (stat_temp->st_dev));
494   SCM_SIMPLE_VECTOR_SET(ans, 1, scm_from_ino_t_or_ino64_t (stat_temp->st_ino));
495   SCM_SIMPLE_VECTOR_SET(ans, 2, scm_from_ulong (stat_temp->st_mode));
496   SCM_SIMPLE_VECTOR_SET(ans, 3, scm_from_ulong (stat_temp->st_nlink));
497   SCM_SIMPLE_VECTOR_SET(ans, 4, scm_from_ulong (stat_temp->st_uid));
498   SCM_SIMPLE_VECTOR_SET(ans, 5, scm_from_ulong (stat_temp->st_gid));
499 #ifdef HAVE_STRUCT_STAT_ST_RDEV
500   SCM_SIMPLE_VECTOR_SET(ans, 6, scm_from_ulong (stat_temp->st_rdev));
501 #else
502   SCM_SIMPLE_VECTOR_SET(ans, 6, SCM_BOOL_F);
503 #endif
504   SCM_SIMPLE_VECTOR_SET(ans, 7, scm_from_off_t_or_off64_t (stat_temp->st_size));
505   SCM_SIMPLE_VECTOR_SET(ans, 8, scm_from_ulong (stat_temp->st_atime));
506   SCM_SIMPLE_VECTOR_SET(ans, 9, scm_from_ulong (stat_temp->st_mtime));
507   SCM_SIMPLE_VECTOR_SET(ans, 10, scm_from_ulong (stat_temp->st_ctime));
508 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
509   SCM_SIMPLE_VECTOR_SET(ans, 11, scm_from_ulong (stat_temp->st_blksize));
510 #else
511   SCM_SIMPLE_VECTOR_SET(ans, 11, scm_from_ulong (4096L));
512 #endif
513 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
514   SCM_SIMPLE_VECTOR_SET(ans, 12, scm_from_blkcnt_t_or_blkcnt64_t (stat_temp->st_blocks));
515 #else
516   SCM_SIMPLE_VECTOR_SET(ans, 12, SCM_BOOL_F);
517 #endif
518   {
519     int mode = stat_temp->st_mode;
520     
521     if (S_ISREG (mode))
522       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_regular);
523     else if (S_ISDIR (mode))
524       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_directory);
525 #ifdef S_ISLNK
526     /* systems without symlinks probably don't have S_ISLNK */
527     else if (S_ISLNK (mode))
528       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_symlink);
529 #endif
530     else if (S_ISBLK (mode))
531       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_block_special);
532     else if (S_ISCHR (mode))
533       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_char_special);
534     else if (S_ISFIFO (mode))
535       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_fifo);
536 #ifdef S_ISSOCK
537     else if (S_ISSOCK (mode))
538       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_sock);
539 #endif
540     else
541       SCM_SIMPLE_VECTOR_SET(ans, 13, scm_sym_unknown);
542
543     SCM_SIMPLE_VECTOR_SET(ans, 14, scm_from_int ((~S_IFMT) & mode));
544
545     /* the layout of the bits in ve[14] is intended to be portable.
546        If there are systems that don't follow the usual convention,
547        the following could be used:
548
549        tmp = 0;
550        if (S_ISUID & mode) tmp += 1;
551        tmp <<= 1;
552        if (S_IRGRP & mode) tmp += 1;
553        tmp <<= 1;
554        if (S_ISVTX & mode) tmp += 1;
555        tmp <<= 1;
556        if (S_IRUSR & mode) tmp += 1;
557        tmp <<= 1;
558        if (S_IWUSR & mode) tmp += 1;
559        tmp <<= 1;
560        if (S_IXUSR & mode) tmp += 1;
561        tmp <<= 1;
562        if (S_IWGRP & mode) tmp += 1;
563        tmp <<= 1;
564        if (S_IXGRP & mode) tmp += 1;
565        tmp <<= 1;
566        if (S_IROTH & mode) tmp += 1;
567        tmp <<= 1;
568        if (S_IWOTH & mode) tmp += 1;
569        tmp <<= 1;
570        if (S_IXOTH & mode) tmp += 1; 
571
572        SCM_SIMPLE_VECTOR_SET(ans, 14, scm_from_int (tmp));
573        
574        */
575   }  
576
577   return ans;
578 }
579
580 #ifdef __MINGW32__
581 /*
582  * Try getting the appropiate stat buffer for a given file descriptor
583  * under Windows. It differentiates between file, pipe and socket 
584  * descriptors.
585  */
586 static int fstat_Win32 (int fdes, struct stat *buf)
587 {
588   int error, optlen = sizeof (int);
589
590   memset (buf, 0, sizeof (struct stat));
591
592   /* Is this a socket ? */
593   if (getsockopt (fdes, SOL_SOCKET, SO_ERROR, (void *) &error, &optlen) >= 0)
594     {
595       buf->st_mode = _S_IFSOCK | _S_IREAD | _S_IWRITE | _S_IEXEC;
596       buf->st_nlink = 1;
597       buf->st_atime = buf->st_ctime = buf->st_mtime = time (NULL);
598       return 0;
599     }
600   /* Maybe a regular file or pipe ? */
601   return fstat (fdes, buf);
602 }
603 #endif /* __MINGW32__ */
604
605 SCM_DEFINE (scm_stat, "stat", 1, 0, 0, 
606             (SCM object),
607             "Return an object containing various information about the file\n"
608             "determined by @var{obj}.  @var{obj} can be a string containing\n"
609             "a file name or a port or integer file descriptor which is open\n"
610             "on a file (in which case @code{fstat} is used as the underlying\n"
611             "system call).\n"
612             "\n"
613             "The object returned by @code{stat} can be passed as a single\n"
614             "parameter to the following procedures, all of which return\n"
615             "integers:\n"
616             "\n"
617             "@table @code\n"
618             "@item stat:dev\n"
619             "The device containing the file.\n"
620             "@item stat:ino\n"
621             "The file serial number, which distinguishes this file from all\n"
622             "other files on the same device.\n"
623             "@item stat:mode\n"
624             "The mode of the file.  This includes file type information and\n"
625             "the file permission bits.  See @code{stat:type} and\n"
626             "@code{stat:perms} below.\n"
627             "@item stat:nlink\n"
628             "The number of hard links to the file.\n"
629             "@item stat:uid\n"
630             "The user ID of the file's owner.\n"
631             "@item stat:gid\n"
632             "The group ID of the file.\n"
633             "@item stat:rdev\n"
634             "Device ID; this entry is defined only for character or block\n"
635             "special files.\n"
636             "@item stat:size\n"
637             "The size of a regular file in bytes.\n"
638             "@item stat:atime\n"
639             "The last access time for the file.\n"
640             "@item stat:mtime\n"
641             "The last modification time for the file.\n"
642             "@item stat:ctime\n"
643             "The last modification time for the attributes of the file.\n"
644             "@item stat:blksize\n"
645             "The optimal block size for reading or writing the file, in\n"
646             "bytes.\n"
647             "@item stat:blocks\n"
648             "The amount of disk space that the file occupies measured in\n"
649             "units of 512 byte blocks.\n"
650             "@end table\n"
651             "\n"
652             "In addition, the following procedures return the information\n"
653             "from stat:mode in a more convenient form:\n"
654             "\n"
655             "@table @code\n"
656             "@item stat:type\n"
657             "A symbol representing the type of file.  Possible values are\n"
658             "regular, directory, symlink, block-special, char-special, fifo,\n"
659             "socket and unknown\n"
660             "@item stat:perms\n"
661             "An integer representing the access permission bits.\n"
662             "@end table")
663 #define FUNC_NAME s_scm_stat
664 {
665   int rv;
666   int fdes;
667   struct stat_or_stat64 stat_temp;
668
669   if (scm_is_integer (object))
670     {
671 #ifdef __MINGW32__
672       SCM_SYSCALL (rv = fstat_Win32 (scm_to_int (object), &stat_temp));
673 #else
674       SCM_SYSCALL (rv = fstat_or_fstat64 (scm_to_int (object), &stat_temp));
675 #endif
676     }
677   else if (scm_is_string (object))
678     {
679       char *file = scm_to_locale_string (object);
680 #ifdef __MINGW32__
681       char *p;
682       p = file + strlen (file) - 1;
683       while (p > file && (*p == '/' || *p == '\\'))
684         *p-- = '\0';
685 #endif
686       SCM_SYSCALL (rv = stat_or_stat64 (file, &stat_temp));
687       free (file);
688     }
689   else
690     {
691       object = SCM_COERCE_OUTPORT (object);
692       SCM_VALIDATE_OPFPORT (1, object);
693       fdes = SCM_FPORT_FDES (object);
694 #ifdef __MINGW32__
695       SCM_SYSCALL (rv = fstat_Win32 (fdes, &stat_temp));
696 #else
697       SCM_SYSCALL (rv = fstat_or_fstat64 (fdes, &stat_temp));
698 #endif
699     }
700
701   if (rv == -1)
702     {
703       int en = errno;
704
705       SCM_SYSERROR_MSG ("~A: ~S",
706                         scm_list_2 (scm_strerror (scm_from_int (en)),
707                                     object),
708                         en);
709     }
710   return scm_stat2scm (&stat_temp);
711 }
712 #undef FUNC_NAME
713
714 \f
715 /* {Modifying Directories}
716  */
717
718 #ifdef HAVE_LINK
719 SCM_DEFINE (scm_link, "link", 2, 0, 0,
720             (SCM oldpath, SCM newpath),
721             "Creates a new name @var{newpath} in the file system for the\n"
722             "file named by @var{oldpath}.  If @var{oldpath} is a symbolic\n"
723             "link, the link may or may not be followed depending on the\n"
724             "system.")
725 #define FUNC_NAME s_scm_link
726 {
727   int val;
728
729   STRING2_SYSCALL (oldpath, c_oldpath,
730                    newpath, c_newpath,
731                    val = link (c_oldpath, c_newpath));
732   if (val != 0)
733     SCM_SYSERROR;
734   return SCM_UNSPECIFIED;
735 }
736 #undef FUNC_NAME
737 #endif /* HAVE_LINK */
738
739 #ifdef HAVE_RENAME
740 #define my_rename rename
741 #else
742 static int
743 my_rename (const char *oldname, const char *newname)
744 {
745   int rv;
746
747   SCM_SYSCALL (rv = link (oldname, newname));
748   if (rv == 0)
749     {
750       SCM_SYSCALL (rv = unlink (oldname));
751       if (rv != 0)
752         /* unlink failed.  remove new name */
753         SCM_SYSCALL (unlink (newname)); 
754     }
755   return rv;
756 }
757 #endif
758
759 SCM_DEFINE (scm_rename, "rename-file", 2, 0, 0,
760             (SCM oldname, SCM newname),
761             "Renames the file specified by @var{oldname} to @var{newname}.\n"
762             "The return value is unspecified.")
763 #define FUNC_NAME s_scm_rename
764 {
765   int rv;
766
767   STRING2_SYSCALL (oldname, c_oldname,
768                    newname, c_newname,
769                    rv = my_rename (c_oldname, c_newname));
770   if (rv != 0)
771     SCM_SYSERROR;
772   return SCM_UNSPECIFIED;
773 }
774 #undef FUNC_NAME
775
776
777 SCM_DEFINE (scm_delete_file, "delete-file", 1, 0, 0, 
778            (SCM str),
779             "Deletes (or \"unlinks\") the file specified by @var{path}.")
780 #define FUNC_NAME s_scm_delete_file
781 {
782   int ans;
783   STRING_SYSCALL (str, c_str, ans = unlink (c_str));
784   if (ans != 0)
785     SCM_SYSERROR;
786   return SCM_UNSPECIFIED;
787 }
788 #undef FUNC_NAME
789
790 #ifdef HAVE_MKDIR
791 SCM_DEFINE (scm_mkdir, "mkdir", 1, 1, 0,
792             (SCM path, SCM mode),
793             "Create a new directory named by @var{path}.  If @var{mode} is omitted\n"
794             "then the permissions of the directory file are set using the current\n"
795             "umask.  Otherwise they are set to the decimal value specified with\n"
796             "@var{mode}.  The return value is unspecified.")
797 #define FUNC_NAME s_scm_mkdir
798 {
799   int rv;
800   mode_t mask;
801
802   if (SCM_UNBNDP (mode))
803     {
804       mask = umask (0);
805       umask (mask);
806       STRING_SYSCALL (path, c_path, rv = mkdir (c_path, 0777 ^ mask));
807     }
808   else
809     {
810       STRING_SYSCALL (path, c_path, rv = mkdir (c_path, scm_to_uint (mode)));
811     }
812   if (rv != 0)
813     SCM_SYSERROR;
814   return SCM_UNSPECIFIED;
815 }
816 #undef FUNC_NAME
817 #endif /* HAVE_MKDIR */
818
819 #ifdef HAVE_RMDIR
820 SCM_DEFINE (scm_rmdir, "rmdir", 1, 0, 0, 
821             (SCM path),
822             "Remove the existing directory named by @var{path}.  The directory must\n"
823             "be empty for this to succeed.  The return value is unspecified.")
824 #define FUNC_NAME s_scm_rmdir
825 {
826   int val;
827
828   STRING_SYSCALL (path, c_path, val = rmdir (c_path));
829   if (val != 0)
830     SCM_SYSERROR;
831   return SCM_UNSPECIFIED;
832 }
833 #undef FUNC_NAME
834 #endif
835
836 \f
837
838 /* {Examining Directories}
839  */
840
841 scm_t_bits scm_tc16_dir;
842
843
844 SCM_DEFINE (scm_directory_stream_p, "directory-stream?", 1, 0, 0, 
845             (SCM obj),
846             "Return a boolean indicating whether @var{object} is a directory\n"
847             "stream as returned by @code{opendir}.")
848 #define FUNC_NAME s_scm_directory_stream_p
849 {
850   return scm_from_bool (SCM_DIRP (obj));
851 }
852 #undef FUNC_NAME
853
854
855 SCM_DEFINE (scm_opendir, "opendir", 1, 0, 0, 
856             (SCM dirname),
857             "Open the directory specified by @var{path} and return a directory\n"
858             "stream.")
859 #define FUNC_NAME s_scm_opendir
860 {
861   DIR *ds;
862   STRING_SYSCALL (dirname, c_dirname, ds = opendir (c_dirname));
863   if (ds == NULL)
864     SCM_SYSERROR;
865   SCM_RETURN_NEWSMOB (scm_tc16_dir | SCM_DIR_FLAG_OPEN, ds);
866 }
867 #undef FUNC_NAME
868
869
870 /* FIXME: The glibc manual has a portability note that readdir_r may not
871    null-terminate its return string.  The circumstances outlined for this
872    are not clear, nor is it clear what should be done about it.  Lets use
873    NAMLEN and worry about what else should be done if/when someone can
874    figure it out.  */
875
876 SCM_DEFINE (scm_readdir, "readdir", 1, 0, 0, 
877             (SCM port),
878             "Return (as a string) the next directory entry from the directory stream\n"
879             "@var{stream}.  If there is no remaining entry to be read then the\n"
880             "end of file object is returned.")
881 #define FUNC_NAME s_scm_readdir
882 {
883   struct dirent_or_dirent64 *rdent;
884
885   SCM_VALIDATE_DIR (1, port);
886   if (!SCM_DIR_OPEN_P (port))
887     SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));
888
889 #if HAVE_READDIR_R
890   /* As noted in the glibc manual, on various systems (such as Solaris) the
891      d_name[] field is only 1 char and you're expected to size the dirent
892      buffer for readdir_r based on NAME_MAX.  The SCM_MAX expressions below
893      effectively give either sizeof(d_name) or NAME_MAX+1, whichever is
894      bigger.
895
896      On solaris 10 there's no NAME_MAX constant, it's necessary to use
897      pathconf().  We prefer NAME_MAX though, since it should be a constant
898      and will therefore save a system call.  We also prefer it since dirfd()
899      is not available everywhere.
900
901      An alternative to dirfd() would be to open() the directory and then use
902      fdopendir(), if the latter is available.  That'd let us hold the fd
903      somewhere in the smob, or just the dirent size calculated once.  */
904   {
905     struct dirent_or_dirent64 de; /* just for sizeof */
906     DIR    *ds = (DIR *) SCM_CELL_WORD_1 (port);
907     size_t namlen;
908 #ifdef NAME_MAX
909     char   buf [SCM_MAX (sizeof (de),
910                          sizeof (de) - sizeof (de.d_name) + NAME_MAX + 1)];
911 #else
912     char   *buf;
913     long   name_max = fpathconf (dirfd (ds), _PC_NAME_MAX);
914     if (name_max == -1)
915       SCM_SYSERROR;
916     buf = alloca (SCM_MAX (sizeof (de),
917                            sizeof (de) - sizeof (de.d_name) + name_max + 1));
918 #endif
919
920     errno = 0;
921     SCM_SYSCALL (readdir_r_or_readdir64_r (ds, (struct dirent_or_dirent64 *) buf, &rdent));
922     if (errno != 0)
923       SCM_SYSERROR;
924     if (! rdent)
925       return SCM_EOF_VAL;
926
927     namlen = NAMLEN (rdent);
928
929     return (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent))
930             : SCM_EOF_VAL);
931   }
932 #else
933   {
934     SCM ret;
935     scm_dynwind_begin (0);
936     scm_i_dynwind_pthread_mutex_lock (&scm_i_misc_mutex);
937
938     errno = 0;
939     SCM_SYSCALL (rdent = readdir_or_readdir64 ((DIR *) SCM_CELL_WORD_1 (port)));
940     if (errno != 0)
941       SCM_SYSERROR;
942
943     ret = (rdent ? scm_from_locale_stringn (rdent->d_name, NAMLEN (rdent))
944            : SCM_EOF_VAL);
945
946     scm_dynwind_end ();
947     return ret;
948   }
949 #endif
950 }
951 #undef FUNC_NAME
952
953
954 SCM_DEFINE (scm_rewinddir, "rewinddir", 1, 0, 0, 
955             (SCM port),
956             "Reset the directory port @var{stream} so that the next call to\n"
957             "@code{readdir} will return the first directory entry.")
958 #define FUNC_NAME s_scm_rewinddir
959 {
960   SCM_VALIDATE_DIR (1, port);
961   if (!SCM_DIR_OPEN_P (port))
962     SCM_MISC_ERROR ("Directory ~S is not open.", scm_list_1 (port));
963
964   rewinddir ((DIR *) SCM_CELL_WORD_1 (port));
965
966   return SCM_UNSPECIFIED;
967 }
968 #undef FUNC_NAME
969
970
971 SCM_DEFINE (scm_closedir, "closedir", 1, 0, 0, 
972             (SCM port),
973             "Close the directory stream @var{stream}.\n"
974             "The return value is unspecified.")
975 #define FUNC_NAME s_scm_closedir
976 {
977   SCM_VALIDATE_DIR (1, port);
978
979   if (SCM_DIR_OPEN_P (port))
980     {
981       int sts;
982
983       SCM_SYSCALL (sts = closedir ((DIR *) SCM_CELL_WORD_1 (port)));
984       if (sts != 0)
985         SCM_SYSERROR;
986
987       SCM_SET_CELL_WORD_0 (port, scm_tc16_dir);
988     }
989
990   return SCM_UNSPECIFIED;
991 }
992 #undef FUNC_NAME
993
994
995 static int 
996 scm_dir_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
997 {
998   scm_puts ("#<", port);
999   if (!SCM_DIR_OPEN_P (exp))
1000     scm_puts ("closed: ", port);
1001   scm_puts ("directory stream ", port);
1002   scm_uintprint (SCM_CELL_WORD_1 (exp), 16, port);
1003   scm_putc ('>', port);
1004   return 1;
1005 }
1006
1007
1008 static size_t 
1009 scm_dir_free (SCM p)
1010 {
1011   if (SCM_DIR_OPEN_P (p))
1012     closedir ((DIR *) SCM_CELL_WORD_1 (p));
1013   return 0;
1014 }
1015
1016 \f
1017 /* {Navigating Directories}
1018  */
1019
1020
1021 SCM_DEFINE (scm_chdir, "chdir", 1, 0, 0, 
1022             (SCM str),
1023             "Change the current working directory to @var{path}.\n"
1024             "The return value is unspecified.")
1025 #define FUNC_NAME s_scm_chdir
1026 {
1027   int ans;
1028
1029   STRING_SYSCALL (str, c_str, ans = chdir (c_str));
1030   if (ans != 0)
1031     SCM_SYSERROR;
1032   return SCM_UNSPECIFIED;
1033 }
1034 #undef FUNC_NAME
1035
1036 #ifdef HAVE_GETCWD
1037 SCM_DEFINE (scm_getcwd, "getcwd", 0, 0, 0,
1038             (),
1039             "Return the name of the current working directory.")
1040 #define FUNC_NAME s_scm_getcwd
1041 {
1042   char *rv;
1043   size_t size = 100;
1044   char *wd;
1045   SCM result;
1046
1047   wd = scm_malloc (size);
1048   while ((rv = getcwd (wd, size)) == 0 && errno == ERANGE)
1049     {
1050       free (wd);
1051       size *= 2;
1052       wd = scm_malloc (size);
1053     }
1054   if (rv == 0)
1055     {
1056       int save_errno = errno;
1057       free (wd);
1058       errno = save_errno;
1059       SCM_SYSERROR;
1060     }
1061   result = scm_from_locale_stringn (wd, strlen (wd));
1062   free (wd);
1063   return result;
1064 }
1065 #undef FUNC_NAME
1066 #endif /* HAVE_GETCWD */
1067
1068 \f
1069
1070 #ifdef HAVE_SELECT
1071
1072 /* check that element is a port or file descriptor.  if it's a port
1073    and its buffer is ready for use, add it to the ports_ready list.
1074    otherwise add its file descriptor to *set.  the type of list can be
1075    determined from pos: SCM_ARG1 for reads, SCM_ARG2 for writes,
1076    SCM_ARG3 for excepts.  */
1077 static int
1078 set_element (SELECT_TYPE *set, SCM *ports_ready, SCM element, int pos)
1079 {
1080   int fd;
1081
1082   if (scm_is_integer (element))
1083     {
1084       fd = scm_to_int (element);
1085     }
1086   else
1087     {
1088       int use_buf = 0;
1089
1090       element = SCM_COERCE_OUTPORT (element);
1091       SCM_ASSERT (SCM_OPFPORTP (element), element, pos, "select");
1092       if (pos == SCM_ARG1)
1093         {
1094           /* check whether port has buffered input.  */
1095           scm_t_port *pt = SCM_PTAB_ENTRY (element);
1096       
1097           if (pt->read_pos < pt->read_end)
1098             use_buf = 1;
1099         }
1100       else if (pos == SCM_ARG2)
1101         {
1102           /* check whether port's output buffer has room.  */
1103           scm_t_port *pt = SCM_PTAB_ENTRY (element);
1104
1105           /* > 1 since writing the last byte in the buffer causes flush.  */
1106           if (pt->write_end - pt->write_pos > 1)
1107             use_buf = 1;
1108         }
1109       fd = use_buf ? -1 : SCM_FPORT_FDES (element);
1110     }
1111   if (fd == -1)
1112     *ports_ready = scm_cons (element, *ports_ready);
1113   else
1114     FD_SET (fd, set);
1115   return fd;
1116 }
1117
1118 /* check list_or_vec, a list or vector of ports or file descriptors,
1119    adding each member to either the ports_ready list (if it's a port
1120    with a usable buffer) or to *set.  the kind of list_or_vec can be
1121    determined from pos: SCM_ARG1 for reads, SCM_ARG2 for writes,
1122    SCM_ARG3 for excepts.  */
1123 static int
1124 fill_select_type (SELECT_TYPE *set, SCM *ports_ready, SCM list_or_vec, int pos)
1125 {
1126   int max_fd = 0;
1127
1128   if (scm_is_simple_vector (list_or_vec))
1129     {
1130       int i = SCM_SIMPLE_VECTOR_LENGTH (list_or_vec);
1131       
1132       while (--i >= 0)
1133         {
1134           int fd = set_element (set, ports_ready,
1135                                 SCM_SIMPLE_VECTOR_REF (list_or_vec, i), pos);
1136
1137           if (fd > max_fd)
1138             max_fd = fd;
1139         }
1140     }
1141   else
1142     {
1143       while (!SCM_NULL_OR_NIL_P (list_or_vec))
1144         {
1145           int fd = set_element (set, ports_ready, SCM_CAR (list_or_vec), pos);
1146
1147           if (fd > max_fd)
1148             max_fd = fd;
1149           list_or_vec = SCM_CDR (list_or_vec);
1150         }
1151     }
1152
1153   return max_fd;
1154 }
1155
1156 /* if element (a file descriptor or port) appears in *set, cons it to
1157    list.  return list.  */
1158 static SCM
1159 get_element (SELECT_TYPE *set, SCM element, SCM list)
1160 {
1161   int fd;
1162
1163   if (scm_is_integer (element))
1164     {
1165       fd = scm_to_int (element);
1166     }
1167   else
1168     {
1169       fd = SCM_FPORT_FDES (SCM_COERCE_OUTPORT (element));
1170     }
1171   if (FD_ISSET (fd, set))
1172     list = scm_cons (element, list);
1173   return list;
1174 }
1175
1176 /* construct component of scm_select return value.
1177    set: pointer to set of file descriptors found by select to be ready
1178    ports_ready: ports ready due to buffering
1179    list_or_vec: original list/vector handed to scm_select.
1180    the return value is a list/vector of ready ports/file descriptors. 
1181    works by finding the objects in list which correspond to members of
1182    *set and appending them to ports_ready.  result is converted to a
1183    vector if list_or_vec is a vector.  */
1184 static SCM 
1185 retrieve_select_type (SELECT_TYPE *set, SCM ports_ready, SCM list_or_vec)
1186 {
1187   SCM answer_list = ports_ready;
1188
1189   if (scm_is_simple_vector (list_or_vec))
1190     {
1191       int i = SCM_SIMPLE_VECTOR_LENGTH (list_or_vec);
1192
1193       while (--i >= 0)
1194         {
1195           answer_list = get_element (set,
1196                                      SCM_SIMPLE_VECTOR_REF (list_or_vec, i),
1197                                      answer_list);
1198         }
1199       return scm_vector (answer_list);
1200     }
1201   else
1202     {
1203       /* list_or_vec must be a list.  */
1204       while (!SCM_NULL_OR_NIL_P (list_or_vec))
1205         {
1206           answer_list = get_element (set, SCM_CAR (list_or_vec), answer_list);
1207           list_or_vec = SCM_CDR (list_or_vec);
1208         }
1209       return answer_list;
1210     }
1211 }
1212
1213 /* Static helper functions above refer to s_scm_select directly as s_select */
1214 SCM_DEFINE (scm_select, "select", 3, 2, 0, 
1215             (SCM reads, SCM writes, SCM excepts, SCM secs, SCM usecs),
1216             "This procedure has a variety of uses: waiting for the ability\n"
1217             "to provide input, accept output, or the existence of\n"
1218             "exceptional conditions on a collection of ports or file\n"
1219             "descriptors, or waiting for a timeout to occur.\n"
1220             "It also returns if interrupted by a signal.\n\n"
1221             "@var{reads}, @var{writes} and @var{excepts} can be lists or\n"
1222             "vectors, with each member a port or a file descriptor.\n"
1223             "The value returned is a list of three corresponding\n"
1224             "lists or vectors containing only the members which meet the\n"
1225             "specified requirement.  The ability of port buffers to\n"
1226             "provide input or accept output is taken into account.\n"
1227             "Ordering of the input lists or vectors is not preserved.\n\n"
1228             "The optional arguments @var{secs} and @var{usecs} specify the\n"
1229             "timeout.  Either @var{secs} can be specified alone, as\n"
1230             "either an integer or a real number, or both @var{secs} and\n"
1231             "@var{usecs} can be specified as integers, in which case\n"
1232             "@var{usecs} is an additional timeout expressed in\n"
1233             "microseconds.  If @var{secs} is omitted or is @code{#f} then\n"
1234             "select will wait for as long as it takes for one of the other\n"
1235             "conditions to be satisfied.\n\n"
1236             "The scsh version of @code{select} differs as follows:\n"
1237             "Only vectors are accepted for the first three arguments.\n"
1238             "The @var{usecs} argument is not supported.\n"
1239             "Multiple values are returned instead of a list.\n"
1240             "Duplicates in the input vectors appear only once in output.\n"
1241             "An additional @code{select!} interface is provided.")
1242 #define FUNC_NAME s_scm_select
1243 {
1244   struct timeval timeout;
1245   struct timeval * time_ptr;
1246   SELECT_TYPE read_set;
1247   SELECT_TYPE write_set;
1248   SELECT_TYPE except_set;
1249   int read_count;
1250   int write_count;
1251   int except_count;
1252   /* these lists accumulate ports which are ready due to buffering.
1253      their file descriptors don't need to be added to the select sets.  */
1254   SCM read_ports_ready = SCM_EOL;
1255   SCM write_ports_ready = SCM_EOL;
1256   int max_fd;
1257
1258   if (scm_is_simple_vector (reads))
1259     {
1260       read_count = SCM_SIMPLE_VECTOR_LENGTH (reads);
1261     }
1262   else
1263     {
1264       read_count = scm_ilength (reads);
1265       SCM_ASSERT (read_count >= 0, reads, SCM_ARG1, FUNC_NAME);
1266     }
1267   if (scm_is_simple_vector (writes))
1268     {
1269       write_count = SCM_SIMPLE_VECTOR_LENGTH (writes);
1270     }
1271   else
1272     {
1273       write_count = scm_ilength (writes);
1274       SCM_ASSERT (write_count >= 0, writes, SCM_ARG2, FUNC_NAME);
1275     }
1276   if (scm_is_simple_vector (excepts))
1277     {
1278       except_count = SCM_SIMPLE_VECTOR_LENGTH (excepts);
1279     }
1280   else
1281     {
1282       except_count = scm_ilength (excepts);
1283       SCM_ASSERT (except_count >= 0, excepts, SCM_ARG3, FUNC_NAME);
1284     }
1285
1286   FD_ZERO (&read_set);
1287   FD_ZERO (&write_set);
1288   FD_ZERO (&except_set);
1289
1290   max_fd = fill_select_type (&read_set, &read_ports_ready, reads, SCM_ARG1);
1291
1292   {
1293     int write_max = fill_select_type (&write_set, &write_ports_ready, 
1294                                       writes, SCM_ARG2);
1295     int except_max = fill_select_type (&except_set, NULL,
1296                                        excepts, SCM_ARG3);
1297
1298     if (write_max > max_fd)
1299       max_fd = write_max;
1300     if (except_max > max_fd)
1301       max_fd = except_max;
1302   }
1303
1304   /* if there's a port with a ready buffer, don't block, just
1305      check for ready file descriptors.  */
1306   if (!scm_is_null (read_ports_ready) || !scm_is_null (write_ports_ready))
1307     {
1308       timeout.tv_sec = 0;
1309       timeout.tv_usec = 0;
1310       time_ptr = &timeout;
1311     }
1312   else if (SCM_UNBNDP (secs) || scm_is_false (secs))
1313     time_ptr = 0;
1314   else
1315     {
1316       if (scm_is_unsigned_integer (secs, 0, ULONG_MAX))
1317         {
1318           timeout.tv_sec = scm_to_ulong (secs);
1319           if (SCM_UNBNDP (usecs))
1320             timeout.tv_usec = 0;
1321           else
1322             timeout.tv_usec = scm_to_long (usecs);
1323         }
1324       else
1325         {
1326           double fl = scm_to_double (secs);
1327
1328           if (!SCM_UNBNDP (usecs))
1329             SCM_WRONG_TYPE_ARG (4, secs);
1330           if (fl > LONG_MAX)
1331             SCM_OUT_OF_RANGE (4, secs);
1332           timeout.tv_sec = (long) fl;
1333           timeout.tv_usec = (long) ((fl - timeout.tv_sec) * 1000000);
1334         }
1335       time_ptr = &timeout;
1336     }
1337
1338   {
1339     int rv = scm_std_select (max_fd + 1,
1340                              &read_set, &write_set, &except_set,
1341                              time_ptr);
1342     if (rv < 0)
1343       SCM_SYSERROR;
1344   }
1345   return scm_list_3 (retrieve_select_type (&read_set, read_ports_ready, reads),
1346                      retrieve_select_type (&write_set, write_ports_ready, writes),
1347                      retrieve_select_type (&except_set, SCM_EOL, excepts));
1348 }
1349 #undef FUNC_NAME
1350 #endif /* HAVE_SELECT */
1351
1352 \f
1353
1354 #ifdef HAVE_FCNTL
1355 SCM_DEFINE (scm_fcntl, "fcntl", 2, 1, 0,
1356             (SCM object, SCM cmd, SCM value),
1357             "Apply @var{command} to the specified file descriptor or the underlying\n"
1358             "file descriptor of the specified port.  @var{value} is an optional\n"
1359             "integer argument.\n\n"
1360             "Values for @var{command} are:\n\n"
1361             "@table @code\n"
1362             "@item F_DUPFD\n"
1363             "Duplicate a file descriptor\n"
1364             "@item F_GETFD\n"
1365             "Get flags associated with the file descriptor.\n"
1366             "@item F_SETFD\n"
1367             "Set flags associated with the file descriptor to @var{value}.\n"
1368             "@item F_GETFL\n"
1369             "Get flags associated with the open file.\n"
1370             "@item F_SETFL\n"
1371             "Set flags associated with the open file to @var{value}\n"
1372             "@item F_GETOWN\n"
1373             "Get the process ID of a socket's owner, for @code{SIGIO} signals.\n"
1374             "@item F_SETOWN\n"
1375             "Set the process that owns a socket to @var{value}, for @code{SIGIO} signals.\n"
1376             "@item FD_CLOEXEC\n"
1377             "The value used to indicate the \"close on exec\" flag with @code{F_GETFL} or\n"
1378             "@code{F_SETFL}.\n"
1379             "@end table")
1380 #define FUNC_NAME s_scm_fcntl
1381 {
1382   int rv;
1383   int fdes;
1384   int ivalue;
1385
1386   object = SCM_COERCE_OUTPORT (object);
1387
1388   if (SCM_OPFPORTP (object))
1389     fdes = SCM_FPORT_FDES (object);
1390   else
1391     fdes = scm_to_int (object);
1392
1393   if (SCM_UNBNDP (value))
1394     ivalue = 0;
1395   else
1396     ivalue = scm_to_int (value);
1397
1398   SCM_SYSCALL (rv = fcntl (fdes, scm_to_int (cmd), ivalue));
1399   if (rv == -1)
1400     SCM_SYSERROR;
1401   return scm_from_int (rv);
1402 }
1403 #undef FUNC_NAME
1404 #endif /* HAVE_FCNTL */
1405
1406 SCM_DEFINE (scm_fsync, "fsync", 1, 0, 0, 
1407             (SCM object),
1408             "Copies any unwritten data for the specified output file descriptor to disk.\n"
1409             "If @var{port/fd} is a port, its buffer is flushed before the underlying\n"
1410             "file descriptor is fsync'd.\n"
1411             "The return value is unspecified.")
1412 #define FUNC_NAME s_scm_fsync
1413 {
1414   int fdes;
1415
1416   object = SCM_COERCE_OUTPORT (object);
1417
1418   if (SCM_OPFPORTP (object))
1419     {
1420       scm_flush (object);
1421       fdes = SCM_FPORT_FDES (object);
1422     }
1423   else
1424     fdes = scm_to_int (object);
1425
1426   if (fsync (fdes) == -1)
1427     SCM_SYSERROR;
1428   return SCM_UNSPECIFIED;
1429 }
1430 #undef FUNC_NAME
1431
1432 #ifdef HAVE_SYMLINK
1433 SCM_DEFINE (scm_symlink, "symlink", 2, 0, 0,
1434             (SCM oldpath, SCM newpath),
1435             "Create a symbolic link named @var{path-to} with the value (i.e., pointing to)\n"
1436             "@var{path-from}.  The return value is unspecified.")
1437 #define FUNC_NAME s_scm_symlink
1438 {
1439   int val;
1440
1441   STRING2_SYSCALL (oldpath, c_oldpath,
1442                    newpath, c_newpath,
1443                    val = symlink (c_oldpath, c_newpath));
1444   if (val != 0)
1445     SCM_SYSERROR;
1446   return SCM_UNSPECIFIED;
1447 }
1448 #undef FUNC_NAME
1449 #endif /* HAVE_SYMLINK */
1450
1451 #ifdef HAVE_READLINK
1452 SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0, 
1453             (SCM path),
1454             "Return the value of the symbolic link named by @var{path} (a\n"
1455             "string), i.e., the file that the link points to.")
1456 #define FUNC_NAME s_scm_readlink
1457 {
1458   int rv;
1459   int size = 100;
1460   char *buf;
1461   SCM result;
1462   char *c_path;
1463   
1464   scm_dynwind_begin (0);
1465
1466   c_path = scm_to_locale_string (path);
1467   scm_dynwind_free (c_path);
1468
1469   buf = scm_malloc (size);
1470
1471   while ((rv = readlink (c_path, buf, size)) == size)
1472     {
1473       free (buf);
1474       size *= 2;
1475       buf = scm_malloc (size);
1476     }
1477   if (rv == -1)
1478     {
1479       int save_errno = errno;
1480       free (buf);
1481       errno = save_errno;
1482       SCM_SYSERROR;
1483     }
1484   result = scm_take_locale_stringn (buf, rv);
1485
1486   scm_dynwind_end ();
1487   return result;
1488 }
1489 #undef FUNC_NAME
1490 #endif /* HAVE_READLINK */
1491
1492 #ifdef HAVE_LSTAT
1493 SCM_DEFINE (scm_lstat, "lstat", 1, 0, 0, 
1494             (SCM str),
1495             "Similar to @code{stat}, but does not follow symbolic links, i.e.,\n"
1496             "it will return information about a symbolic link itself, not the\n"
1497             "file it points to.  @var{path} must be a string.")
1498 #define FUNC_NAME s_scm_lstat
1499 {
1500   int rv;
1501   struct stat_or_stat64 stat_temp;
1502
1503   STRING_SYSCALL (str, c_str, rv = lstat_or_lstat64 (c_str, &stat_temp));
1504   if (rv != 0)
1505     {
1506       int en = errno;
1507
1508       SCM_SYSERROR_MSG ("~A: ~S",
1509                         scm_list_2 (scm_strerror (scm_from_int (en)), str),
1510                         en);
1511     }
1512   return scm_stat2scm (&stat_temp);
1513 }
1514 #undef FUNC_NAME
1515 #endif /* HAVE_LSTAT */
1516
1517 SCM_DEFINE (scm_copy_file, "copy-file", 2, 0, 0,
1518             (SCM oldfile, SCM newfile),
1519             "Copy the file specified by @var{path-from} to @var{path-to}.\n"
1520             "The return value is unspecified.")
1521 #define FUNC_NAME s_scm_copy_file
1522 {
1523   char *c_oldfile, *c_newfile;
1524   int oldfd, newfd;
1525   int n, rv;
1526   char buf[BUFSIZ];
1527   struct stat_or_stat64 oldstat;
1528
1529   scm_dynwind_begin (0);
1530   
1531   c_oldfile = scm_to_locale_string (oldfile);
1532   scm_dynwind_free (c_oldfile);
1533   c_newfile = scm_to_locale_string (newfile);
1534   scm_dynwind_free (c_newfile);
1535
1536   oldfd = open_or_open64 (c_oldfile, O_RDONLY);
1537   if (oldfd == -1)
1538     SCM_SYSERROR;
1539
1540 #ifdef __MINGW32__
1541   SCM_SYSCALL (rv = fstat_Win32 (oldfd, &oldstat));
1542 #else
1543   SCM_SYSCALL (rv = fstat_or_fstat64 (oldfd, &oldstat));
1544 #endif
1545   if (rv == -1)
1546     goto err_close_oldfd;
1547
1548   /* use POSIX flags instead of 07777?.  */
1549   newfd = open_or_open64 (c_newfile, O_WRONLY | O_CREAT | O_TRUNC,
1550                           oldstat.st_mode & 07777);
1551   if (newfd == -1)
1552     {
1553     err_close_oldfd:
1554       close (oldfd);
1555       SCM_SYSERROR;
1556     }
1557
1558   while ((n = read (oldfd, buf, sizeof buf)) > 0)
1559     if (write (newfd, buf, n) != n)
1560       {
1561         close (oldfd);
1562         close (newfd);
1563         SCM_SYSERROR;
1564       }
1565   close (oldfd);
1566   if (close (newfd) == -1)
1567     SCM_SYSERROR;
1568
1569   scm_dynwind_end ();
1570   return SCM_UNSPECIFIED;
1571 }
1572 #undef FUNC_NAME
1573
1574 \f
1575 /* Filename manipulation */
1576
1577 SCM scm_dot_string;
1578
1579 SCM_DEFINE (scm_dirname, "dirname", 1, 0, 0, 
1580             (SCM filename),
1581             "Return the directory name component of the file name\n"
1582             "@var{filename}. If @var{filename} does not contain a directory\n"
1583             "component, @code{.} is returned.")
1584 #define FUNC_NAME s_scm_dirname
1585 {
1586   const char *s;
1587   long int i;
1588   unsigned long int len;
1589
1590   SCM_VALIDATE_STRING (1, filename);
1591
1592   s = scm_i_string_chars (filename);
1593   len = scm_i_string_length (filename);
1594
1595   i = len - 1;
1596 #ifdef __MINGW32__
1597   while (i >= 0 && (s[i] == '/' || s[i] == '\\')) --i;
1598   while (i >= 0 && (s[i] != '/' && s[i] != '\\')) --i;
1599   while (i >= 0 && (s[i] == '/' || s[i] == '\\')) --i;
1600 #else
1601   while (i >= 0 && s[i] == '/') --i;
1602   while (i >= 0 && s[i] != '/') --i;
1603   while (i >= 0 && s[i] == '/') --i;
1604 #endif /* ndef __MINGW32__ */
1605   if (i < 0)
1606     {
1607 #ifdef __MINGW32__
1608       if (len > 0 && (s[0] == '/' || s[0] == '\\'))
1609 #else
1610       if (len > 0 && s[0] == '/')
1611 #endif /* ndef __MINGW32__ */
1612         return scm_c_substring (filename, 0, 1);
1613       else
1614         return scm_dot_string;
1615     }
1616   else
1617     return scm_c_substring (filename, 0, i + 1);
1618 }
1619 #undef FUNC_NAME
1620
1621 SCM_DEFINE (scm_basename, "basename", 1, 1, 0, 
1622             (SCM filename, SCM suffix),
1623             "Return the base name of the file name @var{filename}. The\n"
1624             "base name is the file name without any directory components.\n"
1625             "If @var{suffix} is provided, and is equal to the end of\n"
1626             "@var{basename}, it is removed also.")
1627 #define FUNC_NAME s_scm_basename
1628 {
1629   const char *f, *s = 0;
1630   int i, j, len, end;
1631
1632   SCM_VALIDATE_STRING (1, filename);
1633   f = scm_i_string_chars (filename);
1634   len = scm_i_string_length (filename);
1635
1636   if (SCM_UNBNDP (suffix))
1637     j = -1;
1638   else
1639     {
1640       SCM_VALIDATE_STRING (2, suffix);
1641       s = scm_i_string_chars (suffix);
1642       j = scm_i_string_length (suffix) - 1;
1643     }
1644   i = len - 1;
1645 #ifdef __MINGW32__
1646   while (i >= 0 && (f[i] == '/' || f[i] == '\\')) --i;
1647 #else
1648   while (i >= 0 && f[i] == '/') --i;
1649 #endif /* ndef __MINGW32__ */
1650   end = i;
1651   while (i >= 0 && j >= 0 && f[i] == s[j]) --i, --j;
1652   if (j == -1)
1653     end = i;
1654 #ifdef __MINGW32__
1655   while (i >= 0 && f[i] != '/' && f[i] != '\\') --i;
1656 #else
1657   while (i >= 0 && f[i] != '/') --i;
1658 #endif /* ndef __MINGW32__ */
1659   if (i == end)
1660     {
1661 #ifdef __MINGW32__
1662       if (len > 0 && (f[0] == '/' || f[0] == '\\'))
1663 #else
1664       if (len > 0 && f[0] == '/')
1665 #endif /* ndef __MINGW32__ */
1666         return scm_c_substring (filename, 0, 1);
1667       else
1668         return scm_dot_string;
1669     }
1670   else
1671     return scm_c_substring (filename, i+1, end+1);
1672 }
1673 #undef FUNC_NAME
1674
1675
1676
1677 \f
1678
1679 void
1680 scm_init_filesys ()
1681 {
1682   scm_tc16_dir = scm_make_smob_type ("directory", 0);
1683   scm_set_smob_free (scm_tc16_dir, scm_dir_free);
1684   scm_set_smob_print (scm_tc16_dir, scm_dir_print);
1685
1686   scm_dot_string = scm_permanent_object (scm_from_locale_string ("."));
1687   
1688 #ifdef O_RDONLY
1689   scm_c_define ("O_RDONLY", scm_from_int (O_RDONLY));
1690 #endif         
1691 #ifdef O_WRONLY
1692   scm_c_define ("O_WRONLY", scm_from_int (O_WRONLY));
1693 #endif         
1694 #ifdef O_RDWR
1695   scm_c_define ("O_RDWR", scm_from_int (O_RDWR));
1696 #endif         
1697 #ifdef O_CREAT
1698   scm_c_define ("O_CREAT", scm_from_int (O_CREAT));
1699 #endif         
1700 #ifdef O_EXCL  
1701   scm_c_define ("O_EXCL", scm_from_int (O_EXCL));
1702 #endif         
1703 #ifdef O_NOCTTY
1704   scm_c_define ("O_NOCTTY", scm_from_int (O_NOCTTY));
1705 #endif         
1706 #ifdef O_TRUNC 
1707   scm_c_define ("O_TRUNC", scm_from_int (O_TRUNC));
1708 #endif         
1709 #ifdef O_APPEND
1710   scm_c_define ("O_APPEND", scm_from_int (O_APPEND));
1711 #endif         
1712 #ifdef O_NONBLOCK
1713   scm_c_define ("O_NONBLOCK", scm_from_int (O_NONBLOCK));
1714 #endif         
1715 #ifdef O_NDELAY
1716   scm_c_define ("O_NDELAY", scm_from_int (O_NDELAY));
1717 #endif         
1718 #ifdef O_SYNC  
1719   scm_c_define ("O_SYNC", scm_from_int (O_SYNC));
1720 #endif 
1721 #ifdef O_LARGEFILE  
1722   scm_c_define ("O_LARGEFILE", scm_from_int (O_LARGEFILE));
1723 #endif 
1724
1725 #ifdef F_DUPFD  
1726   scm_c_define ("F_DUPFD", scm_from_int (F_DUPFD));
1727 #endif 
1728 #ifdef F_GETFD  
1729   scm_c_define ("F_GETFD", scm_from_int (F_GETFD));
1730 #endif 
1731 #ifdef F_SETFD  
1732   scm_c_define ("F_SETFD", scm_from_int (F_SETFD));
1733 #endif 
1734 #ifdef F_GETFL  
1735   scm_c_define ("F_GETFL", scm_from_int (F_GETFL));
1736 #endif 
1737 #ifdef F_SETFL  
1738   scm_c_define ("F_SETFL", scm_from_int (F_SETFL));
1739 #endif 
1740 #ifdef F_GETOWN  
1741   scm_c_define ("F_GETOWN", scm_from_int (F_GETOWN));
1742 #endif 
1743 #ifdef F_SETOWN  
1744   scm_c_define ("F_SETOWN", scm_from_int (F_SETOWN));
1745 #endif 
1746 #ifdef FD_CLOEXEC  
1747   scm_c_define ("FD_CLOEXEC", scm_from_int (FD_CLOEXEC));
1748 #endif
1749
1750 #include "libguile/filesys.x"
1751 }
1752
1753 /*
1754   Local Variables:
1755   c-file-style: "gnu"
1756   End:
1757 */