1 /* 2 * fopen.c - open a stream 3 */ 4 /* $Header$ */ 5 6 #if defined(_POSIX_SOURCE) 7 #include <sys/types.h> 8 #endif 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include "loc_incl.h" 12 #include <sys/stat.h> 13 14 #define PMODE 0666 15 16 /* The next 3 defines are true in all UNIX systems known to me. 17 */ 18 #define O_RDONLY 0 19 #define O_WRONLY 1 20 #define O_RDWR 2 21 22 /* Since the O_CREAT flag is not available on all systems, we can't get it 23 * from the standard library. Furthermore, even if we know that <fcntl.h> 24 * contains such a flag, it's not sure whether it can be used, since we 25 * might be cross-compiling for another system, which may use an entirely 26 * different value for O_CREAT (or not support such a mode). The safest 27 * thing is to just use the Version 7 semantics for open, and use creat() 28 * whenever necessary. 29 * 30 * Another problem is O_APPEND, for which the same holds. When "a" 31 * open-mode is used, an lseek() to the end is done before every write() 32 * system-call. 33 * 34 * The O_CREAT, O_TRUNC and O_APPEND given here, are only for convenience. 35 * They are not passed to open(), so the values don't have to match a value 36 * from the real world. It is enough when they are unique. 37 */ 38 #define O_CREAT 0x010 39 #define O_TRUNC 0x020 40 #define O_APPEND 0x040 41 42 int _open(const char *path, int flags); 43 int _creat(const char *path, mode_t mode); 44 int _close(int d); 45 46 FILE * 47 fopen(const char *name, const char *mode) 48 { 49 register int i; 50 int rwmode = 0, rwflags = 0; 51 FILE *stream; 52 struct stat st; 53 int fd, flags = 0; 54 55 for (i = 0; __iotab[i] != 0 ; i++) 56 if ( i >= FOPEN_MAX-1 ) 57 return (FILE *)NULL; 58 59 switch(*mode++) { 60 case 'r': 61 flags |= _IOREAD | _IOREADING; 62 rwmode = O_RDONLY; 63 break; 64 case 'w': 65 flags |= _IOWRITE | _IOWRITING; 66 rwmode = O_WRONLY; 67 rwflags = O_CREAT | O_TRUNC; 68 break; 69 case 'a': 70 flags |= _IOWRITE | _IOWRITING | _IOAPPEND; 71 rwmode = O_WRONLY; 72 rwflags |= O_APPEND | O_CREAT; 73 break; 74 default: 75 return (FILE *)NULL; 76 } 77 78 while (*mode) { 79 switch(*mode++) { 80 case 'b': 81 continue; 82 case '+': 83 rwmode = O_RDWR; 84 flags |= _IOREAD | _IOWRITE; 85 continue; 86 /* The sequence may be followed by additional characters */ 87 default: 88 break; 89 } 90 break; 91 } 92 93 /* Perform a creat() when the file should be truncated or when 94 * the file is opened for writing and the open() failed. 95 */ 96 if ((rwflags & O_TRUNC) 97 || (((fd = _open(name, rwmode)) < 0) 98 && (rwflags & O_CREAT))) { 99 if (((fd = _creat(name, PMODE)) > 0) && flags | _IOREAD) { 100 (void) _close(fd); 101 fd = _open(name, rwmode); 102 } 103 104 } 105 106 if (fd < 0) return (FILE *)NULL; 107 108 if ( fstat( fd, &st ) < 0 ) { 109 _close(fd); 110 return (FILE *)NULL; 111 } 112 113 if ( S_ISFIFO(st.st_mode) ) flags |= _IOFIFO; 114 115 if (( stream = (FILE *) malloc(sizeof(FILE))) == NULL ) { 116 _close(fd); 117 return (FILE *)NULL; 118 } 119 120 if ((flags & (_IOREAD | _IOWRITE)) == (_IOREAD | _IOWRITE)) 121 flags &= ~(_IOREADING | _IOWRITING); 122 123 stream->_count = 0; 124 stream->_fd = fd; 125 stream->_flags = flags; 126 stream->_buf = NULL; 127 __iotab[i] = stream; 128 return stream; 129 } 130