1 /* -*-C-*-
2
3 Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Massachusetts
6 Institute of Technology
7
8 This file is part of MIT/GNU Scheme.
9
10 MIT/GNU Scheme is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or (at
13 your option) any later version.
14
15 MIT/GNU Scheme is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with MIT/GNU Scheme; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
23 USA.
24
25 */
26
27 #include "scheme.h"
28 #include "ux.h"
29 #include "osfs.h"
30 #include "osfile.h"
31 #include "osio.h"
32
33 /* Don't use statfs on unknown systems. It is necessary to enumerate
34 the set of interesting results for the support to be useful. */
35 #if ! ((defined (__linux__)) || (defined (__HPUX__)))
36 # undef HAVE_STATFS
37 #endif
38
39 #ifdef HAVE_STATFS
40 # ifdef HAVE_SYS_VFS_H
41 /* GNU/Linux */
42 # include <sys/vfs.h>
43 # else
44 # ifdef HAVE_SYS_MOUNT_H
45 /* FreeBSD */
46 # include <sys/param.h>
47 # include <sys/mount.h>
48 # endif
49 # endif
50 # ifdef __linux__
51 /* The following superblock magic constants are taken from the kernel
52 headers for Linux 2.0.33. We use these rather than reading the
53 header files, because the Linux kernel header files have
54 definitions that conflict with those of glibc2. These constants
55 are unlikely to be changed, so this ought to be safe. */
56 # ifndef AFFS_SUPER_MAGIC
57 # define AFFS_SUPER_MAGIC 0xadff
58 # endif
59 # ifndef CIFS_MAGIC_NUMBER
60 # define CIFS_MAGIC_NUMBER 0xFF534D42
61 # endif
62 # ifndef COH_SUPER_MAGIC
63 # define COH_SUPER_MAGIC 0x012FF7B7
64 # endif
65 # ifndef EXT_SUPER_MAGIC
66 # define EXT_SUPER_MAGIC 0x137D
67 # endif
68 # ifndef EXT2_SUPER_MAGIC
69 # define EXT2_SUPER_MAGIC 0xEF53
70 # endif
71 # ifndef HPFS_SUPER_MAGIC
72 # define HPFS_SUPER_MAGIC 0xf995e849
73 # endif
74 # ifndef ISOFS_SUPER_MAGIC
75 # define ISOFS_SUPER_MAGIC 0x9660
76 # endif
77 # ifndef MINIX_SUPER_MAGIC
78 # define MINIX_SUPER_MAGIC 0x137F
79 # endif
80 # ifndef MINIX_SUPER_MAGIC2
81 # define MINIX_SUPER_MAGIC2 0x138F
82 # endif
83 # ifndef MINIX2_SUPER_MAGIC
84 # define MINIX2_SUPER_MAGIC 0x2468
85 # endif
86 # ifndef MINIX2_SUPER_MAGIC2
87 # define MINIX2_SUPER_MAGIC2 0x2478
88 # endif
89 # ifndef MSDOS_SUPER_MAGIC
90 # define MSDOS_SUPER_MAGIC 0x4d44
91 # endif
92 # ifndef NCP_SUPER_MAGIC
93 # define NCP_SUPER_MAGIC 0x564c
94 # endif
95 # ifndef NFS_SUPER_MAGIC
96 # define NFS_SUPER_MAGIC 0x6969
97 # endif
98 # ifndef NTFS_SUPER_MAGIC
99 # define NTFS_SUPER_MAGIC 0x5346544E
100 # endif
101 # ifndef PROC_SUPER_MAGIC
102 # define PROC_SUPER_MAGIC 0x9fa0
103 # endif
104 # ifndef SMB_SUPER_MAGIC
105 # define SMB_SUPER_MAGIC 0x517B
106 # endif
107 # ifndef SYSV2_SUPER_MAGIC
108 # define SYSV2_SUPER_MAGIC 0x012FF7B6
109 # endif
110 # ifndef SYSV4_SUPER_MAGIC
111 # define SYSV4_SUPER_MAGIC 0x012FF7B5
112 # endif
113 # ifndef XENIX_SUPER_MAGIC
114 # define XENIX_SUPER_MAGIC 0x012FF7B4
115 # endif
116 # ifndef _XIAFS_SUPER_MAGIC
117 # define _XIAFS_SUPER_MAGIC 0x012FD16D
118 # endif
119 # endif
120 #endif
121
122 #ifndef FILE_TOUCH_OPEN_TRIES
123 # define FILE_TOUCH_OPEN_TRIES 5
124 #endif
125
126 #define STAT_SYSTEM_CALL(name, expression, if_failure) \
127 do { \
128 while ((expression) < 0) \
129 { \
130 if ((errno == ENOENT) || (errno == ENOTDIR)) \
131 if_failure; \
132 if (errno != EINTR) \
133 error_system_call (errno, name); \
134 deliver_pending_interrupts (); \
135 } \
136 } while (0)
137
138 void
UX_read_fd_status(int fd,struct stat * s)139 UX_read_fd_status (int fd, struct stat * s)
140 {
141 STD_VOID_SYSTEM_CALL (syscall_fstat, (UX_fstat (fd, s)));
142 }
143
144 int
UX_read_file_status(const char * filename,struct stat * s)145 UX_read_file_status (const char * filename, struct stat * s)
146 {
147 STAT_SYSTEM_CALL (syscall_lstat, (UX_lstat (filename, s)), return (0));
148 return (1);
149 }
150
151 int
UX_read_file_status_indirect(const char * filename,struct stat * s)152 UX_read_file_status_indirect (const char * filename, struct stat * s)
153 {
154 STAT_SYSTEM_CALL (syscall_stat, (UX_stat (filename, s)), return (0));
155 return (1);
156 }
157
158 enum file_existence
OS_file_existence_test(const char * name)159 OS_file_existence_test (const char * name)
160 {
161 struct stat s;
162 if (!UX_read_file_status (name, (&s)))
163 return (file_doesnt_exist);
164 #ifdef HAVE_SYMLINK
165 if (((s . st_mode) & S_IFMT) == S_IFLNK)
166 {
167 if (UX_read_file_status_indirect (name, (&s)))
168 return (file_does_exist);
169 else
170 return (file_is_link);
171 }
172 #endif
173 return (file_does_exist);
174 }
175
176 enum file_existence
OS_file_existence_test_direct(const char * name)177 OS_file_existence_test_direct (const char * name)
178 {
179 struct stat s;
180 if (!UX_read_file_status (name, (&s)))
181 return (file_doesnt_exist);
182 #ifdef HAVE_SYMLINK
183 if (((s . st_mode) & S_IFMT) == S_IFLNK)
184 return (file_is_link);
185 #endif
186 return (file_does_exist);
187 }
188
189 #ifndef S_ISREG
190 # define S_ISREG(mode) (((mode) & S_IFREG) != 0)
191 #endif
192 #ifndef S_ISDIR
193 # define S_ISDIR(mode) (((mode) & S_IFDIR) != 0)
194 #endif
195 #ifndef S_ISLNK
196 # define S_ISLNK(mode) (((mode) & S_IFLNK) != 0)
197 #endif
198 #ifndef S_ISCHR
199 # define S_ISCHR(mode) (((mode) & S_IFCHR) != 0)
200 #endif
201 #ifndef S_ISBLK
202 # define S_ISBLK(mode) (((mode) & S_IFBLK) != 0)
203 #endif
204 #ifndef S_ISFIFO
205 # define S_ISFIFO(mode) (((mode) & S_IFIFO) != 0)
206 #endif
207 #ifndef S_ISSOCK
208 # define S_ISSOCK(mode) (((mode) & S_IFSOCK) != 0)
209 #endif
210
211 #define COMPUTE_FILE_TYPE(proc, name) \
212 { \
213 struct stat s; \
214 if (!proc ((name), (&s))) \
215 return (file_type_nonexistent); \
216 else if (S_ISREG (s . st_mode)) \
217 return (file_type_regular); \
218 else if (S_ISDIR (s . st_mode)) \
219 return (file_type_directory); \
220 else if (S_ISLNK (s . st_mode)) \
221 return (file_type_unix_symbolic_link); \
222 else if (S_ISCHR (s . st_mode)) \
223 return (file_type_unix_character_device); \
224 else if (S_ISBLK (s . st_mode)) \
225 return (file_type_unix_block_device); \
226 else if (S_ISFIFO (s . st_mode)) \
227 return (file_type_unix_fifo); \
228 else if (S_ISSOCK (s . st_mode)) \
229 return (file_type_unix_stream_socket); \
230 else \
231 return (file_type_unknown); \
232 }
233
234 enum file_type
OS_file_type_direct(const char * name)235 OS_file_type_direct (const char * name)
236 COMPUTE_FILE_TYPE (UX_read_file_status, name)
237
238 enum file_type
239 OS_file_type_indirect (const char * name)
240 COMPUTE_FILE_TYPE (UX_read_file_status_indirect, name)
241
242 const char *
243 UX_file_system_type (const char * name)
244 {
245 #ifdef HAVE_STATFS
246 struct statfs s;
247 STAT_SYSTEM_CALL (syscall_statfs, (UX_statfs (name, (&s))), return (0));
248
249 #ifdef __linux__
250 switch (s . f_type)
251 {
252 case CIFS_MAGIC_NUMBER: return ("cifs");
253 case COH_SUPER_MAGIC: return ("coherent");
254 case EXT_SUPER_MAGIC: return ("ext");
255 case EXT2_SUPER_MAGIC: return ("ext2");
256 case HPFS_SUPER_MAGIC: return ("hpfs");
257 case ISOFS_SUPER_MAGIC: return ("iso9660");
258 case MINIX_SUPER_MAGIC: return ("minix1");
259 case MINIX_SUPER_MAGIC2: return ("minix1-30");
260 case MINIX2_SUPER_MAGIC: return ("minix2");
261 case MINIX2_SUPER_MAGIC2: return ("minix2-30");
262 case MSDOS_SUPER_MAGIC: return ("fat");
263 case NCP_SUPER_MAGIC: return ("ncp");
264 case NFS_SUPER_MAGIC: return ("nfs");
265 case NTFS_SUPER_MAGIC: return ("ntfs");
266 case PROC_SUPER_MAGIC: return ("proc");
267 case SMB_SUPER_MAGIC: return ("smb");
268 case SYSV2_SUPER_MAGIC: return ("sysv2");
269 case SYSV4_SUPER_MAGIC: return ("sysv4");
270 case XENIX_SUPER_MAGIC: return ("xenix");
271 case _XIAFS_SUPER_MAGIC: return ("xiafs");
272 }
273 #endif /* __linux__ */
274
275 #ifdef __HPUX__
276 switch ((s . f_fsid) [1])
277 {
278 case MOUNT_UFS: return ("ufs");
279 case MOUNT_NFS: return ("nfs");
280 case MOUNT_CDFS: return ("iso9660");
281 }
282 #endif /* __HPUX__ */
283 #endif /* HAVE_STATFS */
284
285 return (0);
286 }
287
288 int
OS_file_directory_p(const char * name)289 OS_file_directory_p (const char * name)
290 {
291 struct stat s;
292 return
293 ((UX_read_file_status_indirect (name, (&s)))
294 && (((s . st_mode) & S_IFMT) == S_IFDIR));
295 }
296
297 const char *
OS_file_soft_link_p(const char * name)298 OS_file_soft_link_p (const char * name)
299 {
300 #ifdef HAVE_SYMLINK
301 struct stat s;
302 if (! ((UX_read_file_status (name, (&s)))
303 && (((s . st_mode) & S_IFMT) == S_IFLNK)))
304 return (0);
305 {
306 int scr;
307 int buffer_length = 100;
308 char * buffer = (UX_malloc (buffer_length));
309 if (buffer == 0)
310 error_system_call (ENOMEM, syscall_malloc);
311 while (1)
312 {
313 STD_UINT_SYSTEM_CALL
314 (syscall_readlink, scr, (UX_readlink (name, buffer, buffer_length)));
315 if (scr < buffer_length)
316 break;
317 buffer_length *= 2;
318 buffer = (UX_realloc (buffer, buffer_length));
319 if (buffer == 0)
320 error_system_call (ENOMEM, syscall_realloc);
321 }
322 (buffer[scr]) = '\0';
323 return ((const char *) buffer);
324 }
325 #else
326 return (0);
327 #endif
328 }
329
330 int
OS_file_access(const char * name,unsigned int mode)331 OS_file_access (const char * name, unsigned int mode)
332 {
333 return ((UX_access (name, mode)) == 0);
334 }
335
336 void
OS_file_remove(const char * name)337 OS_file_remove (const char * name)
338 {
339 STD_VOID_SYSTEM_CALL (syscall_unlink, (UX_unlink (name)));
340 }
341
342 void
OS_file_remove_link(const char * name)343 OS_file_remove_link (const char * name)
344 {
345 struct stat s;
346 if ((UX_read_file_status (name, (&s)))
347 && ((((s . st_mode) & S_IFMT) == S_IFREG)
348 #ifdef HAVE_SYMLINK
349 || (((s . st_mode) & S_IFMT) == S_IFLNK)
350 #endif
351 ))
352 UX_unlink (name);
353 }
354
355 void
OS_file_link_hard(const char * from_name,const char * to_name)356 OS_file_link_hard (const char * from_name, const char * to_name)
357 {
358 STD_VOID_SYSTEM_CALL (syscall_link, (UX_link (from_name, to_name)));
359 }
360
361 void
OS_file_link_soft(const char * from_name,const char * to_name)362 OS_file_link_soft (const char * from_name, const char * to_name)
363 {
364 #ifdef HAVE_SYMLINK
365 STD_VOID_SYSTEM_CALL (syscall_symlink, (UX_symlink (from_name, to_name)));
366 #else
367 error_unimplemented_primitive ();
368 #endif
369 }
370
371 void
OS_file_rename(const char * from_name,const char * to_name)372 OS_file_rename (const char * from_name, const char * to_name)
373 {
374 STD_VOID_SYSTEM_CALL (syscall_rename, (UX_rename (from_name, to_name)));
375 }
376
377 #ifndef FILE_COPY_BUFFER_LENGTH
378 #define FILE_COPY_BUFFER_LENGTH 8192
379 #endif
380
381 void
OS_file_copy(const char * from_name,const char * to_name)382 OS_file_copy (const char * from_name, const char * to_name)
383 {
384 Tchannel src, dst;
385 off_t src_len, len;
386 char buffer [FILE_COPY_BUFFER_LENGTH];
387 long nread, nwrite;
388
389 src = (OS_open_input_file (from_name));
390 OS_channel_close_on_abort (src);
391 dst = (OS_open_output_file (to_name));
392 OS_channel_close_on_abort (dst);
393 src_len = (OS_file_length (src));
394 len = (sizeof (buffer));
395 while (src_len > 0)
396 {
397 if (src_len < len)
398 len = src_len;
399 nread = (OS_channel_read (src, buffer, len));
400 if (nread < 0)
401 error_system_call (errno, syscall_read);
402 else if (nread == 0)
403 break;
404 nwrite = (OS_channel_write (dst, buffer, nread));
405 if (nwrite < 0)
406 error_system_call (errno, syscall_write);
407 else if (nwrite < nread)
408 error_system_call (ENOSPC, syscall_write);
409 src_len -= nread;
410 }
411 OS_channel_close (src);
412 OS_channel_close (dst);
413 }
414
415 void
OS_directory_make(const char * name)416 OS_directory_make (const char * name)
417 {
418 STD_VOID_SYSTEM_CALL (syscall_mkdir, (UX_mkdir (name, MODE_DIR)));
419 }
420
421 void
OS_directory_delete(const char * name)422 OS_directory_delete (const char * name)
423 {
424 STD_VOID_SYSTEM_CALL (syscall_rmdir, (UX_rmdir (name)));
425 }
426
427 static void protect_fd (int fd);
428
429 int
OS_file_touch(const char * filename)430 OS_file_touch (const char * filename)
431 {
432 int fd;
433 transaction_begin ();
434 {
435 unsigned int count = 0;
436 while (1)
437 {
438 count += 1;
439 /* Use O_EXCL to prevent overwriting existing file. */
440 fd = (UX_open (filename, (O_RDWR | O_CREAT | O_EXCL), MODE_REG));
441 if (fd >= 0)
442 {
443 protect_fd (fd);
444 transaction_commit ();
445 return (1);
446 }
447 if (errno == EEXIST)
448 {
449 fd = (UX_open (filename, O_RDWR, MODE_REG));
450 if (fd >= 0)
451 {
452 protect_fd (fd);
453 break;
454 }
455 else if ((errno == ENOENT)
456 #ifdef ESTALE
457 || (errno == ESTALE)
458 #endif
459 )
460 continue;
461 }
462 if (count >= FILE_TOUCH_OPEN_TRIES)
463 error_system_call (errno, syscall_open);
464 }
465 }
466 {
467 struct stat file_status;
468 STD_VOID_SYSTEM_CALL (syscall_fstat, (UX_fstat (fd, (&file_status))));
469 if (((file_status . st_mode) & S_IFMT) != S_IFREG)
470 return (-1);
471 /* CASE 3: file length of 0 needs special treatment. */
472 if ((file_status . st_size) == 0)
473 {
474 char buf [1];
475 (buf[0]) = '\0';
476 STD_VOID_SYSTEM_CALL (syscall_write, (UX_write (fd, buf, 1)));
477 #ifdef HAVE_FTRUNCATE
478 STD_VOID_SYSTEM_CALL (syscall_ftruncate, (UX_ftruncate (fd, 0)));
479 transaction_commit ();
480 #else
481 transaction_commit ();
482 /* FIXME: Need to check for EINTR. */
483 fd = (UX_open (filename, (O_WRONLY | O_TRUNC), MODE_REG));
484 if (fd >= 0)
485 (void) UX_close (fd);
486 #endif
487 return (0);
488 }
489 }
490 /* CASE 4: read, then write back the first byte in the file. */
491 {
492 char buf [1];
493 int scr;
494 STD_UINT_SYSTEM_CALL (syscall_read, scr, (UX_read (fd, buf, 1)));
495 if (scr > 0)
496 {
497 STD_VOID_SYSTEM_CALL (syscall_lseek, (UX_lseek (fd, 0, SEEK_SET)));
498 STD_VOID_SYSTEM_CALL (syscall_write, (UX_write (fd, buf, 1)));
499 }
500 }
501 transaction_commit ();
502 return (0);
503 }
504
505 static void
protect_fd_close(void * ap)506 protect_fd_close (void * ap)
507 {
508 (void) UX_close (* ((int *) ap));
509 }
510
511 static void
protect_fd(int fd)512 protect_fd (int fd)
513 {
514 int * p = (dstack_alloc (sizeof (int)));
515 (*p) = fd;
516 transaction_record_action (tat_always, protect_fd_close, p);
517 }
518
519 static DIR ** directory_pointers;
520 static unsigned int n_directory_pointers;
521
522 static void
close_all_directories(void)523 close_all_directories (void)
524 {
525 DIR ** scan = directory_pointers;
526 DIR ** end = (scan + n_directory_pointers);
527 while (scan < end)
528 {
529 if ((*scan) != 0)
530 {
531 closedir (*scan);
532 (*scan) = 0;
533 }
534 scan += 1;
535 }
536 directory_pointers = 0;
537 n_directory_pointers = 0;
538 }
539
540 void
UX_initialize_directory_reader(void)541 UX_initialize_directory_reader (void)
542 {
543 directory_pointers = 0;
544 n_directory_pointers = 0;
545 add_reload_cleanup (close_all_directories);
546 }
547
548 static unsigned int
allocate_directory_pointer(DIR * pointer)549 allocate_directory_pointer (DIR * pointer)
550 {
551 if (n_directory_pointers == 0)
552 {
553 DIR ** pointers = ((DIR **) (UX_malloc ((sizeof (DIR *)) * 4)));
554 if (pointers == 0)
555 error_system_call (ENOMEM, syscall_malloc);
556 directory_pointers = pointers;
557 n_directory_pointers = 4;
558 {
559 DIR ** scan = directory_pointers;
560 DIR ** end = (scan + n_directory_pointers);
561 (*scan++) = pointer;
562 while (scan < end)
563 (*scan++) = 0;
564 }
565 return (0);
566 }
567 {
568 DIR ** scan = directory_pointers;
569 DIR ** end = (scan + n_directory_pointers);
570 while (scan < end)
571 if ((*scan++) == 0)
572 {
573 (*--scan) = pointer;
574 return (scan - directory_pointers);
575 }
576 }
577 {
578 unsigned int result = n_directory_pointers;
579 unsigned int n_pointers = (2 * n_directory_pointers);
580 DIR ** pointers =
581 ((DIR **)
582 (UX_realloc (((void *) directory_pointers),
583 ((sizeof (DIR *)) * n_pointers))));
584 if (pointers == 0)
585 error_system_call (ENOMEM, syscall_realloc);
586 {
587 DIR ** scan = (pointers + result);
588 DIR ** end = (pointers + n_pointers);
589 (*scan++) = pointer;
590 while (scan < end)
591 (*scan++) = 0;
592 }
593 directory_pointers = pointers;
594 n_directory_pointers = n_pointers;
595 return (result);
596 }
597 }
598
599 #define REFERENCE_DIRECTORY(index) (directory_pointers[(index)])
600 #define DEALLOCATE_DIRECTORY(index) ((directory_pointers[(index)]) = 0)
601
602 int
OS_directory_valid_p(unsigned int index)603 OS_directory_valid_p (unsigned int index)
604 {
605 return
606 ((index < n_directory_pointers)
607 && ((REFERENCE_DIRECTORY (index)) != 0));
608 }
609
610 unsigned int
OS_directory_open(const char * name)611 OS_directory_open (const char * name)
612 {
613 DIR * pointer;
614 STD_PTR_SYSTEM_CALL (syscall_opendir, pointer, (opendir (name)));
615 /* FIXME: This leaks a directory pointer if malloc or realloc fails
616 here. Avoiding this safely with a transaction is unfortunately
617 not straightforward. */
618 return (allocate_directory_pointer (pointer));
619 }
620
621 const char *
OS_directory_read(unsigned int index)622 OS_directory_read (unsigned int index)
623 {
624 struct dirent * entry = (readdir (REFERENCE_DIRECTORY (index)));
625 return ((entry == 0) ? 0 : (entry -> d_name));
626 }
627
628 const char *
OS_directory_read_matching(unsigned int index,const char * prefix)629 OS_directory_read_matching (unsigned int index, const char * prefix)
630 {
631 DIR * pointer = (REFERENCE_DIRECTORY (index));
632 unsigned int n = (strlen (prefix));
633 while (1)
634 {
635 struct dirent * entry = (readdir (pointer));
636 if (entry == 0)
637 return (0);
638 if ((strncmp (prefix, (entry -> d_name), n)) == 0)
639 return (entry -> d_name);
640 }
641 }
642
643 void
OS_directory_close(unsigned int index)644 OS_directory_close (unsigned int index)
645 {
646 closedir (REFERENCE_DIRECTORY (index));
647 DEALLOCATE_DIRECTORY (index);
648 }
649