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