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