Annotation of libaitio/src/aitio.c, revision 1.8

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>