00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "klone_conf.h"
00012 #include <unistd.h>
00013 #include <u/libu.h>
00014 #include <klone/io.h>
00015 #include <klone/io.h>
00016 #include <klone/ioprv.h>
00017 #include <klone/codec.h>
00018
00019 enum {
00020 IO_RD_BUFSZ = 4096,
00021 IO_WR_BUFSZ = 4096
00022 };
00023
00024 #define IO_WBUF_AVAIL(io) (io->wbsz - io->wcount)
00025 #define IO_WBUF_FULL(io) (io->wbsz == io->wcount)
00026
00027 static inline int io_transform_codec_buffer(io_t *, codec_t *, char *,
00028 size_t *);
00029
00048 ssize_t io_pipe(io_t *out, io_t *in)
00049 {
00050 enum { BUFSZ = 4096 };
00051 char buf[BUFSZ];
00052 size_t count = 0;
00053 ssize_t c;
00054
00055 dbg_err_if (out == NULL);
00056 dbg_err_if (in == NULL);
00057
00058 for(;;)
00059 {
00060 c = io_read(in, buf, BUFSZ);
00061 dbg_err_if(c < 0);
00062 if(c == 0)
00063 break;
00064
00065
00066 dbg_err_if(io_write(out, buf, c) < 0);
00067
00068 count += c;
00069 }
00070
00071 return count;
00072 err:
00073 return -1;
00074 }
00075
00092 int io_dup(io_t *io, io_t **pio)
00093 {
00094 dbg_return_if (io == NULL, ~0);
00095 dbg_return_if (pio == NULL, ~0);
00096
00097 io->refcnt++;
00098
00099 *pio = io;
00100
00101 return 0;
00102 }
00103
00117 ssize_t io_copy(io_t *out, io_t *in, size_t size)
00118 {
00119 enum { BUFSZ = 4096 };
00120 char buf[BUFSZ];
00121 size_t rem = size;
00122 ssize_t c;
00123
00124 dbg_err_if (in == NULL);
00125 dbg_err_if (out == NULL);
00126
00127 while(rem)
00128 {
00129 c = io_read(in, buf, MIN(BUFSZ, rem));
00130 dbg_err_if(c < 0);
00131 if(c == 0)
00132 break;
00133
00134
00135 dbg_err_if(io_write(out, buf, c) < 0);
00136
00137 rem -= c;
00138 }
00139
00140 return size - rem;
00141 err:
00142 return -1;
00143 }
00144
00145
00159 ssize_t io_seek(io_t *io, size_t off)
00160 {
00161 dbg_err_if (io == NULL);
00162 dbg_err_if (io_flush(io));
00163
00164 if(io->seek)
00165 return io->seek(io, off);
00166 err:
00167 return -1;
00168 }
00169
00180 ssize_t io_tell(io_t *io)
00181 {
00182 dbg_err_if (io == NULL);
00183 dbg_err_if (io_flush(io));
00184
00185 if(io->tell)
00186 return io->tell(io);
00187 err:
00188 return -1;
00189 }
00190
00191
00192 static int io_rbuf_alloc(io_t *io)
00193 {
00194 dbg_err_if (io == NULL);
00195
00196 io->rbsz = IO_RD_BUFSZ;
00197
00198
00199 io->rbuf = (char*)u_malloc(io->rbsz);
00200 dbg_err_if(io->rbuf == NULL);
00201 io->roff = 0;
00202
00203 io->ubuf = (char*)u_malloc(io->rbsz);
00204 dbg_err_if(io->ubuf == NULL);
00205
00206 return 0;
00207 err:
00208 return ~0;
00209 }
00210
00211
00212 static int io_wbuf_alloc(io_t *io)
00213 {
00214 dbg_err_if (io == NULL);
00215
00216 io->wbsz = IO_WR_BUFSZ;
00217
00218
00219 io->wbuf = (char*)u_malloc(io->wbsz);
00220 dbg_err_if(io->wbuf == NULL);
00221
00222 return 0;
00223 err:
00224 return ~0;
00225 }
00226
00227 static ssize_t io_transform(io_t *io, codec_t *codec,
00228 char *dst, size_t *dcount, const char *src, size_t sz)
00229 {
00230 ssize_t c;
00231 size_t cavail, sdcount = *dcount;
00232
00233 dbg_err_if (io == NULL);
00234 dbg_err_if (codec == NULL);
00235 dbg_err_if (src == NULL);
00236 dbg_err_if (dst == NULL);
00237 dbg_err_if (dcount == NULL);
00238
00239 if(codec == TAILQ_LAST(&io->codec_chain, codec_chain_s))
00240 {
00241
00242 c = codec->transform(codec, dst, dcount, src, sz);
00243 dbg_err_if(c == 0 && *dcount == 0);
00244 return c;
00245 } else {
00246 c = 0;
00247 do
00248 {
00249 *dcount = sdcount;
00250 if(codec->ccount)
00251 dbg_err_if(io_transform_codec_buffer(io, codec, dst, dcount));
00252 else
00253 *dcount = 0;
00254
00255 c = 0;
00256 cavail = CODEC_BUFSZ - codec->ccount - codec->coff;
00257 if(sz && cavail)
00258 {
00259 dbg_err_if((c = codec->transform(codec,
00260 codec->cbuf + codec->coff + codec->ccount,
00261 &cavail, src, sz)) < 0);
00262
00263 codec->ccount += cavail;
00264 dbg_err_if(c == 0 && cavail == 0);
00265 }
00266 } while(c == 0 && *dcount == 0 && (codec->ccount || sz));
00267
00268 return c;
00269 }
00270
00271 err:
00272 return -1;
00273 }
00274
00275 static inline int io_transform_codec_buffer(io_t *io, codec_t *codec,
00276 char *dst, size_t *dcount)
00277 {
00278 ssize_t ct;
00279
00280 dbg_err_if (io == NULL);
00281 dbg_err_if (codec == NULL);
00282 dbg_err_if (dst == NULL);
00283 dbg_err_if (dcount == NULL);
00284
00285 if(codec->ccount)
00286 {
00287 dbg_err_if((ct = io_transform(io, TAILQ_NEXT(codec, np),
00288 dst, dcount, codec->cbuf + codec->coff,codec->ccount)) < 0);
00289
00290 codec->ccount -= ct;
00291
00292 if(codec->ccount > 0)
00293 codec->coff += ct;
00294 else
00295 codec->coff = 0;
00296 }
00297
00298 return 0;
00299 err:
00300 return ~0;
00301 }
00302
00303 static inline ssize_t io_transfer(io_t *io, char *dst, size_t *dcount,
00304 const char *src, size_t sz)
00305 {
00306 dbg_err_if (io == NULL);
00307 dbg_err_if (src == NULL);
00308 dbg_err_if (dst == NULL);
00309 dbg_err_if (dcount == NULL);
00310
00311 if(!TAILQ_EMPTY(&io->codec_chain))
00312 {
00313 return io_transform(io, TAILQ_FIRST(&io->codec_chain),
00314 dst, dcount, src, sz);
00315 } else {
00316 ssize_t wr = MIN(sz, *dcount);
00317 memcpy(dst, src, wr);
00318 *dcount = wr;
00319 return wr;
00320 }
00321 err:
00322 return -1;
00323 }
00324
00325 static int io_chain_flush_chunk(io_t *io, char *dst, size_t *dcount)
00326 {
00327 int er;
00328 codec_t *codec;
00329 size_t sz, sdcount;
00330
00331 dbg_err_if (io == NULL);
00332 dbg_err_if (dst == NULL);
00333 dbg_err_if (dcount == NULL);
00334
00335 sdcount = *dcount;
00336
00337 TAILQ_FOREACH(codec, &io->codec_chain, np)
00338 {
00339 *dcount = sdcount;
00340 if(codec == TAILQ_LAST(&io->codec_chain, codec_chain_s))
00341 {
00342 return codec->flush(codec, dst, dcount);
00343 } else {
00344 for(;;)
00345 {
00346 *dcount = sdcount;
00347 if(codec->ccount)
00348 {
00349 int rc = io_transform_codec_buffer(io, codec, dst, dcount);
00350 dbg_err_if (rc);
00351
00352 if(*dcount)
00353 return CODEC_FLUSH_CHUNK;
00354 } else
00355 *dcount = 0;
00356
00357 sz = CODEC_BUFSZ - codec->ccount - codec->coff;
00358 dbg_err_if((er = codec->flush(codec,
00359 codec->cbuf + codec->coff + codec->ccount, &sz)) < 0);
00360
00361 codec->ccount += sz;
00362
00363 if(er == CODEC_FLUSH_COMPLETE && codec->ccount == 0)
00364 break;
00365 }
00366 }
00367 }
00368
00369 return CODEC_FLUSH_COMPLETE;
00370 err:
00371 return -1;
00372 }
00373
00374 static int io_chain_flush(io_t *io)
00375 {
00376 enum { BUFSZ = 4096 };
00377 int er;
00378 size_t sz, count;
00379 char buf[BUFSZ], *ptr;
00380
00381 dbg_err_if (io == NULL);
00382
00383 for(;;)
00384 {
00385
00386
00387
00388 count = BUFSZ;
00389 if((er = io_chain_flush_chunk(io, buf, &count)) == CODEC_FLUSH_COMPLETE)
00390 break;
00391
00392 dbg_err_if(er < 0);
00393
00394 for(ptr = buf; count; )
00395 {
00396 if(IO_WBUF_FULL(io))
00397 dbg_err_if(io_flush(io));
00398
00399 sz = MIN(count, IO_WBUF_AVAIL(io));
00400 memcpy(io->wbuf + io->wcount, ptr, sz);
00401
00402 count -= sz;
00403 io->wcount += sz;
00404 ptr += sz;
00405 }
00406 }
00407
00408 return 0;
00409 err:
00410 return ~0;
00411 }
00412
00427 int io_free(io_t *io)
00428 {
00429 dbg_err_if (io == NULL);
00430 dbg_err_if (io->refcnt == 0);
00431
00432
00433
00434 if(--io->refcnt)
00435 return 0;
00436
00437
00438 dbg_if(io_codecs_remove(io));
00439
00440 dbg_if(io_flush(io));
00441
00442
00443 dbg_if(io->term(io));
00444
00445 U_FREE(io->rbuf);
00446 U_FREE(io->ubuf);
00447 U_FREE(io->wbuf);
00448 U_FREE(io->name);
00449 U_FREE(io);
00450
00451 return 0;
00452 err:
00453 return ~0;
00454 }
00455
00456
00457 static ssize_t io_underflow(io_t *io)
00458 {
00459 ssize_t c;
00460 size_t sz;
00461
00462 dbg_err_if (io == NULL);
00463
00464 if(io->rbuf == NULL)
00465 dbg_err_if(io_rbuf_alloc(io));
00466
00467 while(io->rcount == 0)
00468 {
00469 if(io->ucount == 0)
00470 {
00471 dbg_err_if((c = io->read(io, io->ubuf, io->rbsz)) < 0);
00472 if(c == 0)
00473 {
00474
00475 if(!TAILQ_EMPTY(&io->codec_chain))
00476 {
00477 sz = io->rbsz;
00478 c = io_chain_flush_chunk(io, io->rbuf, &sz);
00479 dbg_err_if(c < 0);
00480 io->rcount += sz;
00481 io->roff = 0;
00482 if(c == 0)
00483 io->eof++;
00484 }
00485 break;
00486 }
00487 io->ucount += c;
00488 }
00489
00490
00491 sz = io->rbsz - io->rcount;
00492 dbg_err_if((c = io_transfer(io, io->rbuf, &sz,
00493 io->ubuf + io->uoff, io->ucount)) < 0);
00494 dbg_err_if(c < 0);
00495 dbg_err_if(c == 0 && sz == 0);
00496 io->ucount -= c;
00497 if(io->ucount == 0)
00498 io->uoff = 0;
00499 else
00500 io->uoff += c;
00501
00502 io->rcount = sz;
00503 io->roff = 0;
00504 }
00505
00506 return io->rcount;
00507 err:
00508 return -1;
00509 }
00510
00525 ssize_t io_read(io_t *io, char *buf, size_t size)
00526 {
00527 char *out = buf;
00528 size_t wr;
00529 ssize_t c;
00530
00531 dbg_err_if (io == NULL);
00532 dbg_err_if (buf == NULL);
00533
00534 if(io->eof)
00535 return 0;
00536
00537 while(size)
00538 {
00539 if(io->rcount == 0)
00540 {
00541 dbg_err_if((c = io_underflow(io)) < 0);
00542 if(c == 0)
00543 break;
00544 }
00545
00546 wr = MIN(io->rcount, size);
00547 memcpy(out, io->rbuf + io->roff, wr);
00548 io->rcount -= wr;
00549 io->roff += wr;
00550 out += wr;
00551 size -= wr;
00552 }
00553
00554 return out - buf;
00555 err:
00556 return -1;
00557 }
00558
00572 ssize_t io_printf(io_t *io, const char *fmt, ...)
00573 {
00574 enum { BUFSZ = 2048 };
00575 char buf[BUFSZ], *bbuf = NULL;
00576 va_list ap, ap2;
00577 int sz;
00578
00579 dbg_err_if (io == NULL);
00580 dbg_err_if (fmt == NULL);
00581
00582
00583 va_start(ap, fmt);
00584
00585 sz = vsnprintf(buf, BUFSZ, fmt, ap);
00586
00587 va_end(ap);
00588
00589 if(sz >= BUFSZ)
00590 {
00591 va_start(ap2, fmt);
00592
00593 bbuf = (char*)u_malloc(++sz);
00594 dbg_err_if(bbuf == NULL);
00595
00596 if((sz = vsnprintf(bbuf, sz, fmt, ap2)) > 0)
00597 {
00598 dbg_err_if(io_write(io, bbuf, sz) < 0);
00599 }
00600
00601 va_end(ap2);
00602
00603 U_FREE(bbuf);
00604 } else if(sz > 0) {
00605 dbg_err_if(io_write(io, buf, sz) < 0);
00606 }
00607
00608 return 0;
00609 err:
00610 return -1;
00611 }
00612
00622 ssize_t io_flush(io_t *io)
00623 {
00624 ssize_t c;
00625 size_t off = 0;
00626
00627 dbg_err_if (io == NULL);
00628
00629 while(io->wcount)
00630 {
00631 c = io->write(io, io->wbuf + off, io->wcount);
00632 dbg_err_if(c < 0);
00633 if(c == 0)
00634 break;
00635
00636 io->wcount -= c;
00637 off += c;
00638 }
00639
00640 return 0;
00641 err:
00642 return -1;
00643 }
00644
00656 ssize_t io_write(io_t *io, const char *buf, size_t size)
00657 {
00658 size_t sz = 0, rem = size;
00659 ssize_t c = 0;
00660
00661 dbg_err_if (io == NULL);
00662 dbg_err_if (buf == NULL);
00663
00664 if(io->wbuf == NULL)
00665 dbg_err_if(io_wbuf_alloc(io));
00666
00667 while(rem)
00668 {
00669 if(IO_WBUF_FULL(io))
00670 dbg_err_if(io_flush(io));
00671
00672 sz = IO_WBUF_AVAIL(io);
00673 c = io_transfer(io, io->wbuf + io->wcount, &sz, buf, rem);
00674 dbg_err_if(c < 0);
00675 dbg_err_if(c == 0 && sz == 0);
00676
00677 io->wcount += sz;
00678 buf += c;
00679 rem -= c;
00680 }
00681
00682 return size;
00683 err:
00684 return -1;
00685 }
00686
00697 inline ssize_t io_putc(io_t *io, char c)
00698 {
00699 return io_write(io, &c, 1);
00700 }
00701
00712 inline ssize_t io_getc(io_t *io, char *pc)
00713 {
00714 return io_read(io, pc, 1);
00715 }
00716
00717 static inline char *io_strnchr(char *buf, size_t sz, char c)
00718 {
00719 register char *p;
00720
00721 dbg_goto_if (buf == NULL, end);
00722
00723 p = buf;
00724
00725 while(sz--)
00726 {
00727 if(*p == c)
00728 return p;
00729 ++p;
00730 }
00731 end:
00732 return NULL;
00733 }
00734
00747 ssize_t io_gets(io_t *io, char *buf, size_t size)
00748 {
00749 ssize_t wr, c, len = 0;
00750 char *p;
00751
00752 dbg_err_if (io == NULL);
00753 dbg_err_if (buf == NULL);
00754
00755 if(size < 2)
00756 return -1;
00757
00758 --size;
00759
00760 if(io->rcount == 0)
00761 dbg_err_if(io_underflow(io) < 0);
00762
00763 if(io->rcount == 0)
00764 return 0;
00765
00766 for(;;)
00767 {
00768 if((p = io_strnchr(io->rbuf + io->roff, io->rcount, '\n')) != NULL)
00769 {
00770 p++;
00771 wr = MIN(p - (io->rbuf + io->roff), size);
00772 memcpy(buf, io->rbuf + io->roff, wr);
00773 buf[wr] = 0;
00774 io->rcount -= wr;
00775 io->roff += wr;
00776 len += wr;
00777 break;
00778 } else {
00779 if(size >= io->rcount)
00780 {
00781 memcpy(buf, io->rbuf + io->roff, io->rcount);
00782 len += io->rcount;
00783 buf += io->rcount;
00784 size -= io->rcount;
00785 io->rcount = 0;
00786 io->roff = 0;
00787 dbg_err_if((c = io_underflow(io)) < 0);
00788 if(c == 0)
00789 break;
00790 } else {
00791
00792 memcpy(buf, io->rbuf + io->roff, size);
00793 len += size;
00794 io->rcount -= size;
00795 io->roff += size;
00796 break;
00797 }
00798 }
00799 }
00800
00801 buf[len] = 0;
00802 return len;
00803 err:
00804 return -1;
00805 }
00806
00815 int io_codec_add_head(io_t *io, codec_t* c)
00816 {
00817 dbg_return_if (io == NULL, ~0);
00818 dbg_return_if (c == NULL, ~0);
00819
00820
00821 TAILQ_INSERT_HEAD(&io->codec_chain, c, np);
00822
00823 return 0;
00824 }
00825
00834 int io_codec_add_tail(io_t *io, codec_t* c)
00835 {
00836 dbg_return_if (io == NULL, ~0);
00837 dbg_return_if (c == NULL, ~0);
00838
00839
00840 TAILQ_INSERT_TAIL(&io->codec_chain, c, np);
00841
00842 return 0;
00843 }
00844
00852 int io_codecs_remove(io_t *io)
00853 {
00854 codec_t *codec;
00855 int rc = 0;
00856
00857 dbg_return_if (io == NULL, ~0);
00858
00859 if(!TAILQ_EMPTY(&io->codec_chain))
00860 {
00861 if(io->wbuf)
00862 dbg_ifb(io_chain_flush(io))
00863 rc++;
00864
00865 while((codec = TAILQ_FIRST(&io->codec_chain)) != NULL)
00866 {
00867 TAILQ_REMOVE(&io->codec_chain, codec, np);
00868 codec_free(codec);
00869 }
00870 }
00871
00872 return rc;
00873 }
00874
00886 int io_name_set(io_t *io, const char *name)
00887 {
00888 char *n;
00889
00890 dbg_err_if (io == NULL);
00891 dbg_err_if (name == NULL);
00892
00893 n = u_strdup(name);
00894 dbg_err_if(n == NULL);
00895
00896 U_FREE(io->name);
00897
00898 io->name = n;
00899
00900 return 0;
00901 err:
00902 return ~0;
00903 }
00904
00916 int io_name_get(io_t *io, char *name, size_t sz)
00917 {
00918 size_t min = 0;
00919
00920 dbg_err_if (io == NULL);
00921 dbg_err_if (io->name == NULL);
00922 dbg_err_if (name == NULL);
00923 dbg_err_if (sz < 2);
00924
00925 min = MIN(sz-1, strlen(io->name));
00926
00927 memcpy(name, io->name, min);
00928 name[min] = 0;
00929
00930 return 0;
00931 err:
00932 return ~0;
00933 }
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 int io_is_secure(io_t *io)
00946 {
00947 dbg_err_if(io == NULL);
00948
00949 return io->is_secure;
00950 err:
00951 return 0;
00952 }
00953
00954
00955
00956
00957 int io_prv_create(size_t dev_sz, io_t **pio)
00958 {
00959 io_t *io = NULL;
00960
00961 dbg_err_if (pio == NULL);
00962
00963 io = u_zalloc(dev_sz);
00964 dbg_err_if(io == NULL);
00965
00966 TAILQ_INIT(&io->codec_chain);
00967
00968
00969 io->refcnt++;
00970
00971
00972 io->size = dev_sz;
00973
00974 *pio = io;
00975
00976 return 0;
00977 err:
00978 U_FREE(io);
00979 return -1;
00980 }
00981