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