Annotation of libaitio/src/aitio.c, revision 1.10.6.5
1.1 misho 1: /*************************************************************************
1.5 misho 2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
1.1 misho 4: *
5: * $Author: misho $
1.10.6.5! misho 6: * $Id: aitio.c,v 1.10.6.4 2012/05/23 13:53:00 misho Exp $
1.1 misho 7: *
1.5 misho 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:
1.9 misho 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
1.5 misho 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: */
1.1 misho 46: #include "global.h"
47:
48:
1.2 misho 49: int io_Debug;
1.10.6.4 misho 50: mpool_t *io_mpool;
51:
52:
53: /* Memory management */
54:
55: void *(*io_malloc)(size_t) = malloc;
56: void *(*io_calloc)(size_t, size_t) = calloc;
57: void *(*io_realloc)(void*, size_t) = realloc;
58: char *(*io_strdup)(const char*) = strdup;
59: void (*io_free)(void*) = free;
1.2 misho 60:
61:
1.1 misho 62: #pragma GCC visibility push(hidden)
63:
1.10.6.4 misho 64: int use_mm;
1.10.6.2 misho 65:
1.1 misho 66: int io_Errno;
67: char io_Error[STRSIZ];
68:
69: #pragma GCC visibility pop
70:
71:
72: // io_GetErrno() Get error code of last operation
1.6 misho 73: inline int
74: io_GetErrno()
1.1 misho 75: {
76: return io_Errno;
77: }
78:
79: // io_GetError() Get error text of last operation
1.6 misho 80: inline const char *
81: io_GetError()
1.1 misho 82: {
83: return io_Error;
84: }
85:
86: // io_SetErr() Set error to variables for internal use!!!
1.6 misho 87: inline void
88: io_SetErr(int eno, char *estr, ...)
1.1 misho 89: {
90: va_list lst;
91:
92: io_Errno = eno;
93: memset(io_Error, 0, STRSIZ);
94: va_start(lst, estr);
95: vsnprintf(io_Error, STRSIZ, estr, lst);
96: va_end(lst);
97: }
98:
1.10.6.4 misho 99: // io_mm_inuse() Check for memory management model
1.10.6.2 misho 100: inline int
1.10.6.4 misho 101: io_mm_inuse()
1.10.6.2 misho 102: {
1.10.6.4 misho 103: return use_mm & IO_MPOOL;
1.10.6.2 misho 104: }
105:
1.1 misho 106:
1.10.6.3 misho 107: // init libaitio routine
108: void
109: _init()
110: {
111: #ifdef USE_MPOOL
1.10.6.4 misho 112: ioLibInit(IO_MPOOL, 0);
1.10.6.3 misho 113: #else
1.10.6.4 misho 114: ioLibInit(IO_SYSM, 0);
1.10.6.3 misho 115: #endif
116: }
117:
118: // fini libaitio routine
119: void
120: _fini()
121: {
1.10.6.4 misho 122: ioLibFini();
123: }
124:
125: /*
126: * ioLibInit() - Init libaitio library memory management
127: *
128: * @mm = memory management (IO_SYSM or IO_MPOOL)
129: * @maxmem = memory limit
130: * return: -1 error or !=-1 used memory management model
131: */
132: inline int
133: ioLibInit(int mm, u_long maxmem)
134: {
135: switch (mm) {
136: case IO_MPOOL: /* mpool */
137: io_mpool = mpool_init(maxmem);
138: if (io_mpool) {
139: io_malloc = mpool_xmalloc;
140: io_calloc = mpool_xcalloc;
141: io_realloc = mpool_xrealloc;
142: io_strdup = mpool_xstrdup;
143: io_free = mpool_xfree;
144: use_mm = mm;
145: break;
146: } else {
147: #undef USE_MPOOL
148: }
149: case IO_SYSM: /* system */
150: io_malloc = malloc;
151: io_calloc = calloc;
152: io_realloc = realloc;
153: io_strdup = strdup;
154: io_free = free;
155: use_mm = mm;
156: break;
157: default: /* not supported */
158: io_SetErr(EINVAL, "Not supported memory management");
159: return -1;
160: }
161:
162: return use_mm;
163: }
164:
165: /*
166: * ioLibFini() - Finish libaitio library memory management
167: *
168: * return: none
169: */
170: inline void
171: ioLibFini()
172: {
173: switch (use_mm) {
1.10.6.5! misho 174: case IO_MPOOL:
1.10.6.4 misho 175: mpool_destroy(&io_mpool);
176:
177: io_malloc = malloc;
178: io_calloc = calloc;
179: io_realloc = realloc;
180: io_strdup = strdup;
181: io_free = free;
182: use_mm = IO_SYSM;
183: break;
184: }
1.10.6.3 misho 185: }
186:
187:
1.1 misho 188: /*
1.10 misho 189: * ioPromptRead() - Read data from input h[0] with prompt to output h[1]
1.9 misho 190: *
1.1 misho 191: * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
192: * @csPrompt = Prompt before input, may be NULL
193: * @psData = Readed data
194: * @dataLen = Length of data
195: * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
196: */
1.6 misho 197: int
198: ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen)
1.1 misho 199: {
200: int ok = 0;
201: FILE *inp, *out;
202: char szLine[BUFSIZ], *pos;
203:
204: if (!psData || !dataLen)
205: return -1;
206:
207: inp = fdopen(!h ? 0 : h[0], "r");
208: if (!inp) {
209: LOGERR;
210: return -1;
211: }
212: out = fdopen(!h ? 1 : h[1], "w");
213: if (!out) {
214: LOGERR;
215: return -1;
216: }
217:
218: while (!ok) {
219: if (csPrompt) {
220: fprintf(out, "%s", csPrompt);
221: fflush(out);
222: }
223:
224: memset(szLine, 0, BUFSIZ);
225: if (!fgets(szLine, BUFSIZ, inp)) {
226: clearerr(inp);
227: fpurge(out);
228: fflush(out);
229: return 0;
230: }
231:
232: if ((pos = strchr(szLine, '\n')))
233: *pos = 0;
234:
235: strlcpy(psData, szLine, dataLen);
236: ok = 1;
237: }
238:
239: return pos - szLine;
240: }
241:
242: /*
1.10 misho 243: * ioPromptPassword() - Read password from input h[0] with prompt to output h[1]
1.9 misho 244: *
1.1 misho 245: * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
246: * @csPrompt = Prompt before input, may be NULL
247: * @psPass = Readed password
248: * @passLen = Length of password
249: * @confirm = Confirm password, 0 - get password, !=0 Ask for confirmation
250: * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
251: */
1.6 misho 252: int
253: ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm)
1.1 misho 254: {
255: int ret, ok = 0;
256: FILE *inp, *out;
257: char szLine[2][STRSIZ];
258: struct sgttyb tty_state;
259:
260: if (!psPass || !passLen)
261: return -1;
262:
263: inp = fdopen(!h ? 0 : h[0], "r");
264: if (!inp) {
265: LOGERR;
266: return -1;
267: }
268: out = fdopen(!h ? 1 : h[1], "w");
269: if (!out) {
270: LOGERR;
271: return -1;
272: }
273:
274: if (ioctl(fileno(inp), TIOCGETP, &tty_state) == -1) {
275: LOGERR;
276: return -1;
277: } else {
278: tty_state.sg_flags &= ~ECHO;
279: if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {
280: LOGERR;
281: return -1;
282: }
283: }
284:
285: while (!ok) {
286: switch ((ret = ioPromptRead(h, (!csPrompt || !*csPrompt) ? "Password:" : csPrompt,
287: szLine[0], STRSIZ))) {
288: case -1:
289: LOGERR;
290: ok = -1;
291: case 0:
292: goto next;
293: }
294: if (confirm) {
295: fprintf(out, "\n");
296: fflush(out);
297:
298: switch (ioPromptRead(h, "Password confirm:", szLine[1], STRSIZ)) {
299: case -1:
300: LOGERR;
301: ok = -1;
302: goto next;
303: case 0:
304: default:
305: if (strcmp(szLine[0], szLine[1])) {
306: fprintf(out, "\n\07\07Mismatch - Try again!\n");
307: fflush(out);
308: continue;
309: }
310: }
311: }
312:
313: strlcpy(psPass, szLine[0], passLen);
314: ok = ret;
315: fprintf(out, "\n");
316: fflush(out);
317: }
318:
319: next:
320: tty_state.sg_flags |= ECHO;
321: if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {
322: LOGERR;
323: return -1;
324: }
325:
326: return ok;
327: }
328:
329: /*
1.10 misho 330: * ioRegexVerify() - Function for verify data match in regex expression
1.9 misho 331: *
1.1 misho 332: * @csRegex = Regulare expression pattern
333: * @csData = Data for check and verify
334: * @startPos = Return start positions
335: * @endPos = Return end positions
336: * return: NULL not match or error; !=NULL begin of matched data
337: */
1.6 misho 338: const char *
339: ioRegexVerify(const char *csRegex, const char *csData, int *startPos, int *endPos)
1.1 misho 340: {
341: regex_t re;
342: regmatch_t match;
343: char szErr[STRSIZ];
344: int ret, flg;
345: const char *pos;
346:
347: if (!csRegex || !csData)
348: return NULL;
349:
350: if ((ret = regcomp(&re, csRegex, REG_EXTENDED))) {
351: regerror(ret, &re, szErr, STRSIZ);
1.10 misho 352: io_SetErr(ret, "%s", szErr);
1.1 misho 353: regfree(&re);
354: return NULL;
355: }
356:
357: for (ret = flg = 0, pos = csData; !(ret = regexec(&re, pos, 1, &match, flg));
358: pos += match.rm_eo, flg = REG_NOTBOL) {
359: if (startPos)
360: *startPos = match.rm_so;
361: if (endPos)
362: *endPos = match.rm_eo;
363:
364: pos += match.rm_so;
365: break;
366: }
367:
368: if (ret) {
369: regerror(ret, &re, szErr, STRSIZ);
1.10 misho 370: io_SetErr(ret, "%s", szErr);
1.1 misho 371: pos = NULL;
372: }
373:
374: regfree(&re);
375: return pos;
376: }
377:
378: /*
1.10 misho 379: * ioRegexGet() - Function for get data match in regex expression
1.9 misho 380: *
1.1 misho 381: * @csRegex = Regulare expression pattern
382: * @csData = Data from get
383: * @psString = Returned string if match
384: * @strLen = Length of string
385: * return: 0 not match; >0 count of returned chars
386: */
1.6 misho 387: int
388: ioRegexGet(const char *csRegex, const char *csData, char * __restrict psString, int strLen)
1.1 misho 389: {
390: int sp, ep, len;
391: const char *str;
392:
393: if (!csRegex || !csData)
394: return -1;
395:
396: str = ioRegexVerify(csRegex, csData, &sp, &ep);
397: if (!str)
398: return 0;
399:
400: len = ep - sp;
401: if (psString && strLen) {
402: memset(psString, 0, strLen);
403: strncpy(psString, str, strLen <= len ? strLen - 1 : len);
404: }
405:
406: return len;
407: }
408:
409: /*
1.10 misho 410: * ioRegexReplace() - Function for replace data match in regex expression with newdata
1.9 misho 411: *
1.1 misho 412: * @csRegex = Regulare expression pattern
413: * @csData = Source data
414: * @csNew = Data for replace
1.10.6.5! misho 415: * return: NULL not match or error; !=NULL allocated new string, must be io_free after use!
1.1 misho 416: */
1.6 misho 417: char *
418: ioRegexReplace(const char *csRegex, const char *csData, const char *csNew)
1.1 misho 419: {
420: int sp, ep, len;
421: char *str = NULL;
422:
423: if (!csRegex || !csData)
424: return NULL;
425:
426: if (!ioRegexVerify(csRegex, csData, &sp, &ep))
427: return NULL;
428:
429: // ___ before match
430: len = sp + 1;
1.10.6.5! misho 431: str = io_malloc(len);
1.1 misho 432: if (!str) {
433: LOGERR;
434: return NULL;
435: } else
436: strlcpy(str, csData, len);
437: // * replace match *
438: if (csNew) {
439: len += strlen(csNew);
1.10.6.5! misho 440: str = io_realloc(str, len);
1.1 misho 441: if (!str) {
442: LOGERR;
443: return NULL;
444: } else
445: strlcat(str, csNew, len);
446: }
447: // after match ___
448: len += strlen(csData) - ep;
1.10.6.5! misho 449: str = io_realloc(str, len);
1.1 misho 450: if (!str) {
451: LOGERR;
452: return NULL;
453: } else
454: strlcat(str, csData + ep, len);
455:
456: return str;
457: }
1.2 misho 458:
1.3 misho 459: /*
1.10 misho 460: * ioStrAst() - Function for evaluate string like asterisk variable "{text[:[-]#[:#]]}"
1.9 misho 461: *
1.3 misho 462: * @csString = Input string
1.10.6.5! misho 463: * return: NULL error, !=NULL Allocated new string evaluated from input string, must be io_free()
1.3 misho 464: */
465: char *
1.8 misho 466: ioStrAst(const char *csString)
1.3 misho 467: {
468: char *ext, *str, *out = NULL;
469: int e[2] = { 0 };
470:
471: if (!csString)
472: return NULL;
473:
474: if (!strchr(csString, '{') || !strrchr(csString, '}')) {
475: memset(io_Error, 0, STRSIZ);
1.10 misho 476: snprintf(io_Error, STRSIZ, "Invalid input string format ... "
1.3 misho 477: "must be like {text[:[-]#[:#]]}");
478: io_Errno = EINVAL;
479: return NULL;
480: } else {
481: str = strdup(strchr(csString, '{') + 1);
482: *strrchr(str, '}') = 0;
483: }
484:
485: if ((ext = strchr(str, ':'))) {
486: *ext++ = 0;
487: e[0] = strtol(ext, NULL, 0);
488: if ((ext = strchr(ext, ':')))
489: e[1] = strtol(++ext, NULL, 0);
490:
491: /* make cut prefix */
492: if (e[0] >= 0)
493: ext = str + e[0];
494: else
495: ext = str + strlen(str) + e[0];
496: /* make cut suffix */
497: if (e[1] > 0)
498: *(ext + e[1]) = 0;
499: } else
500: /* ok, clear show */
501: ext = str;
502:
503: out = strdup(ext);
1.10.6.5! misho 504: io_free(str);
1.3 misho 505:
506: return out;
507: }
508:
1.2 misho 509:
510: /*
1.10 misho 511: * ioMkDir() - Function for racursive directory creation and validation
1.9 misho 512: *
1.2 misho 513: * @csDir = Full directory path
514: * @mode = Mode for directory creation if missing dir
515: * return: -1 error, 0 directory path exist, >0 created missing dirs
516: */
517: int
518: ioMkDir(const char *csDir, int mode)
519: {
520: char *str, *s, *pbrk, szOld[MAXPATHLEN] = { 0 };
521: register int cx = -1;
522:
523: if (!csDir)
524: return cx;
525:
526: str = strdup(csDir);
527: if (!str) {
528: LOGERR;
529: return cx;
530: }
531:
532: getcwd(szOld, MAXPATHLEN);
533: if (*str == '/')
534: chdir("/");
535:
536: for (cx = 0, s = strtok_r(str, "/", &pbrk); s; s = strtok_r(NULL, "/", &pbrk)) {
537: if (mkdir(s, mode) == -1) {
538: if (errno != EEXIST) {
539: LOGERR;
540: cx = -1;
541: goto end;
542: }
543: } else
544: cx++;
545:
546: if (chdir(s) == -1) {
547: LOGERR;
548: cx = -1;
549: goto end;
550: }
551: }
552: end:
553: chdir(szOld);
1.10.6.5! misho 554: io_free(str);
1.2 misho 555: return cx;
556: }
557:
1.3 misho 558: /*
1.10 misho 559: * ioWatchDirLoop() - Function for watching changes in directory and fire callback
1.9 misho 560: *
1.3 misho 561: * @csDir = Full directory path
562: * @callback = Callback if raise event! nOp -1 delete, 0 change/move, 1 create
563: * return: -1 error, !=-1 ok, number of total signaled events
564: */
565: int
566: ioWatchDirLoop(const char *csDir, int (*callback)(const char *csName, int nOp))
567: {
568: glob_t g[2] = {{ 0 }, { 0 }};
569: int d, kq, n = 0;
570: register int j, i;
571: struct kevent req, chg;
572: char wrk[MAXPATHLEN * 2], str[MAXPATHLEN] = { 0 };
573:
574: if (!csDir || !callback)
575: return 0;
576:
577: strlcpy(str, csDir, MAXPATHLEN);
578: strlcat(str, "/*", MAXPATHLEN);
579:
580: kq = kqueue();
581: if (kq == -1) {
582: LOGERR;
583: return -1;
584: }
585: d = open(csDir, O_RDONLY);
586: if (d == -1) {
587: LOGERR;
588: close(kq);
589: return -1;
590: }
591:
1.4 misho 592: EV_SET(&req, d, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
1.3 misho 593:
594: if ((n = glob(str, GLOB_NOCHECK, NULL, &g[0]))) {
595: LOGERR;
596: close(d);
597: close(kq);
598: return -1;
599: } /*else
600: ioDEBUG(3, "Start files %d in %s\n", g[0].gl_matchc, str);*/
601:
602: while (kevent(kq, &req, 1, &chg, 1, NULL) > 0) {
603: /*ioDEBUG(1, "Event:: req=0x%x -> chg=0x%x data=%x\n", req.fflags, chg.fflags, chg.data);*/
604:
605: if (!glob(str, GLOB_NOCHECK, NULL, &g[1])) {
606: /*ioDEBUG(3, "Diffs %d <> %d\n", g[0].gl_matchc, g[1].gl_matchc);*/
607:
608: if (g[0].gl_matchc != g[1].gl_matchc) {
609: /* find new items */
610: for (j = 0; j < g[1].gl_matchc; j++) {
611: for (i = 0; i < g[0].gl_matchc; i++)
612: if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
613: break;
614: if (i == g[0].gl_matchc) {
615: if (callback(g[1].gl_pathv[j], 1) < 0)
616: break;
617: else
618: n++;
619: }
620: }
621: /* find del items */
622: for (j = 0; j < g[0].gl_matchc; j++) {
623: for (i = 0; i < g[1].gl_matchc; i++)
624: if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
625: break;
626: if (i == g[1].gl_matchc) {
627: if (callback(g[0].gl_pathv[j], -1) < 0)
628: break;
629: else
630: n++;
631: }
632: }
633: } else {
634: /* find chg from items */
635: for (j = 0; j < g[0].gl_matchc; j++) {
636: for (i = 0; i < g[1].gl_matchc; i++)
637: if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
638: break;
639: if (i == g[1].gl_matchc) {
640: strlcpy(wrk, g[0].gl_pathv[j], sizeof wrk);
641: strlcat(wrk, ":", sizeof wrk);
642: }
643: }
644: /* find chg to items */
645: for (j = 0; j < g[1].gl_matchc; j++) {
646: for (i = 0; i < g[0].gl_matchc; i++)
647: if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
648: break;
649: if (i == g[0].gl_matchc) {
650: strlcat(wrk, g[1].gl_pathv[j], sizeof wrk);
651: if (callback(wrk, 0) < 0)
652: break;
653: else
654: n++;
655: }
656: }
657: }
658:
659: globfree(&g[0]);
660: g[0] = g[1];
661: }
662: }
663:
664: globfree(&g[0]);
665: close(d);
666: close(kq);
667: return n;
668: }
1.7 misho 669:
670: /*
1.10 misho 671: * ioCreatePIDFile() - Create PID file
1.9 misho 672: *
1.7 misho 673: * @csName = PID filename
674: * @ifExists = !=0 if filename exists return error
675: * return: -1 error or 0 ok
676: */
677: inline int
678: ioCreatePIDFile(const char *csName, int ifExists)
679: {
680: int fd;
681: char str[STRSIZ] = { 0 };
682:
683: if (!csName)
684: return -1;
685:
686: fd = open(csName, O_WRONLY | O_CREAT | (ifExists ? O_EXCL : 0), 0644);
687: if (fd == -1) {
688: LOGERR;
689: return -1;
690: }
691: snprintf(str, sizeof str, "%d", getpid());
692: write(fd, str, strlen(str));
693: close(fd);
694: return 0;
695: }
1.8 misho 696:
697:
698: /*
1.10 misho 699: * ioSendFile() - AITNET sendfile() userland implementation, not dependant from OS
1.9 misho 700: *
1.8 misho 701: * @s = socket
702: * @csFile = file for send
703: * @sendLen = bytes to send, if 0 send all data
704: * @offset = start file offset
705: * @sndbuf = SO_SNDBUF value, if 0 use default
706: * return: 0 error, >0 ok, sended bytes
707: */
708: size_t
709: ioSendFile(int s, const char *csFile, size_t sendLen, off_t offset, int sndbuf)
710: {
711: void *addr;
712: int fd;
713: size_t len = 0;
714: register size_t off = 0;
715:
716: if (!csFile)
717: return 0;
718:
719: if (sndbuf)
720: if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof sndbuf) == -1) {
721: LOGERR;
722: return 0;
723: }
724:
725: fd = open(csFile, O_RDONLY);
726: if (fd == -1) {
727: LOGERR;
728: return 0;
729: }
730: if (!sendLen) {
731: sendLen = lseek(fd, 0, SEEK_END);
732: if (sendLen == -1) {
733: LOGERR;
734: close(fd);
735: return 0;
736: }
737: }
738: addr = mmap(NULL, sendLen, PROT_READ, MAP_SHARED, fd, offset);
739: if (addr == MAP_FAILED) {
740: LOGERR;
741: close(fd);
742: return 0;
743: } else
744: close(fd);
745:
746: while (off < sendLen && (len = write(s, addr + off, sendLen - off)) != -1)
747: off += len;
748: if (len == -1) {
749: LOGERR;
750: munmap(addr, sendLen);
751: return 0;
752: } else
753: len = off;
754:
755: if (len != sendLen) {
756: io_SetErr(ECANCELED, "Different sizes - request %u bytes, actually sended %u bytes\n",
757: sendLen, len);
758: len ^= len;
759: }
760:
761: munmap(addr, sendLen);
762: return len;
763: }
764:
765: /*
1.10 misho 766: * ioRecvFile() - Receive file from socket, fastest (zero-copy) way
1.9 misho 767: *
1.8 misho 768: * @s = socket
769: * @csFile = file for receive
770: * @recvLen = receive bytes
771: * @over = overwrite file if exists with mode like 0644
772: * @rcvbuf = SO_RCVBUF value, if 0 use default
773: * return: 0 error, >0 ok, received bytes
774: */
775: size_t
776: ioRecvFile(int s, const char *csFile, size_t recvLen, int over, int rcvbuf)
777: {
778: void *addr;
779: int fd;
780: size_t len = 0;
781: register size_t off = 0;
782: struct pollfd pfd = { s, POLLIN | POLLPRI, 0 };
783:
784: if (!csFile || !recvLen)
785: return 0;
786: if (!over && !access(csFile, F_OK))
787: return 0;
788:
789: if (rcvbuf)
790: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof rcvbuf) == -1) {
791: LOGERR;
792: return 0;
793: }
794:
795: fd = open(csFile, O_WRONLY | O_CREAT | O_TRUNC, over);
796: if (fd == -1) {
797: LOGERR;
798: unlink(csFile);
799: return 0;
800: }
1.10 misho 801: if (ftruncate(fd, recvLen) == -1) {
1.8 misho 802: LOGERR;
803: close(fd);
804: unlink(csFile);
805: return 0;
806: }
807: addr = mmap(NULL, recvLen, PROT_WRITE, MAP_SHARED, fd, 0);
808: if (addr == MAP_FAILED) {
809: LOGERR;
810: close(fd);
811: unlink(csFile);
812: return 0;
813: } else
814: close(fd);
815:
816: while (off < recvLen && poll(&pfd, 1, RECV_TIMEOUT) != -1)
817: while (off < recvLen && (len = read(s, addr + off, recvLen - off)) != -1)
818: off += len;
819: if (len == -1) {
820: LOGERR;
821: munmap(addr, recvLen);
822: unlink(csFile);
823: return 0;
824: } else
825: len = off;
826:
827: if (len != recvLen)
828: io_SetErr(EAGAIN, "Different sizes - request %u bytes, actually received %u bytes\n",
829: recvLen, len);
830:
831: munmap(addr, recvLen);
832: return len;
833: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>