* net_db.c (scm_resolv_error): Cast result from hstrerror.
[bpt/guile.git] / libguile / filesys.c
CommitLineData
def804a3 1/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
0f2d19dd
JB
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
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
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.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd 45\f
3d8d56df 46#include <stdio.h>
0f2d19dd 47#include "_scm.h"
20e6290e
JB
48#include "genio.h"
49#include "smob.h"
52f4f4d6 50#include "feature.h"
3d8d56df 51#include "fports.h"
44e8413c 52#include "iselect.h"
0f2d19dd 53
1bbd0b84 54#include "scm_validate.h"
20e6290e 55#include "filesys.h"
def804a3 56
0f2d19dd 57\f
def804a3
JB
58#ifdef HAVE_IO_H
59#include <io.h>
60#endif
61
0f2d19dd
JB
62#ifdef TIME_WITH_SYS_TIME
63# include <sys/time.h>
64# include <time.h>
65#else
66# if HAVE_SYS_TIME_H
67# include <sys/time.h>
68# else
69# include <time.h>
70# endif
71#endif
72
73#ifdef HAVE_UNISTD_H
74#include <unistd.h>
75#endif
76
3594582b 77#ifdef LIBC_H_WITH_UNISTD_H
1f9e2226
JB
78#include <libc.h>
79#endif
80
0f2d19dd
JB
81#ifdef HAVE_SYS_SELECT_H
82#include <sys/select.h>
83#endif
84
1f9e2226
JB
85#ifdef HAVE_STRING_H
86#include <string.h>
87#endif
88
8cc71382 89#include <sys/types.h>
0f2d19dd
JB
90#include <sys/stat.h>
91#include <fcntl.h>
92
93#include <pwd.h>
94
95
0f2d19dd
JB
96#if HAVE_DIRENT_H
97# include <dirent.h>
98# define NAMLEN(dirent) strlen((dirent)->d_name)
99#else
100# define dirent direct
101# define NAMLEN(dirent) (dirent)->d_namlen
102# if HAVE_SYS_NDIR_H
103# include <sys/ndir.h>
104# endif
105# if HAVE_SYS_DIR_H
106# include <sys/dir.h>
107# endif
108# if HAVE_NDIR_H
109# include <ndir.h>
110# endif
111#endif
112
d7b8a21a
JB
113/* Ultrix has S_IFSOCK, but no S_ISSOCK. Ipe! */
114#if defined (S_IFSOCK) && ! defined (S_ISSOCK)
115#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
116#endif
0f2d19dd
JB
117\f
118
0f2d19dd
JB
119
120\f
121
122/* {Permissions}
123 */
124
a1ec6916 125SCM_DEFINE (scm_chown, "chown", 3, 0, 0,
1bbd0b84 126 (SCM object, SCM owner, SCM group),
d3818c29
MD
127 "Change the ownership and group of the file referred to by @var{obj} to\n"
128 "the integer userid values @var{owner} and @var{group}. @var{obj} can be\n"
129 "a string containing a file name or a port or integer file descriptor\n"
130 "which is open on the file (in which case fchown is used as the underlying\n"
131 "system call). The return value\n"
132 "is unspecified.\n\n"
133 "If @var{obj} is a symbolic link, either the\n"
134 "ownership of the link or the ownership of the referenced file will be\n"
135 "changed depending on the operating system (lchown is\n"
136 "unsupported at present). If @var{owner} or @var{group} is specified\n"
137 "as @code{-1}, then that ID is not changed.")
1bbd0b84 138#define FUNC_NAME s_scm_chown
0f2d19dd 139{
6afcd3b2
GH
140 int rv;
141 int fdes;
02b754d3 142
78446828
MV
143 object = SCM_COERCE_OUTPORT (object);
144
3b3b36dd
GB
145 SCM_VALIDATE_INUM (2,owner);
146 SCM_VALIDATE_INUM (3,group);
0c95b57d 147 if (SCM_INUMP (object) || (SCM_OPFPORTP (object)))
6afcd3b2
GH
148 {
149 if (SCM_INUMP (object))
150 fdes = SCM_INUM (object);
151 else
77a76b64 152 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
153 SCM_SYSCALL (rv = fchown (fdes, SCM_INUM (owner), SCM_INUM (group)));
154 }
155 else
156 {
c1bfcf60 157 SCM_VALIDATE_ROSTRING(1,object);
6afcd3b2
GH
158 SCM_COERCE_SUBSTR (object);
159 SCM_SYSCALL (rv = chown (SCM_ROCHARS (object),
160 SCM_INUM (owner), SCM_INUM (group)));
161 }
162 if (rv == -1)
1bbd0b84 163 SCM_SYSERROR;
02b754d3 164 return SCM_UNSPECIFIED;
0f2d19dd 165}
1bbd0b84 166#undef FUNC_NAME
0f2d19dd
JB
167
168
a1ec6916 169SCM_DEFINE (scm_chmod, "chmod", 2, 0, 0,
1bbd0b84 170 (SCM object, SCM mode),
d3818c29
MD
171 "Changes the permissions of the file referred to by @var{obj}.\n"
172 "@var{obj} can be a string containing a file name or a port or integer file\n"
173 "descriptor which is open on a file (in which case @code{fchmod} is used\n"
174 "as the underlying system call).\n"
175 "@var{mode} specifies\n"
176 "the new permissions as a decimal number, e.g., @code{(chmod \"foo\" #o755)}.\n"
177 "The return value is unspecified.")
1bbd0b84 178#define FUNC_NAME s_scm_chmod
0f2d19dd
JB
179{
180 int rv;
6afcd3b2
GH
181 int fdes;
182
78446828
MV
183 object = SCM_COERCE_OUTPORT (object);
184
3b3b36dd 185 SCM_VALIDATE_INUM (2,mode);
0c95b57d 186 if (SCM_INUMP (object) || SCM_OPFPORTP (object))
89958ad0 187 {
6afcd3b2
GH
188 if (SCM_INUMP (object))
189 fdes = SCM_INUM (object);
190 else
77a76b64 191 fdes = SCM_FPORT_FDES (object);
6afcd3b2 192 SCM_SYSCALL (rv = fchmod (fdes, SCM_INUM (mode)));
89958ad0 193 }
0f2d19dd
JB
194 else
195 {
3b3b36dd 196 SCM_VALIDATE_ROSTRING (1,object);
6afcd3b2
GH
197 SCM_COERCE_SUBSTR (object);
198 SCM_SYSCALL (rv = chmod (SCM_ROCHARS (object), SCM_INUM (mode)));
0f2d19dd 199 }
6afcd3b2 200 if (rv == -1)
1bbd0b84 201 SCM_SYSERROR;
02b754d3 202 return SCM_UNSPECIFIED;
0f2d19dd 203}
1bbd0b84 204#undef FUNC_NAME
0f2d19dd 205
a1ec6916 206SCM_DEFINE (scm_umask, "umask", 0, 1, 0,
1bbd0b84 207 (SCM mode),
d3818c29
MD
208 "If @var{mode} is omitted, retuns a decimal number representing the current\n"
209 "file creation mask. Otherwise the file creation mask is set to\n"
210 "@var{mode} and the previous value is returned.\n\n"
211 "E.g., @code{(umask #o022)} sets the mask to octal 22, decimal 18.")
1bbd0b84 212#define FUNC_NAME s_scm_umask
0f2d19dd
JB
213{
214 mode_t mask;
215 if (SCM_UNBNDP (mode))
216 {
217 mask = umask (0);
218 umask (mask);
219 }
220 else
221 {
3b3b36dd 222 SCM_VALIDATE_INUM (1,mode);
0f2d19dd
JB
223 mask = umask (SCM_INUM (mode));
224 }
225 return SCM_MAKINUM (mask);
226}
1bbd0b84 227#undef FUNC_NAME
0f2d19dd
JB
228
229\f
0f2d19dd 230
a1ec6916 231SCM_DEFINE (scm_open_fdes, "open-fdes", 2, 1, 0,
1bbd0b84 232 (SCM path, SCM flags, SCM mode),
d3818c29
MD
233 "Similar to @code{open} but returns a file descriptor instead of a\n"
234 "port.")
1bbd0b84 235#define FUNC_NAME s_scm_open_fdes
0f2d19dd
JB
236{
237 int fd;
3d8d56df 238 int iflags;
6afcd3b2 239 int imode;
0f2d19dd 240
3b3b36dd 241 SCM_VALIDATE_ROSTRING (1,path);
6afcd3b2 242 SCM_COERCE_SUBSTR (path);
c1bfcf60
GB
243 iflags = SCM_NUM2LONG(2,flags);
244 imode = SCM_NUM2LONG_DEF(3,mode,0666);
6afcd3b2 245 SCM_SYSCALL (fd = open (SCM_ROCHARS (path), iflags, imode));
3d8d56df 246 if (fd == -1)
1bbd0b84 247 SCM_SYSERROR;
6afcd3b2
GH
248 return SCM_MAKINUM (fd);
249}
1bbd0b84 250#undef FUNC_NAME
6afcd3b2 251
a1ec6916 252SCM_DEFINE (scm_open, "open", 2, 1, 0,
1bbd0b84 253 (SCM path, SCM flags, SCM mode),
d3818c29
MD
254 "Open the file named by @var{path} for reading and/or writing.\n"
255 "@var{flags} is an integer specifying how the file should be opened.\n"
256 "@var{mode} is an integer specifying the permission bits of the file, if\n"
257 "it needs to be created, before the umask is applied. The default is 666\n"
258 "(Unix itself has no default).\n\n"
259 "@var{flags} can be constructed by combining variables using @code{logior}.\n"
260 "Basic flags are:\n\n"
261 "@defvar O_RDONLY\n"
262 "Open the file read-only.\n"
263 "@end defvar\n"
264 "@defvar O_WRONLY\n"
265 "Open the file write-only. \n"
266 "@end defvar\n"
267 "@defvar O_RDWR\n"
268 "Open the file read/write.\n"
269 "@end defvar\n"
270 "@defvar O_APPEND\n"
271 "Append to the file instead of truncating.\n"
272 "@end defvar\n"
273 "@defvar O_CREAT\n"
274 "Create the file if it does not already exist.\n"
275 "@end defvar\n\n"
276 "See the Unix documentation of the @code{open} system call\n"
277 "for additional flags.")
1bbd0b84 278#define FUNC_NAME s_scm_open
6afcd3b2
GH
279{
280 SCM newpt;
281 char *port_mode;
282 int fd;
6afcd3b2
GH
283 int iflags;
284
285 fd = SCM_INUM (scm_open_fdes (path, flags, mode));
c1bfcf60 286 iflags = SCM_NUM2LONG (2,flags);
3d8d56df 287 if (iflags & O_RDWR)
77a76b64
JB
288 {
289 if (iflags & O_APPEND)
290 port_mode = "a+";
291 else if (iflags & O_CREAT)
292 port_mode = "w+";
293 else
294 port_mode = "r+";
295 }
3d8d56df 296 else {
77a76b64
JB
297 if (iflags & O_APPEND)
298 port_mode = "a";
299 else if (iflags & O_WRONLY)
3d8d56df
GH
300 port_mode = "w";
301 else
302 port_mode = "r";
303 }
77a76b64 304 newpt = scm_fdes_to_port (fd, port_mode, path);
3d8d56df 305 return newpt;
0f2d19dd 306}
1bbd0b84 307#undef FUNC_NAME
0f2d19dd 308
a1ec6916 309SCM_DEFINE (scm_close, "close", 1, 0, 0,
1bbd0b84 310 (SCM fd_or_port),
d3818c29
MD
311 "Similar to close-port (@pxref{Generic Port Operations, close-port}),\n"
312 "but also works on file descriptors. A side\n"
313 "effect of closing a file descriptor is that any ports using that file\n"
314 "descriptor are moved to a different file descriptor and have\n"
315 "their revealed counts set to zero.")
1bbd0b84 316#define FUNC_NAME s_scm_close
eadd48de
GH
317{
318 int rv;
319 int fd;
320
78446828
MV
321 fd_or_port = SCM_COERCE_OUTPORT (fd_or_port);
322
0c95b57d 323 if (SCM_PORTP (fd_or_port))
eadd48de 324 return scm_close_port (fd_or_port);
3b3b36dd 325 SCM_VALIDATE_INUM (1,fd_or_port);
eadd48de 326 fd = SCM_INUM (fd_or_port);
eadd48de 327 scm_evict_ports (fd); /* see scsh manual. */
a9488d12 328 SCM_SYSCALL (rv = close (fd));
eadd48de
GH
329 /* following scsh, closing an already closed file descriptor is
330 not an error. */
331 if (rv < 0 && errno != EBADF)
1bbd0b84
GB
332 SCM_SYSERROR;
333 return SCM_NEGATE_BOOL(rv < 0);
eadd48de 334}
1bbd0b84 335#undef FUNC_NAME
eadd48de 336
0f2d19dd
JB
337\f
338/* {Files}
339 */
1cc91f1b 340
ae5253c5
GH
341SCM_SYMBOL (scm_sym_regular, "regular");
342SCM_SYMBOL (scm_sym_directory, "directory");
f326ecf3 343#ifdef HAVE_S_ISLNK
ae5253c5 344SCM_SYMBOL (scm_sym_symlink, "symlink");
f326ecf3 345#endif
ae5253c5
GH
346SCM_SYMBOL (scm_sym_block_special, "block-special");
347SCM_SYMBOL (scm_sym_char_special, "char-special");
348SCM_SYMBOL (scm_sym_fifo, "fifo");
349SCM_SYMBOL (scm_sym_sock, "socket");
350SCM_SYMBOL (scm_sym_unknown, "unknown");
351
0f2d19dd 352static SCM
1bbd0b84 353scm_stat2scm (struct stat *stat_temp)
0f2d19dd 354{
a8741caa 355 SCM ans = scm_make_vector (SCM_MAKINUM (15), SCM_UNSPECIFIED);
0f2d19dd 356 SCM *ve = SCM_VELTS (ans);
ae5253c5 357
0f2d19dd
JB
358 ve[0] = scm_ulong2num ((unsigned long) stat_temp->st_dev);
359 ve[1] = scm_ulong2num ((unsigned long) stat_temp->st_ino);
360 ve[2] = scm_ulong2num ((unsigned long) stat_temp->st_mode);
361 ve[3] = scm_ulong2num ((unsigned long) stat_temp->st_nlink);
362 ve[4] = scm_ulong2num ((unsigned long) stat_temp->st_uid);
363 ve[5] = scm_ulong2num ((unsigned long) stat_temp->st_gid);
364#ifdef HAVE_ST_RDEV
365 ve[6] = scm_ulong2num ((unsigned long) stat_temp->st_rdev);
366#else
367 ve[6] = SCM_BOOL_F;
368#endif
369 ve[7] = scm_ulong2num ((unsigned long) stat_temp->st_size);
370 ve[8] = scm_ulong2num ((unsigned long) stat_temp->st_atime);
371 ve[9] = scm_ulong2num ((unsigned long) stat_temp->st_mtime);
372 ve[10] = scm_ulong2num ((unsigned long) stat_temp->st_ctime);
373#ifdef HAVE_ST_BLKSIZE
374 ve[11] = scm_ulong2num ((unsigned long) stat_temp->st_blksize);
375#else
376 ve[11] = scm_ulong2num (4096L);
377#endif
378#ifdef HAVE_ST_BLOCKS
379 ve[12] = scm_ulong2num ((unsigned long) stat_temp->st_blocks);
380#else
381 ve[12] = SCM_BOOL_F;
382#endif
ae5253c5
GH
383 {
384 int mode = stat_temp->st_mode;
385
386 if (S_ISREG (mode))
387 ve[13] = scm_sym_regular;
388 else if (S_ISDIR (mode))
389 ve[13] = scm_sym_directory;
f326ecf3 390#ifdef HAVE_S_ISLNK
ae5253c5
GH
391 else if (S_ISLNK (mode))
392 ve[13] = scm_sym_symlink;
f326ecf3 393#endif
ae5253c5
GH
394 else if (S_ISBLK (mode))
395 ve[13] = scm_sym_block_special;
396 else if (S_ISCHR (mode))
397 ve[13] = scm_sym_char_special;
398 else if (S_ISFIFO (mode))
399 ve[13] = scm_sym_fifo;
400 else if (S_ISSOCK (mode))
401 ve[13] = scm_sym_sock;
402 else
403 ve[13] = scm_sym_unknown;
404
405 ve[14] = SCM_MAKINUM ((~S_IFMT) & mode);
406
407 /* the layout of the bits in ve[14] is intended to be portable.
408 If there are systems that don't follow the usual convention,
409 the following could be used:
410
411 tmp = 0;
412 if (S_ISUID & mode) tmp += 1;
413 tmp <<= 1;
414 if (S_IRGRP & mode) tmp += 1;
415 tmp <<= 1;
416 if (S_ISVTX & mode) tmp += 1;
417 tmp <<= 1;
418 if (S_IRUSR & mode) tmp += 1;
419 tmp <<= 1;
420 if (S_IWUSR & mode) tmp += 1;
421 tmp <<= 1;
422 if (S_IXUSR & mode) tmp += 1;
423 tmp <<= 1;
424 if (S_IWGRP & mode) tmp += 1;
425 tmp <<= 1;
426 if (S_IXGRP & mode) tmp += 1;
427 tmp <<= 1;
428 if (S_IROTH & mode) tmp += 1;
429 tmp <<= 1;
430 if (S_IWOTH & mode) tmp += 1;
431 tmp <<= 1;
432 if (S_IXOTH & mode) tmp += 1;
433
434 ve[14] = SCM_MAKINUM (tmp);
435
436 */
437 }
0f2d19dd
JB
438
439 return ans;
440}
441
a1ec6916 442SCM_DEFINE (scm_stat, "stat", 1, 0, 0,
1bbd0b84 443 (SCM object),
d3818c29
MD
444 "Returns an object containing various information\n"
445 "about the file determined by @var{obj}.\n"
446 "@var{obj} can be a string containing a file name or a port or integer file\n"
447 "descriptor which is open on a file (in which case @code{fstat} is used\n"
448 "as the underlying system call).\n\n"
449 "The object returned by @code{stat} can be passed as a single parameter\n"
450 "to the following procedures, all of which return integers:\n\n"
451 "@table @code\n"
452 "@item stat:dev\n"
453 "The device containing the file.\n"
454 "@item stat:ino\n"
455 "The file serial number, which distinguishes this file from all other\n"
456 "files on the same device.\n"
457 "@item stat:mode\n"
458 "The mode of the file. This includes file type information\n"
459 "and the file permission bits. See @code{stat:type} and @code{stat:perms}\n"
460 "below.\n"
461 "@item stat:nlink\n"
462 "The number of hard links to the file.\n"
463 "@item stat:uid\n"
464 "The user ID of the file's owner.\n"
465 "@item stat:gid\n"
466 "The group ID of the file.\n"
467 "@item stat:rdev\n"
468 "Device ID; this entry is defined only for character or block\n"
469 "special files.\n"
470 "@item stat:size\n"
471 "The size of a regular file in bytes.\n"
472 "@item stat:atime\n"
473 "The last access time for the file.\n"
474 "@item stat:mtime\n"
475 "The last modification time for the file.\n"
476 "@item stat:ctime\n"
477 "The last modification time for the attributes of the file.\n"
478 "@item stat:blksize\n"
479 "The optimal block size for reading or writing the file, in bytes.\n"
480 "@item stat:blocks\n"
481 "The amount of disk space that the file occupies measured in units of\n"
482 "512 byte blocks.\n"
483 "@end table\n\n"
484 "In addition, the following procedures return the information\n"
485 "from stat:mode in a more convenient form:\n\n"
486 "@table @code\n"
487 "@item stat:type\n"
488 "A symbol representing the type of file. Possible values are\n"
489 "regular, directory, symlink, block-special, char-special,\n"
490 "fifo, socket and unknown\n"
491 "@item stat:perms\n"
492 "An integer representing the access permission bits.\n"
493 "@end table")
1bbd0b84 494#define FUNC_NAME s_scm_stat
0f2d19dd 495{
6afcd3b2
GH
496 int rv;
497 int fdes;
0f2d19dd
JB
498 struct stat stat_temp;
499
1ea47048
MD
500 if (SCM_INUMP (object))
501 SCM_SYSCALL (rv = fstat (SCM_INUM (object), &stat_temp));
502 else
0f2d19dd 503 {
6b5a304f 504 SCM_VALIDATE_NIM (1,object);
1ea47048
MD
505 if (SCM_ROSTRINGP (object))
506 {
507 SCM_COERCE_SUBSTR (object);
508 SCM_SYSCALL (rv = stat (SCM_ROCHARS (object), &stat_temp));
509 }
c0ebd8c5 510 else
0f2d19dd 511 {
1ea47048 512 object = SCM_COERCE_OUTPORT (object);
c1bfcf60 513 SCM_VALIDATE_OPFPORT(1,object);
77a76b64 514 fdes = SCM_FPORT_FDES (object);
1ea47048 515 SCM_SYSCALL (rv = fstat (fdes, &stat_temp));
0f2d19dd 516 }
6afcd3b2
GH
517 }
518 if (rv == -1)
3d8d56df
GH
519 {
520 int en = errno;
521
5d2d2ffc 522 SCM_SYSERROR_MSG ("~A: ~S",
3d8d56df 523 scm_listify (scm_makfrom0str (strerror (errno)),
6afcd3b2 524 object,
5d2d2ffc 525 SCM_UNDEFINED), en);
3d8d56df 526 }
02b754d3 527 return scm_stat2scm (&stat_temp);
0f2d19dd 528}
1bbd0b84 529#undef FUNC_NAME
0f2d19dd 530
0f2d19dd
JB
531\f
532/* {Modifying Directories}
533 */
534
a1ec6916 535SCM_DEFINE (scm_link, "link", 2, 0, 0,
1bbd0b84 536 (SCM oldpath, SCM newpath),
d3818c29
MD
537 "Creates a new name @var{path-to} in the file system for the file\n"
538 "named by @var{path-from}. If @var{path-from} is a symbolic link, the\n"
539 "link may or may not be followed depending on the system.")
1bbd0b84 540#define FUNC_NAME s_scm_link
0f2d19dd
JB
541{
542 int val;
02b754d3 543
3b3b36dd 544 SCM_VALIDATE_ROSTRING (1,oldpath);
0f2d19dd 545 if (SCM_SUBSTRP (oldpath))
6afcd3b2
GH
546 oldpath = scm_makfromstr (SCM_ROCHARS (oldpath),
547 SCM_ROLENGTH (oldpath), 0);
3b3b36dd 548 SCM_VALIDATE_ROSTRING (2,newpath);
0f2d19dd 549 if (SCM_SUBSTRP (newpath))
6afcd3b2
GH
550 newpath = scm_makfromstr (SCM_ROCHARS (newpath),
551 SCM_ROLENGTH (newpath), 0);
0f2d19dd 552 SCM_SYSCALL (val = link (SCM_ROCHARS (oldpath), SCM_ROCHARS (newpath)));
02b754d3 553 if (val != 0)
1bbd0b84 554 SCM_SYSERROR;
02b754d3 555 return SCM_UNSPECIFIED;
0f2d19dd 556}
1bbd0b84 557#undef FUNC_NAME
0f2d19dd
JB
558
559
560
a1ec6916 561SCM_DEFINE (scm_rename, "rename-file", 2, 0, 0,
1bbd0b84 562 (SCM oldname, SCM newname),
d3818c29
MD
563 "Renames the file specified by @var{path-from} to @var{path-to}.\n"
564 "The return value is unspecified.")
1bbd0b84 565#define FUNC_NAME s_scm_rename
0f2d19dd
JB
566{
567 int rv;
3b3b36dd
GB
568 SCM_VALIDATE_ROSTRING (1,oldname);
569 SCM_VALIDATE_ROSTRING (2,newname);
89958ad0
JB
570 SCM_COERCE_SUBSTR (oldname);
571 SCM_COERCE_SUBSTR (newname);
0f2d19dd 572#ifdef HAVE_RENAME
89958ad0 573 SCM_SYSCALL (rv = rename (SCM_ROCHARS (oldname), SCM_ROCHARS (newname)));
0f2d19dd 574#else
89958ad0 575 SCM_SYSCALL (rv = link (SCM_ROCHARS (oldname), SCM_ROCHARS (newname)));
02b754d3 576 if (rv == 0)
0f2d19dd 577 {
89958ad0 578 SCM_SYSCALL (rv = unlink (SCM_ROCHARS (oldname)));;
02b754d3 579 if (rv != 0)
0f2d19dd 580 /* unlink failed. remove new name */
89958ad0 581 SCM_SYSCALL (unlink (SCM_ROCHARS (newname)));
0f2d19dd 582 }
6afcd3b2 583#endif
02b754d3 584 if (rv != 0)
1bbd0b84 585 SCM_SYSERROR;
02b754d3 586 return SCM_UNSPECIFIED;
0f2d19dd 587}
1bbd0b84 588#undef FUNC_NAME
0f2d19dd
JB
589
590
3b3b36dd 591SCM_DEFINE (scm_delete_file, "delete-file", 1, 0, 0,
1bbd0b84 592 (SCM str),
d3818c29 593 "Deletes (or \"unlinks\") the file specified by @var{path}.")
1bbd0b84 594#define FUNC_NAME s_scm_delete_file
2f3ed1ba
JB
595{
596 int ans;
3b3b36dd 597 SCM_VALIDATE_ROSTRING (1,str);
89958ad0
JB
598 SCM_COERCE_SUBSTR (str);
599 SCM_SYSCALL (ans = unlink (SCM_ROCHARS (str)));
2f3ed1ba 600 if (ans != 0)
1bbd0b84 601 SCM_SYSERROR;
2f3ed1ba
JB
602 return SCM_UNSPECIFIED;
603}
1bbd0b84 604#undef FUNC_NAME
2f3ed1ba 605
f25f761d 606#ifdef HAVE_MKDIR
a1ec6916 607SCM_DEFINE (scm_mkdir, "mkdir", 1, 1, 0,
1bbd0b84 608 (SCM path, SCM mode),
d3818c29
MD
609 "Create a new directory named by @var{path}. If @var{mode} is omitted\n"
610 "then the permissions of the directory file are set using the current\n"
611 "umask. Otherwise they are set to the decimal value specified with\n"
612 "@var{mode}. The return value is unspecified.")
1bbd0b84 613#define FUNC_NAME s_scm_mkdir
0f2d19dd 614{
0f2d19dd
JB
615 int rv;
616 mode_t mask;
3b3b36dd 617 SCM_VALIDATE_ROSTRING (1,path);
89958ad0 618 SCM_COERCE_SUBSTR (path);
0f2d19dd
JB
619 if (SCM_UNBNDP (mode))
620 {
621 mask = umask (0);
622 umask (mask);
89958ad0 623 SCM_SYSCALL (rv = mkdir (SCM_ROCHARS (path), 0777 ^ mask));
0f2d19dd
JB
624 }
625 else
626 {
3b3b36dd 627 SCM_VALIDATE_INUM (2,mode);
89958ad0 628 SCM_SYSCALL (rv = mkdir (SCM_ROCHARS (path), SCM_INUM (mode)));
0f2d19dd 629 }
02b754d3 630 if (rv != 0)
1bbd0b84 631 SCM_SYSERROR;
02b754d3 632 return SCM_UNSPECIFIED;
0f2d19dd 633}
1bbd0b84 634#undef FUNC_NAME
f25f761d 635#endif /* HAVE_MKDIR */
0f2d19dd 636
f25f761d 637#ifdef HAVE_RMDIR
a1ec6916 638SCM_DEFINE (scm_rmdir, "rmdir", 1, 0, 0,
1bbd0b84 639 (SCM path),
d3818c29
MD
640 "Remove the existing directory named by @var{path}. The directory must\n"
641 "be empty for this to succeed. The return value is unspecified.")
1bbd0b84 642#define FUNC_NAME s_scm_rmdir
0f2d19dd 643{
0f2d19dd 644 int val;
02b754d3 645
3b3b36dd 646 SCM_VALIDATE_ROSTRING (1,path);
89958ad0
JB
647 SCM_COERCE_SUBSTR (path);
648 SCM_SYSCALL (val = rmdir (SCM_ROCHARS (path)));
02b754d3 649 if (val != 0)
1bbd0b84 650 SCM_SYSERROR;
02b754d3 651 return SCM_UNSPECIFIED;
0f2d19dd 652}
1bbd0b84 653#undef FUNC_NAME
f25f761d 654#endif
0f2d19dd
JB
655
656\f
657/* {Examining Directories}
658 */
659
660long scm_tc16_dir;
661
a1ec6916 662SCM_DEFINE (scm_directory_stream_p, "directory-stream?", 1, 0, 0,
1bbd0b84 663 (SCM obj),
d3818c29
MD
664 "Returns a boolean indicating whether @var{object} is a directory stream\n"
665 "as returned by @code{opendir}.")
1bbd0b84 666#define FUNC_NAME s_scm_directory_stream_p
77242ff9 667{
0c95b57d 668 return SCM_BOOL(SCM_DIRP (obj));
77242ff9 669}
1bbd0b84 670#undef FUNC_NAME
77242ff9 671
a1ec6916 672SCM_DEFINE (scm_opendir, "opendir", 1, 0, 0,
1bbd0b84 673 (SCM dirname),
d3818c29
MD
674 "Open the directory specified by @var{path} and return a directory\n"
675 "stream.")
1bbd0b84 676#define FUNC_NAME s_scm_opendir
0f2d19dd
JB
677{
678 DIR *ds;
3b3b36dd 679 SCM_VALIDATE_ROSTRING (1,dirname);
89958ad0 680 SCM_COERCE_SUBSTR (dirname);
89958ad0 681 SCM_SYSCALL (ds = opendir (SCM_ROCHARS (dirname)));
02b754d3 682 if (ds == NULL)
1bbd0b84 683 SCM_SYSERROR;
23a62151 684 SCM_RETURN_NEWSMOB (scm_tc16_dir | SCM_OPN, ds);
0f2d19dd 685}
1bbd0b84 686#undef FUNC_NAME
0f2d19dd
JB
687
688
a1ec6916 689SCM_DEFINE (scm_readdir, "readdir", 1, 0, 0,
1bbd0b84 690 (SCM port),
d3818c29
MD
691 "Return (as a string) the next directory entry from the directory stream\n"
692 "@var{stream}. If there is no remaining entry to be read then the\n"
693 "end of file object is returned.")
1bbd0b84 694#define FUNC_NAME s_scm_readdir
0f2d19dd
JB
695{
696 struct dirent *rdent;
3b3b36dd 697 SCM_VALIDATE_OPDIR (1,port);
0f2d19dd
JB
698 errno = 0;
699 SCM_SYSCALL (rdent = readdir ((DIR *) SCM_CDR (port)));
02b754d3 700 if (errno != 0)
1bbd0b84 701 SCM_SYSERROR;
02b754d3
GH
702 return (rdent ? scm_makfromstr (rdent->d_name, NAMLEN (rdent), 0)
703 : SCM_EOF_VAL);
0f2d19dd 704}
1bbd0b84 705#undef FUNC_NAME
0f2d19dd
JB
706
707
708
a1ec6916 709SCM_DEFINE (scm_rewinddir, "rewinddir", 1, 0, 0,
1bbd0b84 710 (SCM port),
d3818c29
MD
711 "Reset the directory port @var{stream} so that the next call to\n"
712 "@code{readdir} will return the first directory entry.")
1bbd0b84 713#define FUNC_NAME s_scm_rewinddir
0f2d19dd 714{
3b3b36dd 715 SCM_VALIDATE_OPDIR (1,port);
0f2d19dd
JB
716 rewinddir ((DIR *) SCM_CDR (port));
717 return SCM_UNSPECIFIED;
718}
1bbd0b84 719#undef FUNC_NAME
0f2d19dd
JB
720
721
722
a1ec6916 723SCM_DEFINE (scm_closedir, "closedir", 1, 0, 0,
1bbd0b84 724 (SCM port),
d3818c29
MD
725 "Close the directory stream @var{stream}.\n"
726 "The return value is unspecified.")
1bbd0b84 727#define FUNC_NAME s_scm_closedir
0f2d19dd
JB
728{
729 int sts;
02b754d3 730
3b3b36dd 731 SCM_VALIDATE_DIR (1,port);
0f2d19dd
JB
732 if (SCM_CLOSEDP (port))
733 {
02b754d3 734 return SCM_UNSPECIFIED;
0f2d19dd
JB
735 }
736 SCM_SYSCALL (sts = closedir ((DIR *) SCM_CDR (port)));
02b754d3 737 if (sts != 0)
1bbd0b84 738 SCM_SYSERROR;
a6c64c3c 739 SCM_SETCAR (port, scm_tc16_dir);
02b754d3 740 return SCM_UNSPECIFIED;
0f2d19dd 741}
1bbd0b84 742#undef FUNC_NAME
0f2d19dd
JB
743
744
745
1cc91f1b 746
0f2d19dd 747static int
f8b16091 748scm_dir_print (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 749{
f8b16091
MD
750 scm_puts ("#<", port);
751 if (SCM_CLOSEDP (exp))
752 scm_puts ("closed: ", port);
0d03da62 753 scm_puts ("directory stream ", port);
f8b16091
MD
754 scm_intprint (SCM_CDR (exp), 16, port);
755 scm_putc ('>', port);
0f2d19dd
JB
756 return 1;
757}
758
1cc91f1b 759
0f2d19dd 760static scm_sizet
1bbd0b84 761scm_dir_free (SCM p)
0f2d19dd
JB
762{
763 if (SCM_OPENP (p))
764 closedir ((DIR *) SCM_CDR (p));
765 return 0;
766}
767
0f2d19dd
JB
768\f
769/* {Navigating Directories}
770 */
771
772
a1ec6916 773SCM_DEFINE (scm_chdir, "chdir", 1, 0, 0,
1bbd0b84 774 (SCM str),
d3818c29
MD
775 "Change the current working directory to @var{path}.\n"
776 "The return value is unspecified.")
1bbd0b84 777#define FUNC_NAME s_scm_chdir
0f2d19dd
JB
778{
779 int ans;
02b754d3 780
3b3b36dd 781 SCM_VALIDATE_ROSTRING (1,str);
89958ad0
JB
782 SCM_COERCE_SUBSTR (str);
783 SCM_SYSCALL (ans = chdir (SCM_ROCHARS (str)));
02b754d3 784 if (ans != 0)
1bbd0b84 785 SCM_SYSERROR;
02b754d3 786 return SCM_UNSPECIFIED;
0f2d19dd 787}
1bbd0b84 788#undef FUNC_NAME
0f2d19dd 789
f25f761d 790#ifdef HAVE_GETCWD
a1ec6916 791SCM_DEFINE (scm_getcwd, "getcwd", 0, 0, 0,
1bbd0b84 792 (),
d3818c29 793 "Returns the name of the current working directory.")
1bbd0b84 794#define FUNC_NAME s_scm_getcwd
0f2d19dd 795{
0f2d19dd
JB
796 char *rv;
797
798 scm_sizet size = 100;
799 char *wd;
800 SCM result;
801
1bbd0b84 802 wd = scm_must_malloc (size, FUNC_NAME);
0f2d19dd
JB
803 while ((rv = getcwd (wd, size)) == 0 && errno == ERANGE)
804 {
805 scm_must_free (wd);
806 size *= 2;
1bbd0b84 807 wd = scm_must_malloc (size, FUNC_NAME);
0f2d19dd 808 }
02b754d3 809 if (rv == 0)
1bbd0b84 810 SCM_SYSERROR;
02b754d3 811 result = scm_makfromstr (wd, strlen (wd), 0);
0f2d19dd 812 scm_must_free (wd);
0f2d19dd 813 return result;
0f2d19dd 814}
1bbd0b84 815#undef FUNC_NAME
f25f761d 816#endif /* HAVE_GETCWD */
0f2d19dd
JB
817
818\f
819
cafc12ff
MD
820static int
821set_element (SELECT_TYPE *set, SCM element, int arg)
a48a89bc 822{
cafc12ff 823 int fd;
78446828 824 element = SCM_COERCE_OUTPORT (element);
0c95b57d 825 if (SCM_OPFPORTP (element))
77a76b64 826 fd = SCM_FPORT_FDES (element);
cafc12ff 827 else {
1bbd0b84 828 SCM_ASSERT (SCM_INUMP (element), element, arg, "select");
cafc12ff
MD
829 fd = SCM_INUM (element);
830 }
831 FD_SET (fd, set);
832 return fd;
a48a89bc 833}
1cc91f1b 834
cafc12ff
MD
835static int
836fill_select_type (SELECT_TYPE *set, SCM list, int arg)
0f2d19dd 837{
cafc12ff 838 int max_fd = 0, fd;
0c95b57d 839 if (SCM_VECTORP (list))
0f2d19dd 840 {
a48a89bc
GH
841 int len = SCM_LENGTH (list);
842 SCM *ve = SCM_VELTS (list);
843
844 while (len > 0)
845 {
cafc12ff
MD
846 fd = set_element (set, ve[len - 1], arg);
847 if (fd > max_fd)
848 max_fd = fd;
a48a89bc
GH
849 len--;
850 }
851 }
852 else
853 {
854 while (list != SCM_EOL)
855 {
cafc12ff
MD
856 fd = set_element (set, SCM_CAR (list), arg);
857 if (fd > max_fd)
858 max_fd = fd;
a48a89bc
GH
859 list = SCM_CDR (list);
860 }
0f2d19dd 861 }
cafc12ff
MD
862
863 return max_fd;
0f2d19dd
JB
864}
865
a48a89bc
GH
866static SCM
867get_element (SELECT_TYPE *set, SCM element, SCM list)
868{
78446828 869 element = SCM_COERCE_OUTPORT (element);
0c95b57d 870 if (SCM_OPFPORTP (element))
a48a89bc 871 {
77a76b64 872 if (FD_ISSET (SCM_FPORT_FDES (element), set))
a48a89bc
GH
873 list = scm_cons (element, list);
874 }
875 else if (SCM_INUMP (element))
876 {
877 if (FD_ISSET (SCM_INUM (element), set))
878 list = scm_cons (element, list);
879 }
880 return list;
881}
1cc91f1b 882
0f2d19dd 883static SCM
a48a89bc 884retrieve_select_type (SELECT_TYPE *set, SCM list)
0f2d19dd 885{
a48a89bc
GH
886 SCM answer_list = SCM_EOL;
887
0c95b57d 888 if (SCM_VECTORP (list))
0f2d19dd 889 {
a48a89bc
GH
890 int len = SCM_LENGTH (list);
891 SCM *ve = SCM_VELTS (list);
892
893 while (len > 0)
0f2d19dd 894 {
a48a89bc
GH
895 answer_list = get_element (set, ve[len - 1], answer_list);
896 len--;
0f2d19dd 897 }
a48a89bc
GH
898 return scm_vector (answer_list);
899 }
900 else
901 {
902 /* list is a list. */
903 while (list != SCM_EOL)
0f2d19dd 904 {
a48a89bc
GH
905 answer_list = get_element (set, SCM_CAR (list), answer_list);
906 list = SCM_CDR (list);
0f2d19dd 907 }
a48a89bc 908 return answer_list;
0f2d19dd 909 }
0f2d19dd
JB
910}
911
f25f761d 912#ifdef HAVE_SELECT
1bbd0b84 913/* Static helper functions above refer to s_scm_select directly as s_select */
a1ec6916 914SCM_DEFINE (scm_select, "select", 3, 2, 0,
1bbd0b84 915 (SCM reads, SCM writes, SCM excepts, SCM secs, SCM usecs),
d3818c29
MD
916 "@var{reads}, @var{writes} and @var{excepts} can be lists or vectors: it\n"
917 "doesn't matter which, but the corresponding object returned will be\n"
918 "of the same type.\n"
919 "Each element is a port or file descriptor on which to wait for\n"
920 "readability, writeability\n"
921 "or exceptional conditions respectively. @var{secs} and @var{usecs}\n"
922 "optionally specify a timeout: @var{secs} can be specified alone, as\n"
923 "either an integer or a real number, or both @var{secs} and @var{usecs}\n"
924 "can be specified as integers, in which case @var{usecs} is an additional\n"
925 "timeout expressed in microseconds.\n\n"
926 "Buffered input or output data is (currently, but this may change)\n"
927 "ignored: select uses the underlying file descriptor of a port\n"
928 "(@code{char-ready?} will check input buffers, output buffers are\n"
929 "problematic).\n\n"
930 "The return value is a list of subsets of the input lists or vectors for\n"
931 "which the requested condition has been met.\n\n"
932 "It is not quite compatible with scsh's select: scsh checks port buffers,\n"
933 "doesn't accept input lists or a microsecond timeout, returns multiple\n"
934 "values instead of a list and has an additional select! interface.\n"
935 "")
1bbd0b84 936#define FUNC_NAME s_scm_select
0f2d19dd 937{
0f2d19dd
JB
938 struct timeval timeout;
939 struct timeval * time_p;
940 SELECT_TYPE read_set;
941 SELECT_TYPE write_set;
942 SELECT_TYPE except_set;
cafc12ff 943 int max_fd, fd;
0f2d19dd
JB
944 int sreturn;
945
a48a89bc 946#define assert_set(x, arg) \
0c95b57d 947 SCM_ASSERT (scm_ilength (x) >= 0 || (SCM_VECTORP (x)), \
1bbd0b84 948 x, arg, FUNC_NAME)
a48a89bc
GH
949 assert_set (reads, SCM_ARG1);
950 assert_set (writes, SCM_ARG2);
951 assert_set (excepts, SCM_ARG3);
952#undef assert_set
0f2d19dd
JB
953
954 FD_ZERO (&read_set);
955 FD_ZERO (&write_set);
956 FD_ZERO (&except_set);
957
cafc12ff
MD
958 max_fd = fill_select_type (&read_set, reads, SCM_ARG1);
959 fd = fill_select_type (&write_set, writes, SCM_ARG2);
960 if (fd > max_fd)
961 max_fd = fd;
962 fd = fill_select_type (&except_set, excepts, SCM_ARG3);
963 if (fd > max_fd)
964 max_fd = fd;
0f2d19dd 965
a48a89bc 966 if (SCM_UNBNDP (secs) || SCM_FALSEP (secs))
0f2d19dd
JB
967 time_p = 0;
968 else
969 {
a48a89bc
GH
970 if (SCM_INUMP (secs))
971 {
972 timeout.tv_sec = SCM_INUM (secs);
973 if (SCM_UNBNDP (usecs))
974 timeout.tv_usec = 0;
975 else
976 {
3b3b36dd 977 SCM_VALIDATE_INUM (5,usecs);
a48a89bc
GH
978 timeout.tv_usec = SCM_INUM (usecs);
979 }
980 }
0f2d19dd 981 else
a48a89bc 982 {
1bbd0b84 983 double fl = scm_num2dbl (secs, FUNC_NAME);
a48a89bc
GH
984
985 if (!SCM_UNBNDP (usecs))
c1bfcf60 986 SCM_WRONG_TYPE_ARG (4, secs);
a48a89bc 987 if (fl > LONG_MAX)
c1bfcf60 988 SCM_OUT_OF_RANGE (4, secs);
a48a89bc
GH
989 timeout.tv_sec = (long) fl;
990 timeout.tv_usec = (long) ((fl - timeout.tv_sec) * 1000000);
991 }
0f2d19dd
JB
992 time_p = &timeout;
993 }
994
44e8413c 995#ifdef GUILE_ISELECT
cafc12ff 996 sreturn = scm_internal_select (max_fd + 1,
44e8413c
MD
997 &read_set, &write_set, &except_set, time_p);
998#else
cafc12ff 999 sreturn = select (max_fd + 1,
0f2d19dd 1000 &read_set, &write_set, &except_set, time_p);
44e8413c 1001#endif
0f2d19dd 1002 if (sreturn < 0)
1bbd0b84 1003 SCM_SYSERROR;
02b754d3
GH
1004 return scm_listify (retrieve_select_type (&read_set, reads),
1005 retrieve_select_type (&write_set, writes),
1006 retrieve_select_type (&except_set, excepts),
1007 SCM_UNDEFINED);
0f2d19dd 1008}
1bbd0b84 1009#undef FUNC_NAME
f25f761d 1010#endif /* HAVE_SELECT */
0f2d19dd
JB
1011
1012\f
4c1feaa5 1013
a1ec6916 1014SCM_DEFINE (scm_fcntl, "fcntl", 2, 0, 1,
1bbd0b84 1015 (SCM object, SCM cmd, SCM value),
d3818c29
MD
1016 "Apply @var{command} to the specified file descriptor or the underlying\n"
1017 "file descriptor of the specified port. @var{value} is an optional\n"
1018 "integer argument.\n\n"
1019 "Values for @var{command} are:\n\n"
1020 "@table @code\n"
1021 "@item F_DUPFD\n"
1022 "Duplicate a file descriptor\n"
1023 "@item F_GETFD\n"
1024 "Get flags associated with the file descriptor.\n"
1025 "@item F_SETFD\n"
1026 "Set flags associated with the file descriptor to @var{value}.\n"
1027 "@item F_GETFL\n"
1028 "Get flags associated with the open file.\n"
1029 "@item F_SETFL\n"
1030 "Set flags associated with the open file to @var{value}\n"
1031 "@item F_GETOWN\n"
1032 "Get the process ID of a socket's owner, for @code{SIGIO} signals.\n"
1033 "@item F_SETOWN\n"
1034 "Set the process that owns a socket to @var{value}, for @code{SIGIO} signals.\n"
1035 "@item FD_CLOEXEC\n"
1036 "The value used to indicate the "close on exec" flag with @code{F_GETFL} or
4079f87e
GB
1037@code{F_SETFL}.
1038@end table")
1bbd0b84 1039#define FUNC_NAME s_scm_fcntl
4c1feaa5
JB
1040{
1041 int rv;
6afcd3b2
GH
1042 int fdes;
1043 int ivalue;
4c1feaa5 1044
78446828
MV
1045 object = SCM_COERCE_OUTPORT (object);
1046
3b3b36dd 1047 SCM_VALIDATE_INUM (2,cmd);
0c95b57d 1048 if (SCM_OPFPORTP (object))
77a76b64 1049 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
1050 else
1051 {
3b3b36dd 1052 SCM_VALIDATE_INUM (1,object);
6afcd3b2
GH
1053 fdes = SCM_INUM (object);
1054 }
1055 if (SCM_NULLP (value))
1056 ivalue = 0;
1057 else
1058 {
1bbd0b84 1059 SCM_ASSERT (SCM_INUMP (SCM_CAR (value)), value, SCM_ARG3, FUNC_NAME);
6afcd3b2
GH
1060 ivalue = SCM_INUM (SCM_CAR (value));
1061 }
77a76b64
JB
1062 SCM_SYSCALL (rv = fcntl (fdes, SCM_INUM (cmd), ivalue));
1063 if (rv == -1)
1bbd0b84 1064 SCM_SYSERROR;
4c1feaa5
JB
1065 return SCM_MAKINUM (rv);
1066}
1bbd0b84 1067#undef FUNC_NAME
6afcd3b2 1068
a1ec6916 1069SCM_DEFINE (scm_fsync, "fsync", 1, 0, 0,
1bbd0b84 1070 (SCM object),
d3818c29
MD
1071 "Copies any unwritten data for the specified output file descriptor to disk.\n"
1072 "If @var{port/fd} is a port, its buffer is flushed before the underlying\n"
1073 "file descriptor is fsync'd.\n"
1074 "The return value is unspecified.")
1bbd0b84 1075#define FUNC_NAME s_scm_fsync
6afcd3b2
GH
1076{
1077 int fdes;
1078
78446828
MV
1079 object = SCM_COERCE_OUTPORT (object);
1080
0c95b57d 1081 if (SCM_OPFPORTP (object))
6afcd3b2 1082 {
affc96b5 1083 scm_flush (object);
77a76b64 1084 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
1085 }
1086 else
1087 {
3b3b36dd 1088 SCM_VALIDATE_INUM (1,object);
6afcd3b2
GH
1089 fdes = SCM_INUM (object);
1090 }
1091 if (fsync (fdes) == -1)
1bbd0b84 1092 SCM_SYSERROR;
6afcd3b2
GH
1093 return SCM_UNSPECIFIED;
1094}
1bbd0b84 1095#undef FUNC_NAME
0f2d19dd 1096
f25f761d 1097#ifdef HAVE_SYMLINK
a1ec6916 1098SCM_DEFINE (scm_symlink, "symlink", 2, 0, 0,
1bbd0b84 1099 (SCM oldpath, SCM newpath),
d3818c29
MD
1100 "Create a symbolic link named @var{path-to} with the value (i.e., pointing to)\n"
1101 "@var{path-from}. The return value is unspecified.")
1bbd0b84 1102#define FUNC_NAME s_scm_symlink
0f2d19dd 1103{
0f2d19dd 1104 int val;
02b754d3 1105
3b3b36dd
GB
1106 SCM_VALIDATE_ROSTRING (1,oldpath);
1107 SCM_VALIDATE_ROSTRING (2,newpath);
89958ad0
JB
1108 SCM_COERCE_SUBSTR (oldpath);
1109 SCM_COERCE_SUBSTR (newpath);
1110 SCM_SYSCALL (val = symlink(SCM_ROCHARS(oldpath), SCM_ROCHARS(newpath)));
02b754d3 1111 if (val != 0)
1bbd0b84 1112 SCM_SYSERROR;
02b754d3 1113 return SCM_UNSPECIFIED;
0f2d19dd 1114}
1bbd0b84 1115#undef FUNC_NAME
f25f761d 1116#endif /* HAVE_SYMLINK */
0f2d19dd 1117
f25f761d 1118#ifdef HAVE_READLINK
a1ec6916 1119SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0,
1bbd0b84 1120 (SCM path),
d3818c29
MD
1121 "Returns the value of the symbolic link named by\n"
1122 "@var{path} (a string), i.e., the\n"
1123 "file that the link points to.")
1bbd0b84 1124#define FUNC_NAME s_scm_readlink
0f2d19dd 1125{
6a738a25
JB
1126 int rv;
1127 int size = 100;
0f2d19dd
JB
1128 char *buf;
1129 SCM result;
3b3b36dd 1130 SCM_VALIDATE_ROSTRING (1,path);
89958ad0 1131 SCM_COERCE_SUBSTR (path);
1bbd0b84 1132 buf = scm_must_malloc (size, FUNC_NAME);
6a738a25 1133 while ((rv = readlink (SCM_ROCHARS (path), buf, size)) == size)
0f2d19dd
JB
1134 {
1135 scm_must_free (buf);
1136 size *= 2;
1bbd0b84 1137 buf = scm_must_malloc (size, FUNC_NAME);
0f2d19dd 1138 }
02b754d3 1139 if (rv == -1)
1bbd0b84 1140 SCM_SYSERROR;
02b754d3 1141 result = scm_makfromstr (buf, rv, 0);
0f2d19dd 1142 scm_must_free (buf);
0f2d19dd 1143 return result;
0f2d19dd 1144}
1bbd0b84 1145#undef FUNC_NAME
f25f761d 1146#endif /* HAVE_READLINK */
0f2d19dd 1147
f25f761d 1148#ifdef HAVE_LSTAT
a1ec6916 1149SCM_DEFINE (scm_lstat, "lstat", 1, 0, 0,
1bbd0b84 1150 (SCM str),
d3818c29
MD
1151 "Similar to @code{stat}, but does not follow symbolic links, i.e.,\n"
1152 "it will return information about a symbolic link itself, not the \n"
1153 "file it points to. @var{path} must be a string.")
1bbd0b84 1154#define FUNC_NAME s_scm_lstat
0f2d19dd 1155{
02b754d3 1156 int rv;
0f2d19dd 1157 struct stat stat_temp;
02b754d3 1158
3b3b36dd 1159 SCM_VALIDATE_ROSTRING (1,str);
89958ad0
JB
1160 SCM_COERCE_SUBSTR (str);
1161 SCM_SYSCALL(rv = lstat(SCM_ROCHARS(str), &stat_temp));
02b754d3 1162 if (rv != 0)
3d8d56df
GH
1163 {
1164 int en = errno;
1165
5d2d2ffc 1166 SCM_SYSERROR_MSG ("~A: ~S",
3d8d56df
GH
1167 scm_listify (scm_makfrom0str (strerror (errno)),
1168 str,
5d2d2ffc 1169 SCM_UNDEFINED), en);
3d8d56df 1170 }
02b754d3 1171 return scm_stat2scm(&stat_temp);
0f2d19dd 1172}
1bbd0b84 1173#undef FUNC_NAME
f25f761d 1174#endif /* HAVE_LSTAT */
0f2d19dd 1175
a1ec6916 1176SCM_DEFINE (scm_copy_file, "copy-file", 2, 0, 0,
1bbd0b84 1177 (SCM oldfile, SCM newfile),
d3818c29
MD
1178 "Copy the file specified by @var{path-from} to @var{path-to}.\n"
1179 "The return value is unspecified.")
1bbd0b84 1180#define FUNC_NAME s_scm_copy_file
0f2d19dd
JB
1181{
1182 int oldfd, newfd;
1183 int n;
77a76b64 1184 char buf[BUFSIZ];
0f2d19dd
JB
1185 struct stat oldstat;
1186
3b3b36dd 1187 SCM_VALIDATE_ROSTRING (1,oldfile);
0f2d19dd
JB
1188 if (SCM_SUBSTRP (oldfile))
1189 oldfile = scm_makfromstr (SCM_ROCHARS (oldfile), SCM_ROLENGTH (oldfile), 0);
3b3b36dd 1190 SCM_VALIDATE_ROSTRING (2,newfile);
0f2d19dd
JB
1191 if (SCM_SUBSTRP (newfile))
1192 newfile = scm_makfromstr (SCM_ROCHARS (newfile), SCM_ROLENGTH (newfile), 0);
1193 if (stat (SCM_ROCHARS (oldfile), &oldstat) == -1)
1bbd0b84 1194 SCM_SYSERROR;
0f2d19dd
JB
1195 oldfd = open (SCM_ROCHARS (oldfile), O_RDONLY);
1196 if (oldfd == -1)
1bbd0b84 1197 SCM_SYSERROR;
02b754d3
GH
1198
1199 /* use POSIX flags instead of 07777?. */
0f2d19dd
JB
1200 newfd = open (SCM_ROCHARS (newfile), O_WRONLY | O_CREAT | O_TRUNC,
1201 oldstat.st_mode & 07777);
1202 if (newfd == -1)
1bbd0b84 1203 SCM_SYSERROR;
02b754d3 1204
0f2d19dd
JB
1205 while ((n = read (oldfd, buf, sizeof buf)) > 0)
1206 if (write (newfd, buf, n) != n)
1207 {
1208 close (oldfd);
1209 close (newfd);
1bbd0b84 1210 SCM_SYSERROR;
0f2d19dd
JB
1211 }
1212 close (oldfd);
1213 if (close (newfd) == -1)
1bbd0b84 1214 SCM_SYSERROR;
02b754d3 1215 return SCM_UNSPECIFIED;
0f2d19dd 1216}
1bbd0b84 1217#undef FUNC_NAME
0f2d19dd
JB
1218
1219\f
6a738a25
JB
1220/* Filename manipulation */
1221
1222SCM scm_dot_string;
1223
a1ec6916 1224SCM_DEFINE (scm_dirname, "dirname", 1, 0, 0,
1bbd0b84 1225 (SCM filename),
d3818c29 1226 "")
1bbd0b84 1227#define FUNC_NAME s_scm_dirname
6a738a25
JB
1228{
1229 char *s;
1230 int i, len;
3b3b36dd 1231 SCM_VALIDATE_ROSTRING (1,filename);
6a738a25
JB
1232 s = SCM_ROCHARS (filename);
1233 len = SCM_LENGTH (filename);
1234 i = len - 1;
1235 while (i >= 0 && s[i] == '/') --i;
1236 while (i >= 0 && s[i] != '/') --i;
1237 while (i >= 0 && s[i] == '/') --i;
1238 if (i < 0)
1239 {
1240 if (len > 0 && s[0] == '/')
1241 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
1242 else
1243 return scm_dot_string;
1244 }
1245 else
1246 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (i + 1));
1247}
1bbd0b84 1248#undef FUNC_NAME
6a738a25 1249
a1ec6916 1250SCM_DEFINE (scm_basename, "basename", 1, 1, 0,
1bbd0b84 1251 (SCM filename, SCM suffix),
d3818c29 1252 "")
1bbd0b84 1253#define FUNC_NAME s_scm_basename
6a738a25
JB
1254{
1255 char *f, *s = 0;
1256 int i, j, len, end;
3b3b36dd 1257 SCM_VALIDATE_ROSTRING (1,filename);
6a738a25 1258 SCM_ASSERT (SCM_UNBNDP (suffix)
0c95b57d 1259 || (SCM_ROSTRINGP (suffix)),
6a738a25
JB
1260 suffix,
1261 SCM_ARG2,
1bbd0b84 1262 FUNC_NAME);
6a738a25
JB
1263 f = SCM_ROCHARS (filename);
1264 if (SCM_UNBNDP (suffix))
1265 j = -1;
1266 else
1267 {
1268 s = SCM_ROCHARS (suffix);
1269 j = SCM_LENGTH (suffix) - 1;
1270 }
1271 len = SCM_LENGTH (filename);
1272 i = len - 1;
1273 while (i >= 0 && f[i] == '/') --i;
1274 end = i;
1275 while (i >= 0 && j >= 0 && f[i] == s[j]) --i, --j;
1276 if (j == -1)
1277 end = i;
1278 while (i >= 0 && f[i] != '/') --i;
1279 if (i == end)
1280 {
1281 if (len > 0 && f[0] == '/')
1282 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
1283 else
1284 return scm_dot_string;
1285 }
1286 else
1287 return scm_make_shared_substring (filename,
1288 SCM_MAKINUM (i + 1),
1289 SCM_MAKINUM (end + 1));
1290}
1bbd0b84 1291#undef FUNC_NAME
6a738a25
JB
1292
1293
1294
1295\f
1cc91f1b 1296
0f2d19dd
JB
1297void
1298scm_init_filesys ()
0f2d19dd 1299{
23a62151
MD
1300 scm_tc16_dir = scm_make_smob_type_mfpe ("directory", 0,
1301 NULL, scm_dir_free,scm_dir_print, NULL);
0f2d19dd 1302
a163dda9
MD
1303 scm_dot_string = scm_permanent_object (scm_makfrom0str ("."));
1304
3d8d56df
GH
1305#ifdef O_RDONLY
1306scm_sysintern ("O_RDONLY", scm_long2num (O_RDONLY));
1307#endif
1308#ifdef O_WRONLY
1309scm_sysintern ("O_WRONLY", scm_long2num (O_WRONLY));
1310#endif
1311#ifdef O_RDWR
1312scm_sysintern ("O_RDWR", scm_long2num (O_RDWR));
1313#endif
1314#ifdef O_CREAT
1315scm_sysintern ("O_CREAT", scm_long2num (O_CREAT));
1316#endif
1317#ifdef O_EXCL
1318scm_sysintern ("O_EXCL", scm_long2num (O_EXCL));
1319#endif
1320#ifdef O_NOCTTY
1321scm_sysintern ("O_NOCTTY", scm_long2num (O_NOCTTY));
1322#endif
1323#ifdef O_TRUNC
1324scm_sysintern ("O_TRUNC", scm_long2num (O_TRUNC));
1325#endif
1326#ifdef O_APPEND
1327scm_sysintern ("O_APPEND", scm_long2num (O_APPEND));
1328#endif
6afcd3b2 1329#ifdef O_NONBLOCK
3d8d56df
GH
1330scm_sysintern ("O_NONBLOCK", scm_long2num (O_NONBLOCK));
1331#endif
1332#ifdef O_NDELAY
1333scm_sysintern ("O_NDELAY", scm_long2num (O_NDELAY));
1334#endif
1335#ifdef O_SYNC
1336scm_sysintern ("O_SYNC", scm_long2num (O_SYNC));
1337#endif
1338
4c1feaa5
JB
1339#ifdef F_DUPFD
1340scm_sysintern ("F_DUPFD", scm_long2num (F_DUPFD));
1341#endif
1342#ifdef F_GETFD
1343scm_sysintern ("F_GETFD", scm_long2num (F_GETFD));
1344#endif
1345#ifdef F_SETFD
1346scm_sysintern ("F_SETFD", scm_long2num (F_SETFD));
1347#endif
1348#ifdef F_GETFL
1349scm_sysintern ("F_GETFL", scm_long2num (F_GETFL));
1350#endif
1351#ifdef F_SETFL
1352scm_sysintern ("F_SETFL", scm_long2num (F_SETFL));
1353#endif
1354#ifdef F_GETOWN
1355scm_sysintern ("F_GETOWN", scm_long2num (F_GETOWN));
1356#endif
1357#ifdef F_SETOWN
1358scm_sysintern ("F_SETOWN", scm_long2num (F_SETOWN));
1359#endif
1360#ifdef FD_CLOEXEC
1361scm_sysintern ("FD_CLOEXEC", scm_long2num (FD_CLOEXEC));
1362#endif
3d8d56df 1363
0f2d19dd
JB
1364#include "filesys.x"
1365}