"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/fio.c" (25 Mar 2018, 13412 Bytes) of package /linux/misc/s-nail-14.9.10.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fio.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 14.9.6_vs_14.9.7.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ File operations.
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  */
    7 /*
    8  * Copyright (c) 1980, 1993
    9  *      The Regents of the University of California.  All rights reserved.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 #undef n_FILE
   36 #define n_FILE fio
   37 
   38 #ifndef HAVE_AMALGAMATION
   39 # include "nail.h"
   40 #endif
   41 
   42 /* line is a buffer with the result of fgets(). Returns the first newline or
   43  * the last character read */
   44 static size_t     _length_of_line(char const *line, size_t linesize);
   45 
   46 /* Read a line, one character at a time */
   47 static char *     _fgetline_byone(char **line, size_t *linesize, size_t *llen,
   48                      FILE *fp, int appendnl, size_t n n_MEMORY_DEBUG_ARGS);
   49 
   50 /* Workhorse */
   51 static bool_t a_file_lock(int fd, enum n_file_lock_type ft, off_t off,
   52                off_t len);
   53 
   54 static size_t
   55 _length_of_line(char const *line, size_t linesize)
   56 {
   57    size_t i;
   58    NYD2_ENTER;
   59 
   60    /* Last character is always '\0' and was added by fgets() */
   61    for (--linesize, i = 0; i < linesize; i++)
   62       if (line[i] == '\n')
   63          break;
   64    i = (i < linesize) ? i + 1 : linesize;
   65    NYD2_LEAVE;
   66    return i;
   67 }
   68 
   69 static char *
   70 _fgetline_byone(char **line, size_t *linesize, size_t *llen, FILE *fp,
   71    int appendnl, size_t n n_MEMORY_DEBUG_ARGS)
   72 {
   73    char *rv;
   74    int c;
   75    NYD2_ENTER;
   76 
   77    assert(*linesize == 0 || *line != NULL);
   78    n_pstate &= ~n_PS_READLINE_NL;
   79 
   80    for (rv = *line;;) {
   81       if (*linesize <= LINESIZE || n >= *linesize - 128) {
   82          *linesize += ((rv == NULL) ? LINESIZE + n + 1 : 256);
   83          *line = rv = (n_realloc)(rv, *linesize n_MEMORY_DEBUG_ARGSCALL);
   84       }
   85       c = getc(fp);
   86       if (c != EOF) {
   87          rv[n++] = c;
   88          rv[n] = '\0';
   89          if (c == '\n') {
   90             n_pstate |= n_PS_READLINE_NL;
   91             break;
   92          }
   93       } else {
   94          if (n > 0) {
   95             if (appendnl) {
   96                rv[n++] = '\n';
   97                rv[n] = '\0';
   98             }
   99             break;
  100          } else {
  101             rv = NULL;
  102             goto jleave;
  103          }
  104       }
  105    }
  106    if (llen)
  107       *llen = n;
  108 jleave:
  109    NYD2_LEAVE;
  110    return rv;
  111 }
  112 
  113 static bool_t
  114 a_file_lock(int fd, enum n_file_lock_type flt, off_t off, off_t len)
  115 {
  116    struct flock flp;
  117    bool_t rv;
  118    NYD2_ENTER;
  119 
  120    memset(&flp, 0, sizeof flp);
  121 
  122    switch (flt) {
  123    default:
  124    case FLT_READ:    rv = F_RDLCK;  break;
  125    case FLT_WRITE:   rv = F_WRLCK;  break;
  126    }
  127    flp.l_type = rv;
  128    flp.l_start = off;
  129    flp.l_whence = SEEK_SET;
  130    flp.l_len = len;
  131 
  132    if (!(rv = (fcntl(fd, F_SETLK, &flp) != -1)))
  133       switch (n_err_no) {
  134       case n_ERR_BADF:
  135       case n_ERR_INVAL:
  136          rv = TRUM1;
  137          break;
  138       }
  139    NYD2_LEAVE;
  140    return rv;
  141 }
  142 
  143 FL char *
  144 (fgetline)(char **line, size_t *linesize, size_t *cnt, size_t *llen, FILE *fp,
  145    int appendnl n_MEMORY_DEBUG_ARGS)
  146 {
  147    size_t i_llen, sz;
  148    char *rv;
  149    NYD2_ENTER;
  150 
  151    if (cnt == NULL) {
  152       /* Without count, we can't determine where the chars returned by fgets()
  153        * end if there's no newline.  We have to read one character by one */
  154       rv = _fgetline_byone(line, linesize, llen, fp, appendnl, 0
  155             n_MEMORY_DEBUG_ARGSCALL);
  156       goto jleave;
  157    }
  158 
  159    n_pstate &= ~n_PS_READLINE_NL;
  160 
  161    if ((rv = *line) == NULL || *linesize < LINESIZE)
  162       *line = rv = (n_realloc)(rv, *linesize = LINESIZE
  163             n_MEMORY_DEBUG_ARGSCALL);
  164    sz = (*linesize <= *cnt) ? *linesize : *cnt + 1;
  165    if (sz <= 1 || fgets(rv, sz, fp) == NULL) {
  166       /* Leave llen untouched; it is used to determine whether the last line
  167        * was \n-terminated in some callers */
  168       rv = NULL;
  169       goto jleave;
  170    }
  171 
  172    i_llen = _length_of_line(rv, sz);
  173    *cnt -= i_llen;
  174    while (rv[i_llen - 1] != '\n') {
  175       *line = rv = (n_realloc)(rv, *linesize += 256 n_MEMORY_DEBUG_ARGSCALL);
  176       sz = *linesize - i_llen;
  177       sz = (sz <= *cnt) ? sz : *cnt + 1;
  178       if (sz <= 1 || fgets(rv + i_llen, sz, fp) == NULL) {
  179          if (appendnl) {
  180             rv[i_llen++] = '\n';
  181             rv[i_llen] = '\0';
  182          }
  183          break;
  184       }
  185       sz = _length_of_line(rv + i_llen, sz);
  186       i_llen += sz;
  187       *cnt -= sz;
  188    }
  189    if (llen)
  190       *llen = i_llen;
  191 jleave:
  192    NYD2_LEAVE;
  193    return rv;
  194 }
  195 
  196 FL int
  197 (readline_restart)(FILE *ibuf, char **linebuf, size_t *linesize, size_t n
  198    n_MEMORY_DEBUG_ARGS)
  199 {
  200    /* TODO readline_restart(): always *appends* LF just to strip it again;
  201     * TODO should be configurable just as for fgetline(); ..or whatever..
  202     * TODO intwrap */
  203    int rv = -1;
  204    long sz;
  205    NYD2_ENTER;
  206 
  207    clearerr(ibuf);
  208 
  209    /* Interrupts will cause trouble if we are inside a stdio call. As this is
  210     * only relevant if input is from tty, bypass it by read(), then */
  211    if ((n_psonce & n_PSO_TTYIN) && fileno(ibuf) == 0) {
  212       assert(*linesize == 0 || *linebuf != NULL);
  213       n_pstate &= ~n_PS_READLINE_NL;
  214       for (;;) {
  215          if (*linesize <= LINESIZE || n >= *linesize - 128) {
  216             *linesize += ((*linebuf == NULL) ? LINESIZE + n + 1 : 256);
  217             *linebuf = (n_realloc)(*linebuf, *linesize n_MEMORY_DEBUG_ARGSCALL);
  218          }
  219 jagain:
  220          sz = read(0, *linebuf + n, *linesize - n - 1);
  221          if (sz > 0) {
  222             n += sz;
  223             (*linebuf)[n] = '\0';
  224             if ((*linebuf)[n - 1] == '\n') {
  225                n_pstate |= n_PS_READLINE_NL;
  226                break;
  227             }
  228          } else {
  229             if (sz < 0 && n_err_no == n_ERR_INTR)
  230                goto jagain;
  231             /* TODO eh.  what is this?  that now supposed to be a line?!? */
  232             if (n > 0) {
  233                if ((*linebuf)[n - 1] != '\n') {
  234                   (*linebuf)[n++] = '\n';
  235                   (*linebuf)[n] = '\0';
  236                } else
  237                   n_pstate |= n_PS_READLINE_NL;
  238                break;
  239             } else
  240                goto jleave;
  241          }
  242       }
  243    } else {
  244       /* Not reading from standard input or standard input not a terminal. We
  245        * read one char at a time as it is the only way to get lines with
  246        * embedded NUL characters in standard stdio */
  247       if (_fgetline_byone(linebuf, linesize, &n, ibuf, 1, n
  248             n_MEMORY_DEBUG_ARGSCALL) == NULL)
  249          goto jleave;
  250    }
  251    if (n > 0 && (*linebuf)[n - 1] == '\n')
  252       (*linebuf)[--n] = '\0';
  253    rv = (int)n;
  254 jleave:
  255    NYD2_LEAVE;
  256    return rv;
  257 }
  258 
  259 FL void
  260 setptr(FILE *ibuf, off_t offset)
  261 {
  262    struct message self;
  263    char *cp, *linebuf = NULL;
  264    char const *cp2;
  265    int c, selfcnt = 0;
  266    bool_t need_rfc4155, maybe, inhead, from_;
  267    size_t linesize = 0, filesize, cnt;
  268    NYD_ENTER;
  269 
  270    memset(&self, 0, sizeof self);
  271    self.m_flag = MUSED | MNEW | MNEWEST;
  272    filesize = mailsize - offset;
  273    offset = ftell(mb.mb_otf);
  274    need_rfc4155 = ok_blook(mbox_rfc4155);
  275    maybe = TRU1;
  276    inhead = FAL0;
  277 
  278    for (;;) {
  279       if (fgetline(&linebuf, &linesize, &filesize, &cnt, ibuf, 0) == NULL) {
  280          self.m_xsize = self.m_size;
  281          self.m_xlines = self.m_lines;
  282          self.m_content_info = CI_HAVE_HEADER | CI_HAVE_BODY;
  283          if (selfcnt > 0)
  284             message_append(&self);
  285          message_append_null();
  286          if (linebuf != NULL)
  287             free(linebuf);
  288          break;
  289       }
  290 
  291 #ifdef notdef
  292       if (linebuf[0] == '\0')
  293          linebuf[0] = '.';
  294 #endif
  295       /* XXX Convert CRLF to LF; this should be rethought in that
  296        * XXX CRLF input should possibly end as CRLF output? */
  297       if (cnt >= 2 && linebuf[cnt - 1] == '\n' && linebuf[cnt - 2] == '\r')
  298          linebuf[--cnt - 1] = '\n';
  299       fwrite(linebuf, sizeof *linebuf, cnt, mb.mb_otf);
  300       if (ferror(mb.mb_otf)) {
  301          n_perr(_("/tmp"), 0);
  302          exit(n_EXIT_ERR);
  303       }
  304       if (linebuf[cnt - 1] == '\n')
  305          linebuf[cnt - 1] = '\0';
  306       /* TODO In v15 this should use a/the flat MIME parser in order to ignore
  307        * TODO "From " when MIME boundaries are active -- whereas this opens
  308        * TODO another can of worms, it very likely is better than messing up
  309        * TODO MIME because of a "From " line! */
  310       if (maybe && linebuf[0] == 'F' &&
  311             (from_ = is_head(linebuf, cnt, TRU1)) &&
  312             (from_ == TRU1 || !need_rfc4155)) {
  313          /* TODO char date[n_FROM_DATEBUF];
  314           * TODO extract_date_from_from_(linebuf, cnt, date);
  315           * TODO self.m_time = 10000; */
  316          if (from_ == TRUM1) {
  317             if (n_poption & n_PO_D_V)
  318                n_err(_("Invalid MBOX \"From_ line\": %.*s\n"),
  319                   (int)cnt, linebuf);
  320             else if (!(mb.mb_active & MB_FROM__WARNED))
  321                n_err(_("MBOX mailbox contains non-conforming From_ line(s)!\n"
  322                   "  Message boundaries may have been falsely detected!\n"
  323                   "  Setting variable *mbox-rfc4155* and reopen should improve "
  324                      "the result.\n"
  325                   "  If so, make changes permanent: \"copy * SOME-FILE\".  "
  326                      "Then unset *mbox-rfc4155*\n"));
  327             mb.mb_active |= MB_FROM__WARNED;
  328          }
  329          self.m_xsize = self.m_size;
  330          self.m_xlines = self.m_lines;
  331          self.m_content_info = CI_HAVE_HEADER | CI_HAVE_BODY;
  332          if (selfcnt++ > 0)
  333             message_append(&self);
  334          msgCount++;
  335          self.m_flag = MUSED | MNEW | MNEWEST;
  336          self.m_size = 0;
  337          self.m_lines = 0;
  338          self.m_block = mailx_blockof(offset);
  339          self.m_offset = mailx_offsetof(offset);
  340          inhead = TRU1;
  341       } else if (linebuf[0] == 0) {
  342          inhead = FAL0;
  343       } else if (inhead) {
  344          for (cp = linebuf, cp2 = "status";; ++cp) {
  345             if ((c = *cp2++) == 0) {
  346                while (c = *cp++, whitechar(c))
  347                   ;
  348                if (cp[-1] != ':')
  349                   break;
  350                while ((c = *cp++) != '\0')
  351                   if (c == 'R')
  352                      self.m_flag |= MREAD;
  353                   else if (c == 'O')
  354                      self.m_flag &= ~MNEW;
  355                break;
  356             }
  357             if (*cp != c && *cp != upperconv(c))
  358                break;
  359          }
  360          for (cp = linebuf, cp2 = "x-status";; ++cp) {
  361             if ((c = *cp2++) == 0) {
  362                while ((c = *cp++, whitechar(c)))
  363                   ;
  364                if (cp[-1] != ':')
  365                   break;
  366                while ((c = *cp++) != '\0')
  367                   if (c == 'F')
  368                      self.m_flag |= MFLAGGED;
  369                   else if (c == 'A')
  370                      self.m_flag |= MANSWERED;
  371                   else if (c == 'T')
  372                      self.m_flag |= MDRAFTED;
  373                break;
  374             }
  375             if (*cp != c && *cp != upperconv(c))
  376                break;
  377          }
  378       }
  379       offset += cnt;
  380       self.m_size += cnt;
  381       ++self.m_lines;
  382       maybe = (linebuf[0] == 0);
  383    }
  384    NYD_LEAVE;
  385 }
  386 
  387 FL off_t
  388 fsize(FILE *iob)
  389 {
  390    struct stat sbuf;
  391    off_t rv;
  392    NYD_ENTER;
  393 
  394    rv = (fstat(fileno(iob), &sbuf) == -1) ? 0 : sbuf.st_size;
  395    NYD_LEAVE;
  396    return rv;
  397 }
  398 
  399 FL bool_t
  400 n_file_lock(int fd, enum n_file_lock_type flt, off_t off, off_t len,
  401    size_t pollmsecs)
  402 {
  403    size_t tries;
  404    bool_t didmsg, rv;
  405    NYD_ENTER;
  406 
  407    if(pollmsecs == UIZ_MAX)
  408       pollmsecs = FILE_LOCK_MILLIS;
  409 
  410    n_UNINIT(rv, 0);
  411    for (didmsg = FAL0, tries = 0; tries <= FILE_LOCK_TRIES; ++tries) {
  412       rv = a_file_lock(fd, flt, off, len);
  413 
  414       if (rv == TRUM1) {
  415          rv = FAL0;
  416          break;
  417       }
  418       if (rv || pollmsecs == 0)
  419          break;
  420       else {
  421          if(!didmsg){
  422             n_err(_("Failed to create a file lock, waiting %lu milliseconds "),
  423                pollmsecs);
  424             didmsg = TRU1;
  425          }else
  426             n_err(".");
  427          n_msleep(pollmsecs, FAL0);
  428       }
  429    }
  430    if(didmsg)
  431       n_err(" %s\n", (rv ? _("ok") : _("failure")));
  432    NYD_LEAVE;
  433    return rv;
  434 }
  435 
  436 /* s-it-mode */