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