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 #include <dirent.h>
00039 #include <unistd.h>
00040 #include <sys/stat.h>
00041 
00042 #include "common/wave_ex.h"
00043 #include "perf/perf.h"
00044 #include "util/token_stream.h"
00045 
00046 
00047 namespace nstream {
00048 
00049 
00050 ////////////////////////////////////////////////////////////////////////////////
00051 //
00052 //      static helper methods
00053 //
00054 ////////////////////////////////////////////////////////////////////////////////
00055 
00056 // declaration only
00057 static smart_ptr<Entry> getEntryForName(IN const char * name,
00058                                 IN const char * rootDir);   // namespace root
00059 
00060 
00061 static std::string
00062 getFullPath
00063 (
00064 IN const char * rootDir,
00065 IN const char * name
00066 )
00067 {
00068         std::string retval = rootDir;
00069         if (*rootDir) {
00070                 retval += "/";
00071         }
00072         retval += name;
00073 
00074         return retval;
00075 }
00076 
00077 
00078 
00079 ////////////////////////////////////////////////////////////////////////////////
00080 //
00081 //      FSStream -- class that implements the nstream::Stream interface for a
00082 //              local filesystem.
00083 //
00084 ////////////////////////////////////////////////////////////////////////////////
00085 
00086 class FSStream : public Stream {
00087 public:
00088         // constructor, destructor ---------------------------------------------
00089         ~FSStream(void) throw() { }
00090 
00091         // nstream::Stream class interface methods ----------------------------
00092         std::istream& getStream(void) { return m_stream; }
00093         smart_ptr<File> getFile(void);
00094 
00095         // static factory methods ----------------------------------------------
00096         static smart_ptr<Stream> create(IN const char * name,
00097                                 IN const char * rootDir);
00098 
00099 private:
00100         // private helper methods ----------------------------------------------
00101         FSStream(void) throw() { }
00102 
00103         // private member data -------------------------------------------------
00104         std::ifstream           m_stream;       // raw fstream
00105         std::string             m_name;
00106         std::string             m_rootDir;
00107 };
00108 
00109 
00110 
00111 smart_ptr<File>
00112 FSStream::getFile
00113 (
00114 void
00115 )
00116 {
00117         // we create entry and rely on auto-upcast
00118         smart_ptr<File> file =
00119             getEntryForName(m_name.c_str(), m_rootDir.c_str());
00120 
00121         // this routine isn't supposed to return null, so throw if there's a
00122         //      problem.  in general we'll get errors only if the file has been
00123         //      renamed out from under us
00124         THROW(file,
00125             "filesystem stream is for file now gone: " << m_rootDir << "/"
00126             << m_name);
00127 
00128         // all good
00129         return file;
00130 }
00131 
00132 
00133 
00134 smart_ptr<Stream>
00135 FSStream::create
00136 (
00137 IN const char * name,
00138 IN const char * rootDir
00139 )
00140 {
00141         ASSERT(name, "null");
00142         ASSERT(rootDir, "null");
00143 
00144         smart_ptr<FSStream> local = new FSStream;
00145         ASSERT(local, "out of memory");
00146 
00147         local->m_name = name;
00148         local->m_rootDir = rootDir;
00149 
00150         // get full path
00151         std::string full_path = getFullPath(rootDir, name);
00152 
00153         // open stream!
00154         local->m_stream.open(full_path.c_str());
00155         THROW(local->m_stream.good(),
00156             "Failed to open file for reading: " << full_path);
00157 
00158         // all good
00159         return local;
00160 }
00161 
00162 
00163 
00164 ////////////////////////////////////////////////////////////////////////////////
00165 //
00166 //      FSFile -- class that implements the nstream::File interface for a
00167 //              local filesystem.
00168 //
00169 ////////////////////////////////////////////////////////////////////////////////
00170 
00171 class FSFile : public File {
00172 public:
00173         // constructor, destructor ---------------------------------------------
00174         ~FSFile(void) throw() { }
00175 
00176         // nstream::Entry class interface methods -----------------------------
00177         eType getType(void) const throw() { return eType_File; }
00178         const char * getName(void) const throw() { return m_name.c_str(); }
00179         smart_ptr<Manager> getManager(void) {
00180                         return getFilesystemManager(m_rootDir.c_str());
00181                 }
00182 
00183         // nstream::File class interface methods ------------------------------
00184         smart_ptr<Stream> openStream(void);
00185 
00186         // static factory methods ----------------------------------------------
00187         static smart_ptr<File> create(IN const char * name,
00188                                 IN const char * rootDir);
00189 
00190 private:
00191         // private helper methods ----------------------------------------------
00192         FSFile(void) throw() { }
00193 
00194         // private member data -------------------------------------------------
00195         std::string             m_name;
00196         std::string             m_rootDir;
00197 };
00198 
00199 
00200 
00201 smart_ptr<Stream>
00202 FSFile::openStream
00203 (
00204 void
00205 )
00206 {
00207         return FSStream::create(m_name.c_str(), m_rootDir.c_str());
00208 }
00209 
00210 
00211 
00212 smart_ptr<File>
00213 FSFile::create
00214 (
00215 IN const char * name,
00216 IN const char * rootDir
00217 )
00218 {
00219         ASSERT(name, "null");
00220         ASSERT(rootDir, "null");
00221 
00222         smart_ptr<FSFile> local = new FSFile;
00223         ASSERT(local, "out of memory");
00224 
00225         local->m_name = name;
00226         local->m_rootDir = rootDir;
00227 
00228         return local;
00229 }
00230 
00231 
00232 
00233 ////////////////////////////////////////////////////////////////////////////////
00234 //
00235 //      FSFolder -- class that implements the nstream::Folder interface for a
00236 //              local filesystem.
00237 //
00238 //      NOTE: this is built with an iterative model.  This is to handle the
00239 //      (extreme) cases where a filesystem contains thousands of entries per
00240 //      directory.
00241 //
00242 ////////////////////////////////////////////////////////////////////////////////
00243 
00244 class FSFolder : public Folder {
00245 public:
00246         // constructor, destructor ---------------------------------------------
00247         ~FSFolder(void) throw();
00248 
00249         // nstream::Entry class interface methods -----------------------------
00250         eType getType(void) const throw() { return eType_Folder; }
00251         const char * getName(void) const throw() { return m_name.c_str(); }
00252         smart_ptr<Manager> getManager(void) {
00253                         return getFilesystemManager(m_rootDir.c_str());
00254                 }
00255 
00256         // nstream::Folder class interface methods ----------------------------
00257         smart_ptr<Entry> getChildByName(IN const char * name);
00258         void resetIteration(void);
00259         smart_ptr<Entry> getNextChild(void);
00260 
00261         // static factory methods ----------------------------------------------
00262         static smart_ptr<Folder> create(IN const char * name,
00263                                 IN const char * root);
00264 
00265 private:
00266         // private helper methods ----------------------------------------------
00267         FSFolder(void) throw();
00268         void closeDir(void) throw();
00269 
00270         // private member data -------------------------------------------------
00271         DIR *           m_DIR;          // directory handle
00272         std::string     m_name;
00273         std::string     m_rootDir;
00274 };
00275 
00276 
00277 
00278 FSFolder::FSFolder(void)
00279 throw()
00280 :
00281 m_DIR(NULL)
00282 {
00283 }
00284 
00285 
00286 
00287 FSFolder::~FSFolder(void)
00288 throw()
00289 {
00290         this->closeDir();
00291 }
00292 
00293 
00294 
00295 smart_ptr<Entry>
00296 FSFolder::getChildByName
00297 (
00298 IN const char * name
00299 )
00300 {
00301         ASSERT(name, "null");
00302 
00303         std::string relPath = getFullPath(m_name.c_str(), name);
00304         return getEntryForName(relPath.c_str(), m_rootDir.c_str());
00305 }
00306 
00307 
00308 
00309 void
00310 FSFolder::resetIteration
00311 (
00312 void
00313 )
00314 {
00315         this->closeDir();
00316 }
00317 
00318 
00319 
00320 smart_ptr<Entry>
00321 FSFolder::getNextChild
00322 (
00323 void
00324 )
00325 {
00326         if (!m_DIR) {
00327                 // no directory handle yet!  Need to open directory
00328                 std::string full_path =
00329                     getFullPath(m_rootDir.c_str(), m_name.c_str());
00330                 m_DIR = opendir(full_path.c_str());
00331                 THROW(m_DIR,
00332                     "Failed to open directory: " << full_path);
00333         }
00334 
00335         // get next entry
00336         struct dirent * entry = NULL;
00337         while (true) {
00338                 entry = readdir(m_DIR);
00339                 if (!entry) {
00340                         // end of directory entries!
00341                         this->closeDir();
00342                         return NULL;
00343                 }
00344 
00345                 // skip entries that aren't semantically valid for the
00346                 //   nstream::Folder iteration
00347                 if (!strcmp(".", entry->d_name) ||
00348                     !strcmp("..", entry->d_name)) {
00349                         continue;       // skip these
00350                 }
00351 
00352                 // entry is valid!
00353                 break;
00354         }
00355         ASSERT(entry, "null");
00356 
00357         // have a valid entry
00358         std::string relPath = getFullPath(m_name.c_str(), entry->d_name);
00359         return getEntryForName(relPath.c_str(), m_rootDir.c_str());
00360 }
00361 
00362 
00363 
00364 void
00365 FSFolder::closeDir
00366 (
00367 void
00368 )
00369 throw()
00370 {
00371         if (m_DIR) {
00372                 closedir(m_DIR);
00373                 m_DIR = NULL;
00374         }
00375 }
00376 
00377 
00378 
00379 smart_ptr<Folder>
00380 FSFolder::create
00381 (
00382 IN const char * name,
00383 IN const char * rootDir
00384 )
00385 {
00386         ASSERT(name, "null");
00387         ASSERT(rootDir, "null");
00388 
00389 //      DPRINTF("Creating folder for name: %s", name);
00390 //      DPRINTF("  root dir: %s", rootDir);
00391 
00392         smart_ptr<FSFolder> local = new FSFolder();
00393         ASSERT(local, "out of memory");
00394 
00395         local->m_name = name;
00396         local->m_rootDir = rootDir;
00397 
00398         return local;
00399 }
00400 
00401 
00402 
00403 ////////////////////////////////////////////////////////////////////////////////
00404 //
00405 //      FSMgr -- class that implements the nstream::Manager interface for a
00406 //              local filesystem
00407 //
00408 ////////////////////////////////////////////////////////////////////////////////
00409 
00410 class FSMgr : public Manager {
00411 public:
00412         // constructor, destructor ---------------------------------------------
00413         ~FSMgr(void) throw() { }
00414 
00415         // public class methods ------------------------------------------------
00416         void initialize(IN const char * rootDir);
00417 
00418         // nstream::Manager class interface methods ---------------------------
00419         smart_ptr<Entry> getEntry(IN const char * name);
00420         smart_ptr<Folder> getRoot(void);
00421         std::string getFullName(IN const char * name);
00422 
00423 private:
00424         // private member data -------------------------------------------------
00425         std::string             m_rootDir;
00426 };
00427 
00428 
00429 
00430 void
00431 FSMgr::initialize
00432 (
00433 IN const char * rootDir
00434 )
00435 {
00436         ASSERT(rootDir, "null");
00437 
00438         m_rootDir = rootDir;
00439 }
00440 
00441 
00442 
00443 smart_ptr<Entry>
00444 FSMgr::getEntry
00445 (
00446 IN const char * name
00447 )
00448 {
00449         ASSERT(name, "null");
00450 
00451         return getEntryForName(name, m_rootDir.c_str());
00452 }
00453 
00454 
00455 
00456 smart_ptr<Folder>
00457 FSMgr::getRoot
00458 (
00459 void
00460 )
00461 {
00462         return FSFolder::create("", m_rootDir.c_str());
00463 }
00464 
00465 
00466 
00467 std::string
00468 FSMgr::getFullName
00469 (
00470 IN const char * name
00471 )
00472 {
00473         ASSERT(name, "null");
00474         return getFullPath(m_rootDir.c_str(), name);
00475 }
00476 
00477 
00478 
00479 ////////////////////////////////////////////////////////////////////////////////
00480 //
00481 //      static methods needed by the above
00482 //
00483 ////////////////////////////////////////////////////////////////////////////////
00484 
00485 static smart_ptr<Entry>
00486 getEntryForName
00487 (
00488 IN const char * name,
00489 IN const char * rootDir
00490 )
00491 {
00492         ASSERT(name, "null");
00493         ASSERT(rootDir, "null");
00494 
00495         // DPRINTF("Creating entry for name: %s", name);
00496         // DPRINTF("  root dir: %s", rootDir);
00497 
00498         std::string full_path = getFullPath(rootDir, name);
00499         const char * path = full_path.c_str();
00500 
00501         // look up stats on this path
00502         struct stat sb;
00503         if (stat(path, &sb)) {
00504                 DPRINTF("Could not stat filesystem path: %s", path);
00505                 return NULL;
00506         }
00507 
00508         // see if directory
00509         if (S_IFDIR & sb.st_mode) {
00510                 return FSFolder::create(name, rootDir);
00511         }
00512 
00513         // assume file
00514         return FSFile::create(name, rootDir);
00515 }
00516 
00517 
00518 
00519 ////////////////////////////////////////////////////////////////////////////////
00520 //
00521 //      Public APIs
00522 //
00523 ////////////////////////////////////////////////////////////////////////////////
00524 
00525 smart_ptr<Manager>
00526 getFilesystemManager
00527 (
00528 IN const char * root_dir
00529 )
00530 {
00531         ASSERT(root_dir, "null");
00532 
00533         smart_ptr<FSMgr> local = new FSMgr;
00534         local->initialize(root_dir);
00535 
00536         return local;
00537 }
00538 
00539 
00540 
00541 };      // nstream namespace
00542