Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / fileio.c
1 /*
2  * IRC - Internet Relay Chat, ircd/fileio.c
3  * Copyright (C) 1998 Thomas Helvey <tomh@inxpress.net>
4  * Copyright (C) 1990 Jarkko Oikarinen and
5  *                  University of Oulu, Co Center
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 1, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 #include "fileio.h"
22 #include "ircd_alloc.h"         /* MyMalloc, MyFree */
23
24 #include <assert.h>             /* assert */
25 #include <fcntl.h>              /* O_RDONLY, O_WRONLY, ... */
26 #include <stdio.h>              /* BUFSIZ, EOF */
27 #include <sys/stat.h>           /* struct stat */
28 #include <unistd.h>             /* read, write, open, close */
29
30 #define FB_EOF  0x01
31 #define FB_FAIL 0x02
32
33 struct FileBuf {
34   int fd;                       /* file descriptor */
35   char *endp;                   /* one past the end */
36   char *ptr;                    /* current read pos */
37   int flags;                    /* file state */
38   char buf[BUFSIZ];             /* buffer */
39 };
40
41 FBFILE* fbopen(const char *filename, const char *mode)
42 {
43   int openmode = 0;
44   int pmode = 0;
45   FBFILE *fb = NULL;
46   int fd;
47   assert(filename);
48   assert(mode);
49
50   while (*mode) {
51     switch (*mode) {
52     case 'r':
53       openmode = O_RDONLY;
54       break;
55     case 'w':
56       openmode = O_WRONLY | O_CREAT | O_TRUNC;
57       pmode = S_IREAD | S_IWRITE;
58       break;
59     case 'a':
60       openmode = O_WRONLY | O_CREAT | O_APPEND;
61       pmode = S_IREAD | S_IWRITE;
62       break;
63     case '+':
64       openmode &= ~(O_RDONLY | O_WRONLY);
65       openmode |= O_RDWR;
66       break;
67     default:
68       break;
69     }
70     ++mode;
71   }
72   /*
73    * stop NFS hangs...most systems should be able to open a file in
74    * 3 seconds. -avalon (curtesy of wumpus)
75    */
76   alarm(3);
77   if ((fd = open(filename, openmode, pmode)) == -1) {
78     alarm(0);
79     return fb;
80   }
81   alarm(0);
82
83   if (NULL == (fb = fdbopen(fd, NULL)))
84     close(fd);
85   return fb;
86 }
87
88 FBFILE* fdbopen(int fd, const char *mode)
89 {
90   /*
91    * ignore mode, if file descriptor hasn't been opened with the
92    * correct mode, the first use will fail
93    */
94   FBFILE *fb = (FBFILE *) MyMalloc(sizeof(FBFILE));
95   assert(0 != fb);
96   fb->ptr   = fb->endp = fb->buf;
97   fb->fd    = fd;
98   fb->flags = 0;
99
100   return fb;
101 }
102
103 void fbclose(FBFILE* fb)
104 {
105   assert(fb);
106   close(fb->fd);
107   MyFree(fb);
108 }
109
110 static int fbfill(FBFILE * fb)
111 {
112   int n;
113   assert(fb);
114   if (fb->flags)
115     return -1;
116   n = read(fb->fd, fb->buf, BUFSIZ);
117   if (0 < n)
118   {
119     fb->ptr = fb->buf;
120     fb->endp = fb->buf + n;
121   }
122   else if (n < 0)
123     fb->flags |= FB_FAIL;
124   else
125     fb->flags |= FB_EOF;
126   return n;
127 }
128
129 int fbgetc(FBFILE * fb)
130 {
131   assert(fb);
132   if (fb->ptr < fb->endp || fbfill(fb) > 0)
133     return *fb->ptr++;
134   return EOF;
135 }
136
137 char *fbgets(char *buf, size_t len, FBFILE * fb)
138 {
139   char *p = buf;
140   assert(buf);
141   assert(fb);
142   assert(0 < len);
143
144   if (fb->ptr == fb->endp && fbfill(fb) < 1)
145     return 0;
146   --len;
147   while (len--) {
148     *p = *fb->ptr++;
149     if ('\n' == *p)
150     {
151       ++p;
152       break;
153     }
154     /*
155      * deal with CR's
156      */
157     else if ('\r' == *p) {
158       if (fb->ptr < fb->endp || fbfill(fb) > 0) {
159         if ('\n' == *fb->ptr)
160           ++fb->ptr;
161       }
162       *p++ = '\n';
163       break;
164     }
165     ++p;
166     if (fb->ptr == fb->endp && fbfill(fb) < 1)
167       break;
168   }
169   *p = '\0';
170   return buf;
171 }
172
173 int fbputs(const char *str, FBFILE * fb)
174 {
175   int n = -1;
176   assert(str);
177   assert(fb);
178
179   if (0 == fb->flags) {
180     n = write(fb->fd, str, strlen(str));
181     if (-1 == n)
182       fb->flags |= FB_FAIL;
183   }
184   return n;
185 }
186
187 int fbstat(struct stat *sb, FBFILE * fb)
188 {
189   assert(sb);
190   assert(fb);
191   return fstat(fb->fd, sb);
192 }
193