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