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