"Fossies" - the Fresh Open Source Software Archive

Member "OpenSP-1.5.2/lib/PosixStorage.cxx" (21 Jul 2005, 17748 Bytes) of package /linux/misc/old/OpenSP-1.5.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "PosixStorage.cxx" see the Fossies "Dox" file reference documentation.

    1 // Copyright (c) 1994, 1995 James Clark
    2 // See the file COPYING for copying permission.
    3 
    4 #ifdef __GNUG__
    5 #pragma implementation
    6 #endif
    7 
    8 #include "splib.h"
    9 #include "PosixStorage.h"
   10 #include "RewindStorageObject.h"
   11 #include "StorageManager.h"
   12 #include "DescriptorManager.h"
   13 #include "MessageArg.h"
   14 #include "ErrnoMessageArg.h"
   15 #include "SearchResultMessageArg.h"
   16 #include "Message.h"
   17 #include "StringC.h"
   18 #include "StringOf.h"
   19 #include "CharsetInfo.h"
   20 #include "CodingSystem.h"
   21 #include "macros.h"
   22 #include "PosixStorageMessages.h"
   23 
   24 #include <sys/types.h>
   25 #include <stdio.h>
   26 #include <ctype.h>
   27 
   28 #ifdef SP_INCLUDE_IO_H
   29 #include <io.h>     // for open, fstat, lseek, read prototypes
   30 #endif
   31 
   32 #ifdef SP_INCLUDE_UNISTD_H
   33 #include <unistd.h>
   34 #endif
   35 
   36 #ifdef SP_INCLUDE_OSFCN_H
   37 #include <osfcn.h>
   38 #endif
   39 
   40 #include <fcntl.h>
   41 #include <sys/stat.h>
   42 #include <errno.h>
   43 #include <stddef.h>
   44 
   45 #ifndef S_ISREG
   46 #ifndef S_IFREG
   47 #define S_IFREG _S_IFREG
   48 #endif
   49 #ifndef S_IFMT
   50 #define S_IFMT _S_IFMT
   51 #endif
   52 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
   53 #endif /* not S_ISREG */
   54 
   55 #ifndef O_BINARY
   56 #define O_BINARY 0
   57 #endif
   58 
   59 #ifdef SP_WIDE_SYSTEM
   60 #include <windows.h>
   61 #endif
   62 
   63 #ifdef SP_NAMESPACE
   64 namespace SP_NAMESPACE {
   65 #endif
   66 
   67 #ifdef SP_WIDE_SYSTEM
   68 typedef wchar_t FChar;
   69 #else
   70 typedef char FChar;
   71 #endif
   72 
   73 class PosixBaseStorageObject : public RewindStorageObject {
   74 public:
   75   PosixBaseStorageObject(int fd, Boolean mayRewind);
   76   size_t getBlockSize() const;
   77 protected:
   78   enum { defaultBlockSize = 8192 };
   79   int fd_;
   80   PackedBoolean eof_;
   81 
   82   Boolean seekToStart(Messenger &);
   83   virtual Boolean seek(off_t, Messenger &) = 0;
   84   static int xclose(int fd);
   85 private:
   86   Boolean canSeek(int fd);
   87   off_t startOffset_;
   88 };
   89 
   90 PosixBaseStorageObject::PosixBaseStorageObject(int fd, Boolean mayRewind)
   91 : fd_(fd), eof_(0),
   92   RewindStorageObject(mayRewind, mayRewind && canSeek(fd))
   93 {
   94 }
   95 
   96 Boolean PosixBaseStorageObject::canSeek(int fd)
   97 {
   98   struct stat sb;
   99   if (fstat(fd, &sb) < 0 || !S_ISREG(sb.st_mode)
  100       || (startOffset_ = lseek(fd, off_t(0), SEEK_CUR)) < 0)
  101     return 0;
  102   else
  103     return 1;
  104 }
  105 
  106 Boolean PosixBaseStorageObject::seekToStart(Messenger &mgr)
  107 {
  108   eof_ = 0;
  109   return seek(startOffset_, mgr);
  110 }
  111 
  112 int PosixBaseStorageObject::xclose(int fd)
  113 {
  114   int ret;
  115   do {
  116     ret = ::close(fd);
  117   } while (ret < 0 && errno == EINTR);
  118   return ret;
  119 }
  120 
  121 class PosixStorageObject : public PosixBaseStorageObject, private DescriptorUser {
  122 public:
  123   PosixStorageObject(int fd,
  124              const StringC &,
  125              const String<FChar> &,
  126              Boolean mayRewind,
  127              DescriptorManager *);
  128   ~PosixStorageObject();
  129   Boolean read(char *buf, size_t bufSize, Messenger &mgr, size_t &nread);
  130   Boolean suspend();
  131   Boolean seek(off_t, Messenger &);
  132   void willNotRewind();
  133 private:
  134   void resume(Messenger &);
  135 
  136   PackedBoolean suspended_;
  137   off_t suspendPos_;
  138   const MessageType2 *suspendFailedMessage_;
  139   int suspendErrno_;
  140   StringC filename_;
  141   String<FChar> cfilename_;
  142 
  143   void systemError(Messenger &, const MessageType2 &, int);
  144 };
  145 
  146 inline int openFile(const FChar *s) {
  147 #ifdef SP_WIDE_SYSTEM
  148    int fd = _wopen(s, O_RDONLY|O_BINARY);
  149    if (fd < 0 && errno != ENOENT) {
  150      String<char> buf;
  151      int len = WideCharToMultiByte(CP_ACP, 0, s, -1, 0, 0, 0, 0);
  152      buf.resize(len + 1);
  153      WideCharToMultiByte(CP_ACP, 0, s, -1, buf.begin(), len, 0, 0);
  154      buf[len] = '\0';
  155      return ::open(buf.data(), O_RDONLY|O_BINARY);
  156    }
  157    return fd;
  158 #else
  159     return ::open(s, O_RDONLY|O_BINARY);
  160 #endif
  161   }
  162 
  163 PosixStorageManager::PosixStorageManager(const char *type,
  164                      const CharsetInfo *filenameCharset,
  165 #ifndef SP_WIDE_SYSTEM
  166                      const OutputCodingSystem *filenameCodingSystem,
  167 #endif
  168                      int maxFDs,
  169                      Boolean restrictFileReading)
  170 : IdStorageManager(filenameCharset),
  171   type_(type),
  172 #ifndef SP_WIDE_SYSTEM
  173   filenameCodingSystem_(filenameCodingSystem),
  174 #endif
  175   descriptorManager_(maxFDs),
  176   restrictFileReading_(restrictFileReading)
  177 {
  178   Char newline = idCharset()->execToDesc('\n');
  179   reString_.assign(&newline, 1);
  180 }
  181 
  182 const char *PosixStorageManager::type() const
  183 {
  184   return type_;
  185 }
  186 
  187 void PosixStorageManager::addSearchDir(const StringC &str)
  188 {
  189   searchDirs_.push_back(str);
  190 }
  191 
  192 Boolean PosixStorageManager::isSafe(const StringC &file) const
  193 {
  194   size_t i = 0;
  195   for (; i < file.size(); i++) {
  196     if (file[i] == '.' && i > 0 && file[i - 1] == '.') return 0;
  197     if (!(   (file[i] >= 'a' && file[i] <= 'z')
  198           || (file[i] >= 'A' && file[i] <= 'Z')
  199           || (file[i] >= '0' && file[i] <= '9')
  200           || file[i] == '/'
  201           || file[i] == '.'
  202           || file[i] == '-'
  203           || file[i] == '_'
  204 #ifdef SP_MSDOS_FILENAMES
  205           || file[i] == '\\'
  206           || file[i] == ':'
  207 #endif
  208        )) return 0;
  209   }
  210 
  211   const StringC &dir = extractDir(file);
  212 
  213   for (i = 0; i < searchDirs_.size(); i++) {
  214     const StringC &searchDir = searchDirs_[i];
  215 
  216     if (dir.size() >= searchDir.size()) {
  217       size_t j = 0;
  218       for (; j < searchDir.size(); j++) {
  219         if (searchDir[j] != dir[j]
  220 #ifdef SP_MSDOS_FILENAMES
  221         && ((searchDir[j] != '/' && dir[j] == '\\') ||
  222             (searchDir[j] != '\\' && dir[j] == '/'))
  223 #endif
  224         ) break;
  225       }
  226 
  227       if (j == searchDir.size() &&
  228            (dir.size() == searchDir.size() || dir[j] == '/'
  229 #ifdef SP_MSDOS_FILENAMES
  230                                            || dir[j] == '\\'
  231 #endif
  232            )) return 1;
  233     }
  234   }
  235 
  236   return 0;
  237 }
  238 
  239 #ifdef SP_POSIX_FILENAMES
  240 
  241 #define FILENAME_TYPE_DEFINED
  242 
  243 // FIXME should use idCharset.
  244 
  245 Boolean PosixStorageManager::isAbsolute(const StringC &file) const
  246 {
  247   return file.size() > 0 && file[0] == '/';
  248 }
  249 
  250 StringC PosixStorageManager::extractDir(const StringC &str) const
  251 {
  252   for (size_t i = str.size(); i > 0; i--)
  253     if (str[i - 1] == '/')
  254       return StringC(str.data(), i);    // include slash for root case
  255   return StringC();
  256 }
  257 
  258 StringC PosixStorageManager::combineDir(const StringC &dir,
  259                     const StringC &base) const
  260 {
  261   StringC result(dir);
  262   if (dir.size() > 0 && dir[dir.size() - 1] != '/')
  263     result += '/';
  264   result += base;
  265   return result;
  266 }
  267 
  268 Boolean PosixStorageManager::transformNeutral(StringC &str, Boolean fold,
  269                           Messenger &) const
  270 {
  271   if (fold)
  272     for (size_t i = 0; i < str.size(); i++) {
  273       Char c = str[i];
  274       if (c <= (unsigned char)-1)
  275     str[i] = tolower(str[i]);
  276     }
  277   return 1;
  278 }
  279 
  280 #endif /* SP_POSIX_FILENAMES */
  281 
  282 #ifdef SP_MSDOS_FILENAMES
  283 
  284 #define FILENAME_TYPE_DEFINED
  285 
  286 Boolean PosixStorageManager::isAbsolute(const StringC &s) const
  287 {
  288   if (s.size() == 0)
  289     return 0;
  290   return s[0] == '/' || s[0] == '\\' || (s.size() > 1 && s[1] == ':');
  291 }
  292 
  293 StringC PosixStorageManager::extractDir(const StringC &str) const
  294 {
  295   for (size_t i = str.size(); i > 0; i--)
  296     if (str[i - 1] == '/' || str[i - 1] == '\\'
  297     || (i == 2  && str[i - 1] == ':'))
  298       return StringC(str.data(), i);    // include separator
  299   return StringC();
  300 }
  301 
  302 StringC PosixStorageManager::combineDir(const StringC &dir,
  303                     const StringC &base) const
  304 {
  305   StringC result(dir);
  306   if (dir.size() > 0) {
  307     Char lastChar = dir[dir.size() - 1];
  308     if (lastChar != '/' && lastChar != '\\'
  309     && !(dir.size() == 2 && lastChar == ':'))
  310     result += '\\';
  311   }
  312   result += base;
  313   return result;
  314 }
  315 
  316 Boolean PosixStorageManager::transformNeutral(StringC &str, Boolean,
  317                           Messenger &) const
  318 {
  319   for (size_t i = 0; i < str.size(); i++)
  320     if (str[i] == '/')
  321       str[i] = '\\';
  322   return 1;
  323 }
  324 
  325 #endif /* SP_MSDOS_FILENAMES */
  326 
  327 #ifdef SP_MAC_FILENAMES
  328 // Colons separate directory names
  329 // relative path-names start with a colon, or have no colons
  330 // absolute path-names don't start with a colon and have at least one colon
  331 #define FILENAME_TYPE_DEFINED
  332 
  333 Boolean PosixStorageManager::isAbsolute(const StringC &s) const
  334 {
  335   if (s.size() == 0)
  336     return 0;
  337   if (s[0] == ':')
  338     return 0;   // starts with a colon => relative
  339   size_t ss = s.size();
  340   for (size_t i = 0; i < ss; i++)
  341     if (s[i] == ':')
  342       return 1; // absolute
  343   return 0; // no colons => relative
  344 }
  345 
  346 StringC PosixStorageManager::extractDir(const StringC &str) const
  347 {
  348   for (size_t i = str.size(); i > 0; i--)
  349     if (str[i - 1] == ':')
  350       return StringC(str.data(), i);    // include separator
  351   return StringC();
  352 }
  353 
  354 StringC PosixStorageManager::combineDir(const StringC &dir,
  355                     const StringC &base) const
  356 {
  357   StringC result(dir);
  358   if (dir.size() > 0) {
  359     Char lastChar = dir[dir.size() - 1];
  360     if (lastChar != ':')
  361     result += ':';
  362   }
  363   if (base[0] == ':') {
  364     StringC newbase(base.data() + 1,base.size() - 1);
  365     result += newbase;
  366   }
  367   else result += base;
  368   return result;
  369 }
  370 
  371 Boolean PosixStorageManager::transformNeutral(StringC &str, Boolean,
  372                           Messenger &) const
  373 {
  374   if (str[0] == '/') {  // absolute
  375     StringC nstr(str.data() + 1,str.size()-1);
  376     str = nstr;
  377   }
  378   else {    // relative
  379     Char cc = ':';
  380     StringC colon(&cc,1);
  381     str.insert(0,colon);
  382   }
  383   for (size_t i = 0; i < str.size(); i++)
  384     if (str[i] == '/')
  385       str[i] = ':';
  386   return 1;
  387 }
  388 
  389 #endif /* SP_MAC_FILENAMES */
  390 
  391 #ifndef FILENAME_TYPE_DEFINED
  392 
  393 Boolean PosixStorageManager::isAbsolute(const StringC &) const
  394 {
  395   return 1;
  396 }
  397 
  398 StringC PosixStorageManager::extractDir(const StringC &) const
  399 {
  400   return StringC();
  401 }
  402 
  403 StringC PosixStorageManager::combineDir(const StringC &,
  404                     const StringC &base) const
  405 {
  406   return base;
  407 }
  408 
  409 Boolean PosixStorageManager::transformNeutral(StringC &, Boolean,
  410                           Messenger &) const
  411 {
  412   return 1;
  413 }
  414 
  415 #endif /* not FILENAME_TYPE_DEFINED */
  416 
  417 Boolean PosixStorageManager::resolveRelative(const StringC &baseId,
  418                          StringC &specId,
  419                          Boolean search) const
  420 {
  421   if (isAbsolute(specId))
  422     return 1;
  423   if (!search || searchDirs_.size() == 0) {
  424     specId = combineDir(extractDir(baseId), specId);
  425     return 1;
  426   }
  427   return 0;
  428 }
  429 
  430 StorageObject *
  431 PosixStorageManager::makeStorageObject(const StringC &spec,
  432                        const StringC &base,
  433                        Boolean search,
  434                        Boolean mayRewind,
  435                        Messenger &mgr,
  436                        StringC &found)
  437 {
  438   if (spec.size() == 0) {
  439     mgr.message(PosixStorageMessages::invalidFilename,
  440         StringMessageArg(spec));
  441     return 0;
  442   }
  443   descriptorManager_.acquireD();
  444   Boolean absolute = isAbsolute(spec);
  445   SearchResultMessageArg sr;
  446   for (size_t i = 0; i < searchDirs_.size() + 1; i++) {
  447     StringC filename;
  448     if (absolute)
  449       filename = spec;
  450     else if (i == 0)
  451         filename = combineDir(extractDir(base), spec);
  452     else
  453       filename = combineDir(searchDirs_[i - 1], spec);
  454 
  455     if (restrictFileReading_ && !isSafe(filename)) continue;
  456 
  457 #ifdef SP_WIDE_SYSTEM
  458     String<FChar> cfilename;
  459     for (size_t j = 0; j < filename.size(); j++)
  460       cfilename += FChar(filename[j]);
  461     cfilename += FChar(0);
  462 #else
  463     String<FChar> cfilename = filenameCodingSystem_->convertOut(filename);
  464 #endif
  465     int fd;
  466     do {
  467       fd = openFile(cfilename.data());
  468     } while (fd < 0 && errno == EINTR);
  469     if (fd >= 0) {
  470       found = filename;
  471       return new PosixStorageObject(fd,
  472                     filename,
  473                     cfilename,
  474                     mayRewind,
  475                     &descriptorManager_);
  476     }
  477     int savedErrno = errno;
  478     if ((absolute || !search || searchDirs_.size() == 0) && !restrictFileReading_) {
  479       ParentLocationMessenger(mgr).message(PosixStorageMessages::openSystemCall,
  480                        StringMessageArg(filename),
  481                        ErrnoMessageArg(savedErrno));
  482       descriptorManager_.releaseD();
  483       return 0;
  484     }
  485     if (!restrictFileReading_) sr.add(filename, savedErrno);
  486   }
  487   descriptorManager_.releaseD();
  488   ParentLocationMessenger(mgr).message(PosixStorageMessages::cannotFind,
  489                        StringMessageArg(spec), sr);
  490   return 0;
  491 }
  492 
  493 PosixStorageObject::PosixStorageObject(int fd,
  494                        const StringC &filename,
  495                        const String<FChar> &cfilename,
  496                        Boolean mayRewind,
  497                        DescriptorManager *manager)
  498 : DescriptorUser(manager),
  499   PosixBaseStorageObject(fd, mayRewind),
  500   suspended_(0),
  501   filename_(filename),
  502   cfilename_(cfilename)
  503 {
  504 }
  505 
  506 PosixStorageObject::~PosixStorageObject()
  507 {
  508   if (fd_ >= 0) {
  509     (void)xclose(fd_);
  510     releaseD();
  511   }
  512 }
  513 
  514 Boolean PosixStorageObject::seek(off_t off, Messenger &mgr)
  515 {
  516   if (lseek(fd_, off, SEEK_SET) < 0) {
  517     fd_ = -1;
  518     systemError(mgr, PosixStorageMessages::lseekSystemCall, errno);
  519     return 0;
  520   }
  521   else
  522     return 1;
  523 }
  524 
  525 Boolean PosixStorageObject::read(char *buf, size_t bufSize, Messenger &mgr,
  526                  size_t &nread)
  527 {
  528   if (readSaved(buf, bufSize, nread))
  529     return 1;
  530   if (suspended_)
  531     resume(mgr);
  532   if (fd_ < 0 || eof_)
  533     return 0;
  534   long n;
  535   do {
  536     n = ::read(fd_, buf, bufSize);
  537   } while (n < 0 && errno == EINTR);
  538   if (n > 0) {
  539     nread = size_t(n);
  540     saveBytes(buf, nread);
  541     return 1;
  542   }
  543   if (n < 0) {
  544     int saveErrno = errno;
  545     releaseD();
  546     (void)xclose(fd_);
  547     systemError(mgr, PosixStorageMessages::readSystemCall, saveErrno);
  548     fd_ = -1;
  549   }
  550   else {
  551     eof_ = 1;
  552     // n == 0, so end of file
  553     if (!mayRewind_) {
  554       releaseD();
  555       if (xclose(fd_) < 0)
  556     systemError(mgr, PosixStorageMessages::closeSystemCall, errno);
  557       fd_ = -1;
  558     }
  559     
  560   }
  561   return 0;
  562 }
  563 
  564 void PosixStorageObject::willNotRewind()
  565 {
  566   RewindStorageObject::willNotRewind();
  567   if (eof_ && fd_ >= 0) {
  568     releaseD();
  569     (void)xclose(fd_);
  570     fd_ = -1;
  571   }
  572 }
  573 
  574 Boolean PosixStorageObject::suspend()
  575 {
  576   if (fd_ < 0 || suspended_)
  577     return 0;
  578   struct stat sb;
  579   if (fstat(fd_, &sb) < 0 || !S_ISREG(sb.st_mode))
  580     return 0;
  581   suspendFailedMessage_ = 0;
  582   suspendPos_ = lseek(fd_, 0, SEEK_CUR);
  583   if (suspendPos_ == (off_t)-1) {
  584     suspendFailedMessage_ = &PosixStorageMessages::lseekSystemCall;
  585     suspendErrno_ = errno;
  586   }
  587   if (xclose(fd_) < 0 && !suspendFailedMessage_) {
  588     suspendFailedMessage_ = &PosixStorageMessages::closeSystemCall;
  589     suspendErrno_ = errno;
  590   }
  591   fd_ = -1;
  592   suspended_ = 1;
  593   releaseD();
  594   return 1;
  595 }
  596 
  597 void PosixStorageObject::resume(Messenger &mgr)
  598 {
  599   ASSERT(suspended_);
  600   if (suspendFailedMessage_) {
  601     systemError(mgr, *suspendFailedMessage_, suspendErrno_);
  602     suspended_ = 0;
  603     return;
  604   }
  605   acquireD();
  606   // suspended_ must be 1 until after acquireD() is called,
  607   // so that we don't try to suspend this one before it is resumed.
  608   suspended_ = 0;
  609   do {
  610     fd_ = openFile(cfilename_.data());
  611   } while (fd_ < 0 && errno == EINTR);
  612   if (fd_ < 0) {
  613     releaseD();
  614     systemError(mgr, PosixStorageMessages::openSystemCall, errno);
  615     return;
  616   }
  617   if (lseek(fd_, suspendPos_, SEEK_SET) < 0) {
  618     systemError(mgr, PosixStorageMessages::lseekSystemCall, errno);
  619     (void)xclose(fd_);
  620     fd_ = -1;
  621     releaseD();
  622   }
  623 }
  624 
  625 #ifdef SP_STAT_BLKSIZE
  626 
  627 size_t PosixBaseStorageObject::getBlockSize() const
  628 {
  629   struct stat sb;
  630   long sz;
  631   if (fstat(fd_, &sb) < 0)
  632     return defaultBlockSize;
  633   if (!S_ISREG(sb.st_mode))
  634     return defaultBlockSize;
  635   if ((unsigned long)sb.st_blksize > size_t(-1))
  636     sz = size_t(-1);
  637   else
  638     sz = sb.st_blksize;
  639   return sz;
  640 }
  641 
  642 #else /* not SP_STAT_BLKSIZE */
  643 
  644 size_t PosixBaseStorageObject::getBlockSize() const
  645 {
  646   return defaultBlockSize;
  647 }
  648 
  649 #endif /* not SP_STAT_BLKSIZE */
  650 
  651 void PosixStorageObject::systemError(Messenger &mgr,
  652                      const MessageType2 &msg,
  653                      int err)
  654 {
  655   ParentLocationMessenger(mgr).message(msg,
  656                        StringMessageArg(filename_),
  657                        ErrnoMessageArg(err));
  658 }
  659 
  660 class PosixFdStorageObject : public PosixBaseStorageObject {
  661 public:
  662   PosixFdStorageObject(int, Boolean mayRewind);
  663   Boolean read(char *buf, size_t bufSize, Messenger &mgr, size_t &nread);
  664   Boolean seek(off_t, Messenger &);
  665   enum {
  666     noError,
  667     readError,
  668     invalidNumberError,
  669     lseekError
  670   };
  671 private:
  672   int origFd_;
  673 };
  674 
  675 PosixFdStorageManager::PosixFdStorageManager(const char *type,
  676                          const CharsetInfo *idCharset)
  677 : IdStorageManager(idCharset), type_(type)
  678 {
  679 }
  680 
  681 Boolean PosixFdStorageManager::inheritable() const
  682 {
  683   return 0;
  684 }
  685 
  686 StorageObject *PosixFdStorageManager::makeStorageObject(const StringC &id,
  687                             const StringC &,
  688                             Boolean,
  689                             Boolean mayRewind,
  690                             Messenger &mgr,
  691                             StringC &foundId)
  692 {
  693   int n = 0;
  694   size_t i;
  695   for (i = 0; i < id.size(); i++) {
  696     UnivChar ch;
  697     if (!idCharset()->descToUniv(id[i], ch))
  698       break;
  699     if (ch < UnivCharsetDesc::zero || ch > UnivCharsetDesc::zero + 9)
  700       break;
  701     int digit = ch - UnivCharsetDesc::zero;
  702     // Allow the division to be done at compile-time.
  703     if (n > INT_MAX/10)
  704       break;
  705     n *= 10;
  706     if (n > INT_MAX - digit)
  707       break;
  708     n += digit;
  709   }
  710   if (i < id.size() || i == 0) {
  711     mgr.message(PosixStorageMessages::invalidNumber,
  712         StringMessageArg(id));
  713     return 0;
  714   }
  715   foundId = id;
  716   // Could check access mode with fcntl(n, F_GETFL).
  717   return new PosixFdStorageObject(n, mayRewind);
  718 }
  719 
  720 PosixFdStorageObject::PosixFdStorageObject(int fd, Boolean mayRewind)
  721 : PosixBaseStorageObject(fd, mayRewind), origFd_(fd)
  722 {
  723 }
  724 
  725 const char *PosixFdStorageManager::type() const
  726 {
  727   return type_;
  728 }
  729 
  730 Boolean PosixFdStorageObject::read(char *buf, size_t bufSize, Messenger &mgr,
  731                    size_t &nread)
  732 {
  733   if (readSaved(buf, bufSize, nread))
  734     return 1;
  735   if (fd_ < 0 || eof_)
  736     return 0;
  737   long n;
  738   do {
  739     n = ::read(fd_, buf, bufSize);
  740   } while (n < 0 && errno == EINTR);
  741   if (n > 0) {
  742     nread = size_t(n);
  743     saveBytes(buf, nread);
  744     return 1;
  745   }
  746   if (n < 0) {
  747     ParentLocationMessenger(mgr).message(PosixStorageMessages::fdRead,
  748                      NumberMessageArg(fd_),
  749                      ErrnoMessageArg(errno));
  750     fd_ = -1;
  751   }
  752   else
  753     eof_ = 1;
  754   return 0;
  755 }
  756 
  757 Boolean PosixFdStorageObject::seek(off_t off, Messenger &mgr)
  758 {
  759   if (lseek(fd_, off, SEEK_SET) < 0) {
  760     ParentLocationMessenger(mgr).message(PosixStorageMessages::fdLseek,
  761                      NumberMessageArg(fd_),
  762                      ErrnoMessageArg(errno));
  763     return 0;
  764   }
  765   else
  766     return 1;
  767 }
  768 
  769 #ifdef SP_NAMESPACE
  770 }
  771 #endif