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