Annotation of embedaddon/php/ext/zip/lib/zip_dirent.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   zip_dirent.c -- read directory entry (local or central), clean dirent
        !             3:   Copyright (C) 1999-2009 Dieter Baron and Thomas Klausner
        !             4: 
        !             5:   This file is part of libzip, a library to manipulate ZIP archives.
        !             6:   The authors can be contacted at <libzip@nih.at>
        !             7: 
        !             8:   Redistribution and use in source and binary forms, with or without
        !             9:   modification, are permitted provided that the following conditions
        !            10:   are met:
        !            11:   1. Redistributions of source code must retain the above copyright
        !            12:      notice, this list of conditions and the following disclaimer.
        !            13:   2. Redistributions in binary form must reproduce the above copyright
        !            14:      notice, this list of conditions and the following disclaimer in
        !            15:      the documentation and/or other materials provided with the
        !            16:      distribution.
        !            17:   3. The names of the authors may not be used to endorse or promote
        !            18:      products derived from this software without specific prior
        !            19:      written permission.
        !            20:  
        !            21:   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
        !            22:   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            23:   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
        !            25:   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
        !            27:   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            28:   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
        !            29:   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
        !            30:   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
        !            31:   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            32: */
        !            33: 
        !            34: 
        !            35: 
        !            36: #include <stdio.h>
        !            37: #include <stdlib.h>
        !            38: #include <string.h>
        !            39: #include <errno.h>
        !            40: #include <sys/types.h>
        !            41: #include <sys/stat.h>
        !            42: 
        !            43: #include "zipint.h"
        !            44: 
        !            45: static time_t _zip_d2u_time(int, int);
        !            46: static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *);
        !            47: static char *_zip_readstr(unsigned char **, int, int, struct zip_error *);
        !            48: static void _zip_u2d_time(time_t, unsigned short *, unsigned short *);
        !            49: static void _zip_write2(unsigned short, FILE *);
        !            50: static void _zip_write4(unsigned int, FILE *);
        !            51: 
        !            52: 
        !            53: 
        !            54: void
        !            55: _zip_cdir_free(struct zip_cdir *cd)
        !            56: {
        !            57:     int i;
        !            58: 
        !            59:     if (!cd)
        !            60:        return;
        !            61: 
        !            62:     for (i=0; i<cd->nentry; i++)
        !            63:        _zip_dirent_finalize(cd->entry+i);
        !            64:     free(cd->comment);
        !            65:     free(cd->entry);
        !            66:     free(cd);
        !            67: }
        !            68: 
        !            69: 
        !            70: 
        !            71: int
        !            72: _zip_cdir_grow(struct zip_cdir *cd, int nentry, struct zip_error *error)
        !            73: {
        !            74:     struct zip_dirent *entry;
        !            75: 
        !            76:     if (nentry < cd->nentry) {
        !            77:        _zip_error_set(error, ZIP_ER_INTERNAL, 0);
        !            78:        return -1;
        !            79:     }
        !            80: 
        !            81:     if ((entry=((struct zip_dirent *)
        !            82:                realloc(cd->entry, sizeof(*(cd->entry))*nentry))) == NULL) {
        !            83:        _zip_error_set(error, ZIP_ER_MEMORY, 0);
        !            84:        return -1;
        !            85:     }
        !            86: 
        !            87:     cd->nentry = nentry;
        !            88:     cd->entry = entry;
        !            89: 
        !            90:     return 0;
        !            91: }
        !            92: 
        !            93: 
        !            94: 
        !            95: struct zip_cdir *
        !            96: _zip_cdir_new(int nentry, struct zip_error *error)
        !            97: {
        !            98:     struct zip_cdir *cd;
        !            99:     
        !           100:     if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) {
        !           101:        _zip_error_set(error, ZIP_ER_MEMORY, 0);
        !           102:        return NULL;
        !           103:     }
        !           104: 
        !           105:     if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry))
        !           106:        == NULL) {
        !           107:        _zip_error_set(error, ZIP_ER_MEMORY, 0);
        !           108:        free(cd);
        !           109:        return NULL;
        !           110:     }
        !           111: 
        !           112:     /* entries must be initialized by caller */
        !           113: 
        !           114:     cd->nentry = nentry;
        !           115:     cd->size = cd->offset = 0;
        !           116:     cd->comment = NULL;
        !           117:     cd->comment_len = 0;
        !           118: 
        !           119:     return cd;
        !           120: }
        !           121: 
        !           122: 
        !           123: 
        !           124: int
        !           125: _zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error)
        !           126: {
        !           127:     int i;
        !           128: 
        !           129:     cd->offset = ftello(fp);
        !           130: 
        !           131:     for (i=0; i<cd->nentry; i++) {
        !           132:        if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0)
        !           133:            return -1;
        !           134:     }
        !           135: 
        !           136:     cd->size = ftello(fp) - cd->offset;
        !           137:     
        !           138:     /* clearerr(fp); */
        !           139:     fwrite(EOCD_MAGIC, 1, 4, fp);
        !           140:     _zip_write4(0, fp);
        !           141:     _zip_write2((unsigned short)cd->nentry, fp);
        !           142:     _zip_write2((unsigned short)cd->nentry, fp);
        !           143:     _zip_write4(cd->size, fp);
        !           144:     _zip_write4(cd->offset, fp);
        !           145:     _zip_write2(cd->comment_len, fp);
        !           146:     fwrite(cd->comment, 1, cd->comment_len, fp);
        !           147: 
        !           148:     if (ferror(fp)) {
        !           149:        _zip_error_set(error, ZIP_ER_WRITE, errno);
        !           150:        return -1;
        !           151:     }
        !           152: 
        !           153:     return 0;
        !           154: }
        !           155: 
        !           156: 
        !           157: 
        !           158: void
        !           159: _zip_dirent_finalize(struct zip_dirent *zde)
        !           160: {
        !           161:     free(zde->filename);
        !           162:     zde->filename = NULL;
        !           163:     free(zde->extrafield);
        !           164:     zde->extrafield = NULL;
        !           165:     free(zde->comment);
        !           166:     zde->comment = NULL;
        !           167: }
        !           168: 
        !           169: 
        !           170: 
        !           171: void
        !           172: _zip_dirent_init(struct zip_dirent *de)
        !           173: {
        !           174:     de->version_madeby = 0;
        !           175:     de->version_needed = 20; /* 2.0 */
        !           176:     de->bitflags = 0;
        !           177:     de->comp_method = 0;
        !           178:     de->last_mod = 0;
        !           179:     de->crc = 0;
        !           180:     de->comp_size = 0;
        !           181:     de->uncomp_size = 0;
        !           182:     de->filename = NULL;
        !           183:     de->filename_len = 0;
        !           184:     de->extrafield = NULL;
        !           185:     de->extrafield_len = 0;
        !           186:     de->comment = NULL;
        !           187:     de->comment_len = 0;
        !           188:     de->disk_number = 0;
        !           189:     de->int_attrib = 0;
        !           190:     de->ext_attrib = 0;
        !           191:     de->offset = 0;
        !           192: }
        !           193: 
        !           194: 
        !           195: 
        !           196: /* _zip_dirent_read(zde, fp, bufp, left, localp, error):
        !           197:    Fills the zip directory entry zde.
        !           198: 
        !           199:    If bufp is non-NULL, data is taken from there and bufp is advanced
        !           200:    by the amount of data used; otherwise data is read from fp as needed.
        !           201:    
        !           202:    if leftp is non-NULL, no more bytes than specified by it are used,
        !           203:    and *leftp is reduced by the number of bytes used.
        !           204: 
        !           205:    If local != 0, it reads a local header instead of a central
        !           206:    directory entry.
        !           207: 
        !           208:    Returns 0 if successful. On error, error is filled in and -1 is
        !           209:    returned.
        !           210: 
        !           211:    XXX: leftp and file position undefined on error.
        !           212: */
        !           213: 
        !           214: int
        !           215: _zip_dirent_read(struct zip_dirent *zde, FILE *fp,
        !           216:                 unsigned char **bufp, unsigned int *leftp, int local,
        !           217:                 struct zip_error *error)
        !           218: {
        !           219:     unsigned char buf[CDENTRYSIZE];
        !           220:     unsigned char *cur;
        !           221:     unsigned short dostime, dosdate;
        !           222:     unsigned int size;
        !           223: 
        !           224:     if (local)
        !           225:        size = LENTRYSIZE;
        !           226:     else
        !           227:        size = CDENTRYSIZE;
        !           228: 
        !           229:     if (leftp && (*leftp < size)) {
        !           230:        _zip_error_set(error, ZIP_ER_NOZIP, 0);
        !           231:        return -1;
        !           232:     }
        !           233: 
        !           234:     if (bufp) {
        !           235:        /* use data from buffer */
        !           236:        cur = *bufp;
        !           237:     }
        !           238:     else {
        !           239:        /* read entry from disk */
        !           240:        if ((fread(buf, 1, size, fp)<size)) {
        !           241:            _zip_error_set(error, ZIP_ER_READ, errno);
        !           242:            return -1;
        !           243:        }
        !           244:        cur = buf;
        !           245:     }
        !           246: 
        !           247:     if (memcmp(cur, (local ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {
        !           248:        _zip_error_set(error, ZIP_ER_NOZIP, 0);
        !           249:        return -1;
        !           250:     }
        !           251:     cur += 4;
        !           252: 
        !           253:     
        !           254:     /* convert buffercontents to zip_dirent */
        !           255:     
        !           256:     if (!local)
        !           257:        zde->version_madeby = _zip_read2(&cur);
        !           258:     else
        !           259:        zde->version_madeby = 0;
        !           260:     zde->version_needed = _zip_read2(&cur);
        !           261:     zde->bitflags = _zip_read2(&cur);
        !           262:     zde->comp_method = _zip_read2(&cur);
        !           263:     
        !           264:     /* convert to time_t */
        !           265:     dostime = _zip_read2(&cur);
        !           266:     dosdate = _zip_read2(&cur);
        !           267:     zde->last_mod = _zip_d2u_time(dostime, dosdate);
        !           268:     
        !           269:     zde->crc = _zip_read4(&cur);
        !           270:     zde->comp_size = _zip_read4(&cur);
        !           271:     zde->uncomp_size = _zip_read4(&cur);
        !           272:     
        !           273:     zde->filename_len = _zip_read2(&cur);
        !           274:     zde->extrafield_len = _zip_read2(&cur);
        !           275:     
        !           276:     if (local) {
        !           277:        zde->comment_len = 0;
        !           278:        zde->disk_number = 0;
        !           279:        zde->int_attrib = 0;
        !           280:        zde->ext_attrib = 0;
        !           281:        zde->offset = 0;
        !           282:     } else {
        !           283:        zde->comment_len = _zip_read2(&cur);
        !           284:        zde->disk_number = _zip_read2(&cur);
        !           285:        zde->int_attrib = _zip_read2(&cur);
        !           286:        zde->ext_attrib = _zip_read4(&cur);
        !           287:        zde->offset = _zip_read4(&cur);
        !           288:     }
        !           289: 
        !           290:     zde->filename = NULL;
        !           291:     zde->extrafield = NULL;
        !           292:     zde->comment = NULL;
        !           293: 
        !           294:     size += zde->filename_len+zde->extrafield_len+zde->comment_len;
        !           295: 
        !           296:     if (leftp && (*leftp < size)) {
        !           297:        _zip_error_set(error, ZIP_ER_NOZIP, 0);
        !           298:        return -1;
        !           299:     }
        !           300: 
        !           301:     if (bufp) {
        !           302:        if (zde->filename_len) {
        !           303:            zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error);
        !           304:            if (!zde->filename)
        !           305:                    return -1;
        !           306:        }
        !           307: 
        !           308:        if (zde->extrafield_len) {
        !           309:            zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0,
        !           310:                                           error);
        !           311:            if (!zde->extrafield)
        !           312:                return -1;
        !           313:        }
        !           314: 
        !           315:        if (zde->comment_len) {
        !           316:            zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error);
        !           317:            if (!zde->comment)
        !           318:                return -1;
        !           319:        }
        !           320:     }
        !           321:     else {
        !           322:        if (zde->filename_len) {
        !           323:            zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error);
        !           324:            if (!zde->filename)
        !           325:                    return -1;
        !           326:        }
        !           327: 
        !           328:        if (zde->extrafield_len) {
        !           329:            zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0,
        !           330:                                             error);
        !           331:            if (!zde->extrafield)
        !           332:                return -1;
        !           333:        }
        !           334: 
        !           335:        if (zde->comment_len) {
        !           336:            zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error);
        !           337:            if (!zde->comment)
        !           338:                return -1;
        !           339:        }
        !           340:     }
        !           341: 
        !           342:     if (bufp)
        !           343:       *bufp = cur;
        !           344:     if (leftp)
        !           345:        *leftp -= size;
        !           346: 
        !           347:     return 0;
        !           348: }
        !           349: 
        !           350: 
        !           351: 
        !           352: /* _zip_dirent_torrent_normalize(de);
        !           353:    Set values suitable for torrentzip.
        !           354: */
        !           355: 
        !           356: void
        !           357: _zip_dirent_torrent_normalize(struct zip_dirent *de)
        !           358: {
        !           359:     static struct tm torrenttime;
        !           360:     static time_t last_mod = 0;
        !           361: 
        !           362:     if (last_mod == 0) {
        !           363: #ifdef HAVE_STRUCT_TM_TM_ZONE
        !           364:        time_t now;
        !           365:        struct tm *l;
        !           366: #endif
        !           367: 
        !           368:        torrenttime.tm_sec = 0;
        !           369:        torrenttime.tm_min = 32;
        !           370:        torrenttime.tm_hour = 23;
        !           371:        torrenttime.tm_mday = 24;
        !           372:        torrenttime.tm_mon = 11;
        !           373:        torrenttime.tm_year = 96;
        !           374:        torrenttime.tm_wday = 0;
        !           375:        torrenttime.tm_yday = 0;
        !           376:        torrenttime.tm_isdst = 0;
        !           377: 
        !           378: #ifdef HAVE_STRUCT_TM_TM_ZONE
        !           379:        time(&now);
        !           380:        l = localtime(&now);
        !           381:        torrenttime.tm_gmtoff = l->tm_gmtoff;
        !           382:        torrenttime.tm_zone = l->tm_zone;
        !           383: #endif
        !           384: 
        !           385:        last_mod = mktime(&torrenttime);
        !           386:     }
        !           387:     
        !           388:     de->version_madeby = 0;
        !           389:     de->version_needed = 20; /* 2.0 */
        !           390:     de->bitflags = 2; /* maximum compression */
        !           391:     de->comp_method = ZIP_CM_DEFLATE;
        !           392:     de->last_mod = last_mod;
        !           393: 
        !           394:     de->disk_number = 0;
        !           395:     de->int_attrib = 0;
        !           396:     de->ext_attrib = 0;
        !           397:     de->offset = 0;
        !           398: 
        !           399:     free(de->extrafield);
        !           400:     de->extrafield = NULL;
        !           401:     de->extrafield_len = 0;
        !           402:     free(de->comment);
        !           403:     de->comment = NULL;
        !           404:     de->comment_len = 0;
        !           405: }
        !           406: 
        !           407: 
        !           408: 
        !           409: /* _zip_dirent_write(zde, fp, localp, error):
        !           410:    Writes zip directory entry zde to file fp.
        !           411: 
        !           412:    If localp != 0, it writes a local header instead of a central
        !           413:    directory entry.
        !           414: 
        !           415:    Returns 0 if successful. On error, error is filled in and -1 is
        !           416:    returned.
        !           417: */
        !           418: 
        !           419: int
        !           420: _zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp,
        !           421:                  struct zip_error *error)
        !           422: {
        !           423:     unsigned short dostime, dosdate;
        !           424: 
        !           425:     fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp);
        !           426: 
        !           427:     if (!localp)
        !           428:        _zip_write2(zde->version_madeby, fp);
        !           429:     _zip_write2(zde->version_needed, fp);
        !           430:     _zip_write2(zde->bitflags, fp);
        !           431:     _zip_write2(zde->comp_method, fp);
        !           432: 
        !           433:     _zip_u2d_time(zde->last_mod, &dostime, &dosdate);
        !           434:     _zip_write2(dostime, fp);
        !           435:     _zip_write2(dosdate, fp);
        !           436:     
        !           437:     _zip_write4(zde->crc, fp);
        !           438:     _zip_write4(zde->comp_size, fp);
        !           439:     _zip_write4(zde->uncomp_size, fp);
        !           440:     
        !           441:     _zip_write2(zde->filename_len, fp);
        !           442:     _zip_write2(zde->extrafield_len, fp);
        !           443:     
        !           444:     if (!localp) {
        !           445:        _zip_write2(zde->comment_len, fp);
        !           446:        _zip_write2(zde->disk_number, fp);
        !           447:        _zip_write2(zde->int_attrib, fp);
        !           448:        _zip_write4(zde->ext_attrib, fp);
        !           449:        _zip_write4(zde->offset, fp);
        !           450:     }
        !           451: 
        !           452:     if (zde->filename_len)
        !           453:        fwrite(zde->filename, 1, zde->filename_len, fp);
        !           454: 
        !           455:     if (zde->extrafield_len)
        !           456:        fwrite(zde->extrafield, 1, zde->extrafield_len, fp);
        !           457: 
        !           458:     if (!localp) {
        !           459:        if (zde->comment_len)
        !           460:            fwrite(zde->comment, 1, zde->comment_len, fp);
        !           461:     }
        !           462: 
        !           463:     if (ferror(fp)) {
        !           464:        _zip_error_set(error, ZIP_ER_WRITE, errno);
        !           465:        return -1;
        !           466:     }
        !           467: 
        !           468:     return 0;
        !           469: }
        !           470: 
        !           471: 
        !           472: 
        !           473: static time_t
        !           474: _zip_d2u_time(int dtime, int ddate)
        !           475: {
        !           476:     struct tm tm = {0};
        !           477: 
        !           478:     /* let mktime decide if DST is in effect */
        !           479:     tm.tm_isdst = -1;
        !           480:     
        !           481:     tm.tm_year = ((ddate>>9)&127) + 1980 - 1900;
        !           482:     tm.tm_mon = ((ddate>>5)&15) - 1;
        !           483:     tm.tm_mday = ddate&31;
        !           484: 
        !           485:     tm.tm_hour = (dtime>>11)&31;
        !           486:     tm.tm_min = (dtime>>5)&63;
        !           487:     tm.tm_sec = (dtime<<1)&62;
        !           488: 
        !           489:     return mktime(&tm);
        !           490: }
        !           491: 
        !           492: 
        !           493: 
        !           494: unsigned short
        !           495: _zip_read2(unsigned char **a)
        !           496: {
        !           497:     unsigned short ret;
        !           498: 
        !           499:     ret = (*a)[0]+((*a)[1]<<8);
        !           500:     *a += 2;
        !           501: 
        !           502:     return ret;
        !           503: }
        !           504: 
        !           505: 
        !           506: 
        !           507: unsigned int
        !           508: _zip_read4(unsigned char **a)
        !           509: {
        !           510:     unsigned int ret;
        !           511: 
        !           512:     ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0];
        !           513:     *a += 4;
        !           514: 
        !           515:     return ret;
        !           516: }
        !           517: 
        !           518: 
        !           519: 
        !           520: static char *
        !           521: _zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error)
        !           522: {
        !           523:     char *r, *o;
        !           524: 
        !           525:     r = (char *)malloc(nulp ? len+1 : len);
        !           526:     if (!r) {
        !           527:        _zip_error_set(error, ZIP_ER_MEMORY, 0);
        !           528:        return NULL;
        !           529:     }
        !           530: 
        !           531:     if (fread(r, 1, len, fp)<len) {
        !           532:        free(r);
        !           533:        _zip_error_set(error, ZIP_ER_READ, errno);
        !           534:        return NULL;
        !           535:     }
        !           536: 
        !           537:     if (nulp) {
        !           538:        /* replace any in-string NUL characters with spaces */
        !           539:        r[len] = 0;
        !           540:        for (o=r; o<r+len; o++)
        !           541:            if (*o == '\0')
        !           542:                *o = ' ';
        !           543:     }
        !           544:     
        !           545:     return r;
        !           546: }
        !           547: 
        !           548: 
        !           549: 
        !           550: static char *
        !           551: _zip_readstr(unsigned char **buf, int len, int nulp, struct zip_error *error)
        !           552: {
        !           553:     char *r, *o;
        !           554: 
        !           555:     r = (char *)malloc(nulp ? len+1 : len);
        !           556:     if (!r) {
        !           557:        _zip_error_set(error, ZIP_ER_MEMORY, 0);
        !           558:        return NULL;
        !           559:     }
        !           560:     
        !           561:     memcpy(r, *buf, len);
        !           562:     *buf += len;
        !           563: 
        !           564:     if (nulp) {
        !           565:        /* replace any in-string NUL characters with spaces */
        !           566:        r[len] = 0;
        !           567:        for (o=r; o<r+len; o++)
        !           568:            if (*o == '\0')
        !           569:                *o = ' ';
        !           570:     }
        !           571: 
        !           572:     return r;
        !           573: }
        !           574: 
        !           575: 
        !           576: 
        !           577: static void
        !           578: _zip_write2(unsigned short i, FILE *fp)
        !           579: {
        !           580:     putc(i&0xff, fp);
        !           581:     putc((i>>8)&0xff, fp);
        !           582: 
        !           583:     return;
        !           584: }
        !           585: 
        !           586: 
        !           587: 
        !           588: static void
        !           589: _zip_write4(unsigned int i, FILE *fp)
        !           590: {
        !           591:     putc(i&0xff, fp);
        !           592:     putc((i>>8)&0xff, fp);
        !           593:     putc((i>>16)&0xff, fp);
        !           594:     putc((i>>24)&0xff, fp);
        !           595:     
        !           596:     return;
        !           597: }
        !           598: 
        !           599: 
        !           600: 
        !           601: static void
        !           602: _zip_u2d_time(time_t time, unsigned short *dtime, unsigned short *ddate)
        !           603: {
        !           604:     struct tm *tm;
        !           605: 
        !           606:     tm = localtime(&time);
        !           607:     *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5)
        !           608:        + tm->tm_mday;
        !           609:     *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5)
        !           610:        + ((tm->tm_sec)>>1);
        !           611: 
        !           612:     return;
        !           613: }

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