fsio.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:14k
源码类别:

Symbian

开发平台:

Visual C++

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