/[pearpc]/src/tools/stream.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/tools/stream.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 27906 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * HT Editor
3     * stream.cc
4     *
5     * Copyright (C) 1999-2002 Stefan Weyergraf
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License version 2 as
9     * published by the Free Software Foundation.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     */
20    
21     #include <cerrno>
22     #include <fcntl.h>
23     #include <limits.h>
24     #include <new>
25     #include <cstring>
26     #include <cstdio>
27     #include <cstdlib>
28     #include <sys/stat.h> /* for mode definitions */
29     #include <sys/types.h> /* for mode definitions */
30     #include <unistd.h>
31    
32     #include "debug.h"
33     #include "except.h"
34     #include "system/sys.h"
35     #include "snprintf.h"
36     #include "stream.h"
37    
38     /*
39     * Listener
40     */
41     #if 0
42     class Listener: public Object {
43     public:
44     StreamEventListener *listener;
45     StreamEvent notify_mask;
46    
47     Listener(StreamEventListener *l, StreamEvent nmask)
48     {
49     listener = l;
50     notify_mask = nmask;
51     }
52    
53     /* extends Object */
54     virtual int compareTo(const Object *obj) const
55     {
56     return ((Listener*)obj)->listener == listener ? 0 : 1;
57     }
58     };
59     #endif
60     /*
61     * Stream
62     */
63     #define STREAM_COPYBUF_SIZE (64*1024)
64    
65     Stream::Stream()
66     {
67     mAccessMode = IOAM_NULL;
68     // mListeners = NULL;
69     }
70    
71     Stream::~Stream()
72     {
73     // if (mListeners) delete mListeners;
74     }
75     /*
76     void Stream::addEventListener(StreamEventListener *l, StreamEvent mask)
77     {
78     if (!mListeners) mListeners = new Array(true);
79     *mListeners += new Listener(l, mask);
80     }
81     */
82     void Stream::checkAccess(IOAccessMode mask)
83     {
84     if (mAccessMode & mask != mask) throw IOException(EACCES);
85     }
86    
87     /**
88     * Copy (whole) stream to another (i.e. copy until EOF)
89     * @param stream Stream to copy this Stream to
90     * @returns number of bytes copied
91     */
92     uint Stream::copyAllTo(Stream *stream)
93     {
94     byte *buf = new byte[STREAM_COPYBUF_SIZE];
95     uint result = 0;
96     uint r, t;
97     do {
98     uint k = STREAM_COPYBUF_SIZE;
99     r = read(buf, k);
100     ASSERT(r <= k);
101     t = stream->write(buf, r);
102     ASSERT(t <= r);
103     result += t;
104     if (t != k) break;
105     } while (t);
106     delete[] buf;
107     return result;
108     }
109    
110     /**
111     * Copy (partial) stream to another
112     * @param stream Stream to copy this Stream to
113     * @param count maximum number of bytes to copy
114     * @returns number of bytes copied
115     */
116     uint Stream::copyTo(Stream *stream, uint count)
117     {
118     byte *buf = new byte[STREAM_COPYBUF_SIZE];
119     uint result = 0;
120     while (count) {
121     uint k = STREAM_COPYBUF_SIZE;
122     if (k > count) k = count;
123     uint r = read(buf, k);
124     ASSERT(r <= k);
125     uint t = stream->write(buf, r);
126     ASSERT(t <= r);
127     count -= t;
128     result += t;
129     if (t != k) break;
130     }
131     delete[] buf;
132     return result;
133     }
134    
135     /**
136     * Get access-mode
137     */
138     IOAccessMode Stream::getAccessMode() const
139     {
140     return mAccessMode;
141     }
142    
143     /**
144     * Get descriptive name
145     */
146     String &Stream::getDesc(String &result) const
147     {
148     result = "";
149     return result;
150     }
151     /*
152     void Stream::notifyListeners(StreamEvent event,...)
153     {
154     if (!mListeners) return;
155     foreach(Listener, l, *mListeners,
156     if (l->notify_mask & event) {
157     va_list ap;
158     va_start(ap, event);
159     l->listener->handleEvent(event, ap);
160     va_end(ap);
161     }
162     );
163     }
164     */
165     /**
166     * Set access-mode
167     */
168     int Stream::setAccessMode(IOAccessMode mode)
169     {
170     mAccessMode = mode;
171     return 0;
172     }
173    
174     /**
175     * Read from stream.
176     * Read up to <i>size</i> bytes from stream into <i>buf</i>.
177     * If less than <i>size</i> bytes are read, the exact number is
178     * returned and a (temporary) end-of-file (EOF) is encountered.
179     *
180     * @param buf pointer to bytes to read
181     * @param size number of bytes to read
182     * @returns number of bytes read
183     * @throws IOException
184     */
185     uint Stream::read(void *buf, uint size)
186     {
187     return 0;
188     }
189    
190     /**
191     * Exact read from stream.
192     * Read exactly <i>size</i> bytes from stream into <i>buf</i>.
193     * If less than <i>size</i> bytes are read, IOException is thrown.
194     *
195     * @param buf pointer to bytes to read
196     * @param size number of bytes to read
197     * @throws IOException
198     */
199     //#include "snprintf.h"
200     void Stream::readx(void *buf, uint size)
201     {
202     // File *f = dynamic_cast<File*>(this);
203     // FileOfs t = f ? f->tell() : mkfofs(0);
204     if (read(buf, size) != size) {
205     // FileOfs sz = f ? f->getSize() : mkfofs(0);
206     // ht_printf("readx failed, ofs = 0x%qx, size = %d (file size 0x%qx)\n", t, size, sz);
207     throw IOException(EIO);
208     }
209     }
210     /*
211     void Stream::removeEventListener(StreamEventListener *l)
212     {
213     Listener t(l, SEV_NULL);
214     bool b = (*mListeners -= &t);
215     ASSERT(b);
216     }
217     */
218     /**
219     * Write to stream.
220     * Write up to <i>size</i> bytes from <i>buf</i> into stream.
221     * If less than <i>size</i> bytes are written, the exact number is
222     * returned and a (temporary) end-of-file (EOF) is encountered.
223     *
224     * @param buf pointer to bytes to write
225     * @param size number of bytes to write
226     * @returns number of bytes written
227     * @throws IOException
228     */
229     uint Stream::write(const void *buf, uint size)
230     {
231     return 0;
232     }
233    
234     /**
235     * Exact write to stream.
236     * Write exactly <i>size</i> bytes from <i>buf</i> into stream.
237     * If less than <i>size</i> bytes are written, IOException is thrown.
238     *
239     * @param buf pointer to bytes to write
240     * @param size number of bytes to write
241     * @throws IOException
242     */
243     void Stream::writex(const void *buf, uint size)
244     {
245     if (write(buf, size) != size) throw IOException(EIO);
246     }
247    
248     /*
249     * StreamLayer
250     */
251    
252     StreamLayer::StreamLayer(Stream *s, bool own) : Stream()
253     {
254     mStream = s;
255     mOwnStream = own;
256     }
257    
258     StreamLayer::~StreamLayer()
259     {
260     if (mOwnStream) delete mStream;
261     }
262    
263     IOAccessMode StreamLayer::getAccessMode() const
264     {
265     return mStream->getAccessMode();
266     }
267    
268     String &StreamLayer::getDesc(String &result) const
269     {
270     return mStream->getDesc(result);
271     }
272    
273     int StreamLayer::setAccessMode(IOAccessMode mode)
274     {
275     return mStream->setAccessMode(mode);
276     }
277    
278     uint StreamLayer::read(void *buf, uint size)
279     {
280     return mStream->read(buf, size);
281     }
282    
283     uint StreamLayer::write(const void *buf, uint size)
284     {
285     return mStream->write(buf, size);
286     }
287    
288     Stream *StreamLayer::getLayered() const
289     {
290     return mStream;
291     }
292    
293     void StreamLayer::setLayered(Stream *newLayered, bool ownNewLayered)
294     {
295     mStream = newLayered;
296     mOwnStream = ownNewLayered;
297     }
298    
299     /*
300     * A File
301     */
302    
303     File::File()
304     {
305     mcount = 0;
306     }
307    
308     #define FILE_TRANSFER_BUFSIZE 4*1024
309     /**
310     * Low-level control function.
311     * @param cmd file control command number
312     * @returns 0 on success, POSIX.1 I/O error code on error
313     */
314     int File::cntl(uint cmd, ...)
315     {
316     va_list vargs;
317     va_start(vargs, cmd);
318     int ret = vcntl(cmd, vargs);
319     va_end(vargs);
320     return ret;
321     }
322    
323     void fileMove(File *file, FileOfs src, FileOfs dest, FileOfs size)
324     {
325     if (dest < src) {
326     char tbuf[FILE_TRANSFER_BUFSIZE];
327     while (size != 0) {
328     FileOfs k = size;
329     if (k > sizeof tbuf) k = sizeof tbuf;
330     file->seek(src);
331     file->readx(tbuf, k);
332     file->seek(dest);
333     file->writex(tbuf, k);
334     src += k;
335     dest += k;
336     size -= k;
337     }
338     } else if (dest > src) {
339     src += size;
340     dest += size;
341     char tbuf[FILE_TRANSFER_BUFSIZE];
342     while (size != 0) {
343     FileOfs k = size;
344     if (k > sizeof tbuf) k = sizeof tbuf;
345     src -= k;
346     dest -= k;
347     file->seek(src);
348     file->readx(tbuf, k);
349     file->seek(dest);
350     file->writex(tbuf, k);
351     size -= k;
352     }
353     }
354     }
355    
356     /**
357     * Delete bytes from file.
358     * Delete <i>size</i> bytes at current file pointer and shorten file
359     * accordingly.
360     Does not modify the current file pointer.
361     *
362     * @param size number of bytes to delete
363     * @throws IOException
364     */
365     void File::del(uint size)
366     {
367     FileOfs t = tell();
368     FileOfs o = t+size;
369     if (o > getSize()) throw IOException(EINVAL);
370     FileOfs s = getSize()-o;
371     fileMove(this, o, t, s);
372     truncate(getSize()-size);
373     seek(t);
374     }
375    
376     /**
377     * Extend file.
378     * Extend file to new size <i>newsize</i>.
379     * The current file pointer is undefined (but valid) after this operation.
380     *
381     * @param newsize new extended file size
382     * @throws IOException
383     */
384     void File::extend(FileOfs newsize)
385     {
386     if (getSize() > newsize) throw IOException(EINVAL);
387     if (getSize() == newsize) return;
388    
389     FileOfs save_ofs = tell();
390     int e = 0;
391    
392     IOAccessMode oldmode = getAccessMode();
393     if (!(oldmode & IOAM_WRITE)) {
394     int f = setAccessMode(oldmode | IOAM_WRITE);
395     if (f) throw IOException(f);
396     }
397    
398     FileOfs s = getSize();
399     char buf[FILE_TRANSFER_BUFSIZE];
400     memset(buf, 0, sizeof buf);
401     newsize -= s;
402     seek(s);
403     while (newsize != 0) {
404     uint k = MIN(sizeof buf, newsize);
405     uint l = write(buf, k);
406     if (l != k) {
407     e = EIO;
408     break;
409     }
410     newsize -= l;
411     }
412    
413     if (!(oldmode & IOAM_WRITE)) {
414     int f = setAccessMode(oldmode);
415     if (f) e = f;
416     }
417     if (e) throw IOException(e);
418     seek(save_ofs);
419     }
420    
421     /**
422     * Get filename.
423     *
424     * @param result String that receives the filename
425     * @returns its argument
426     */
427     String &File::getFilename(String &result) const
428     {
429     result = "";
430     return result;
431     }
432    
433     /**
434     * Get file size.
435     *
436     * @returns file size
437     */
438     FileOfs File::getSize() const
439     {
440     return 0;
441     }
442    
443     #define FILE_INSERT_BUFSIZE 4*1024
444     /**
445     * Insert bytes into file.
446     * Insert <i>size</i> bytes from <i>buf</i> at the current file pointer
447     * into the file and extend file accordingly.
448     *
449     * @param buf pointer to buffer that holds at least <i>size</i> bytes
450     * @param size number of bytes to insert
451     * @throws IOException
452     */
453     void File::insert(const void *buf, uint size)
454     {
455     FileOfs t = tell();
456     FileOfs s = getSize()-t;
457     extend(getSize()+size);
458     fileMove(this, t, t+size, s);
459     seek(t);
460     writex(buf, size);
461     }
462    
463     /**
464     * Get file status in a portable way.
465     * @param s structure that receives the file status
466     */
467     void File::pstat(pstat_t &s) const
468     {
469     s.caps = 0;
470     }
471    
472     /**
473     * Set current file pointer.
474     * @param offset new value for current file pointer
475     */
476     void File::seek(FileOfs offset)
477     {
478     throw NotImplementedException(HERE);
479     }
480    
481     /**
482     * Get current file pointer.
483     * @returns current file pointer
484     */
485     FileOfs File::tell() const
486     {
487     return 0;
488     }
489    
490     /**
491     * Truncate file.
492     * Truncate file to new size <i>newsize</i>.
493     * The current file pointer is undefined (but valid) after this operation.
494     *
495     * @param newsize new truncated file size
496     * @throws IOException
497     */
498     void File::truncate(FileOfs newsize)
499     {
500     if (getSize() < newsize) throw IOException(EINVAL);
501     if (getSize() == newsize) return;
502    
503     throw NotImplementedException(HERE);
504     }
505    
506     /**
507     * Vararg wrapper for cntl()
508     */
509     int File::vcntl(uint cmd, va_list vargs)
510     {
511     switch (cmd) {
512     case FCNTL_GET_MOD_COUNT: { // int &mcount
513     int *mc = va_arg(vargs, int *);
514     *mc = mcount;
515     return 0;
516     }
517     }
518     return ENOSYS;
519     }
520    
521     /*
522     * FileLayer
523     */
524     FileLayer::FileLayer(File *f, bool own_f) : File()
525     {
526     mFile = f;
527     mOwnFile = own_f;
528     }
529    
530     FileLayer::~FileLayer()
531     {
532     if (mOwnFile) delete mFile;
533     }
534    
535     void FileLayer::del(uint size)
536     {
537     return mFile->del(size);
538     }
539    
540     void FileLayer::extend(FileOfs newsize)
541     {
542     return mFile->extend(newsize);
543     }
544    
545     IOAccessMode FileLayer::getAccessMode() const
546     {
547     return mFile->getAccessMode();
548     }
549    
550     String &FileLayer::getDesc(String &result) const
551     {
552     return mFile->getDesc(result);
553     }
554    
555     String &FileLayer::getFilename(String &result) const
556     {
557     return mFile->getFilename(result);
558     }
559    
560     FileOfs FileLayer::getSize() const
561     {
562     return mFile->getSize();
563     }
564    
565     void FileLayer::insert(const void *buf, uint size)
566     {
567     return mFile->insert(buf, size);
568     }
569    
570     void FileLayer::pstat(pstat_t &s) const
571     {
572     return mFile->pstat(s);
573     }
574    
575     uint FileLayer::read(void *buf, uint size)
576     {
577     return mFile->read(buf, size);
578     }
579    
580     void FileLayer::seek(FileOfs offset)
581     {
582     return mFile->seek(offset);
583     }
584    
585     int FileLayer::setAccessMode(IOAccessMode mode)
586     {
587     return mFile->setAccessMode(mode);
588     }
589    
590     File *FileLayer::getLayered() const
591     {
592     return mFile;
593     }
594    
595     void FileLayer::setLayered(File *newLayered, bool ownNewLayered)
596     {
597     mFile = newLayered;
598     mOwnFile = ownNewLayered;
599     }
600    
601     FileOfs FileLayer::tell() const
602     {
603     return mFile->tell();
604     }
605    
606     void FileLayer::truncate(FileOfs newsize)
607     {
608     return mFile->truncate(newsize);
609     }
610    
611     int FileLayer::vcntl(uint cmd, va_list vargs)
612     {
613     return mFile->vcntl(cmd, vargs);
614     }
615    
616     uint FileLayer::write(const void *buf, uint size)
617     {
618     return mFile->write(buf, size);
619     }
620    
621     #if 0
622     /*
623     * LocalFileFD
624     */
625    
626     /**
627     * create open file
628     */
629     LocalFileFD::LocalFileFD(const String &aFilename, IOAccessMode am, FileOpenMode om)
630     : File(), mFilename(aFilename)
631     {
632     mOpenMode = om;
633     fd = -1;
634     own_fd = false;
635     int e = setAccessMode(am);
636     if (e) throw IOException(e);
637     mOpenMode = FOM_EXISTS;
638     }
639    
640     /**
641     * map a file descriptor [fd]
642     */
643     LocalFileFD::LocalFileFD(int f, bool own_f, IOAccessMode am)
644     : File()
645     {
646     mFilename = NULL;
647     fd = f;
648     own_fd = own_f;
649     offset = 0;
650     int e = File::setAccessMode(am);
651     if (e) throw IOException(e);
652     }
653    
654     LocalFileFD::~LocalFileFD()
655     {
656     if (own_fd && (fd>=0)) ::close(fd);
657     }
658    
659     String &LocalFileFD::getDesc(String &result) const
660     {
661     result = mFilename;
662     return result;
663     }
664    
665     String &LocalFileFD::getFilename(String &result) const
666     {
667     result = mFilename;
668     return result;
669     }
670    
671     FileOfs LocalFileFD::getSize() const
672     {
673     uint t = tell();
674     uint r = ::lseek(fd, 0, SEEK_END);
675     lseek(fd, t, SEEK_SET);
676     return r;
677     }
678    
679     uint LocalFileFD::read(void *buf, uint size)
680     {
681     if (!(getAccessMode() & IOAM_READ)) throw IOException(EACCES);
682     errno = 0;
683     uint r = ::read(fd, buf, size);
684     int e = errno;
685     if (e) {
686     off_t r = ::lseek(fd, 0, SEEK_SET);
687     offset = r;
688     if (e != EAGAIN) throw IOException(e);
689     return 0;
690     } else {
691     offset += r;
692     return r;
693     }
694     }
695    
696     void LocalFileFD::seek(FileOfs o)
697     {
698     if (o == offset) return;
699     off_t r = ::lseek(fd, o, SEEK_SET);
700     offset = r;
701     if (offset != o) throw IOException(EIO);
702     }
703    
704     int LocalFileFD::setAccessMode(IOAccessMode am)
705     {
706     IOAccessMode orig_access_mode = getAccessMode();
707     int e = setAccessModeInternal(am);
708     if (e && setAccessModeInternal(orig_access_mode))
709     throw IOException(e);
710     return e;
711     }
712    
713     int LocalFileFD::setAccessModeInternal(IOAccessMode am)
714     {
715     //RETRY:
716     if (getAccessMode() == am) return 0;
717     if (fd >= 0) {
718     // must own fd to change its access mode cause we can't
719     // reopen a fd. right ?
720     if (!own_fd) throw NotImplementedException(HERE);
721     // FIXME: race condition here, how to reopen a fd atomically ?
722     close(fd);
723     fd = -1;
724     }
725     File::setAccessMode(IOAM_NULL);
726    
727     int mode = 0;
728    
729     if ((am & IOAM_READ) && (am & IOAM_WRITE)) mode = O_RDWR;
730     else if (am & IOAM_READ) mode = O_RDONLY;
731     else if (am & IOAM_WRITE) mode = O_WRONLY;
732    
733     // mode |= O_BINARY;
734    
735     switch (mOpenMode) {
736     case FOM_APPEND:
737     mode |= O_APPEND;
738     break;
739     case FOM_CREATE:
740     mode |= O_CREAT | O_TRUNC;
741     break;
742     case FOM_EXISTS:
743     ;
744     }
745    
746     int e = 0;
747     if (am != IOAM_NULL) {
748     pstat_t s;
749     fd = ::open(mFilename, mode);
750     if (fd < 0) e = errno;
751     if (!e) {
752     own_fd = true;
753     e = sys_pstat_fd(s, fd);
754     if (!e) {
755     if (HT_S_ISDIR(s.mode)) {
756     e = EISDIR;
757     } else if (!HT_S_ISREG(s.mode) && !HT_S_ISBLK(s.mode)) {
758     e = EINVAL;
759     }
760     }
761     }
762     }
763     return e ? e : File::setAccessMode(am);
764     }
765    
766     FileOfs LocalFileFD::tell() const
767     {
768     return offset;
769     }
770    
771     void LocalFileFD::truncate(FileOfs newsize)
772     {
773     errno = 0;
774     int e = sys_truncate_fd(fd, newsize);
775     if (errno) e = errno;
776     if (e) throw IOException(e);
777     }
778    
779     int LocalFileFD::vcntl(uint cmd, va_list vargs)
780     {
781     switch (cmd) {
782     case FCNTL_FLUSH_STAT: {
783     IOAccessMode m = getAccessMode();
784     int e, f;
785     e = setAccessMode(IOAM_NULL);
786     f = setAccessMode(m);
787     return e ? e : f;
788     }
789     case FCNTL_GET_FD: { // (int &fd)
790     int *pfd = va_arg(vargs, int*);
791     *pfd = fd;
792     return 0;
793     }
794     }
795     return File::vcntl(cmd, vargs);
796     }
797    
798     uint LocalFileFD::write(const void *buf, uint size)
799     {
800     if (!(getAccessMode() & IOAM_WRITE)) throw IOException(EACCES);
801     errno = 0;
802     uint r = ::write(fd, buf, size);
803     int e = errno;
804     if (e) {
805     off_t r = ::lseek(fd, 0, SEEK_SET);
806     offset = r;
807     if (e != EAGAIN) throw IOException(e);
808     return 0;
809     } else {
810     offset += r;
811     return r;
812     }
813     }
814     #endif
815    
816     /*
817     * StdIoFile
818     */
819    
820     /**
821     * create open file
822     */
823     LocalFile::LocalFile(const String &aFilename, IOAccessMode am, FileOpenMode om)
824     : File(), mFilename(aFilename)
825     {
826     mOpenMode = om;
827     file = NULL;
828     own_file = false;
829     offset = 0;
830     int e = setAccessMode(am);
831     if (e) throw IOException(e);
832     mOpenMode = FOM_EXISTS;
833     }
834    
835     /**
836     * map a file stream [FILE*]
837     */
838     LocalFile::LocalFile(FILE *f, bool own_f, IOAccessMode am)
839     : File()
840     {
841     mFilename = NULL;
842     file = f;
843     own_file = own_f;
844     int e = LocalFile::setAccessMode(am);
845     if (e) throw IOException(e);
846     }
847    
848     LocalFile::~LocalFile()
849     {
850     if (own_file && file) fclose(file);
851     }
852    
853     String &LocalFile::getDesc(String &result) const
854     {
855     result = mFilename;
856     return result;
857     }
858    
859     String &LocalFile::getFilename(String &result) const
860     {
861     result = mFilename;
862     return result;
863     }
864    
865     FileOfs LocalFile::getSize() const
866     {
867     int t = tell();
868     fseek(file, 0, SEEK_END);
869     int r = ftell(file);
870     fseek(file, t, SEEK_SET);
871     return r;
872     }
873    
874     void LocalFile::pstat(pstat_t &s) const
875     {
876     sys_pstat(s, mFilename.contentChar());
877     }
878    
879     uint LocalFile::read(void *buf, uint size)
880     {
881     if (!(getAccessMode() & IOAM_READ)) throw IOException(EACCES);
882     errno = 0;
883     uint r = fread(buf, 1, size, file);
884     if (errno) throw IOException(errno);
885     offset += r;
886     return r;
887     }
888    
889     void LocalFile::seek(FileOfs o)
890     {
891     if (o == offset) return;
892     int e = fseek(file, o, SEEK_SET);
893     if (e) throw IOException(e);
894     offset = o; // unreliable for DJGPP
895     }
896    
897     int LocalFile::setAccessMode(IOAccessMode am)
898     {
899     IOAccessMode orig_access_mode = getAccessMode();
900     int e = setAccessModeInternal(am);
901     if (e && setAccessModeInternal(orig_access_mode))
902     throw IOException(e);
903     return e;
904     }
905    
906     int LocalFile::setAccessModeInternal(IOAccessMode am)
907     {
908     //RETRY:
909     if (getAccessMode() == am) return 0;
910     char *mode = NULL;
911    
912     switch (mOpenMode) {
913     case FOM_APPEND:
914     mode = "ab+";
915     break;
916     case FOM_CREATE:
917     if (am & IOAM_WRITE) mode = "wb";
918     if (am & IOAM_READ) mode = "wb+";
919     break;
920     case FOM_EXISTS:
921     if (am & IOAM_READ) mode = "rb";
922     if (am & IOAM_WRITE) mode = "rb+";
923     break;
924     }
925    
926     int e = 0;
927     if (am != IOAM_NULL) {
928     pstat_t s;
929     if (file) {
930     file = freopen(mFilename.contentChar(), mode, file);
931     if (!file) setAccessMode(IOAM_NULL);
932     } else {
933     file = fopen(mFilename.contentChar(), mode);
934     }
935     if (!file) e = errno;
936     if (!e) {
937     own_file = true;
938     e = sys_pstat_fd(s, fileno(file));
939     if (!e) {
940     if (HT_S_ISDIR(s.mode)) {
941     e = EISDIR;
942     } else if (!HT_S_ISREG(s.mode) && !HT_S_ISBLK(s.mode)) {
943     e = EINVAL;
944     }
945     }
946     }
947     }
948     return e ? e : File::setAccessMode(am);
949     }
950    
951     FileOfs LocalFile::tell() const
952     {
953     return offset;
954     }
955    
956     void LocalFile::truncate(FileOfs newsize)
957     {
958     errno = 0;
959    
960     IOAccessMode old_am = getAccessMode();
961     int e;
962     e = setAccessMode(IOAM_NULL);
963     if (!e) {
964     e = sys_truncate(mFilename.contentChar(), newsize);
965     if (errno) e = errno;
966     }
967     if (!e) e = setAccessMode(old_am);
968     if (e) throw IOException(e);
969     }
970    
971     int LocalFile::vcntl(uint cmd, va_list vargs)
972     {
973     switch (cmd) {
974     case FCNTL_FLUSH_STAT: {
975     IOAccessMode m = getAccessMode();
976     int e, f;
977     e = setAccessMode(IOAM_NULL);
978     f = setAccessMode(m);
979     return e ? e : f;
980     }
981     case FCNTL_GET_FD: { // (int &fd)
982     if (file) {
983     int *pfd = va_arg(vargs, int*);
984     *pfd = fileno(file);
985     return 0;
986     }
987     break;
988     }
989     }
990     return File::vcntl(cmd, vargs);
991     }
992    
993     uint LocalFile::write(const void *buf, uint size)
994     {
995     if (!(getAccessMode() & IOAM_WRITE)) throw IOException(EACCES);
996     errno = 0;
997     uint r = fwrite(buf, 1, size, file);
998     if (errno) throw IOException(errno);
999     offset += r;
1000     return r;
1001     }
1002    
1003     /*
1004     * TempFile
1005     */
1006     TempFile::TempFile(uint am) : LocalFile(tmpfile(), true, am)
1007     {
1008     }
1009    
1010     String &TempFile::getDesc(String &result) const
1011     {
1012     result = "temporary file";
1013     return result;
1014     }
1015    
1016     void TempFile::pstat(pstat_t &s) const
1017     {
1018     s.caps = pstat_size;
1019     s.size = getSize();
1020     }
1021    
1022     /*
1023     * MemMapFile
1024     */
1025     MemMapFile::MemMapFile(void *b, uint s) : ConstMemMapFile(b, s)
1026     {
1027     }
1028    
1029     uint MemMapFile::write(const void *b, uint size)
1030     {
1031     if (pos > this->size) return 0; // or throw exception?
1032     if (pos+size > this->size) size = this->size - pos;
1033     memmove(((byte*)buf)+pos, b, size);
1034     pos += size;
1035     return size;
1036     }
1037    
1038     /*
1039     * ConstMemMapFile
1040     */
1041     ConstMemMapFile::ConstMemMapFile(const void *b, uint s)
1042     : File()
1043     {
1044     buf = b;
1045     pos = 0;
1046     size = s;
1047     }
1048    
1049     String &ConstMemMapFile::getDesc(String &result) const
1050     {
1051     result = "MemMapFile";
1052     return result;
1053     }
1054    
1055     FileOfs ConstMemMapFile::getSize() const
1056     {
1057     return size;
1058     }
1059    
1060     uint ConstMemMapFile::read(void *b, uint size)
1061     {
1062     if (pos > this->size) return 0;
1063     if (pos+size > this->size) size = this->size - pos;
1064     memmove(b, (const byte*)buf+pos, size);
1065     pos += size;
1066     return size;
1067     }
1068    
1069     void ConstMemMapFile::seek(FileOfs offset)
1070     {
1071     pos = offset;
1072     }
1073    
1074     FileOfs ConstMemMapFile::tell() const
1075     {
1076     return pos;
1077     }
1078    
1079     /*
1080     * A file layer, representing a cropped version of a file
1081     */
1082     CroppedFile::CroppedFile(File *file, bool own_file, FileOfs aCropStart, FileOfs aCropSize)
1083     : FileLayer(file, own_file)
1084     {
1085     mCropStart = aCropStart;
1086     mHasCropSize = true;
1087     mCropSize = aCropSize;
1088     seek(0);
1089     }
1090    
1091     CroppedFile::CroppedFile(File *file, bool own_file, FileOfs aCropStart)
1092     : FileLayer(file, own_file)
1093     {
1094     mCropStart = aCropStart;
1095     mHasCropSize = false;
1096     seek(0);
1097     }
1098    
1099     void CroppedFile::extend(FileOfs newsize)
1100     {
1101     throw IOException(ENOSYS);
1102     }
1103    
1104     String &CroppedFile::getDesc(String &result) const
1105     {
1106     String s;
1107     if (mHasCropSize) {
1108     result.assignFormat("[->0x%qx,0x%qx] of %y", mCropStart, mCropSize, &FileLayer::getDesc(s));
1109     } else {
1110     result.assignFormat("[->0x%qx] of %y", mCropStart, &FileLayer::getDesc(s));
1111     }
1112     return result;
1113     }
1114    
1115     FileOfs CroppedFile::getSize() const
1116     {
1117     FileOfs lsize = FileLayer::getSize();
1118     if (lsize < mCropStart) return 0;
1119     lsize -= mCropStart;
1120     if (mHasCropSize) {
1121     if (lsize > mCropSize) lsize = mCropSize;
1122     }
1123     return lsize;
1124     }
1125    
1126     void CroppedFile::pstat(pstat_t &s) const
1127     {
1128     FileLayer::pstat(s);
1129     if (s.caps & pstat_size) {
1130     s.size = getSize();
1131     }
1132     }
1133    
1134     uint CroppedFile::read(void *buf, uint size)
1135     {
1136     FileOfs offset = FileLayer::tell();
1137     if (offset<mCropStart) return 0;
1138     if (mHasCropSize) {
1139     if (offset >= mCropStart+mCropSize) return 0;
1140     if (offset+size >= mCropStart+mCropSize) size = mCropStart+mCropSize-offset;
1141     }
1142     // ht_printf("CroppedFile::read 0x%08x bytes @ 0x%08qx\n", size, offset);
1143     return FileLayer::read(buf, size);
1144     }
1145    
1146     void CroppedFile::seek(FileOfs offset)
1147     {
1148     /* if (mHasCropSize) {
1149     ...
1150     if (offset>mCropStart) throw IOException(EIO);
1151     }*/
1152     FileLayer::seek(offset+mCropStart);
1153     }
1154    
1155     FileOfs CroppedFile::tell() const
1156     {
1157     FileOfs offset = FileLayer::tell();
1158     if (offset<mCropStart) throw IOException(EIO);
1159     return offset - mCropStart;
1160     }
1161    
1162     void CroppedFile::truncate(FileOfs newsize)
1163     {
1164     // not implemented because not considered safe
1165     throw IOException(ENOSYS);
1166     }
1167    
1168     uint CroppedFile::write(const void *buf, uint size)
1169     {
1170     FileOfs offset = FileLayer::tell();
1171     if (offset<mCropStart) return 0;
1172     if (mHasCropSize) {
1173     if (offset >= mCropStart+mCropSize) return 0;
1174     if (offset+size >= mCropStart+mCropSize) size = mCropStart+mCropSize-offset;
1175     }
1176     return FileLayer::write(buf, size);
1177     }
1178    
1179     /*
1180     * NullFile
1181     */
1182     NullFile::NullFile() : File()
1183     {
1184     }
1185    
1186     void NullFile::extend(FileOfs newsize)
1187     {
1188     if (newsize!=0) throw IOException(EINVAL);
1189     }
1190    
1191     String &NullFile::getDesc(String &result) const
1192     {
1193     result = "null device";
1194     return result;
1195     }
1196    
1197     FileOfs NullFile::getSize() const
1198     {
1199     return 0;
1200     }
1201    
1202     void NullFile::pstat(pstat_t &s) const
1203     {
1204     s.caps = pstat_size;
1205     s.size = getSize();
1206     }
1207    
1208     uint NullFile::read(void *buf, uint size)
1209     {
1210     return 0;
1211     }
1212    
1213     void NullFile::seek(FileOfs offset)
1214     {
1215     if (offset!=0) throw IOException(EINVAL);
1216     }
1217    
1218     int NullFile::setAccessMode(IOAccessMode am)
1219     {
1220     return (am == getAccessMode()) ? 0 : EACCES;
1221     }
1222    
1223     FileOfs NullFile::tell() const
1224     {
1225     return 0;
1226     }
1227    
1228     void NullFile::truncate(FileOfs newsize)
1229     {
1230     if (newsize!=0) throw IOException(EINVAL);
1231     }
1232    
1233     uint NullFile::write(const void *buf, uint size)
1234     {
1235     return 0;
1236     }
1237    
1238     /*
1239     * MemoryFile
1240     */
1241    
1242     #define MEMORYFILE_GROW_FACTOR_NUM 4
1243     #define MEMORYFILE_GROW_FACTOR_DENOM 3
1244     #define MEMORYFILE_MIN_BUFSIZE 32
1245    
1246     MemoryFile::MemoryFile(FileOfs o, uint size, IOAccessMode mode) : File()
1247     {
1248     ofs = o;
1249     dsize = size;
1250     buf = NULL;
1251     ibufsize = size;
1252     if (ibufsize < MEMORYFILE_MIN_BUFSIZE) ibufsize = MEMORYFILE_MIN_BUFSIZE;
1253     resizeBuf(ibufsize);
1254     memset(buf, 0, dsize);
1255     mcount = 0;
1256    
1257     pos = 0;
1258     int e = setAccessMode(mode);
1259     if (e) throw IOException(e);
1260     }
1261    
1262     MemoryFile::~MemoryFile()
1263     {
1264     free(buf);
1265     }
1266    
1267     byte *MemoryFile::getBufPtr() const
1268     {
1269     return buf;
1270     }
1271    
1272     void MemoryFile::extend(FileOfs newsize)
1273     {
1274     // MemoryFiles may not be > 2G
1275     if (newsize > 0x7fffffff) throw IOException(EINVAL);
1276     if (newsize < getSize()) throw IOException(EINVAL);
1277     if (newsize == getSize()) return;
1278     while (bufsize<newsize) extendBuf();
1279     memset(buf+dsize, 0, newsize-dsize);
1280     dsize = newsize;
1281     mcount++;
1282     }
1283    
1284     void MemoryFile::extendBuf()
1285     {
1286     resizeBuf(extendBufSize(bufsize));
1287     }
1288    
1289     uint MemoryFile::extendBufSize(uint bufsize)
1290     {
1291     return bufsize * MEMORYFILE_GROW_FACTOR_NUM / MEMORYFILE_GROW_FACTOR_DENOM;
1292     }
1293    
1294     IOAccessMode MemoryFile::getAccessMode() const
1295     {
1296     return Stream::getAccessMode();
1297     }
1298    
1299     String &MemoryFile::getDesc(String &result) const
1300     {
1301     result = "MemoryFile";
1302     return result;
1303     }
1304    
1305     FileOfs MemoryFile::getSize() const
1306     {
1307     return dsize;
1308     }
1309    
1310     void MemoryFile::pstat(pstat_t &s) const
1311     {
1312     s.caps = pstat_size;
1313     s.size = getSize();
1314     }
1315    
1316     uint MemoryFile::read(void *b, uint size)
1317     {
1318     if ((pos+size) > dsize) {
1319     if (pos >= dsize) return 0;
1320     size = dsize-pos;
1321     }
1322     memcpy(b, buf+pos, size);
1323     pos += size;
1324     return size;
1325     }
1326    
1327     void MemoryFile::resizeBuf(uint newsize)
1328     {
1329     bufsize = newsize;
1330    
1331     ASSERT(dsize <= bufsize);
1332    
1333     buf = (byte*)realloc(buf, bufsize ? bufsize : 1);
1334     if (!buf) throw std::bad_alloc();
1335     }
1336    
1337     void MemoryFile::seek(FileOfs o)
1338     {
1339     if (o<ofs) throw IOException(EINVAL);
1340     pos = o-ofs;
1341     }
1342    
1343     int MemoryFile::setAccessMode(IOAccessMode mode)
1344     {
1345     int e = Stream::setAccessMode(mode);
1346     if (e) return e;
1347     seek(ofs);
1348     return 0;
1349     }
1350    
1351     uint MemoryFile::shrinkBufSize(uint bufsize)
1352     {
1353     return bufsize * MEMORYFILE_GROW_FACTOR_DENOM / MEMORYFILE_GROW_FACTOR_NUM;
1354     }
1355    
1356     void MemoryFile::shrinkBuf()
1357     {
1358     resizeBuf(shrinkBufSize(bufsize));
1359     }
1360    
1361     FileOfs MemoryFile::tell() const
1362     {
1363     return pos+ofs;
1364     }
1365    
1366     void MemoryFile::truncate(FileOfs newsize)
1367     {
1368     dsize = newsize;
1369    
1370     uint s = ibufsize;
1371     while (s<dsize) s = extendBufSize(s);
1372    
1373     resizeBuf(s);
1374     mcount++;
1375     }
1376    
1377     uint MemoryFile::write(const void *b, uint size)
1378     {
1379     while (pos+size >= bufsize) extendBuf();
1380     memmove(((byte*)buf)+pos, b, size);
1381     pos += size;
1382     if (pos>dsize) dsize = pos;
1383     mcount++;
1384     return size;
1385     }
1386    
1387     /*
1388     * string stream functions
1389     */
1390    
1391     char *fgetstrz(File *file)
1392     {
1393     FileOfs o = file->tell();
1394     /* get string size */
1395     char buf[64];
1396     int s, z = 0;
1397     bool found = false;
1398     while (!found) {
1399     s = file->read(buf, 64);
1400     for (int i=0; i<s; i++) {
1401     z++;
1402     if (buf[i] == 0) {
1403     found = true;
1404     break;
1405     }
1406     }
1407     }
1408     /* read string */
1409     char *str = (char*)malloc(z);
1410     if (!str) throw std::bad_alloc();
1411     file->seek(o);
1412     file->readx(str, z);
1413     return str;
1414     }
1415    
1416     // FIXME: more dynamical solution appreciated
1417     #define REASONABLE_STRING_LIMIT 1024
1418    
1419     char *getstrz(Stream *stream)
1420     {
1421     /* get string size */
1422     char buf[REASONABLE_STRING_LIMIT];
1423     int z = 0;
1424     while (1) {
1425     stream->readx(buf+z, 1);
1426     z++;
1427     if (z >= REASONABLE_STRING_LIMIT) {
1428     z = REASONABLE_STRING_LIMIT;
1429     break;
1430     }
1431     if (buf[z-1] == 0) break;
1432     }
1433     if (!z) return NULL;
1434     char *str = (char*)malloc(z);
1435     if (!str) throw std::bad_alloc();
1436     memmove(str, buf, z-1);
1437     str[z-1] = 0;
1438     return str;
1439     }
1440    
1441     void putstrz(Stream *stream, const char *str)
1442     {
1443     stream->writex(str, strlen(str)+1);
1444     }
1445    
1446     char *getstrp(Stream *stream)
1447     {
1448     unsigned char l;
1449     stream->readx(&l, 1);
1450     char *str = (char*)malloc(l+1);
1451     if (!str) throw std::bad_alloc();
1452     stream->readx(str, l);
1453     *(str+l) = 0;
1454     return str;
1455     }
1456    
1457     void putstrp(Stream *stream, const char *str)
1458     {
1459     unsigned char l = strlen(str);
1460     stream->writex(&l, 1);
1461     stream->writex(str, l);
1462     }
1463    
1464     char *getstrw(Stream *stream)
1465     {
1466     short t;
1467     byte lbuf[2];
1468     stream->readx(lbuf, 2);
1469     int l = lbuf[0] | lbuf[1] << 8;
1470     char *a = (char*)malloc(l+1);
1471     if (!a) throw std::bad_alloc();
1472     for (int i=0; i<l; i++) {
1473     stream->readx(&t, 2);
1474     a[i] = (char)t;
1475     }
1476     a[l] = 0;
1477     return a;
1478     }
1479    
1480     void putstrw(Stream *stream, const char *str)
1481     {
1482     /* FIXME: someone implement me ? */
1483     throw NotImplementedException(HERE);
1484     }
1485    

  ViewVC Help
Powered by ViewVC 1.1.26