Drizzled Public API Documentation

cached_directory.cc
Go to the documentation of this file.
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; version 2 of the License.
00009  *
00010  *  This program 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
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00028 #include <config.h>
00029 #include <dirent.h>
00030 #include <drizzled/definitions.h>
00031 
00032 #include <boost/foreach.hpp>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <unistd.h>
00036 
00037 #include <strings.h>
00038 #include <limits.h>
00039 
00040 #include <drizzled/cached_directory.h>
00041 #include <drizzled/util/find_ptr.h>
00042 #include <drizzled/error_t.h>
00043 #include <drizzled/error.h>
00044 #include <drizzled/errmsg_print.h>
00045 
00046 using namespace std;
00047 using namespace drizzled;
00048 
00049 namespace drizzled {
00050 
00051 CachedDirectory::CachedDirectory() : 
00052   error(0)
00053 {
00054 }
00055 
00056 
00057 CachedDirectory::CachedDirectory(const string &in_path) :
00058   error(0),
00059   use_full_path(false)
00060 {
00061   // TODO: Toss future exception
00062   (void) open(in_path);
00063 }
00064 
00065 
00066 CachedDirectory::CachedDirectory(const string& in_path, set<string>& allowed_exts) :
00067   error(0),
00068   use_full_path(false)
00069 {
00070   // TODO: Toss future exception
00071   (void) open(in_path, allowed_exts);
00072 }
00073 
00074 CachedDirectory::CachedDirectory(const string& in_path, enum CachedDirectory::FILTER filter, bool use_full_path_arg) :
00075   error(0),
00076   use_full_path(use_full_path_arg)
00077 {
00078   set<string> empty;
00079   // TODO: Toss future exception
00080   (void) open(in_path, empty, filter);
00081 }
00082 
00083 
00084 CachedDirectory::~CachedDirectory()
00085 {
00086   BOOST_FOREACH(Entries::reference iter, entries)
00087     delete iter;
00088 }
00089 
00090 bool CachedDirectory::open(const string &in_path)
00091 {
00092   set<string> empty;
00093   return open(in_path, empty);
00094 }
00095 
00096 bool CachedDirectory::open(const string &in_path, set<string> &allowed_exts)
00097 {
00098   return open(in_path, allowed_exts, CachedDirectory::NONE);
00099 }
00100 
00101 bool CachedDirectory::open(const string &in_path, set<string> &allowed_exts, enum CachedDirectory::FILTER filter)
00102 {
00103   DIR *dirp= opendir(in_path.c_str());
00104 
00105   if (dirp == NULL)
00106   {
00107     error= errno;
00108     return false;
00109   }
00110 
00111   path= in_path;
00112 
00113   union {
00114     dirent entry;
00115 #ifdef __sun
00116     /*
00117      * The readdir_r() call on Solaris operates a bit differently from other
00118      * systems in that the dirent structure must be allocated along with enough
00119      * space to contain the filename (see man page for readdir_r on Solaris).
00120      * Instead of dynamically try to allocate this buffer, just set the max
00121      * name for a path instead.
00122      */
00123     char space[sizeof(dirent) + PATH_MAX + 1];
00124 #endif
00125   } buffer;
00126 
00127   int retcode;
00128   dirent *result;
00129 
00130   while ((retcode= readdir_r(dirp, &buffer.entry, &result)) == 0 &&
00131          result != NULL)
00132   {
00133     std::string buffered_fullpath;
00134     if (not allowed_exts.empty())
00135     {
00136       char *ptr= rindex(result->d_name, '.');
00137       if (ptr && allowed_exts.count(ptr))
00138       {
00139         entries.push_back(new Entry(result->d_name));
00140       }
00141     }
00142     else
00143     {
00144       switch (filter)
00145       {
00146       case DIRECTORY:
00147         {
00148           struct stat entrystat;
00149 
00150           if (result->d_name[0] == '.') // We don't pass back anything hidden at the moment.
00151             continue;
00152 
00153           if (use_full_path)
00154           {
00155             buffered_fullpath.append(in_path);
00156             if (buffered_fullpath[buffered_fullpath.length()] != '/')
00157               buffered_fullpath.append(1, FN_LIBCHAR);
00158           }
00159 
00160           buffered_fullpath.append(result->d_name);
00161 
00162           int err= stat(buffered_fullpath.c_str(), &entrystat);
00163 
00164           if (err != 0)
00165           {
00166             errmsg_printf(error::WARN, ER(ER_CANT_GET_STAT),
00167                           buffered_fullpath.c_str(),
00168                           errno);
00169           }
00170 
00171           if (err == 0 && S_ISDIR(entrystat.st_mode))
00172           {
00173             entries.push_back(new Entry(result->d_name));
00174           }
00175         }
00176         break;
00177       case FILE:
00178         {
00179           struct stat entrystat;
00180 
00181           buffered_fullpath.append(in_path);
00182           if (buffered_fullpath[buffered_fullpath.length() - 1] != '/')
00183             buffered_fullpath.append(1, FN_LIBCHAR);
00184 
00185           buffered_fullpath= result->d_name;
00186 
00187           stat(buffered_fullpath.c_str(), &entrystat);
00188 
00189           if (S_ISREG(entrystat.st_mode))
00190           {
00191             entries.push_back(new Entry(result->d_name));
00192           }
00193         }
00194         break;
00195       case NONE:
00196       case MAX:
00197         entries.push_back(new Entry(result->d_name));
00198         break;
00199       }
00200     }
00201   }
00202     
00203   closedir(dirp);
00204   error= retcode;
00205 
00206   return error == 0;
00207 }
00208 
00209 std::ostream& operator<<(std::ostream& output, const CachedDirectory &directory)
00210 {
00211   output << "CachedDirectory:(Path: " << directory.getPath() << ")\n";
00212   BOOST_FOREACH(const CachedDirectory::Entry* iter, directory.getEntries())
00213     output << "\t(" << iter->filename << ")\n";
00214   return output;
00215 }
00216 
00217 } /* namespace drizzled */