fsio.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:13k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hlxclib/stdlib.h"
  36. #include "hlxclib/stdio.h"
  37. #include "hlxclib/string.h"
  38. #include "hxtypes.h"
  39. #include "debug.h"
  40. #include "roundup.h"
  41. #ifndef _MACINTOSH // if hxheap.h is included here, OpenTransport.h will not compile
  42. #include "hxheap.h"
  43. #endif
  44. #ifdef _DEBUG
  45. #undef HX_THIS_FILE
  46. static const char HX_THIS_FILE[] = __FILE__;
  47. #endif
  48. #include "bio.h"
  49. #include "sio.h"
  50. #include "fsio.h"
  51. #include "fio.h"
  52. #include "sockio.h"
  53. #include "hxassert.h"
  54. #ifdef _MACINTOSH // so we include it here
  55. #include "hxheap.h"
  56. #endif
  57. FSIO::FSIO(IO* i, int bsize)
  58. {
  59.     would_block = 0;
  60.     io = i;
  61.     bufsize = bsize;
  62.     
  63.     flags = (int)(i->flags() & O_ACCMODE);
  64.     if (flags == O_RDONLY || flags == O_RDWR)
  65.     {
  66. reader.end = reader.ptr = new Byte[bufsize];
  67. reader.creg->set_buf(reader.ptr, bufsize);
  68.     }
  69.     if (flags == O_WRONLY || flags == O_RDWR)
  70.     {
  71. writer.end = writer.ptr = new Byte[bufsize];
  72. writer.creg->set_buf(writer.ptr, bufsize);
  73.     }
  74.     pathname = 0;
  75. }
  76. FSIO::FSIO(const char* name, int f, mode_t m)
  77. {
  78.     would_block = 0;
  79.     io = new FileIO(name, f, m);
  80.     mode = m;
  81.     flags = f & O_ACCMODE;
  82.     err = (int)io->error();
  83.     bufsize = 0x1000;
  84.     if (flags == O_RDONLY || flags == O_RDWR)
  85.     {
  86. reader.end = reader.ptr = new Byte[bufsize];
  87. reader.creg->set_buf(reader.ptr, bufsize);
  88.     }
  89.     if (flags == O_WRONLY || flags == O_RDWR)
  90.     {
  91.     // N.B. 4096 bytes should be big enough to hold a superblock
  92. writer.end = writer.ptr = new Byte[bufsize];
  93. writer.creg->set_buf(writer.ptr, bufsize);
  94.     }
  95.     pathname = new char[strlen(name) + 1];
  96.     strcpy (pathname, name); /* Flawfinder: ignore */
  97. }
  98. FSIO::~FSIO()
  99. {
  100.     /*
  101.      * Delete any buffers we allocated.
  102.      * Regions will be freed by SIO::~SIO().
  103.      */
  104.     if (flags == O_RDONLY || flags == O_RDWR)
  105.     {
  106. Region* reg = reader.regs;
  107. while (reg)
  108. {
  109.     delete[] reg->base;
  110.     reg = reg->next;
  111. }
  112.     }
  113.     if (flags == O_WRONLY || flags == O_RDWR)
  114.     {
  115. ASSERT(writer.creg->refcount == 0);
  116. Region* reg = writer.regs;
  117. while (reg)
  118. {
  119.     //DPRINTF(D_INFO, ("deleting write region %p base %p next %pn", reg, reg->base, reg->next));
  120.     delete[] reg->base;
  121.     reg = reg->next;
  122. }
  123.     }
  124.     if (delete_io)
  125. delete io;
  126.     if (pathname)
  127.     {
  128. delete[] pathname;
  129. pathname = 0;
  130.     }
  131. }
  132. int
  133. FSIO::get_would_block()
  134. {
  135.     return would_block;
  136. }
  137. Byte*
  138. FSIO::_read_alloc(int& size)
  139. {
  140.     int count = _read_count();
  141.     if (count == 0 && (reader.eof || err))
  142. return 0;
  143.     ASSERT(reader.ptr <= reader.end);
  144.     
  145.     off_t off = read_offset();
  146.     Byte* b = reader.ptr;
  147.     reader.ptr += size;
  148.     /*
  149.      * if there isn't enough space in the current buffer,
  150.      * update the current region.
  151.      */
  152.     if (reader.ptr > reader.creg->limit)
  153.     {
  154. int bsize = roundup(size, bufsize);
  155. Byte* oldbuffer = 0;
  156. if (reader.creg->refcount != 0)
  157. {
  158.     /* creg is in use => allocate a new region */
  159.     reader.creg->limit = b;
  160.     reader.creg = new Region(reader.creg);
  161.     reader.creg->set_buf(new unsigned char[bsize], bsize);
  162. }
  163. else if (bsize != bufsize)
  164. {
  165.     /* need a bigger buffer => allocate a new buffer */
  166.     oldbuffer = reader.creg->base;
  167.     reader.creg->set_buf(new unsigned char[bsize], bsize);
  168. } /* else reuse existing buffer and region */
  169. reader.creg->flush_off = reader.creg->off = off;
  170. /*
  171.  * if there is unused but read data in the
  172.  * old buffer, copy it to the new buffer.
  173.  */
  174. if (count)
  175.     memmove(reader.creg->base, b, count);
  176. if (oldbuffer)
  177.     delete[] oldbuffer;
  178. b = reader.creg->base;
  179. reader.ptr = b + size;
  180. reader.end = b + count;
  181.     }
  182.     int readcount = (int)io->read(reader.end, _read_space());
  183.     if (readcount <= 0)
  184.     {
  185. if (readcount == 0)
  186.     reader.eof = 1;
  187. else if (io->error() != EWOULDBLOCK)
  188. {
  189.     err = (int)io->error();
  190.     DPRINTF(D_INFO, ("read_alloc error %d count %dn", err, count));
  191. }
  192. /* return if the buffer is empty and we have seen eof or err */
  193. if (count == 0 && (reader.eof || err))
  194. {
  195.     reader.ptr = reader.end;
  196.     return 0;
  197. }
  198.     }
  199.     else
  200. reader.end += readcount;
  201.     /* truncate request if not enough data was read in */
  202.     if (reader.ptr > reader.end)
  203.     {
  204. size = reader.end - b;
  205. ASSERT(size >= 0);
  206. reader.ptr = reader.end;
  207.     }
  208.     reader.creg->refcount++;
  209.     return b;
  210. }
  211. off_t
  212. FSIO::read_seek(off_t new_off, int whence)
  213. {
  214.     // reset error
  215.     err = 0;
  216.     // Compute actual offset
  217.     off_t offset = read_offset();
  218.     switch (whence)
  219.     {
  220. case SEEK_SET:
  221.     break;
  222. case SEEK_CUR:
  223.     new_off += offset;
  224.     break;
  225. #if 0 /* XXX PSH - SIO no longer supports file_size */
  226. case SEEK_END:
  227.     new_off += file_size();
  228.     break;
  229. #endif /* 0 */
  230. default:
  231.     err = EINVAL;
  232.     return 0;
  233.     }
  234.     // see if seek is within the current region
  235.     if (reader.creg->off <= new_off && new_off <= offset + _read_count())
  236.     {
  237. reader.ptr += new_off - offset;
  238. return new_off;
  239.     }
  240.     offset = new_off;
  241.     // relocate creg
  242.     if (reader.creg->refcount == 0)
  243.     {
  244. Byte* base = reader.remove(reader.creg);
  245. if (base)
  246.     delete[] base;
  247.     }
  248.     else
  249.     {
  250. reader.creg->limit = reader.end; // adjust limit
  251.     }
  252.     Region** rp;
  253.     Region *reg = reader.find(new_off, rp);
  254.     if (reg)
  255.     {
  256. reader.ptr = reg->base + new_off - reg->off;
  257. // XXX use another field in reg so that we can continue using
  258. // already allocated space past where we left off. May be.
  259. reader.end = reg->limit;
  260. new_off = reg->off + reg->limit - reg->base;
  261.     }
  262.     else
  263.     {
  264. reg = new Region;
  265. reg->next = *rp;
  266. *rp = reg;
  267. reg->set_buf(new Byte[bufsize], bufsize, new_off);
  268. reader.ptr = reader.end = reg->base;
  269.     }
  270.     reader.creg = reg;
  271.     reader.eof = 0;
  272.     if (io->seek(new_off, SEEK_SET) == -1)
  273.     {
  274. err = (int)io->error();
  275. // XXX clean up creg -- its offset is not valid
  276. return 0;
  277.     }
  278.     return offset;
  279. }
  280. Byte*
  281. FSIO::read_alloc(int& size, off_t new_off, int whence)
  282. {
  283.     if (read_seek(new_off, whence) == (off_t)-1)
  284. return 0;
  285.     return SIO::read_alloc(size);
  286. }
  287. void
  288. FSIO::_read_free(Byte* buf)
  289. {
  290.     Region **rp;
  291.     Region* reg = reader.find(buf, rp);
  292.     if (!reg)
  293. return;
  294.     reg->refcount--;
  295.     if (reg->refcount == 0)
  296.     {
  297. *rp = reg->next;
  298. delete[] reg->base;
  299. delete reg;
  300.     }
  301. }
  302. Byte*
  303. FSIO::_write_alloc(int& size)
  304. {
  305.     int count = _write_count();
  306.     // XXX deal with any outstanding writes
  307.     if (err)
  308. return 0;
  309.     ASSERT(writer.ptr <= writer.end);
  310.     off_t off = write_offset();
  311.     Byte* b = writer.ptr;
  312.     writer.ptr += size;
  313.     if (writer.ptr > writer.creg->limit)
  314.     {
  315. int bsize = roundup(size, bufsize);
  316. Byte* oldbuffer = 0;
  317. /*
  318.  * If creg is in use, we must allocate a new region
  319.  */
  320. if (writer.creg->refcount != 0)
  321. {
  322.     writer.creg->limit = b;
  323.     writer.creg = new Region(writer.creg);
  324.     writer.creg->set_buf(new unsigned char[bsize], bsize);
  325. }
  326. else if (bsize != bufsize)
  327. {
  328.     oldbuffer = writer.creg->base;
  329.     writer.creg->set_buf(new unsigned char[bsize], bsize);
  330. } /* else reuse existing buffer and region */
  331. writer.creg->flush_off = writer.creg->off = off;
  332. if (count)
  333.     memmove(writer.creg->base, b, count);
  334. if (oldbuffer)
  335.     delete[] oldbuffer;
  336. b = writer.creg->base;
  337. writer.ptr = b + size;
  338. writer.end = b + count;
  339.     }
  340.     if (writer.ptr > writer.end)
  341. writer.end = writer.ptr;
  342.     writer.creg->refcount++;
  343.     return b;
  344. }
  345. off_t
  346. FSIO::write_seek(off_t new_off, int whence)
  347. {
  348.     /*
  349.      * Before calling write_seek, the program must ensure that all
  350.      * regions have been freed. This may be unnecessarily restrictive,
  351.      * but it makes the routine much easier to code
  352.      */
  353.     if (writer.regs != writer.creg && writer.creg->refcount != 0)
  354.     {
  355. err = EINVAL;
  356. return 0;
  357.     }
  358.     // Compute actual offset
  359.     off_t offset = writer.creg->off;
  360.     switch (whence)
  361.     {
  362. case SEEK_SET:
  363.     break;
  364. case SEEK_CUR:
  365.     new_off += offset;
  366.     break;
  367. #if 0 /* XXX PSH - sio no longer supports file_size() */
  368. case SEEK_END:
  369.     new_off += file_size();
  370.     break;
  371. #endif /* 0 */
  372. default:
  373.     err = EINVAL;
  374.     return 0;
  375.     }
  376.     // relocate creg
  377.     writer.ptr = writer.end = writer.creg->base;
  378.     write_off = writer.creg->flush_off = writer.creg->off = new_off;
  379.     if (io->seek(new_off, SEEK_SET) == -1)
  380.     {
  381. err = (int)io->error();
  382. return 0;
  383.     }
  384.     return new_off;
  385. }
  386. Byte*
  387. FSIO::write_alloc(int& size, off_t seek, int whence)
  388. {
  389.     // XXX this code's been disabled since 1996 so it was removed
  390.     // XXX incomplete
  391.     return 0;
  392. }
  393. int
  394. FSIO::_write_free(Byte* buf)
  395. {
  396.     Region** rp;
  397.     Region* reg = writer.find(buf, rp);
  398.     if (!reg || reg->refcount == 0)
  399.     {
  400. err = EINVAL;
  401. return -1;
  402.     }
  403.     reg->refcount--;
  404.     if (reg->refcount == 0)
  405.     {
  406. if (reg == writer.creg)
  407. {
  408.     off_t off = write_offset();
  409.     writer.creg->limit = writer.end;
  410.     writer.creg = new Region(writer.creg);
  411.     writer.creg->set_buf(new unsigned char[bufsize], bufsize, off);
  412.     writer.ptr = writer.end = writer.creg->base;
  413. }
  414. if (_write_flush(reg) < 0)
  415. {
  416.     if (err)
  417. return -1;
  418.     return 0;
  419. }
  420. *rp = reg->next;
  421. delete[] reg->base;
  422. delete reg;
  423.     }
  424.     
  425.     return 0;
  426. }
  427. int
  428. FSIO::_write_flush(Region* reg)
  429. {
  430.     Region* r = reg;
  431.     /*
  432.      * Can only flush if region is unreferenced and everything previous
  433.      * to this region has been written out
  434.      */
  435.     if (r->refcount != 0 || write_off != r->flush_off)
  436. return -1;
  437.     do
  438.     {
  439. Region* next;
  440. int flush_count = HX_SAFEINT(r->flush_off - r->off);
  441. Byte* b = r->base + flush_count;
  442. int count = r->limit - r->base - flush_count;
  443. INT32 writecount = io->write(b, count);
  444. would_block = 0;
  445. if (writecount < count)
  446. {
  447.             if (writecount < 0)
  448.             {
  449.         if (io->error() != EWOULDBLOCK)
  450.         {
  451.     err = (int)io->error();
  452.     DPRINTF(D_INFO, ("write_flush error %dn", err));
  453.     /*
  454.      * If the current region is not the starting region,
  455.      * then the next pointer must be updated
  456.      */
  457.     if (r != reg)
  458.         reg->next = r;
  459.     return -1;
  460.         }
  461.         else
  462.         {
  463.     would_block = 1;
  464.         }
  465.             }
  466.             else
  467.             {
  468. /*
  469.  * Adjust region by the number of bytes written out
  470.  */
  471. r->flush_off += writecount;
  472. write_off = r->flush_off;
  473.                 
  474.                 would_block = 1;
  475.             }
  476.     
  477.     /*
  478.      * If the current region has not been flushed, then return
  479.      * a fail status
  480.      */
  481.     if (r == reg)
  482. return -1;
  483.     reg->next = r;
  484.     return 0;
  485. }
  486. write_off = r->flush_off + count;
  487. next = r->next;
  488. if (r != reg)
  489. {
  490.     /* delete all but the first region */
  491.     delete[] r->base;
  492.     delete r;
  493. }
  494. r = next;
  495.     } while (r && r->refcount == 0 && r != writer.creg);
  496.     
  497.     reg->next = r;
  498.     return 0;
  499. }
  500. /*
  501.  * Push back some data in the current buffer.
  502.  * This can be used to initialize the buffer
  503.  * with some data. Use read_undo() or read_realloc()
  504.  * To put back anything read with read_alloc().
  505.  * XXX this is a minimal implementation.
  506.  * Ideally we want a read/writeable object
  507.  * So that read_pushback is not needed.
  508.  */
  509. int
  510. FSIO::read_pushback(Byte* buf, int len)
  511. {
  512. int space = reader.creg->limit - reader.end;
  513. if (space < len)
  514. len = space;
  515. memcpy(reader.end, buf, len); /* Flawfinder: ignore */
  516. reader.end += len;
  517. reader.creg->off += len;
  518. return len;
  519. }
  520. off_t
  521. FSIO::file_size()
  522. {
  523.     return io->file_size();
  524. }