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