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