1: /*************************************************************************
2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
6: * $Id: bufio.c,v 1.9.8.1 2016/08/11 12:25:51 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004 - 2016
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: static void
50: unmap_cf(struct tagBufIO *buf)
51: {
52: if (buf)
53: munmap(buf->buf_base, buf->buf_size);
54: }
55:
56: #ifndef __linux__
57: static int
58: cf_(struct tagBufIO *buf)
59: {
60: if (!buf) {
61: io_SetErr(EINVAL, "Invalid arguments ...");
62: return -1;
63: }
64:
65: if (buf->buf_mode == BUFIO_MODE_INFINIT)
66: e_free(buf->buf_base);
67: else if (buf->buf_unmap)
68: buf->buf_unmap(buf);
69:
70: e_free(buf);
71: return 0;
72: }
73:
74: #ifdef __NetBSD__
75: static off_t
76: sf_lim(struct tagBufIO *buf, off_t pos, int w)
77: #else
78: static fpos_t
79: sf_lim(struct tagBufIO *buf, fpos_t pos, int w)
80: #endif
81: {
82: if (!buf)
83: goto err;
84:
85: switch (w) {
86: case SEEK_SET:
87: if (buf->buf_size < pos || pos < 0)
88: goto err;
89: buf->buf_offset = pos;
90: break;
91: case SEEK_CUR:
92: if (buf->buf_size < (buf->buf_offset + pos) || (buf->buf_offset + pos) < 0)
93: goto err;
94: buf->buf_offset += pos;
95: break;
96: case SEEK_END:
97: if (buf->buf_size < (buf->buf_size + pos) || (buf->buf_size + pos) < 0)
98: goto err;
99: buf->buf_offset = buf->buf_size + pos;
100: break;
101: default:
102: goto err;
103: }
104:
105: return buf->buf_offset;
106: err:
107: io_SetErr(EINVAL, "Invalid arguments ...");
108: return -1;
109: }
110:
111: static int
112: rf_lim(struct tagBufIO *buf, char *dat, int siz)
113: {
114: if (!buf || !dat) {
115: io_SetErr(EINVAL, "Invalid arguments ...");
116: return -1;
117: }
118:
119: if (buf->buf_offset + siz > buf->buf_size)
120: siz = buf->buf_size - buf->buf_offset;
121:
122: memcpy(dat, buf->buf_base + buf->buf_offset, siz);
123: buf->buf_offset += siz;
124: return siz;
125: }
126:
127: static int
128: wf_lim(struct tagBufIO *buf, const char *dat, int siz)
129: {
130: if (!buf || !dat) {
131: io_SetErr(EINVAL, "Invalid arguments ...");
132: return -1;
133: }
134:
135: if (buf->buf_offset + siz > buf->buf_size)
136: siz = buf->buf_size - buf->buf_offset;
137:
138: memcpy(buf->buf_base + buf->buf_offset, dat, siz);
139: buf->buf_offset += siz;
140: return siz;
141: }
142:
143: #ifdef __NetBSD__
144: static off_t
145: sf_inf(struct tagBufIO *buf, off_t pos, int w)
146: #else
147: static fpos_t
148: sf_inf(struct tagBufIO *buf, fpos_t pos, int w)
149: #endif
150: {
151: void *b;
152:
153: if (!buf)
154: goto err;
155:
156: switch (w) {
157: case SEEK_SET:
158: if (pos < 0)
159: goto err;
160: if (buf->buf_size < pos) {
161: b = e_realloc(buf->buf_base, pos);
162: if (!b) {
163: LOGERR;
164: return -1;
165: } else {
166: buf->buf_base = b;
167: memset(buf->buf_base + buf->buf_size, 0, pos - buf->buf_size);
168: buf->buf_size = pos;
169: }
170: }
171: buf->buf_offset = pos;
172: break;
173: case SEEK_CUR:
174: if ((buf->buf_offset + pos) < 0)
175: goto err;
176: if (buf->buf_size < (buf->buf_offset + pos)) {
177: b = e_realloc(buf->buf_base, buf->buf_offset + pos);
178: if (!b) {
179: LOGERR;
180: return -1;
181: } else {
182: buf->buf_base = b;
183: memset(buf->buf_base + buf->buf_size, 0,
184: buf->buf_offset + pos - buf->buf_size);
185: buf->buf_size = buf->buf_offset + pos;
186: }
187: }
188: buf->buf_offset += pos;
189: break;
190: case SEEK_END:
191: if ((buf->buf_size + pos) < 0)
192: goto err;
193: if (buf->buf_size < (buf->buf_size + pos)) {
194: b = e_realloc(buf->buf_base, buf->buf_size + pos);
195: if (!b) {
196: LOGERR;
197: return -1;
198: } else {
199: buf->buf_base = b;
200: memset(buf->buf_base + buf->buf_size, 0, pos);
201: buf->buf_size += pos;
202: buf->buf_offset = buf->buf_size;
203: }
204: } else
205: buf->buf_offset = buf->buf_size + pos;
206: break;
207: default:
208: goto err;
209: }
210:
211: return buf->buf_offset;
212: err:
213: io_SetErr(EINVAL, "Invalid arguments ...");
214: return -1;
215: }
216:
217: static int
218: wf_inf(struct tagBufIO *buf, const char *dat, int siz)
219: {
220: void *b;
221:
222: if (!buf || !dat) {
223: io_SetErr(EINVAL, "Invalid arguments ...");
224: return -1;
225: }
226:
227: if (buf->buf_offset + siz > buf->buf_size) {
228: b = e_realloc(buf->buf_base, buf->buf_offset + siz);
229: if (!b) {
230: LOGERR;
231: return -1;
232: } else {
233: buf->buf_base = b;
234: memset(buf->buf_base + buf->buf_size, 0,
235: buf->buf_offset + siz - buf->buf_size);
236: buf->buf_size = buf->buf_offset + siz;
237: }
238: }
239:
240: memcpy(buf->buf_base + buf->buf_offset, dat, siz);
241: buf->buf_offset += siz;
242: return siz;
243: }
244: #endif
245:
246:
247: /*
248: * io_fmemopen() - File buffered stream operations over memory block
249: *
250: * @base = Base address of memory block, if =NULL Infinit length(auto-grow)
251: * @basesize = Size of memory block
252: * return: NULL error or !=NULL Opened file resource
253: */
254: FILE *
255: io_fmemopen(void ** __restrict base, off_t basesize)
256: {
257: FILE *f = NULL;
258: struct tagBufIO *buf;
259:
260: if (!base) {
261: io_SetErr(EINVAL, "Invalid base argument ...");
262: return NULL;
263: }
264:
265: buf = e_malloc(sizeof(struct tagBufIO));
266: if (!buf) {
267: LOGERR;
268: return NULL;
269: } else
270: memset(buf, 0, sizeof(struct tagBufIO));
271:
272: if (!*base) {
273: #ifndef __linux__
274: *base = e_malloc(basesize);
275: if (!*base) {
276: LOGERR;
277: e_free(buf);
278: return NULL;
279: } else
280: memset(*base, 0, basesize);
281:
282: buf->buf_base = *base;
283: buf->buf_size = basesize;
284: #endif
285: buf->buf_mode = BUFIO_MODE_INFINIT;
286: } else {
287: buf->buf_base = *base;
288: buf->buf_size = basesize;
289:
290: buf->buf_mode = BUFIO_MODE_LIMIT;
291: }
292:
293: #ifndef __linux__
294: #ifdef __NetBSD__
295: if (buf->buf_mode == BUFIO_MODE_INFINIT)
296: f = funopen(buf, (int (*)(void *, char *, int)) rf_lim,
297: (int (*)(void *, char const *, int)) wf_inf,
298: (off_t (*)(void *, off_t, int)) sf_inf,
299: (int (*)(void *)) cf_);
300: else
301: f = funopen(buf, (int (*)(void *, char *, int)) rf_lim,
302: (int (*)(void *, char const *, int)) wf_lim,
303: (off_t (*)(void *, off_t, int)) sf_lim,
304: (int (*)(void *)) cf_);
305: #else
306: if (buf->buf_mode == BUFIO_MODE_INFINIT)
307: f = funopen(buf, (int (*)(void *, char *, int)) rf_lim,
308: (int (*)(void *, char const *, int)) wf_inf,
309: (fpos_t (*)(void *, fpos_t, int)) sf_inf,
310: (int (*)(void *)) cf_);
311: else
312: f = funopen(buf, (int (*)(void *, char *, int)) rf_lim,
313: (int (*)(void *, char const *, int)) wf_lim,
314: (fpos_t (*)(void *, fpos_t, int)) sf_lim,
315: (int (*)(void *)) cf_);
316: #endif
317: #else
318: if (buf->buf_mode == BUFIO_MODE_INFINIT)
319: f = open_memstream((char**) &buf->buf_base, (size_t*) &buf->buf_size);
320: else
321: f = fmemopen(buf->buf_base, buf->buf_size, "r+");
322: #endif
323: if (!f) {
324: LOGERR;
325: #ifndef __linux__
326: if (buf->buf_mode == BUFIO_MODE_INFINIT) {
327: e_free(*base);
328: *base = NULL;
329: }
330: #endif
331: e_free(buf);
332: return NULL;
333: }
334: #ifdef __linux__
335: if (buf->buf_mode == BUFIO_MODE_INFINIT)
336: *base = buf->buf_base;
337: #endif
338:
339: return f;
340: }
341:
342: /*
343: * io_fmapopen() - File buffered stream operations over MMAP block
344: *
345: * @csFile = Filename for MMAP, if =NULL private MMAP block
346: * @mode = File open mode
347: * @perm = If file not exists will be created with this access permissions
348: * @prot = MMAP protection
349: * @flags = MMAP mode flags
350: * @offset = Map from file offset, if csFile==NULL then this is size of MMAP private block
351: * return: NULL error or !=NULL Opened file resource
352: */
353: FILE *
354: io_fmapopen(const char *csFile, int mode, int perm, int prot, int flags, off_t offset)
355: {
356: FILE *f;
357: struct tagBufIO *buf;
358: void *base;
359: off_t basesize;
360: int fd = -1;
361:
362: if (csFile) {
363: fd = open(csFile, mode, perm);
364: if (fd == -1) {
365: LOGERR;
366: return NULL;
367: }
368: basesize = lseek(fd, 0, SEEK_END);
369: if (basesize == -1) {
370: LOGERR;
371: close(fd);
372: return NULL;
373: } else
374: lseek(fd, 0, SEEK_SET);
375:
376: base = mmap(NULL, basesize, prot, flags | MAP_FILE, fd, offset);
377: if (base == MAP_FAILED) {
378: LOGERR;
379: close(fd);
380: return NULL;
381: } else
382: close(fd);
383: } else if (offset) {
384: basesize = offset;
385: base = mmap(NULL, basesize, prot, MAP_ANON, -1, 0);
386: if (base == MAP_FAILED) {
387: LOGERR;
388: return NULL;
389: }
390: } else {
391: io_SetErr(EINVAL, "Invalid base argument ...");
392: return NULL;
393: }
394:
395:
396: buf = e_malloc(sizeof(struct tagBufIO));
397: if (!buf) {
398: LOGERR;
399: munmap(base, basesize);
400: return NULL;
401: } else
402: memset(buf, 0, sizeof(struct tagBufIO));
403:
404: buf->buf_mode = BUFIO_MODE_LIMIT;
405: buf->buf_base = base;
406: buf->buf_size = basesize;
407: buf->buf_unmap = unmap_cf;
408:
409: #ifndef __linux__
410: #ifdef __NetBSD__
411: f = funopen(buf, (int (*)(void *, char *, int)) rf_lim,
412: (int (*)(void *, char const *, int)) wf_lim,
413: (off_t (*)(void *, off_t, int)) sf_lim,
414: (int (*)(void *)) cf_);
415: #else
416: f = funopen(buf, (int (*)(void *, char *, int)) rf_lim,
417: (int (*)(void *, char const *, int)) wf_lim,
418: (fpos_t (*)(void *, fpos_t, int)) sf_lim,
419: (int (*)(void *)) cf_);
420: #endif
421: #else
422: f = fmemopen(buf->buf_base, buf->buf_size, "r+");
423: #endif
424: if (!f) {
425: LOGERR;
426: e_free(buf);
427: munmap(base, basesize);
428: return NULL;
429: }
430:
431: return f;
432: }
433:
434: /*
435: * io_dumbFile() - Create empry or dumb file with fixed size
436: *
437: * @csFile = Filename for create
438: * @mode = File access permissions
439: * @size = File size
440: * return: -1 error or open file handle
441: */
442: int
443: io_dumbFile(const char *csFile, int mode, off_t size)
444: {
445: int fd;
446:
447: fd = open(csFile, O_RDWR | O_CREAT, mode);
448: if (fd == -1) {
449: LOGERR;
450: return -1;
451: }
452:
453: if (lseek(fd, size - 1, SEEK_SET) == -1)
454: goto err;
455: if (write(fd, "", 1) != 1)
456: goto err;
457: else
458: lseek(fd, 0, SEEK_SET);
459:
460: return fd;
461: err:
462: LOGERR;
463: close(fd);
464: return -1;
465: }
466:
467: /*
468: * io_fd2buf() - Convert open file handle to buffered file I/O
469: *
470: * @fd = File handle
471: * @mode = Permissions for new buffered file I/O
472: * return: NULL error or open buffered file
473: */
474: FILE *
475: io_fd2buf(int fd, const char *mode)
476: {
477: FILE *f;
478:
479: f = fdopen(fd, mode);
480: if (!f)
481: LOGERR;
482:
483: return f;
484: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>