BESCatalogDirectory.cc

Go to the documentation of this file.
00001 // BESCatalogDirectory.cc
00002 
00003 // This file is part of bes, A C++ back-end server implementation framework
00004 // for the OPeNDAP Data Access Protocol.
00005 
00006 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 // 
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact University Corporation for Atmospheric Research at
00024 // 3080 Center Green Drive, Boulder, CO 80301
00025  
00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
00028 //
00029 // Authors:
00030 //      pwest       Patrick West <pwest@ucar.edu>
00031 //      jgarcia     Jose Garcia <jgarcia@ucar.edu>
00032 
00033 #include "sys/types.h"
00034 #include "sys/stat.h"
00035 #include "dirent.h"
00036 
00037 #include <cstring>
00038 #include <cerrno>
00039 #include <sstream>
00040 
00041 using std::stringstream ;
00042 using std::endl ;
00043 
00044 #include "BESCatalogDirectory.h"
00045 #include "BESCatalogUtils.h"
00046 #include "BESInfo.h"
00047 #include "BESResponseNames.h"
00048 #include "BESCatalogUtils.h"
00049 #include "BESContainerStorageList.h"
00050 #include "BESContainerStorageCatalog.h"
00051 #include "BESLog.h"
00052 #include "BESForbiddenError.h"
00053 #include "BESNotFoundError.h"
00054 
00055 BESCatalogDirectory::BESCatalogDirectory( const string &name )
00056     : BESCatalog( name )
00057 {
00058     _utils = BESCatalogUtils::Utils( name ) ;
00059 }
00060 
00061 BESCatalogDirectory::~BESCatalogDirectory( )
00062 {
00063 }
00064 
00065 void
00066 BESCatalogDirectory::show_catalog( const string &node,
00067                                    const string &coi,
00068                                    BESInfo *info )
00069 {
00070     // remove any trailing slash
00071     string use_node = node ;
00072     if( node != "" )
00073     {
00074         string::size_type stopat = node.length() - 1 ;
00075         while( node[stopat] == '/' )
00076         {
00077             stopat-- ;
00078         }
00079         use_node = use_node.substr( 0, stopat + 1 ) ;
00080     }
00081 
00082     string rootdir = _utils->get_root_dir() ;
00083     string fullnode = rootdir ;
00084     if( !use_node.empty() )
00085     {
00086         fullnode = fullnode + "/" + use_node ;
00087     }
00088 
00089     string basename ;
00090     string::size_type slash = fullnode.rfind( "/" ) ;
00091     if( slash != string::npos )
00092     {
00093         basename = fullnode.substr( slash+1, fullnode.length() - slash ) ;
00094     }
00095     else
00096     {
00097         basename = fullnode ;
00098     }
00099 
00100     // This will throw the appropriate exception (Forbidden or Not Found).
00101     // Checks to make sure the different elements of the path are not
00102     // symbolic links if follow_sym_links is set to false, and checks to
00103     // make sure have permission to access node and the node exists.
00104     BESUtil::check_path( use_node, rootdir, _utils->follow_sym_links() ) ;
00105 
00106     // Is this node a directory?
00107     DIR *dip = opendir( fullnode.c_str() ) ;
00108     if( dip != NULL )
00109     {
00110         // The node is a directory
00111 
00112         // if the directory requested is in the exclude list then we won't
00113         // let the user see it.
00114         if( _utils->exclude( basename ) )
00115         {
00116             closedir( dip ) ;
00117             string error = "You do not have permission to view the node "
00118                            + use_node ;
00119             throw BESForbiddenError( error, __FILE__, __LINE__ ) ;
00120         }
00121         struct stat cbuf ;
00122         int statret = stat( fullnode.c_str(), &cbuf ) ;
00123         int my_errno = errno ;
00124         if( statret == 0 )
00125         {
00126             map<string,string> a1 ;
00127             a1["thredds_collection"] = "\"true\"" ;
00128             a1["isData"] = "\"false\"" ;
00129             info->begin_tag( "dataset", &a1 ) ;
00130             if( use_node == "" )
00131             {
00132                 add_stat_info( info, cbuf, "/" ) ;
00133             }
00134             else
00135             {
00136                 add_stat_info( info, cbuf, use_node ) ;
00137             }
00138 
00139             struct dirent *dit;
00140             unsigned int cnt = 0 ;
00141             struct stat buf;
00142             struct stat lbuf;
00143 
00144             map<string,bes_dir_entry> dir_list ;
00145             while( ( dit = readdir( dip ) ) != NULL )
00146             {
00147                 string dirEntry = dit->d_name ;
00148                 if( dirEntry != "." && dirEntry != ".." )
00149                 {
00150                     string fullPath = fullnode + "/" + dirEntry ;
00151 
00152                     // if follow_sym_links is true then continue with
00153                     // the checking. If false, first see if the entry is
00154                     // a symbolic link. If it is, do not include in the
00155                     // listing for this node. If not, then continue
00156                     // checking the entry.
00157                     bool continue_checking = true ;
00158                     if( _utils->follow_sym_links() == false )
00159                     {
00160                         int lstatret = lstat( fullPath.c_str(), &lbuf ) ;
00161                         if( S_ISLNK( lbuf.st_mode ) )
00162                         {
00163                             continue_checking = false ;
00164                         }
00165                     }
00166 
00167                     if( continue_checking )
00168                     {
00169                         // look at the mode and determine if this is a
00170                         // directory or a regular file. If it is not
00171                         // accessible, the stat failes, is not a directory
00172                         // or regular file, then simply do not include it.
00173                         statret = stat( fullPath.c_str(), &buf ) ;
00174                         if ( statret == 0 && S_ISDIR( buf.st_mode ) )
00175                         {
00176                             if( _utils->exclude( dirEntry ) == false )
00177                             {
00178                                 cnt++ ;
00179                                 if( coi == CATALOG_RESPONSE )
00180                                 {
00181                                     bes_dir_entry entry ;
00182                                     entry.collection = true ;
00183                                     entry.isData = false ;
00184                                     add_stat_info( entry, buf, dirEntry ) ;
00185                                     dir_list[dirEntry] = entry ;
00186                                 }
00187                             }
00188                         }
00189                         else if ( statret == 0 && S_ISREG( buf.st_mode ) )
00190                         {
00191                             if( _utils->include( dirEntry ) )
00192                             {
00193                                 cnt++ ;
00194                                 if( coi == CATALOG_RESPONSE )
00195                                 {
00196                                     bes_dir_entry entry ;
00197                                     entry.collection = false ;
00198                                     list<string> provides ;
00199                                     if( isData( fullPath, provides ) )
00200                                         entry.isData = true ;
00201                                     else
00202                                         entry.isData = false ;
00203                                     add_stat_info( entry, buf, dirEntry ) ;
00204                                     dir_list[dirEntry] = entry ;
00205                                 }
00206                             }
00207                         }
00208                     }
00209                 }
00210             }
00211             stringstream sscnt ;
00212             sscnt << cnt ;
00213             info->add_tag( "count", sscnt.str() ) ;
00214 
00215             // Now iterate through the entry list and add it to info. This
00216             // will add it in alpha order
00217             if( coi == CATALOG_RESPONSE )
00218             {
00219                 map<string,bes_dir_entry>::iterator i = dir_list.begin() ;
00220                 map<string,bes_dir_entry>::iterator e = dir_list.end() ;
00221                 for( ; i != e; i++ )
00222                 {
00223                     map<string,string> attrs ;
00224                     if( (*i).second.collection )
00225                         attrs["thredds_collection"] = "\"true\"" ;
00226                     else
00227                         attrs["thredds_collection"] = "\"false\"" ;
00228                     if( (*i).second.isData )
00229                         attrs["isData"] = "\"true\"" ;
00230                     else
00231                         attrs["isData"] = "\"false\"" ;
00232                     info->begin_tag( "dataset", &attrs ) ;
00233                     info->add_tag( "name", (*i).second.name ) ;
00234                     info->add_tag( "size", (*i).second.size ) ;
00235                     info->begin_tag( "lastmodified" ) ;
00236                     info->add_tag( "date", (*i).second.mod_date ) ;
00237                     info->add_tag( "time", (*i).second.mod_time ) ;
00238                     info->end_tag( "lastmodified" ) ;
00239                     info->end_tag( "dataset" ) ;
00240                 }
00241             }
00242             closedir( dip ) ;
00243             info->end_tag( "dataset" ) ;
00244         }
00245         else
00246         {
00247             closedir( dip ) ;
00248             // ENOENT means that the path or part of the path does not exist
00249             if( my_errno == ENOENT )
00250             {
00251                 string error = "Node " + use_node + " does not exist" ;
00252                 char *s_err = strerror( my_errno ) ;
00253                 if( s_err )
00254                 {
00255                     error = s_err ;
00256                 }
00257                 throw BESNotFoundError( error, __FILE__, __LINE__ ) ;
00258             }
00259             // any other error means that access is denied for some reason
00260             else
00261             {
00262                 string error = "Access denied for node " + use_node ;
00263                 char *s_err = strerror( my_errno ) ;
00264                 if( s_err )
00265                 {
00266                     error = error + s_err ;
00267                 }
00268                 throw BESNotFoundError( error, __FILE__, __LINE__ ) ;
00269             }
00270         }
00271     }
00272     else
00273     {
00274         // if the node is not in the include list then the requester does
00275         // not have access to that node
00276         if( _utils->include( basename ) )
00277         {
00278             struct stat buf;
00279             int statret = 0 ;
00280             if( _utils->follow_sym_links() == false )
00281             {
00282                 statret = lstat( fullnode.c_str(), &buf ) ;
00283                 if( S_ISLNK( buf.st_mode ) )
00284                 {
00285                     string error = "You do not have permission to access node "
00286                                    + use_node ;
00287                     throw BESForbiddenError( error, __FILE__, __LINE__ ) ;
00288                 }
00289             }
00290             statret = stat( fullnode.c_str(), &buf ) ;
00291             if ( statret == 0 && S_ISREG( buf.st_mode ) )
00292             {
00293                 map<string,string> a4 ;
00294                 a4["thredds_collection"] = "\"false\"" ;
00295                 list<string> provides ;
00296                 if( isData( node, provides ) )
00297                     a4["isData"] = "\"true\"" ;
00298                 else
00299                     a4["isData"] = "\"false\"" ;
00300                 info->begin_tag( "dataset", &a4 ) ;
00301                 add_stat_info( info, buf, node ) ;
00302                 info->end_tag( "dataset" ) ;
00303             }
00304             else if( statret == 0 )
00305             {
00306                 string error = "You do not have permission to access "
00307                                + use_node ;
00308                 throw BESForbiddenError( error, __FILE__, __LINE__ ) ;
00309             }
00310             else
00311             {
00312                 // ENOENT means that the path or part of the path does not
00313                 // exist
00314                 if( errno == ENOENT )
00315                 {
00316                     string error = "Node " + use_node + " does not exist" ;
00317                     char *s_err = strerror( errno ) ;
00318                     if( s_err )
00319                     {
00320                         error = s_err ;
00321                     }
00322                     throw BESNotFoundError( error, __FILE__, __LINE__ ) ;
00323                 }
00324                 // any other error means that access is denied for some reason
00325                 else
00326                 {
00327                     string error = "Access denied for node " + use_node ;
00328                     char *s_err = strerror( errno ) ;
00329                     if( s_err )
00330                     {
00331                         error = error + s_err ;
00332                     }
00333                     throw BESNotFoundError( error, __FILE__, __LINE__ ) ;
00334                 }
00335             }
00336         }
00337         else
00338         {
00339             string error = "You do not have permission to access " + use_node ;
00340             throw BESForbiddenError( error, __FILE__, __LINE__ ) ;
00341         }
00342     }
00343 }
00344 
00345 void
00346 BESCatalogDirectory::add_stat_info( BESInfo *info,
00347                                     struct stat &buf,
00348                                     const string &node )
00349 {
00350     bes_dir_entry entry ;
00351     add_stat_info( entry, buf, node ) ;
00352     info->add_tag( "name", entry.name ) ;
00353     info->add_tag( "size", entry.size ) ;
00354     info->begin_tag( "lastmodified" ) ;
00355     info->add_tag( "date", entry.mod_date ) ;
00356     info->add_tag( "time", entry.mod_time ) ;
00357     info->end_tag( "lastmodified" ) ;
00358 }
00359 
00360 void
00361 BESCatalogDirectory::add_stat_info( bes_dir_entry &entry,
00362                                     struct stat &buf,
00363                                     const string &node )
00364 {
00365     entry.name = node ;
00366 
00367     off_t sz = buf.st_size ;
00368     stringstream ssz ;
00369     ssz << sz ;
00370     entry.size = ssz.str() ;
00371 
00372     // %T = %H:%M:%S
00373     // %F = %Y-%m-%d
00374     time_t mod = buf.st_mtime ;
00375     struct tm *stm = gmtime( &mod ) ;
00376     char mdate[64] ;
00377     strftime( mdate, 64, "%Y-%m-%d", stm ) ;
00378     char mtime[64] ;
00379     strftime( mtime, 64, "%T", stm ) ;
00380 
00381     stringstream sdt ;
00382     sdt << mdate ;
00383     entry.mod_date = sdt.str() ;
00384 
00385     stringstream stt ;
00386     stt << mtime ;
00387     entry.mod_time = stt.str() ;
00388 }
00389 
00390 bool
00391 BESCatalogDirectory::isData( const string &inQuestion,
00392                              list<string> &provides )
00393 {
00394     BESContainerStorage *store =
00395         BESContainerStorageList::TheList()->find_persistence( get_catalog_name() ) ;
00396     if( !store )
00397         return false ;
00398 
00399     BESContainerStorageCatalog *cat_store =
00400         dynamic_cast<BESContainerStorageCatalog *>(store ) ;
00401     if( !cat_store )
00402         return false ;
00403 
00404     return cat_store->isData( inQuestion, provides ) ;
00405 }
00406 
00414 void
00415 BESCatalogDirectory::dump( ostream &strm ) const
00416 {
00417     strm << BESIndent::LMarg << "BESCatalogDirectory::dump - ("
00418                              << (void *)this << ")" << endl ;
00419     BESIndent::Indent() ;
00420 
00421     strm << BESIndent::LMarg << "catalog utilities: " << endl ;
00422     BESIndent::Indent() ;
00423     _utils->dump( strm ) ;
00424     BESIndent::UnIndent() ;
00425     BESIndent::UnIndent() ;
00426 }
00427 

Generated on Tue Mar 4 23:13:33 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1