1 /***************************************************************************/
2 /*    This code is part of WWW grabber called pavuk                        */
3 /*    Copyright (c) 1997 - 2001 Stefan Ondrejicka                          */
4 /*    Distributed under GPL 2 or later                                     */
5 /***************************************************************************/
6 
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/socket.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <errno.h>
15 
16 #include "config.h"
17 #include "bufio.h"
18 #include "tools.h"
19 #include "absio.h"
20 #include "myssl.h"
21 
22 #ifndef MAX
23 #define MAX(x,y) ((x) > (y) ? (x) : (y))
24 #endif
25 
26 #define BUFIO_BUF_SIZE  4096
27 
_bufio_tl_write(bufio * desc,char * buf,size_t size)28 static int _bufio_tl_write(bufio * desc, char *buf, size_t size)
29 {
30   if(desc->is_sock)
31     return tl_sock_write(desc->fd, buf, size, desc->ssl_hook_data);
32   else
33     return tl_file_write(desc->fd, buf, size);
34 }
35 
_bufio_tl_read(bufio * desc,char * buf,size_t size)36 static int _bufio_tl_read(bufio * desc, char *buf, size_t size)
37 {
38   if(desc->is_sock)
39     return tl_sock_read(desc->fd, buf, size, desc->ssl_hook_data);
40   else
41     return tl_file_read(desc->fd, buf, size);
42 }
43 
bufio_new(void)44 static bufio *bufio_new(void)
45 {
46   bufio *retv;
47 
48   retv = _malloc(sizeof(bufio));
49   retv->buf = _malloc(BUFIO_BUF_SIZE);
50   retv->fd = -1;
51   retv->buf_size = BUFIO_BUF_SIZE;
52   retv->buf_start = 0;
53   retv->buf_end = 0;
54   retv->bufio_errno = 0;
55   retv->eof = 0;
56   retv->is_sock = 0;
57   retv->ssl_hook_data = NULL;
58 
59   return retv;
60 }
61 
bufio_sock_fdopen(int fd)62 bufio *bufio_sock_fdopen(int fd)
63 {
64   bufio *retv;
65 
66   retv = bufio_fdopen(fd);
67 
68   if(retv)
69     retv->is_sock = 1;
70 
71   return retv;
72 }
73 
bufio_fdopen(int fd)74 bufio *bufio_fdopen(int fd)
75 {
76   bufio *retv;
77 
78   if(fd < 0)
79     return NULL;
80 
81   retv = bufio_new();
82   retv->fd = fd;
83 
84   return retv;
85 }
86 
bufio_dupfd(int fd)87 bufio *bufio_dupfd(int fd)
88 {
89   int cfd;
90 
91   if(fd < 0)
92     return NULL;
93 
94   cfd = dup(fd);
95 
96   return bufio_fdopen(cfd);
97 }
98 
bufio_open(const char * filename,int flags)99 bufio *bufio_open(const char *filename, int flags)
100 {
101   int fd;
102 
103   fd = open(filename, flags);
104 
105   if(fd < 0)
106     return NULL;
107 
108   return bufio_fdopen(fd);
109 }
110 
bufio_copen(const char * filename,int flags,int mask)111 bufio *bufio_copen(const char *filename, int flags, int mask)
112 {
113   int fd;
114 
115   fd = open(filename, flags, mask);
116 
117   if(fd < 0)
118     return NULL;
119 
120   return bufio_fdopen(fd);
121 }
122 
bufio_new_sslcon(bufio * sock,void * con)123 bufio *bufio_new_sslcon(bufio * sock, void *con)
124 {
125   bufio *retv;
126 
127   retv = bufio_new();
128   retv->ssl_hook_data = con;
129   retv->is_sock = 1;
130   retv->fd = bufio_getfd(sock);
131 
132   return retv;
133 }
134 
bufio_free(bufio * desc)135 void bufio_free(bufio * desc)
136 {
137   _free(desc->buf);
138   _free(desc);
139 }
140 
bufio_close(bufio * desc)141 int bufio_close(bufio * desc)
142 {
143   int rv = 0;
144 
145 #ifdef USE_SSL
146   if(desc->ssl_hook_data)
147   {
148     my_ssl_connection_destroy(desc->ssl_hook_data);
149     desc->ssl_hook_data = NULL;
150     desc->fd = -1;
151   }
152 #endif
153 
154 
155   if(desc->fd >= 0)
156   {
157     if(desc->is_sock)
158     {
159       shutdown(desc->fd, 2);
160 #ifdef __BEOS__
161       rv = closesocket(desc->fd);
162 #else
163       rv = close(desc->fd);
164 #endif
165     }
166     else
167       rv = close(desc->fd);
168   }
169 
170   desc->fd = -1;
171 
172   _free(desc->buf);
173   _free(desc);
174 
175   return rv;
176 }
177 
bufio_write(bufio * desc,char * buf,size_t size)178 int bufio_write(bufio * desc, char *buf, size_t size)
179 {
180   return _bufio_tl_write(desc, buf, size);
181 }
182 
bufio_read(bufio * desc,char * buf,size_t size)183 int bufio_read(bufio * desc, char *buf, size_t size)
184 {
185   int read_sz = 0;
186   int read_act;
187   int miss_size = size;
188   int acnt;
189 
190   if(desc->eof)
191   {
192     return 0;
193   }
194 
195   if(desc->bufio_errno)
196   {
197     errno = desc->bufio_errno;
198     return -1;
199   }
200 
201   for(;;)
202   {
203     if(desc->buf_start < desc->buf_end)
204     {
205       read_act = miss_size < desc->buf_end - desc->buf_start ?
206         miss_size : desc->buf_end - desc->buf_start;
207 
208       memcpy(buf + read_sz, desc->buf + desc->buf_start, read_act);
209 
210       desc->buf_start += read_act;
211       miss_size -= read_act;
212       read_sz += read_act;
213 
214       if(read_sz == size)
215         return read_sz;
216     }
217     else
218     {
219       desc->buf_start = 0;
220       desc->buf_end = 0;
221       acnt = _bufio_tl_read(desc, desc->buf, desc->buf_size);
222 
223       if(acnt <= 0)
224       {
225         if(acnt == 0)
226           desc->eof = 1;
227         if(read_sz)
228         {
229           desc->bufio_errno = errno;
230           return read_sz;
231         }
232         else
233           return acnt;
234       }
235 
236       desc->buf_end = acnt;
237     }
238   }
239 }
240 
bufio_nbfread(bufio * desc,char * buf,size_t size)241 int bufio_nbfread(bufio * desc, char *buf, size_t size)
242 {
243   int read_sz;
244 
245   if(desc->eof)
246   {
247     return 0;
248   }
249   if(desc->bufio_errno)
250   {
251     errno = desc->bufio_errno;
252     return -1;
253   }
254 
255   if(desc->buf_start < desc->buf_end)
256   {
257     read_sz = size < desc->buf_end - desc->buf_start ?
258       size : desc->buf_end - desc->buf_start;
259 
260     memcpy(buf, desc->buf + desc->buf_start, read_sz);
261 
262     desc->buf_start += read_sz;
263 
264     return read_sz;
265   }
266   else
267   {
268     desc->buf_start = 0;
269     desc->buf_end = 0;
270     read_sz = _bufio_tl_read(desc, buf, size);
271 
272     if(read_sz <= 0)
273     {
274       if(read_sz == 0)
275         desc->eof = 1;
276       if(read_sz < 0)
277         desc->bufio_errno = errno;
278     }
279     return read_sz;
280   }
281 }
282 
bufio_readln(bufio * desc,char * buf,size_t size)283 int bufio_readln(bufio * desc, char *buf, size_t size)
284 {
285   int read_sz = 0;
286   int read_act;
287   int miss_size = size - 1;
288   int acnt;
289   char *mc = NULL;
290 
291   if(desc->eof)
292   {
293     return 0;
294   }
295 
296   if(desc->bufio_errno)
297   {
298     errno = desc->bufio_errno;
299     return -1;
300   }
301 
302   size--;
303 
304   for(;;)
305   {
306     if(desc->buf_start < desc->buf_end)
307     {
308       mc = memchr(desc->buf + desc->buf_start, '\n',
309         desc->buf_end - desc->buf_start);
310 
311       if(mc && (mc - (desc->buf + desc->buf_start) < miss_size))
312       {
313         read_act = mc + 1 - (desc->buf + desc->buf_start);
314       }
315       else
316         read_act = miss_size < desc->buf_end - desc->buf_start ?
317           miss_size : desc->buf_end - desc->buf_start;
318 
319       memcpy(buf + read_sz, desc->buf + desc->buf_start, read_act);
320 
321       desc->buf_start += read_act;
322       miss_size -= read_act;
323       read_sz += read_act;
324 
325       if(read_sz == size || mc)
326       {
327         *(buf + read_sz) = '\0';
328         return read_sz;
329       }
330     }
331     else
332     {
333       desc->buf_start = 0;
334       desc->buf_end = 0;
335       acnt = _bufio_tl_read(desc, desc->buf, desc->buf_size);
336 
337       if(acnt <= 0)
338       {
339         if(acnt == 0)
340           desc->eof = 1;
341         if(read_sz)
342         {
343           desc->bufio_errno = errno;
344           *(buf + read_sz + 1) = '\0';
345           return read_sz;
346         }
347         else
348           return acnt;
349       }
350 
351       desc->buf_end = acnt;
352     }
353   }
354 }
355 
bufio_unread(bufio * desc,char * buf,size_t size)356 void bufio_unread(bufio * desc, char *buf, size_t size)
357 {
358   char *p = desc->buf;
359 
360   desc->buf_size =
361     MAX(desc->buf_size, (size + desc->buf_end - desc->buf_start));
362 
363   desc->buf = _malloc(desc->buf_size);
364 
365   memmove(desc->buf, buf, size);
366   memmove(desc->buf + size, p + desc->buf_start,
367     desc->buf_end - desc->buf_start);
368 
369   desc->buf_end = size + desc->buf_end - desc->buf_start;
370   desc->buf_start = 0;
371 
372   _free(p);
373 }
374 
bufio_reset(bufio * desc)375 void bufio_reset(bufio * desc)
376 {
377   desc->buf_start = 0;
378   desc->buf_end = 0;
379 }
380