This commit was generated by cvs2svn to compensate for changes in r2,
[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 "runmalloc.h"          /* RunMalloc, RunFree */
23 #include <stdio.h>              /* BUFSIZ, EOF */
24 #include <fcntl.h>              /* O_RDONLY, O_WRONLY, ... */
25 #include <unistd.h>             /* read, write, open, close */
26 #include <assert.h>             /* assert */
27
28 #define FB_EOF  0x01
29 #define FB_FAIL 0x02
30
31 struct FileBuf {
32   int fd;                       /* file descriptor */
33   char *endp;                   /* one past the end */
34   char *ptr;                    /* current read pos */
35   int flags;                    /* file state */
36   char buf[BUFSIZ];             /* buffer */
37 };
38
39 FBFILE *fbopen(const char *filename, const char *mode)
40 {
41   int openmode = 0;
42   int pmode = 0;
43   FBFILE *fb = NULL;
44   int fd;
45   assert(filename);
46   assert(mode);
47
48   while (*mode)
49   {
50     switch (*mode)
51     {
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   {
79     alarm(0);
80     return fb;
81   }
82   alarm(0);
83
84   if (NULL == (fb = fdbopen(fd, NULL)))
85     close(fd);
86   return fb;
87 }
88
89 FBFILE *fdbopen(int fd, const char *mode)
90 {
91   /*
92    * ignore mode, if file descriptor hasn't been opened with the
93    * correct mode, the first use will fail
94    */
95   FBFILE *fb = (FBFILE *) RunMalloc(sizeof(FBFILE));
96   if (NULL != fb)
97   {
98     fb->ptr = fb->endp = fb->buf;
99     fb->fd = fd;
100     fb->flags = 0;
101   }
102   return fb;
103 }
104
105 void fbclose(FBFILE * fb)
106 {
107   assert(fb);
108   close(fb->fd);
109   RunFree(fb);
110 }
111
112 static int fbfill(FBFILE * fb)
113 {
114   int n;
115   assert(fb);
116   if (fb->flags)
117     return -1;
118   n = read(fb->fd, fb->buf, BUFSIZ);
119   if (0 < n)
120   {
121     fb->ptr = fb->buf;
122     fb->endp = fb->buf + n;
123   }
124   else if (n < 0)
125     fb->flags |= FB_FAIL;
126   else
127     fb->flags |= FB_EOF;
128   return n;
129 }
130
131 int fbgetc(FBFILE * fb)
132 {
133   assert(fb);
134   if (fb->ptr < fb->endp || fbfill(fb) > 0)
135     return *fb->ptr++;
136   return EOF;
137 }
138
139 char *fbgets(char *buf, size_t len, FBFILE * fb)
140 {
141   char *p = buf;
142   assert(buf);
143   assert(fb);
144   assert(0 < len);
145
146   if (fb->ptr == fb->endp && fbfill(fb) < 1)
147     return 0;
148   --len;
149   while (len--)
150   {
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     {
162       if (fb->ptr < fb->endp || fbfill(fb) > 0)
163       {
164         if ('\n' == *fb->ptr)
165           ++fb->ptr;
166       }
167       *p++ = '\n';
168       break;
169     }
170     ++p;
171     if (fb->ptr == fb->endp && fbfill(fb) < 1)
172       break;
173   }
174   *p = '\0';
175   return buf;
176 }
177
178 int fbputs(const char *str, FBFILE * fb)
179 {
180   int n = -1;
181   assert(str);
182   assert(fb);
183
184   if (0 == fb->flags)
185   {
186     n = write(fb->fd, str, strlen(str));
187     if (-1 == n)
188       fb->flags |= FB_FAIL;
189   }
190   return n;
191 }
192
193 int fbstat(struct stat *sb, FBFILE * fb)
194 {
195   assert(sb);
196   assert(fb);
197   return fstat(fb->fd, sb);
198 }