*** empty log message ***
[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),
d831b039
GH
127 "Change the ownership and group of the file referred to by @var{object} to\n"
128 "the integer values @var{owner} and @var{group}. @var{object} can be\n"
129 "a string containing a file name or, if the platform\n"
130 "supports fchown, a port or integer file descriptor\n"
131 "which is open on the file. The return value\n"
d3818c29 132 "is unspecified.\n\n"
d831b039 133 "If @var{object} is a symbolic link, either the\n"
d3818c29
MD
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 140 int rv;
02b754d3 141
78446828
MV
142 object = SCM_COERCE_OUTPORT (object);
143
3b3b36dd
GB
144 SCM_VALIDATE_INUM (2,owner);
145 SCM_VALIDATE_INUM (3,group);
d831b039 146#ifdef HAVE_FCHOWN
0c95b57d 147 if (SCM_INUMP (object) || (SCM_OPFPORTP (object)))
6afcd3b2 148 {
d831b039
GH
149 int fdes = SCM_INUMP (object) ? SCM_INUM (object)
150 : SCM_FPORT_FDES (object);
151
6afcd3b2
GH
152 SCM_SYSCALL (rv = fchown (fdes, SCM_INUM (owner), SCM_INUM (group)));
153 }
154 else
d831b039 155#endif
6afcd3b2 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;
d831b039 824
78446828 825 element = SCM_COERCE_OUTPORT (element);
0c95b57d 826 if (SCM_OPFPORTP (element))
77a76b64 827 fd = SCM_FPORT_FDES (element);
cafc12ff 828 else {
1bbd0b84 829 SCM_ASSERT (SCM_INUMP (element), element, arg, "select");
cafc12ff
MD
830 fd = SCM_INUM (element);
831 }
832 FD_SET (fd, set);
833 return fd;
a48a89bc 834}
1cc91f1b 835
cafc12ff
MD
836static int
837fill_select_type (SELECT_TYPE *set, SCM list, int arg)
0f2d19dd 838{
cafc12ff 839 int max_fd = 0, fd;
0c95b57d 840 if (SCM_VECTORP (list))
0f2d19dd 841 {
a48a89bc
GH
842 int len = SCM_LENGTH (list);
843 SCM *ve = SCM_VELTS (list);
844
845 while (len > 0)
846 {
cafc12ff
MD
847 fd = set_element (set, ve[len - 1], arg);
848 if (fd > max_fd)
849 max_fd = fd;
a48a89bc
GH
850 len--;
851 }
852 }
853 else
854 {
855 while (list != SCM_EOL)
856 {
cafc12ff
MD
857 fd = set_element (set, SCM_CAR (list), arg);
858 if (fd > max_fd)
859 max_fd = fd;
a48a89bc
GH
860 list = SCM_CDR (list);
861 }
0f2d19dd 862 }
cafc12ff
MD
863
864 return max_fd;
0f2d19dd
JB
865}
866
a48a89bc
GH
867static SCM
868get_element (SELECT_TYPE *set, SCM element, SCM list)
869{
78446828 870 element = SCM_COERCE_OUTPORT (element);
0c95b57d 871 if (SCM_OPFPORTP (element))
a48a89bc 872 {
77a76b64 873 if (FD_ISSET (SCM_FPORT_FDES (element), set))
a48a89bc
GH
874 list = scm_cons (element, list);
875 }
876 else if (SCM_INUMP (element))
877 {
878 if (FD_ISSET (SCM_INUM (element), set))
879 list = scm_cons (element, list);
880 }
881 return list;
882}
1cc91f1b 883
0f2d19dd 884static SCM
a48a89bc 885retrieve_select_type (SELECT_TYPE *set, SCM list)
0f2d19dd 886{
a48a89bc
GH
887 SCM answer_list = SCM_EOL;
888
0c95b57d 889 if (SCM_VECTORP (list))
0f2d19dd 890 {
a48a89bc
GH
891 int len = SCM_LENGTH (list);
892 SCM *ve = SCM_VELTS (list);
893
894 while (len > 0)
0f2d19dd 895 {
a48a89bc
GH
896 answer_list = get_element (set, ve[len - 1], answer_list);
897 len--;
0f2d19dd 898 }
a48a89bc
GH
899 return scm_vector (answer_list);
900 }
901 else
902 {
903 /* list is a list. */
904 while (list != SCM_EOL)
0f2d19dd 905 {
a48a89bc
GH
906 answer_list = get_element (set, SCM_CAR (list), answer_list);
907 list = SCM_CDR (list);
0f2d19dd 908 }
a48a89bc 909 return answer_list;
0f2d19dd 910 }
0f2d19dd
JB
911}
912
f25f761d 913#ifdef HAVE_SELECT
1bbd0b84 914/* Static helper functions above refer to s_scm_select directly as s_select */
a1ec6916 915SCM_DEFINE (scm_select, "select", 3, 2, 0,
1bbd0b84 916 (SCM reads, SCM writes, SCM excepts, SCM secs, SCM usecs),
d3818c29
MD
917 "@var{reads}, @var{writes} and @var{excepts} can be lists or vectors: it\n"
918 "doesn't matter which, but the corresponding object returned will be\n"
919 "of the same type.\n"
920 "Each element is a port or file descriptor on which to wait for\n"
921 "readability, writeability\n"
922 "or exceptional conditions respectively. @var{secs} and @var{usecs}\n"
923 "optionally specify a timeout: @var{secs} can be specified alone, as\n"
924 "either an integer or a real number, or both @var{secs} and @var{usecs}\n"
925 "can be specified as integers, in which case @var{usecs} is an additional\n"
926 "timeout expressed in microseconds.\n\n"
927 "Buffered input or output data is (currently, but this may change)\n"
928 "ignored: select uses the underlying file descriptor of a port\n"
929 "(@code{char-ready?} will check input buffers, output buffers are\n"
930 "problematic).\n\n"
931 "The return value is a list of subsets of the input lists or vectors for\n"
932 "which the requested condition has been met.\n\n"
933 "It is not quite compatible with scsh's select: scsh checks port buffers,\n"
934 "doesn't accept input lists or a microsecond timeout, returns multiple\n"
935 "values instead of a list and has an additional select! interface.\n"
936 "")
1bbd0b84 937#define FUNC_NAME s_scm_select
0f2d19dd 938{
0f2d19dd
JB
939 struct timeval timeout;
940 struct timeval * time_p;
941 SELECT_TYPE read_set;
942 SELECT_TYPE write_set;
943 SELECT_TYPE except_set;
cafc12ff 944 int max_fd, fd;
0f2d19dd
JB
945 int sreturn;
946
a48a89bc 947#define assert_set(x, arg) \
0c95b57d 948 SCM_ASSERT (scm_ilength (x) >= 0 || (SCM_VECTORP (x)), \
1bbd0b84 949 x, arg, FUNC_NAME)
a48a89bc
GH
950 assert_set (reads, SCM_ARG1);
951 assert_set (writes, SCM_ARG2);
952 assert_set (excepts, SCM_ARG3);
953#undef assert_set
0f2d19dd
JB
954
955 FD_ZERO (&read_set);
956 FD_ZERO (&write_set);
957 FD_ZERO (&except_set);
958
cafc12ff
MD
959 max_fd = fill_select_type (&read_set, reads, SCM_ARG1);
960 fd = fill_select_type (&write_set, writes, SCM_ARG2);
961 if (fd > max_fd)
962 max_fd = fd;
963 fd = fill_select_type (&except_set, excepts, SCM_ARG3);
964 if (fd > max_fd)
965 max_fd = fd;
0f2d19dd 966
a48a89bc 967 if (SCM_UNBNDP (secs) || SCM_FALSEP (secs))
0f2d19dd
JB
968 time_p = 0;
969 else
970 {
a48a89bc
GH
971 if (SCM_INUMP (secs))
972 {
973 timeout.tv_sec = SCM_INUM (secs);
974 if (SCM_UNBNDP (usecs))
975 timeout.tv_usec = 0;
976 else
977 {
3b3b36dd 978 SCM_VALIDATE_INUM (5,usecs);
a48a89bc
GH
979 timeout.tv_usec = SCM_INUM (usecs);
980 }
981 }
0f2d19dd 982 else
a48a89bc 983 {
1bbd0b84 984 double fl = scm_num2dbl (secs, FUNC_NAME);
a48a89bc
GH
985
986 if (!SCM_UNBNDP (usecs))
c1bfcf60 987 SCM_WRONG_TYPE_ARG (4, secs);
a48a89bc 988 if (fl > LONG_MAX)
c1bfcf60 989 SCM_OUT_OF_RANGE (4, secs);
a48a89bc
GH
990 timeout.tv_sec = (long) fl;
991 timeout.tv_usec = (long) ((fl - timeout.tv_sec) * 1000000);
992 }
0f2d19dd
JB
993 time_p = &timeout;
994 }
995
44e8413c 996#ifdef GUILE_ISELECT
cafc12ff 997 sreturn = scm_internal_select (max_fd + 1,
44e8413c
MD
998 &read_set, &write_set, &except_set, time_p);
999#else
cafc12ff 1000 sreturn = select (max_fd + 1,
0f2d19dd 1001 &read_set, &write_set, &except_set, time_p);
44e8413c 1002#endif
0f2d19dd 1003 if (sreturn < 0)
1bbd0b84 1004 SCM_SYSERROR;
02b754d3
GH
1005 return scm_listify (retrieve_select_type (&read_set, reads),
1006 retrieve_select_type (&write_set, writes),
1007 retrieve_select_type (&except_set, excepts),
1008 SCM_UNDEFINED);
0f2d19dd 1009}
1bbd0b84 1010#undef FUNC_NAME
f25f761d 1011#endif /* HAVE_SELECT */
0f2d19dd
JB
1012
1013\f
4c1feaa5 1014
a1ec6916 1015SCM_DEFINE (scm_fcntl, "fcntl", 2, 0, 1,
1bbd0b84 1016 (SCM object, SCM cmd, SCM value),
d3818c29
MD
1017 "Apply @var{command} to the specified file descriptor or the underlying\n"
1018 "file descriptor of the specified port. @var{value} is an optional\n"
1019 "integer argument.\n\n"
1020 "Values for @var{command} are:\n\n"
1021 "@table @code\n"
1022 "@item F_DUPFD\n"
1023 "Duplicate a file descriptor\n"
1024 "@item F_GETFD\n"
1025 "Get flags associated with the file descriptor.\n"
1026 "@item F_SETFD\n"
1027 "Set flags associated with the file descriptor to @var{value}.\n"
1028 "@item F_GETFL\n"
1029 "Get flags associated with the open file.\n"
1030 "@item F_SETFL\n"
1031 "Set flags associated with the open file to @var{value}\n"
1032 "@item F_GETOWN\n"
1033 "Get the process ID of a socket's owner, for @code{SIGIO} signals.\n"
1034 "@item F_SETOWN\n"
1035 "Set the process that owns a socket to @var{value}, for @code{SIGIO} signals.\n"
1036 "@item FD_CLOEXEC\n"
a3c8b9fc
MD
1037 "The value used to indicate the \"close on exec\" flag with @code{F_GETFL} or"
1038 "@code{F_SETFL}."
1039 "@end table")
1bbd0b84 1040#define FUNC_NAME s_scm_fcntl
4c1feaa5
JB
1041{
1042 int rv;
6afcd3b2
GH
1043 int fdes;
1044 int ivalue;
4c1feaa5 1045
78446828
MV
1046 object = SCM_COERCE_OUTPORT (object);
1047
3b3b36dd 1048 SCM_VALIDATE_INUM (2,cmd);
0c95b57d 1049 if (SCM_OPFPORTP (object))
77a76b64 1050 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
1051 else
1052 {
3b3b36dd 1053 SCM_VALIDATE_INUM (1,object);
6afcd3b2
GH
1054 fdes = SCM_INUM (object);
1055 }
1056 if (SCM_NULLP (value))
1057 ivalue = 0;
1058 else
1059 {
1bbd0b84 1060 SCM_ASSERT (SCM_INUMP (SCM_CAR (value)), value, SCM_ARG3, FUNC_NAME);
6afcd3b2
GH
1061 ivalue = SCM_INUM (SCM_CAR (value));
1062 }
77a76b64
JB
1063 SCM_SYSCALL (rv = fcntl (fdes, SCM_INUM (cmd), ivalue));
1064 if (rv == -1)
1bbd0b84 1065 SCM_SYSERROR;
4c1feaa5
JB
1066 return SCM_MAKINUM (rv);
1067}
1bbd0b84 1068#undef FUNC_NAME
6afcd3b2 1069
a1ec6916 1070SCM_DEFINE (scm_fsync, "fsync", 1, 0, 0,
1bbd0b84 1071 (SCM object),
d3818c29
MD
1072 "Copies any unwritten data for the specified output file descriptor to disk.\n"
1073 "If @var{port/fd} is a port, its buffer is flushed before the underlying\n"
1074 "file descriptor is fsync'd.\n"
1075 "The return value is unspecified.")
1bbd0b84 1076#define FUNC_NAME s_scm_fsync
6afcd3b2
GH
1077{
1078 int fdes;
1079
78446828
MV
1080 object = SCM_COERCE_OUTPORT (object);
1081
0c95b57d 1082 if (SCM_OPFPORTP (object))
6afcd3b2 1083 {
affc96b5 1084 scm_flush (object);
77a76b64 1085 fdes = SCM_FPORT_FDES (object);
6afcd3b2
GH
1086 }
1087 else
1088 {
3b3b36dd 1089 SCM_VALIDATE_INUM (1,object);
6afcd3b2
GH
1090 fdes = SCM_INUM (object);
1091 }
1092 if (fsync (fdes) == -1)
1bbd0b84 1093 SCM_SYSERROR;
6afcd3b2
GH
1094 return SCM_UNSPECIFIED;
1095}
1bbd0b84 1096#undef FUNC_NAME
0f2d19dd 1097
f25f761d 1098#ifdef HAVE_SYMLINK
a1ec6916 1099SCM_DEFINE (scm_symlink, "symlink", 2, 0, 0,
1bbd0b84 1100 (SCM oldpath, SCM newpath),
d3818c29
MD
1101 "Create a symbolic link named @var{path-to} with the value (i.e., pointing to)\n"
1102 "@var{path-from}. The return value is unspecified.")
1bbd0b84 1103#define FUNC_NAME s_scm_symlink
0f2d19dd 1104{
0f2d19dd 1105 int val;
02b754d3 1106
3b3b36dd
GB
1107 SCM_VALIDATE_ROSTRING (1,oldpath);
1108 SCM_VALIDATE_ROSTRING (2,newpath);
89958ad0
JB
1109 SCM_COERCE_SUBSTR (oldpath);
1110 SCM_COERCE_SUBSTR (newpath);
1111 SCM_SYSCALL (val = symlink(SCM_ROCHARS(oldpath), SCM_ROCHARS(newpath)));
02b754d3 1112 if (val != 0)
1bbd0b84 1113 SCM_SYSERROR;
02b754d3 1114 return SCM_UNSPECIFIED;
0f2d19dd 1115}
1bbd0b84 1116#undef FUNC_NAME
f25f761d 1117#endif /* HAVE_SYMLINK */
0f2d19dd 1118
f25f761d 1119#ifdef HAVE_READLINK
a1ec6916 1120SCM_DEFINE (scm_readlink, "readlink", 1, 0, 0,
1bbd0b84 1121 (SCM path),
d3818c29
MD
1122 "Returns the value of the symbolic link named by\n"
1123 "@var{path} (a string), i.e., the\n"
1124 "file that the link points to.")
1bbd0b84 1125#define FUNC_NAME s_scm_readlink
0f2d19dd 1126{
6a738a25
JB
1127 int rv;
1128 int size = 100;
0f2d19dd
JB
1129 char *buf;
1130 SCM result;
3b3b36dd 1131 SCM_VALIDATE_ROSTRING (1,path);
89958ad0 1132 SCM_COERCE_SUBSTR (path);
1bbd0b84 1133 buf = scm_must_malloc (size, FUNC_NAME);
6a738a25 1134 while ((rv = readlink (SCM_ROCHARS (path), buf, size)) == size)
0f2d19dd
JB
1135 {
1136 scm_must_free (buf);
1137 size *= 2;
1bbd0b84 1138 buf = scm_must_malloc (size, FUNC_NAME);
0f2d19dd 1139 }
02b754d3 1140 if (rv == -1)
1bbd0b84 1141 SCM_SYSERROR;
02b754d3 1142 result = scm_makfromstr (buf, rv, 0);
0f2d19dd 1143 scm_must_free (buf);
0f2d19dd 1144 return result;
0f2d19dd 1145}
1bbd0b84 1146#undef FUNC_NAME
f25f761d 1147#endif /* HAVE_READLINK */
0f2d19dd 1148
f25f761d 1149#ifdef HAVE_LSTAT
a1ec6916 1150SCM_DEFINE (scm_lstat, "lstat", 1, 0, 0,
1bbd0b84 1151 (SCM str),
d3818c29
MD
1152 "Similar to @code{stat}, but does not follow symbolic links, i.e.,\n"
1153 "it will return information about a symbolic link itself, not the \n"
1154 "file it points to. @var{path} must be a string.")
1bbd0b84 1155#define FUNC_NAME s_scm_lstat
0f2d19dd 1156{
02b754d3 1157 int rv;
0f2d19dd 1158 struct stat stat_temp;
02b754d3 1159
3b3b36dd 1160 SCM_VALIDATE_ROSTRING (1,str);
89958ad0
JB
1161 SCM_COERCE_SUBSTR (str);
1162 SCM_SYSCALL(rv = lstat(SCM_ROCHARS(str), &stat_temp));
02b754d3 1163 if (rv != 0)
3d8d56df
GH
1164 {
1165 int en = errno;
1166
5d2d2ffc 1167 SCM_SYSERROR_MSG ("~A: ~S",
3d8d56df
GH
1168 scm_listify (scm_makfrom0str (strerror (errno)),
1169 str,
5d2d2ffc 1170 SCM_UNDEFINED), en);
3d8d56df 1171 }
02b754d3 1172 return scm_stat2scm(&stat_temp);
0f2d19dd 1173}
1bbd0b84 1174#undef FUNC_NAME
f25f761d 1175#endif /* HAVE_LSTAT */
0f2d19dd 1176
a1ec6916 1177SCM_DEFINE (scm_copy_file, "copy-file", 2, 0, 0,
1bbd0b84 1178 (SCM oldfile, SCM newfile),
d3818c29
MD
1179 "Copy the file specified by @var{path-from} to @var{path-to}.\n"
1180 "The return value is unspecified.")
1bbd0b84 1181#define FUNC_NAME s_scm_copy_file
0f2d19dd
JB
1182{
1183 int oldfd, newfd;
1184 int n;
77a76b64 1185 char buf[BUFSIZ];
0f2d19dd
JB
1186 struct stat oldstat;
1187
3b3b36dd 1188 SCM_VALIDATE_ROSTRING (1,oldfile);
0f2d19dd
JB
1189 if (SCM_SUBSTRP (oldfile))
1190 oldfile = scm_makfromstr (SCM_ROCHARS (oldfile), SCM_ROLENGTH (oldfile), 0);
3b3b36dd 1191 SCM_VALIDATE_ROSTRING (2,newfile);
0f2d19dd
JB
1192 if (SCM_SUBSTRP (newfile))
1193 newfile = scm_makfromstr (SCM_ROCHARS (newfile), SCM_ROLENGTH (newfile), 0);
1194 if (stat (SCM_ROCHARS (oldfile), &oldstat) == -1)
1bbd0b84 1195 SCM_SYSERROR;
0f2d19dd
JB
1196 oldfd = open (SCM_ROCHARS (oldfile), O_RDONLY);
1197 if (oldfd == -1)
1bbd0b84 1198 SCM_SYSERROR;
02b754d3
GH
1199
1200 /* use POSIX flags instead of 07777?. */
0f2d19dd
JB
1201 newfd = open (SCM_ROCHARS (newfile), O_WRONLY | O_CREAT | O_TRUNC,
1202 oldstat.st_mode & 07777);
1203 if (newfd == -1)
1bbd0b84 1204 SCM_SYSERROR;
02b754d3 1205
0f2d19dd
JB
1206 while ((n = read (oldfd, buf, sizeof buf)) > 0)
1207 if (write (newfd, buf, n) != n)
1208 {
1209 close (oldfd);
1210 close (newfd);
1bbd0b84 1211 SCM_SYSERROR;
0f2d19dd
JB
1212 }
1213 close (oldfd);
1214 if (close (newfd) == -1)
1bbd0b84 1215 SCM_SYSERROR;
02b754d3 1216 return SCM_UNSPECIFIED;
0f2d19dd 1217}
1bbd0b84 1218#undef FUNC_NAME
0f2d19dd
JB
1219
1220\f
6a738a25
JB
1221/* Filename manipulation */
1222
1223SCM scm_dot_string;
1224
a1ec6916 1225SCM_DEFINE (scm_dirname, "dirname", 1, 0, 0,
1bbd0b84 1226 (SCM filename),
d3818c29 1227 "")
1bbd0b84 1228#define FUNC_NAME s_scm_dirname
6a738a25
JB
1229{
1230 char *s;
1231 int i, len;
3b3b36dd 1232 SCM_VALIDATE_ROSTRING (1,filename);
6a738a25
JB
1233 s = SCM_ROCHARS (filename);
1234 len = SCM_LENGTH (filename);
1235 i = len - 1;
1236 while (i >= 0 && s[i] == '/') --i;
1237 while (i >= 0 && s[i] != '/') --i;
1238 while (i >= 0 && s[i] == '/') --i;
1239 if (i < 0)
1240 {
1241 if (len > 0 && s[0] == '/')
1242 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
1243 else
1244 return scm_dot_string;
1245 }
1246 else
1247 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (i + 1));
1248}
1bbd0b84 1249#undef FUNC_NAME
6a738a25 1250
a1ec6916 1251SCM_DEFINE (scm_basename, "basename", 1, 1, 0,
1bbd0b84 1252 (SCM filename, SCM suffix),
d3818c29 1253 "")
1bbd0b84 1254#define FUNC_NAME s_scm_basename
6a738a25
JB
1255{
1256 char *f, *s = 0;
1257 int i, j, len, end;
3b3b36dd 1258 SCM_VALIDATE_ROSTRING (1,filename);
6a738a25 1259 SCM_ASSERT (SCM_UNBNDP (suffix)
0c95b57d 1260 || (SCM_ROSTRINGP (suffix)),
6a738a25
JB
1261 suffix,
1262 SCM_ARG2,
1bbd0b84 1263 FUNC_NAME);
6a738a25
JB
1264 f = SCM_ROCHARS (filename);
1265 if (SCM_UNBNDP (suffix))
1266 j = -1;
1267 else
1268 {
1269 s = SCM_ROCHARS (suffix);
1270 j = SCM_LENGTH (suffix) - 1;
1271 }
1272 len = SCM_LENGTH (filename);
1273 i = len - 1;
1274 while (i >= 0 && f[i] == '/') --i;
1275 end = i;
1276 while (i >= 0 && j >= 0 && f[i] == s[j]) --i, --j;
1277 if (j == -1)
1278 end = i;
1279 while (i >= 0 && f[i] != '/') --i;
1280 if (i == end)
1281 {
1282 if (len > 0 && f[0] == '/')
1283 return scm_make_shared_substring (filename, SCM_INUM0, SCM_MAKINUM (1));
1284 else
1285 return scm_dot_string;
1286 }
1287 else
1288 return scm_make_shared_substring (filename,
1289 SCM_MAKINUM (i + 1),
1290 SCM_MAKINUM (end + 1));
1291}
1bbd0b84 1292#undef FUNC_NAME
6a738a25
JB
1293
1294
1295
1296\f
1cc91f1b 1297
0f2d19dd
JB
1298void
1299scm_init_filesys ()
0f2d19dd 1300{
23a62151
MD
1301 scm_tc16_dir = scm_make_smob_type_mfpe ("directory", 0,
1302 NULL, scm_dir_free,scm_dir_print, NULL);
0f2d19dd 1303
a163dda9
MD
1304 scm_dot_string = scm_permanent_object (scm_makfrom0str ("."));
1305
3d8d56df
GH
1306#ifdef O_RDONLY
1307scm_sysintern ("O_RDONLY", scm_long2num (O_RDONLY));
1308#endif
1309#ifdef O_WRONLY
1310scm_sysintern ("O_WRONLY", scm_long2num (O_WRONLY));
1311#endif
1312#ifdef O_RDWR
1313scm_sysintern ("O_RDWR", scm_long2num (O_RDWR));
1314#endif
1315#ifdef O_CREAT
1316scm_sysintern ("O_CREAT", scm_long2num (O_CREAT));
1317#endif
1318#ifdef O_EXCL
1319scm_sysintern ("O_EXCL", scm_long2num (O_EXCL));
1320#endif
1321#ifdef O_NOCTTY
1322scm_sysintern ("O_NOCTTY", scm_long2num (O_NOCTTY));
1323#endif
1324#ifdef O_TRUNC
1325scm_sysintern ("O_TRUNC", scm_long2num (O_TRUNC));
1326#endif
1327#ifdef O_APPEND
1328scm_sysintern ("O_APPEND", scm_long2num (O_APPEND));
1329#endif
6afcd3b2 1330#ifdef O_NONBLOCK
3d8d56df
GH
1331scm_sysintern ("O_NONBLOCK", scm_long2num (O_NONBLOCK));
1332#endif
1333#ifdef O_NDELAY
1334scm_sysintern ("O_NDELAY", scm_long2num (O_NDELAY));
1335#endif
1336#ifdef O_SYNC
1337scm_sysintern ("O_SYNC", scm_long2num (O_SYNC));
1338#endif
1339
4c1feaa5
JB
1340#ifdef F_DUPFD
1341scm_sysintern ("F_DUPFD", scm_long2num (F_DUPFD));
1342#endif
1343#ifdef F_GETFD
1344scm_sysintern ("F_GETFD", scm_long2num (F_GETFD));
1345#endif
1346#ifdef F_SETFD
1347scm_sysintern ("F_SETFD", scm_long2num (F_SETFD));
1348#endif
1349#ifdef F_GETFL
1350scm_sysintern ("F_GETFL", scm_long2num (F_GETFL));
1351#endif
1352#ifdef F_SETFL
1353scm_sysintern ("F_SETFL", scm_long2num (F_SETFL));
1354#endif
1355#ifdef F_GETOWN
1356scm_sysintern ("F_GETOWN", scm_long2num (F_GETOWN));
1357#endif
1358#ifdef F_SETOWN
1359scm_sysintern ("F_SETOWN", scm_long2num (F_SETOWN));
1360#endif
1361#ifdef FD_CLOEXEC
1362scm_sysintern ("FD_CLOEXEC", scm_long2num (FD_CLOEXEC));
1363#endif
3d8d56df 1364
0f2d19dd
JB
1365#include "filesys.x"
1366}