fs-nstream.cpp

Go to the documentation of this file.
00001 /*
00002  * fs-nstream.cpp
00003  *
00004  * Copyright (c) 2009 Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Basic filesystem namespace.  See nstream.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "nstream.h"            // always include our own header first
00036 
00037 #include <fstream>
00038 #ifdef WIN32
00039 #define stat _stat
00040 #include <sys/types.h>
00041 #else   // WIN32
00042 #include <unistd.h>
00043 #endif  // WIN32
00044 #include <sys/stat.h>
00045 
00046 #include "common/wave_ex.h"
00047 #include "perf/perf.h"
00048 #include "util/file.h"
00049 #include "util/token_stream.h"
00050 
00051 
00052 namespace nstream {
00053 
00054 
00055 ////////////////////////////////////////////////////////////////////////////////
00056 //
00057 //      static helper methods
00058 //
00059 ////////////////////////////////////////////////////////////////////////////////
00060 
00061 // declaration only
00062 static smart_ptr<Entry> getEntryForName(IN const char * name,
00063                                 IN const char * rootDir);   // namespace root
00064 
00065 
00066 static std::string
00067 getFullPath
00068 (
00069 IN const char * rootDir,
00070 IN const char * name
00071 )
00072 {
00073         ASSERT(rootDir, "null");
00074         ASSERT(name, "null");
00075 
00076         std::string retval;
00077         appendPath(rootDir, name, retval);
00078         return retval;
00079 }
00080 
00081 
00082 
00083 ////////////////////////////////////////////////////////////////////////////////
00084 //
00085 //      FSStream -- class that implements the nstream::Stream interface for a
00086 //              local filesystem.
00087 //
00088 ////////////////////////////////////////////////////////////////////////////////
00089 
00090 class FSStream : public Stream {
00091 public:
00092         // constructor, destructor ---------------------------------------------
00093         ~FSStream(void) throw() { }
00094 
00095         // nstream::Stream class interface methods ----------------------------
00096         std::istream& getStream(void) { return m_stream; }
00097         smart_ptr<File> getFile(void);
00098 
00099         // static factory methods ----------------------------------------------
00100         static smart_ptr<Stream> create(IN const char * name,
00101                                 IN const char * rootDir);
00102 
00103 private:
00104         // private helper methods ----------------------------------------------
00105         FSStream(void) throw() { }
00106 
00107         // private member data -------------------------------------------------
00108         std::ifstream           m_stream;       // raw fstream
00109         std::string             m_name;
00110         std::string             m_rootDir;
00111 };
00112 
00113 
00114 
00115 smart_ptr<File>
00116 FSStream::getFile
00117 (
00118 void
00119 )
00120 {
00121         // we create entry and rely on auto-upcast
00122         smart_ptr<File> file =
00123             getEntryForName(m_name.c_str(), m_rootDir.c_str());
00124 
00125         // this routine isn't supposed to return null, so throw if there's a
00126         //      problem.  in general we'll get errors only if the file has been
00127         //      renamed out from under us
00128         THROW(file,
00129             "filesystem stream is for file now gone: " << m_rootDir << "/"
00130             << m_name);
00131 
00132         // all good
00133         return file;
00134 }
00135 
00136 
00137 
00138 smart_ptr<Stream>
00139 FSStream::create
00140 (
00141 IN const char * name,
00142 IN const char * rootDir
00143 )
00144 {
00145         ASSERT(name, "null");
00146         ASSERT(rootDir, "null");
00147 
00148         smart_ptr<FSStream> local = new FSStream;
00149         ASSERT(local, "out of memory");
00150 
00151         local->m_name = name;
00152         local->m_rootDir = rootDir;
00153 
00154         // get full path
00155         std::string full_path = getFullPath(rootDir, name);
00156 
00157         // open stream!
00158         local->m_stream.open(full_path.c_str(), std::ios::binary);
00159         THROW(local->m_stream.good(),
00160             "Failed to open file for reading: " << full_path);
00161 
00162         // all good
00163         return local;
00164 }
00165 
00166 
00167 
00168 ////////////////////////////////////////////////////////////////////////////////
00169 //
00170 //      FSFile -- class that implements the nstream::File interface for a
00171 //              local filesystem.
00172 //
00173 ////////////////////////////////////////////////////////////////////////////////
00174 
00175 class FSFile : public File {
00176 public:
00177         // constructor, destructor ---------------------------------------------
00178         ~FSFile(void) throw() { }
00179 
00180         // nstream::Entry class interface methods -----------------------------
00181         eType getType(void) const throw() { return eType_File; }
00182         const char * getName(void) const throw() { return m_name.c_str(); }
00183         smart_ptr<Manager> getManager(void) {
00184                         return getFilesystemManager(m_rootDir.c_str());
00185                 }
00186 
00187         // nstream::File class interface methods ------------------------------
00188         smart_ptr<Stream> openStream(void);
00189 
00190         // static factory methods ----------------------------------------------
00191         static smart_ptr<File> create(IN const char * name,
00192                                 IN const char * rootDir);
00193 
00194 private:
00195         // private helper methods ----------------------------------------------
00196         FSFile(void) throw() { }
00197 
00198         // private member data -------------------------------------------------
00199         std::string             m_name;
00200         std::string             m_rootDir;
00201 };
00202 
00203 
00204 
00205 smart_ptr<Stream>
00206 FSFile::openStream
00207 (
00208 void
00209 )
00210 {
00211         return FSStream::create(m_name.c_str(), m_rootDir.c_str());
00212 }
00213 
00214 
00215 
00216 smart_ptr<File>
00217 FSFile::create
00218 (
00219 IN const char * name,
00220 IN const char * rootDir
00221 )
00222 {
00223         ASSERT(name, "null");
00224         ASSERT(rootDir, "null");
00225 
00226         smart_ptr<FSFile> local = new FSFile;
00227         ASSERT(local, "out of memory");
00228 
00229         local->m_name = name;
00230         local->m_rootDir = rootDir;
00231 
00232         return local;
00233 }
00234 
00235 
00236 
00237 ////////////////////////////////////////////////////////////////////////////////
00238 //
00239 //      FSFolder -- class that implements the nstream::Folder interface for a
00240 //              local filesystem.
00241 //
00242 //      NOTE: this is built with an iterative model.  This is to handle the
00243 //      (extreme) cases where a filesystem contains thousands of entries per
00244 //      directory.
00245 //
00246 ////////////////////////////////////////////////////////////////////////////////
00247 
00248 class FSFolder : public Folder {
00249 public:
00250         // constructor, destructor ---------------------------------------------
00251         ~FSFolder(void) throw();
00252 
00253         // nstream::Entry class interface methods -----------------------------
00254         eType getType(void) const throw() { return eType_Folder; }
00255         const char * getName(void) const throw() { return m_name.c_str(); }
00256         smart_ptr<Manager> getManager(void) {
00257                         return getFilesystemManager(m_rootDir.c_str());
00258                 }
00259 
00260         // nstream::Folder class interface methods ----------------------------
00261         smart_ptr<Entry> getChildByName(IN const char * name);
00262         void resetIteration(void);
00263         smart_ptr<Entry> getNextChild(void);
00264 
00265         // static factory methods ----------------------------------------------
00266         static smart_ptr<Folder> create(IN const char * name,
00267                                 IN const char * root);
00268 
00269 private:
00270         // private helper methods ----------------------------------------------
00271         FSFolder(void) throw();
00272         void closeDir(void) throw();
00273 
00274         // private member data -------------------------------------------------
00275         DIR *           m_DIR;          // directory handle
00276         std::string     m_name;
00277         std::string     m_rootDir;
00278 };
00279 
00280 
00281 
00282 FSFolder::FSFolder(void)
00283 throw()
00284 :
00285 m_DIR(NULL)
00286 {
00287 }
00288 
00289 
00290 
00291 FSFolder::~FSFolder(void)
00292 throw()
00293 {
00294         this->closeDir();
00295 }
00296 
00297 
00298 
00299 smart_ptr<Entry>
00300 FSFolder::getChildByName
00301 (
00302 IN const char * name
00303 )
00304 {
00305         ASSERT(name, "null");
00306 
00307         std::string relPath = getFullPath(m_name.c_str(), name);
00308         return getEntryForName(relPath.c_str(), m_rootDir.c_str());
00309 }
00310 
00311 
00312 
00313 void
00314 FSFolder::resetIteration
00315 (
00316 void
00317 )
00318 {
00319         this->closeDir();
00320 }
00321 
00322 
00323 
00324 smart_ptr<Entry>
00325 FSFolder::getNextChild
00326 (
00327 void
00328 )
00329 {
00330         if (!m_DIR) {
00331                 // no directory handle yet!  Need to open directory
00332                 std::string full_path =
00333                     getFullPath(m_rootDir.c_str(), m_name.c_str());
00334                 m_DIR = opendir(full_path.c_str());
00335                 THROW(m_DIR,
00336                     "Failed to open directory: " << full_path);
00337         }
00338 
00339         // get next entry
00340         struct dirent * entry = NULL;
00341         while (true) {
00342                 entry = readdir(m_DIR);
00343                 if (!entry) {
00344                         // end of directory entries!
00345                         this->closeDir();
00346                         return NULL;
00347                 }
00348 
00349                 // skip entries that aren't semantically valid for the
00350                 //   nstream::Folder iteration
00351                 if (!strcmp(".", entry->d_name) ||
00352                     !strcmp("..", entry->d_name)) {
00353                         continue;       // skip these
00354                 }
00355 
00356                 // entry is valid!
00357                 break;
00358         }
00359         ASSERT(entry, "null");
00360 
00361         // have a valid entry
00362         std::string relPath = getFullPath(m_name.c_str(), entry->d_name);
00363         return getEntryForName(relPath.c_str(), m_rootDir.c_str());
00364 }
00365 
00366 
00367 
00368 void
00369 FSFolder::closeDir
00370 (
00371 void
00372 )
00373 throw()
00374 {
00375         if (m_DIR) {
00376                 closedir(m_DIR);
00377                 m_DIR = NULL;
00378         }
00379 }
00380 
00381 
00382 
00383 smart_ptr<Folder>
00384 FSFolder::create
00385 (
00386 IN const char * name,
00387 IN const char * rootDir
00388 )
00389 {
00390         ASSERT(name, "null");
00391         ASSERT(rootDir, "null");
00392 
00393 //      DPRINTF("Creating folder for name: %s", name);
00394 //      DPRINTF("  root dir: %s", rootDir);
00395 
00396         smart_ptr<FSFolder> local = new FSFolder();
00397         ASSERT(local, "out of memory");
00398 
00399         local->m_name = name;
00400         local->m_rootDir = rootDir;
00401 
00402         return local;
00403 }
00404 
00405 
00406 
00407 ////////////////////////////////////////////////////////////////////////////////
00408 //
00409 //      FSMgr -- class that implements the nstream::Manager interface for a
00410 //              local filesystem
00411 //
00412 ////////////////////////////////////////////////////////////////////////////////
00413 
00414 class FSMgr : public Manager {
00415 public:
00416         // constructor, destructor ---------------------------------------------
00417         ~FSMgr(void) throw() { }
00418 
00419         // public class methods ------------------------------------------------
00420         void initialize(IN const char * rootDir);
00421 
00422         // nstream::Manager class interface methods ---------------------------
00423         smart_ptr<Entry> getEntry(IN const char * name);
00424         smart_ptr<Folder> getRoot(void);
00425         std::string getFullName(IN const char * name);
00426 
00427 private:
00428         // private member data -------------------------------------------------
00429         std::string             m_rootDir;
00430 };
00431 
00432 
00433 
00434 void
00435 FSMgr::initialize
00436 (
00437 IN const char * rootDir
00438 )
00439 {
00440         ASSERT(rootDir, "null");
00441 
00442         m_rootDir = rootDir;
00443 }
00444 
00445 
00446 
00447 smart_ptr<Entry>
00448 FSMgr::getEntry
00449 (
00450 IN const char * name
00451 )
00452 {
00453         ASSERT(name, "null");
00454 
00455         return getEntryForName(name, m_rootDir.c_str());
00456 }
00457 
00458 
00459 
00460 smart_ptr<Folder>
00461 FSMgr::getRoot
00462 (
00463 void
00464 )
00465 {
00466         return FSFolder::create("", m_rootDir.c_str());
00467 }
00468 
00469 
00470 
00471 std::string
00472 FSMgr::getFullName
00473 (
00474 IN const char * name
00475 )
00476 {
00477         ASSERT(name, "null");
00478         return getFullPath(m_rootDir.c_str(), name);
00479 }
00480 
00481 
00482 
00483 ////////////////////////////////////////////////////////////////////////////////
00484 //
00485 //      static methods needed by the above
00486 //
00487 ////////////////////////////////////////////////////////////////////////////////
00488 
00489 static smart_ptr<Entry>
00490 getEntryForName
00491 (
00492 IN const char * name,
00493 IN const char * rootDir
00494 )
00495 {
00496         ASSERT(name, "null");
00497         ASSERT(rootDir, "null");
00498 
00499         // DPRINTF("Creating entry for name: %s", name);
00500         // DPRINTF("  root dir: %s", rootDir);
00501 
00502         std::string full_path = getFullPath(rootDir, name);
00503         const char * path = full_path.c_str();
00504 
00505         // look up stats on this path
00506         struct stat sb;
00507         if (stat(path, &sb)) {
00508                 DPRINTF("Could not stat filesystem path: %s", path);
00509                 return NULL;
00510         }
00511 
00512         // see if directory
00513         if (S_IFDIR & sb.st_mode) {
00514                 return FSFolder::create(name, rootDir);
00515         }
00516 
00517         // assume file
00518         return FSFile::create(name, rootDir);
00519 }
00520 
00521 
00522 
00523 ////////////////////////////////////////////////////////////////////////////////
00524 //
00525 //      Public APIs
00526 //
00527 ////////////////////////////////////////////////////////////////////////////////
00528 
00529 smart_ptr<Manager>
00530 getFilesystemManager
00531 (
00532 IN const char * root_dir
00533 )
00534 {
00535         ASSERT(root_dir, "null");
00536 
00537         smart_ptr<FSMgr> local = new FSMgr;
00538         local->initialize(root_dir);
00539 
00540         return local;
00541 }
00542 
00543 
00544 
00545 };      // nstream namespace
00546