Author: Kev <klmitch@mit.edu>
[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 "config.h"
22
23 #include "fileio.h"
24 #include "ircd_alloc.h"         /* MyMalloc, MyFree */
25
26 #include <assert.h>             /* assert */
27 #include <fcntl.h>              /* O_RDONLY, O_WRONLY, ... */
28 #include <stdio.h>              /* BUFSIZ, EOF */
29 #include <sys/stat.h>           /* struct stat */
30 #include <unistd.h>             /* read, write, open, close */
31 #include <string.h>
32
33 #define FB_EOF  0x01
34 #define FB_FAIL 0x02
35
36 struct FileBuf {
37   int fd;                       /* file descriptor */
38   char *endp;                   /* one past the end */
39   char *ptr;                    /* current read pos */
40   int flags;                    /* file state */
41   char buf[BUFSIZ];             /* buffer */
42 };
43
44 FBFILE* fbopen(const char *filename, const char *mode)
45 {
46   int openmode = 0;
47   int pmode = 0;
48   FBFILE *fb = NULL;
49   int fd;
50   assert(filename);
51   assert(mode);
52
53   while (*mode) {
54     switch (*mode) {
55     case 'r':
56       openmode = O_RDONLY;
57       break;
58     case 'w':
59       openmode = O_WRONLY | O_CREAT | O_TRUNC;
60       pmode = S_IREAD | S_IWRITE;
61       break;
62     case 'a':
63       openmode = O_WRONLY | O_CREAT | O_APPEND;
64       pmode = S_IREAD | S_IWRITE;
65       break;
66     case '+':
67       openmode &= ~(O_RDONLY | O_WRONLY);
68       openmode |= O_RDWR;
69       break;
70     default:
71       break;
72     }
73     ++mode;
74   }
75   /*
76    * stop NFS hangs...most systems should be able to open a file in
77    * 3 seconds. -avalon (curtesy of wumpus)
78    */
79   alarm(3);
80   if ((fd = open(filename, openmode, pmode)) == -1) {
81     alarm(0);
82     return fb;
83   }
84   alarm(0);
85
86   if (NULL == (fb = fdbopen(fd, NULL)))
87     close(fd);
88   return fb;
89 }
90
91 FBFILE* fdbopen(int fd, const char *mode)
92 {
93   /*
94    * ignore mode, if file descriptor hasn't been opened with the
95    * correct mode, the first use will fail
96    */
97   FBFILE *fb = (FBFILE *) MyMalloc(sizeof(FBFILE));
98   assert(0 != fb);
99   fb->ptr   = fb->endp = fb->buf;
100   fb->fd    = fd;
101   fb->flags = 0;
102
103   return fb;
104 }
105
106 void fbclose(FBFILE* fb)
107 {
108   assert(fb);
109   close(fb->fd);
110   MyFree(fb);
111 }
112
113 static int fbfill(FBFILE * fb)
114 {
115   int n;
116   assert(fb);
117   if (fb->flags)
118     return -1;
119   n = read(fb->fd, fb->buf, BUFSIZ);
120   if (0 < n)
121   {
122     fb->ptr = fb->buf;
123     fb->endp = fb->buf + n;
124   }
125   else if (n < 0)
126     fb->flags |= FB_FAIL;
127   else
128     fb->flags |= FB_EOF;
129   return n;
130 }
131
132 int fbgetc(FBFILE * fb)
133 {
134   assert(fb);
135   if (fb->ptr < fb->endp || fbfill(fb) > 0)
136     return *fb->ptr++;
137   return EOF;
138 }
139
140 char *fbgets(char *buf, size_t len, FBFILE * fb)
141 {
142   char *p = buf;
143   assert(buf);
144   assert(fb);
145   assert(0 < len);
146
147   if (fb->ptr == fb->endp && fbfill(fb) < 1)
148     return 0;
149   --len;
150   while (len--) {
151     *p = *fb->ptr++;
152     if ('\n' == *p)
153     {
154       ++p;
155       break;
156     }
157     /*
158      * deal with CR's
159      */
160     else if ('\r' == *p) {
161       if (fb->ptr < fb->endp || fbfill(fb) > 0) {
162         if ('\n' == *fb->ptr)
163           ++fb->ptr;
164       }
165       *p++ = '\n';
166       break;
167     }
168     ++p;
169     if (fb->ptr == fb->endp && fbfill(fb) < 1)
170       break;
171   }
172   *p = '\0';
173   return buf;
174 }
175
176 int fbputs(const char *str, FBFILE * fb)
177 {
178   int n = -1;
179   assert(str);
180   assert(fb);
181
182   if (0 == fb->flags) {
183     n = write(fb->fd, str, strlen(str));
184     if (-1 == n)
185       fb->flags |= FB_FAIL;
186   }
187   return n;
188 }
189
190 int fbstat(struct stat *sb, FBFILE * fb)
191 {
192   assert(sb);
193   assert(fb);
194   return fstat(fb->fd, sb);
195 }
196