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