bes  Updated for version 3.19.1
BESCatalogDirectory.cc
1 // BESCatalogDirectory.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include "config.h"
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <dirent.h>
38 
39 #include <cstring>
40 #include <cerrno>
41 #include <sstream>
42 
43 using std::stringstream;
44 using std::endl;
45 
46 #include "BESUtil.h"
47 #include "BESCatalogDirectory.h"
48 #include "BESCatalogUtils.h"
49 #include "BESCatalogEntry.h"
50 #include "BESInfo.h"
51 #include "BESCatalogUtils.h"
52 #include "BESContainerStorageList.h"
53 #include "BESContainerStorageCatalog.h"
54 #include "BESLog.h"
55 #include "BESForbiddenError.h"
56 #include "BESNotFoundError.h"
57 #include "BESDebug.h"
58 
59 BESCatalogDirectory::BESCatalogDirectory(const string &name) :
60  BESCatalog(name)
61 {
62  _utils = BESCatalogUtils::Utils(name);
63 }
64 
65 BESCatalogDirectory::~BESCatalogDirectory()
66 {
67 }
68 
70 BESCatalogDirectory::show_catalog(const string &node, const string &coi, BESCatalogEntry *entry)
71 {
72  string use_node = node;
73  // use_node should only end in '/' is that's the only character in which
74  // case there's no need to call find()
75  if (!node.empty() && node != "/") {
76  string::size_type pos = use_node.find_last_not_of("/");
77  use_node = use_node.substr(0, pos + 1);
78  }
79 
80  // This takes care of bizarre cases like "///" where use_node would be
81  // empty after the substring call.
82  if (use_node.empty())
83  use_node = "/";
84 
85  string rootdir = _utils->get_root_dir();
86  string fullnode = rootdir;
87  if (!use_node.empty()) {
88  fullnode = fullnode + "/" + use_node;
89  }
90 
91  string basename;
92  string::size_type slash = fullnode.rfind("/");
93  if (slash != string::npos) {
94  basename = fullnode.substr(slash + 1, fullnode.length() - slash);
95  }
96  else {
97  basename = fullnode;
98  }
99 
100  BESDEBUG( "bes", "BESCatalogDirectory::show_catalog: "
101  << "use_node = " << use_node << endl
102  << "rootdir = " << rootdir << endl
103  << "fullnode = " << fullnode << endl
104  << "basename = " << basename << endl );
105 
106  // This will throw the appropriate exception (Forbidden or Not Found).
107  // Checks to make sure the different elements of the path are not
108  // symbolic links if follow_sym_links is set to false, and checks to
109  // make sure have permission to access node and the node exists.
110  BESUtil::check_path(use_node, rootdir, _utils->follow_sym_links());
111 
112  BESCatalogEntry *myentry = new BESCatalogEntry(use_node, get_catalog_name());
113  if (entry) {
114  // if an entry was passed, then add this one to it
115  entry->add_entry(myentry);
116  }
117  else {
118  // else we want to return the new entry created
119  entry = myentry;
120  }
121 
122  // Is this node a directory?
123  DIR *dip = opendir(fullnode.c_str());
124  if (dip != NULL) {
125  try {
126  // The node is a directory
127 
128  // if the directory requested is in the exclude list then we won't
129  // let the user see it.
130  if (_utils->exclude(basename)) {
131  string error = "You do not have permission to view the node " + use_node;
132  throw BESForbiddenError(error, __FILE__, __LINE__);
133  }
134 
135  // Now that we are ready to start building the response data we
136  // cancel any pending timeout alarm according to the configuration.
138 
139  bool dirs_only = false;
140  _utils->get_entries(dip, fullnode, use_node, coi, myentry, dirs_only);
141  } catch (... /*BESError &e */) {
142  closedir(dip);
143  throw /* e */;
144  }
145  closedir(dip);
146 
147  BESCatalogUtils::bes_add_stat_info(myentry, fullnode);
148  }
149  else {
150  // if the node is not in the include list then the requester does
151  // not have access to that node
152  if (_utils->include(basename)) {
153  struct stat buf;
154  int statret = 0;
155  if (_utils->follow_sym_links() == false) {
156  /*statret =*/(void) lstat(fullnode.c_str(), &buf);
157  if (S_ISLNK(buf.st_mode)) {
158  string error = "You do not have permission to access node " + use_node;
159  throw BESForbiddenError(error, __FILE__, __LINE__);
160  }
161  }
162  statret = stat(fullnode.c_str(), &buf);
163  if (statret == 0 && S_ISREG(buf.st_mode)) {
164  BESCatalogUtils::bes_add_stat_info(myentry, fullnode);
165 
166  list < string > services;
167  BESCatalogUtils::isData(node, get_catalog_name(), services);
168  myentry->set_service_list(services);
169  }
170  else if (statret == 0) {
171  string error = "You do not have permission to access " + use_node;
172  throw BESForbiddenError(error, __FILE__, __LINE__);
173  }
174  else {
175  // ENOENT means that the path or part of the path does not
176  // exist
177  if (errno == ENOENT) {
178  string error = "Node " + use_node + " does not exist";
179  char *s_err = strerror(errno);
180  if (s_err) {
181  error = s_err;
182  }
183  throw BESNotFoundError(error, __FILE__, __LINE__);
184  }
185  // any other error means that access is denied for some reason
186  else {
187  string error = "Access denied for node " + use_node;
188  char *s_err = strerror(errno);
189  if (s_err) {
190  error = error + s_err;
191  }
192  throw BESNotFoundError(error, __FILE__, __LINE__);
193  }
194  }
195  }
196  else {
197  string error = "You do not have permission to access " + use_node;
198  throw BESForbiddenError(error, __FILE__, __LINE__);
199  }
200  }
201 
202  return entry;
203 }
204 
212 void BESCatalogDirectory::dump(ostream &strm) const
213 {
214  strm << BESIndent::LMarg << "BESCatalogDirectory::dump - (" << (void *) this << ")" << endl;
215  BESIndent::Indent();
216 
217  strm << BESIndent::LMarg << "catalog utilities: " << endl;
218  BESIndent::Indent();
219  _utils->dump(strm);
220  BESIndent::UnIndent();
221  BESIndent::UnIndent();
222 }
223 
error thrown if the resource requested cannot be found
static void conditional_timeout_cancel()
Definition: BESUtil.cc:878
virtual void dump(ostream &strm) const
dumps information about this object
virtual void dump(ostream &strm) const
dump the contents of this object to the specified ostream
abstract base class catalog object. Derived classes know how to show nodes and leaves in a catalog.
Definition: BESCatalog.h:47
error thrown if the BES is not allowed to access the resource requested
static void check_path(const string &path, const string &root, bool follow_sym_links)
Definition: BESUtil.cc:242