Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

FdStream.C

Go to the documentation of this file.
00001 // Copyright (C) 2004, Kenneth C. Schalk
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 #include <assert.h>
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <fcntl.h>
00023 #include <unistd.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <errno.h>
00027 
00028 #include <Basics.H>
00029 #include "FdStream.H"
00030 
00031 // ==================== FS::FdStreambuf ====================
00032 
00033 // ---------- private members ----------
00034 
00035 bool FS::FdStreambuf::get_pos_to_fd_pos()
00036 {
00037   // If there's a get area, we need to figure out the exact stream
00038   // position and seek the file descriptor to that file position.
00039   if(gptr() && (gptr() < egptr()))
00040     {
00041       long int unread_count = (egptr() - gptr());
00042       off_t seek_res;
00043       do
00044         seek_res = lseek(this->_fd, -unread_count, SEEK_CUR);
00045       while((seek_res == ((off_t)-1)) && (errno == EINTR));
00046 
00047       // Seek failed: error.
00048       if (seek_res < 0)
00049         return false;
00050     }
00051 
00052   // Reset the get area.
00053   setg(0,0,0);
00054 
00055   return true;
00056 }
00057 
00058 // ---------- constructors/destructor ----------
00059 
00060 FS::FdStreambuf::FdStreambuf(int fd)
00061   : _fd(-1), should_close(false), buffer(0), buf_size(0)
00062 {
00063   this->attach(fd);
00064 }
00065 
00066 FS::FdStreambuf::FdStreambuf(const char *filename, stream_mode_t mode,
00067                              mode_t prot,
00068                              bool create, bool replace)
00069   : _fd(-1), should_close(false), buffer(0), buf_size(0)
00070 {
00071   this->open(filename, mode, prot, create, replace);
00072 }
00073 
00074 FS::FdStreambuf::~FdStreambuf()
00075 {
00076   (void) this->close();
00077 
00078   // Free the buffer if we've allocated it.
00079   if(buffer)
00080     delete [] buffer;
00081 }
00082 
00083 // ---------- public members ----------
00084 
00085 FS::FdStreambuf* FS::FdStreambuf::attach(int fd)
00086 {
00087   // Don't overwrite existing fd
00088   if(is_open())
00089     return NULL;
00090   this->_fd = fd;
00091   this->should_close = false;
00092   // Check whether this is a valid fd with lseek
00093   off_t seek_res;
00094   do
00095     seek_res = lseek(this->_fd, 0, SEEK_CUR);
00096   while((seek_res == ((off_t)-1)) && (errno == EINTR));
00097   if(seek_res == ((off_t)-1))
00098     {
00099       this->_fd = -1;
00100       return 0;
00101     }
00102   // Assume read/write.
00103   this->mode = std::ios::in|std::ios::out;
00104   // OK, we're attached
00105   return this;
00106 }
00107 
00108 FS::FdStreambuf* FS::FdStreambuf::open(const char *filename,
00109                                        stream_mode_t mode,
00110                                        mode_t prot,
00111                                        bool create, bool replace)
00112 {
00113   // Determine whether we're opening for read, write, or read/write.
00114   int openflag;
00115   if((mode & std::ios::in) && (mode & std::ios::out))
00116     openflag = O_RDWR;
00117   else if(mode & std::ios::in)
00118     openflag = O_RDONLY;
00119   else if(mode & std::ios::out)
00120     openflag = O_WRONLY;
00121   else
00122     // Bogus mode: fail
00123     return 0;
00124 
00125   // Additional flags for the open(2) syscall.
00126   if(create)
00127     openflag |= O_CREAT;
00128   if(!replace)
00129     openflag |= O_EXCL;
00130   if(mode & std::ios::trunc)
00131     openflag |= O_TRUNC;
00132   if(mode & std::ios::app)
00133     openflag |= O_APPEND;
00134     
00135   // Open the file
00136   do
00137     this->_fd = ::open(filename, openflag, prot);
00138   while((this->_fd < 0) && (errno == EINTR));
00139   if(this->_fd < 0)
00140     return 0;
00141   else
00142     // We opened it, so we should close it.
00143     this->should_close = true;
00144 
00145   // Save the mode we used to open the file.
00146   this->mode = mode;
00147 
00148   // Seek to the end if that was requested.
00149   if(mode & std::ios::ate)
00150     {
00151       off_t seek_res;
00152       do
00153         seek_res = lseek(this->_fd, 0, SEEK_END);
00154       while((seek_res == ((off_t)-1)) && (errno == EINTR));
00155       if(seek_res == ((off_t)-1))
00156         return 0;
00157     }
00158 
00159   // All is well.
00160   return this;
00161 }
00162 
00163 FS::FdStreambuf* FS::FdStreambuf::close()
00164 {
00165   // If we have an open file descriptor.
00166   if(is_open())
00167     {
00168       // Flush buffered data.
00169       sync();
00170       // Close the file descriptor if we're supposed to.
00171       if(should_close)
00172         {
00173           // Loop on EINTR
00174           int close_res;
00175           do
00176             close_res = ::close(this->_fd);
00177           while((close_res != 0) && (errno == EINTR));
00178           // Indicate any other errors to the caller
00179           if(close_res != 0)
00180             return 0;
00181         }
00182       // Reset the file descriptor.
00183       this->_fd = -1;
00184 
00185       return this;
00186     }
00187 
00188   return 0;
00189 }
00190 
00191 FS::FdStreambuf::stream_pos_t FS::FdStreambuf::seekoff(stream_off_t offset,
00192                                                        stream_seek_t way,
00193                                                        // NOTE: mode ignored!
00194                                                        stream_mode_t mode)
00195 {
00196   // Flush any bytes waiting to be written.
00197   if(pptr() && (pptr() > pbase()))
00198     {
00199       // If overflow fails, indicate failure to the caller.
00200       if(overflow() == EOF)
00201         return ((stream_pos_t)-1);
00202     }
00203   // If there's a partially-read get area, seek the file descriptor
00204   // position to the logical get position.
00205   else if(!get_pos_to_fd_pos())
00206     return ((stream_pos_t)-1);
00207 
00208   // Reset the get and put areas before seeking.
00209   setg(0,0,0);
00210   setp(0,0);
00211 
00212   // Convert the seek type.
00213   int whence = SEEK_END;
00214   if(way == std::ios::beg)
00215     whence = SEEK_SET;
00216   else if(way == std::ios::cur)
00217     whence = SEEK_CUR;
00218 
00219   // Loop on EINTR
00220   off_t result;
00221   do
00222     result = lseek(this->_fd, offset, whence);
00223   while((result == ((off_t)-1)) && (errno == EINTR));
00224 
00225   if (result < 0)
00226     return ((stream_pos_t)-1);
00227 
00228   return result;
00229 }
00230 
00231 FS::FdStreambuf::stream_pos_t FS::FdStreambuf::seekpos(stream_pos_t pos, 
00232                                                        // NOTE: mode ignored!
00233                                                        stream_mode_t mode)
00234 {
00235   return this->seekoff(pos, std::ios::beg, mode);
00236 }
00237 
00238 // ---------- protected members ----------
00239 
00240 int FS::FdStreambuf::underflow()
00241 {
00242   // No good if we're not in input mode or don't have a valid file
00243   // descriptor.
00244   if(!(mode & std::ios::in))
00245     return EOF;
00246   if(!is_open())
00247     return EOF;
00248 
00249   // Flush any bytes waiting to be written.
00250   if(pptr() && (pptr() > pbase()))
00251     return overflow();
00252 
00253   // Reset the put area while we're reading.
00254   assert(pptr() == pbase());
00255   setp(0,0);
00256 
00257   // Allocate space if neccessary
00258   if(buffer == 0)
00259     {
00260       buf_size = BUFSIZ;
00261       buffer = NEW_PTRFREE_ARRAY(char, buf_size);
00262     }
00263 
00264   int read_count;
00265   do
00266     read_count = ::read(this->_fd, buffer, buf_size);
00267   while((read_count == -1) && (errno == EINTR));
00268   if(read_count < 1)
00269     {
00270       // Error or end-of-file: reset the get area and indicate a
00271       // failure to read more bytes to the caller.
00272       setg(0,0,0);
00273       return EOF;
00274     }
00275 
00276   // Set the get area to the bytes we read.
00277   assert(read_count <= buf_size);
00278   setg(buffer, buffer, buffer+read_count);
00279 
00280   // Return the first character of the get area.
00281   return ((*eback())&0x00ff);
00282 }
00283 
00284 std::streamsize FS::FdStreambuf::xsgetn(char* s, std::streamsize n)
00285 {
00286   std::streamsize result = 0;
00287     
00288   // If there's a get area with some uncomsumed bytes, take from that
00289   // first.
00290   if(gptr() && (gptr() < egptr()))
00291     {
00292       unsigned int unread_count = (egptr() - gptr());
00293 
00294       unsigned int use_count = (unread_count < n) ? unread_count : n;
00295 
00296       memcpy(s, gptr(), use_count);
00297         
00298       gbump(use_count);
00299       result += use_count;
00300       s += use_count;
00301     }
00302 
00303   // Not enough from the get area?  Read straight from the file
00304   // descriptor.
00305   if(result < n)
00306     {
00307       int read_count;
00308       do
00309         read_count = ::read(this->_fd, s, n-result);
00310       while((read_count == -1) && (errno == EINTR));
00311       if(read_count >= 0)
00312         {
00313           result += read_count;
00314         }
00315     }
00316 
00317   return result;
00318 }
00319 
00320 int FS::FdStreambuf::overflow(int c)
00321 {
00322   // No good if we're not in output mode or don't have a valid file
00323   // descriptor.
00324   if(!(mode & std::ios::out))
00325     return EOF;
00326   if(!is_open())
00327     return EOF;
00328 
00329   // Before writing, seek to the correct position and reset the get
00330   // area.
00331   if(!get_pos_to_fd_pos())
00332     return EOF;
00333 
00334   // Make sure we have a put area.
00335   if(!pptr())
00336     {
00337       // Allocate space if neccessary
00338       if(buffer == 0)
00339         {
00340           buf_size = BUFSIZ;
00341           buffer = NEW_PTRFREE_ARRAY(char, buf_size);
00342         }
00343 
00344       // Set the put area.  We leave one byte extra to handle the
00345       // character passed into an overflow call.
00346       setp(buffer, buffer+(buf_size-1));
00347     }
00348   assert(pbase() == buffer);
00349 
00350   // Count the number of bytes currently in the put area.
00351   unsigned int count = pptr() - pbase();
00352   assert(count < buf_size);
00353 
00354   // If this was a real character being written (not just a request
00355   // that we flush), stick it in the put area before performing a
00356   // write.
00357   if(c != EOF)
00358     {
00359       *pptr() = c;
00360       count++;
00361     }
00362 
00363   if(count > 0)
00364     {
00365       // Write to the file descriptor.
00366       int written_count;
00367       do
00368         written_count = ::write(this->_fd, pbase(), count);
00369       while((written_count == -1) && (errno == EINTR));
00370 
00371       if(written_count < count)
00372         {
00373           setp(0,0);
00374           return EOF;
00375         }
00376 
00377       assert(written_count == count);
00378     }
00379 
00380   // Reset the put area (again leaving one extra byte).
00381   assert(buffer != 0);
00382   setp(buffer, buffer+(buf_size-1));
00383 
00384   // Indicate that everything is fine by returning the character
00385   // passed (converting an EOF into a non-EOF).
00386   return (c & 0x00ff);
00387 }
00388 
00389 std::streamsize FS::FdStreambuf::xsputn(const char* s, std::streamsize n)
00390 {
00391   // Handle degenrate case
00392   if(n < 1)
00393     return 0;
00394     
00395   // Allocate buffer if neccessary
00396   if(buffer == 0)
00397     {
00398       assert(pptr() == 0);
00399       buf_size = BUFSIZ;
00400       buffer = NEW_PTRFREE_ARRAY(char, buf_size);
00401 
00402       // Set the put area.  We leave one byte extra to handle the
00403       // character passed into an overflow call.
00404       setp(buffer, buffer+(buf_size-1));
00405     }
00406 
00407   // If we can fit this in the current put area, just stuff it in.
00408   if((pptr() != 0) &&
00409      (((pptr() - pbase()) + n) <= (buf_size - 1)))
00410     {
00411       memcpy(pptr(), s, n);
00412       pbump(n);
00413       return n;
00414     }
00415 
00416   // Too big to fit in the current buffer (or no buffer): overflow.
00417   // If overflow fails, indicate failure to the caller.
00418   if(overflow() == EOF)
00419     return -1;
00420 
00421   // If it would fit in the put area now that if it's empty,
00422   // copy it in.
00423   if(n <= (buf_size - 1))
00424     {
00425       memcpy(pptr(), s, n);
00426       pbump(n);
00427       return n;
00428     }
00429 
00430   // Too big to fit in the put area.  Write it directly to the
00431   // file descriptor.
00432   assert(n >= buf_size);
00433   assert(pptr() == pbase());
00434   int written_count;
00435   do
00436     written_count = ::write(this->_fd, s, n);
00437   while((written_count == -1) && (errno == EINTR));
00438 
00439   // If the write failed, reset the put area.
00440   if(written_count < n)
00441     {
00442       setp(0,0);
00443     }
00444 
00445   // Pass the result of the write(2) call up to the caller.
00446   return written_count;
00447 }
00448 
00449 int FS::FdStreambuf::sync()
00450 {
00451   // Flush any waiting output.
00452   if(pptr() && (pptr() > pbase()))
00453     // Return -1 on error, 0 on success.
00454     return (overflow() == EOF) ? -1 : 0;
00455 
00456   // Otherwise, there's nothing to do.
00457   return 0;
00458 }

Generated on Mon May 8 00:48:30 2006 for Vesta by  doxygen 1.4.2