![]() |
|
|
Generated: 8 Jan 2009 |
00001 #include "xercesc/framework/LocalFileFormatTarget.hpp" 00002 #include "xercesc/framework/MemBufInputSource.hpp" 00003 #include "xercesc/sax/SAXParseException.hpp" 00004 #include "xercesc/sax/EntityResolver.hpp" 00005 #include "xercesc/sax/InputSource.hpp" 00006 #include "xercesc/parsers/XercesDOMParser.hpp" 00007 #include "xercesc/util/PlatformUtils.hpp" 00008 #include "xercesc/util/XercesDefs.hpp" 00009 #include "xercesc/util/XMLUni.hpp" 00010 #include "xercesc/util/XMLURL.hpp" 00011 #include "xercesc/util/XMLString.hpp" 00012 #include "xercesc/dom/DOM.hpp" 00013 00014 #include "GaudiKernel/MsgStream.h" 00015 #include "GaudiKernel/Service.h" 00016 #include "Reflex/PluginService.h" 00017 00018 #include "XMLFileCatalog.h" 00019 00020 #include <fstream> 00021 #include <iostream> 00022 #include <stdexcept> 00023 #include <sys/types.h> 00024 #include <sys/stat.h> 00025 #include "uuid/uuid.h" 00026 00027 using namespace xercesc; 00028 using namespace Gaudi; 00029 using namespace std; 00030 00031 PLUGINSVC_FACTORY(XMLFileCatalog,IInterface*(std::string, IMessageSvc*)) 00032 00033 namespace { 00034 typedef const string& CSTR; 00035 inline string _toString(const XMLCh *toTranscode) { 00036 char * buff = XMLString::transcode(toTranscode); 00037 string tmp(buff==0 ? "" : buff); 00038 XMLString::release(&buff); 00039 return tmp; 00040 } 00041 struct __Init { 00042 __Init() { 00043 try { XMLPlatformUtils::Initialize(); } 00044 catch (const XMLException& e) { 00045 cout << "Xerces-c error in initialization:" << _toString(e.getMessage()) << endl; 00046 } 00047 } 00048 ~__Init() { 00049 XMLPlatformUtils::Terminate(); 00050 } 00051 }; 00052 __Init __In__; 00053 00054 struct XMLStr { 00055 XMLCh* m_xml; 00056 XMLStr(CSTR c) { m_xml=XMLString::transcode(c.c_str()); } 00057 ~XMLStr() { if (m_xml) XMLString::release(&m_xml); } 00058 operator const XMLCh*() const { return m_xml; } 00059 }; 00060 struct XMLTag : public XMLStr { 00061 string m_str; 00062 XMLTag(CSTR s) : XMLStr(s), m_str(s) { } 00063 ~XMLTag() { } 00064 operator CSTR () const { return m_str; } 00065 }; 00066 bool operator==(const XMLTag& b, CSTR c) { return c==b.m_str; } 00067 bool operator==(CSTR c, const XMLTag& b) { return c==b.m_str; } 00068 struct XMLCollection { 00069 DOMElement* m_node; 00070 XMLCollection(DOMNode* n, bool use_children=true) : m_node((DOMElement*)n) { 00071 if ( use_children ) { 00072 if ( m_node ) m_node = (DOMElement*)m_node->getFirstChild(); 00073 if ( m_node && m_node->getNodeType() != DOMNode::ELEMENT_NODE ) ++(*this); 00074 } 00075 } 00076 operator bool() const { return 0 != m_node; } 00077 operator DOMNode* () const { return m_node; } 00078 operator DOMElement* () const { return m_node; } 00079 DOMElement* operator->() const { return m_node; } 00080 string attr(const XMLTag& tag) const { return _toString(m_node->getAttribute(tag));} 00081 string attr(CSTR tag) const { return attr(XMLTag(tag)); } 00082 string tag() const { return _toString(m_node->getTagName()); } 00083 void operator++() { 00084 while(m_node) { 00085 m_node = (DOMElement*)m_node->getNextSibling(); 00086 if ( m_node && m_node->getNodeType() == DOMNode::ELEMENT_NODE ) { 00087 return; 00088 } 00089 } 00090 } 00091 }; 00092 struct ErrHandler : public ErrorHandler { 00094 IMessageSvc* m_msg; 00096 ErrHandler(IMessageSvc* m) : m_msg(m) {} 00098 void resetErrors() { } 00100 void warning(const SAXParseException& /* e */) { } 00102 void error(const SAXParseException& e); 00104 void fatalError(const SAXParseException& e); 00105 }; 00106 struct DTDRedirect : public EntityResolver { 00107 InputSource* resolveEntity(const XMLCh* const /* pubId */, const XMLCh* const /* sysId */) { 00108 static const char* dtdID = "redirectinmem.dtd"; 00109 static const char* dtd = \ 00110 "\ 00111 <!ELEMENT POOLFILECATALOG (META*,File*)>\ 00112 <!ELEMENT META EMPTY>\ 00113 <!ELEMENT File (physical,logical,metadata*)>\ 00114 <!ATTLIST META name CDATA #REQUIRED>\ 00115 <!ATTLIST META type CDATA #REQUIRED>\ 00116 <!ELEMENT physical (pfn)+>\ 00117 <!ELEMENT logical (lfn)*>\ 00118 <!ELEMENT metadata EMPTY>\ 00119 <!ELEMENT lfn EMPTY>\ 00120 <!ELEMENT pfn EMPTY>\ 00121 <!ATTLIST File ID ID #REQUIRED>\ 00122 <!ATTLIST pfn name ID #REQUIRED>\ 00123 <!ATTLIST pfn filetype CDATA #IMPLIED>\ 00124 <!ATTLIST lfn name ID #REQUIRED>\ 00125 <!ATTLIST metadata att_name CDATA #REQUIRED>\ 00126 <!ATTLIST metadata att_value CDATA #REQUIRED>\ 00127 "; 00128 static const size_t len = strlen(dtd); 00129 return new MemBufInputSource((const XMLByte*)dtd,len,dtdID,false); 00130 } 00131 }; 00132 00133 void ErrHandler::error(const SAXParseException& e) { 00134 string m(_toString(e.getMessage())); 00135 if (m.find("The values for attribute 'name' must be names or name tokens")!=string::npos || 00136 m.find("The values for attribute 'ID' must be names or name tokens")!=string::npos || 00137 m.find("for attribute 'name' must be Name or Nmtoken")!=string::npos || 00138 m.find("for attribute 'ID' must be Name or Nmtoken")!=string::npos ) 00139 return; 00140 string sys(_toString(e.getSystemId())); 00141 MsgStream log(m_msg,"XMLCatalog"); 00142 log << MSG::ERROR << "Error at file \"" << sys 00143 << "\", line " << e.getLineNumber() << ", column " << e.getColumnNumber() << endmsg 00144 << "Message: " << m << endmsg; 00145 } 00146 void ErrHandler::fatalError(const SAXParseException& e) { 00147 MsgStream log(m_msg,"XMLCatalog"); 00148 string m(_toString(e.getMessage())); 00149 string sys(_toString(e.getSystemId())); 00150 log << MSG::ERROR << "Fatal Error at file \"" << sys 00151 << "\", line " << e.getLineNumber() << ", column " << e.getColumnNumber() << endmsg 00152 << "Message: " << m << endmsg; 00153 throw runtime_error( "Standard pool exception : Fatal Error on the DOM Parser" ); 00154 } 00155 00156 const XMLTag EmptyCatalog("<!-- Edited By POOL -->\n" 00157 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n" 00158 "<POOLFILECATALOG>\n" 00159 "</POOLFILECATALOG>\n"); 00160 const XMLTag PFNCOLL ("physical"); 00161 const XMLTag LFNCOLL ("logical"); 00162 const XMLTag PFNNODE ( "pfn"); 00163 const XMLTag LFNNODE ( "lfn"); 00164 const XMLTag Attr_type ( "type"); 00165 const XMLTag Attr_ID ( "ID"); 00166 const XMLTag Attr_name ( "name"); 00167 const XMLTag Attr_ftype ( "filetype"); 00168 const XMLTag MetaNode ( "metadata"); 00169 const XMLTag Attr_metaName ( "att_name"); 00170 const XMLTag Attr_metaValue ( "att_value"); 00171 } 00172 00174 std::string Gaudi::createGuidAsString() { 00175 char text[64]; 00176 uuid_t uuid; 00177 ::uuid_generate_time(uuid); 00178 struct Guid { 00179 unsigned int Data1; 00180 unsigned short Data2; 00181 unsigned short Data3; 00182 unsigned char Data4[8]; 00183 } *g = (Guid*)&uuid; 00184 ::sprintf(text, "%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", 00185 g->Data1, g->Data2, g->Data3, 00186 g->Data4[0], g->Data4[1], g->Data4[2], g->Data4[3], 00187 g->Data4[4], g->Data4[5], g->Data4[6], g->Data4[7]); 00188 return text; 00189 } 00190 // ---------------------------------------------------------------------------- 00191 XMLFileCatalog::XMLFileCatalog(CSTR uri, IMessageSvc* m) 00192 : m_rdOnly(false),m_update(false),m_doc(0),m_parser(0),m_errHdlr(0), 00193 m_file(uri), m_refCount(0), m_msgSvc(m) 00194 { 00195 } 00196 // ---------------------------------------------------------------------------- 00197 XMLFileCatalog::~XMLFileCatalog() { 00198 if (m_parser) delete m_parser; 00199 m_parser = 0; 00200 if (m_errHdlr) delete m_errHdlr; 00201 m_errHdlr = 0; 00202 m_doc = 0; 00203 } 00204 // ---------------------------------------------------------------------------- 00205 unsigned long XMLFileCatalog::addRef() { 00206 return ++m_refCount; 00207 } 00208 // ---------------------------------------------------------------------------- 00209 unsigned long XMLFileCatalog::release() { 00210 long cnt = --m_refCount; 00211 if ( cnt <= 0 ) { 00212 delete this; 00213 } 00214 return cnt; 00215 } 00216 // ---------------------------------------------------------------------------- 00217 StatusCode XMLFileCatalog::queryInterface(const InterfaceID& riid, void** ppv) { 00218 if ( riid.versionMatch(IFileCatalog::interfaceID()) ) { 00219 *ppv = (IFileCatalog*)this; 00220 } 00221 else if ( riid.versionMatch(IInterface::interfaceID()) ) { 00222 *ppv = (IInterface*)this; 00223 } 00224 else { 00225 *ppv = 0; 00226 return StatusCode::FAILURE; 00227 } 00228 addRef(); 00229 return StatusCode::SUCCESS; 00230 } 00232 std::string XMLFileCatalog::createFID() const { 00233 return createGuidAsString(); 00234 } 00235 // ---------------------------------------------------------------------------- 00236 DOMDocument* XMLFileCatalog::getDoc(bool throw_if_no_exists) const { 00237 if ( !m_doc && throw_if_no_exists ) 00238 printError("The XML catalog was not started.",true); 00239 return m_doc; 00240 } 00241 // ---------------------------------------------------------------------------- 00242 void XMLFileCatalog::printError(CSTR msg, bool rethrow) const { 00243 MsgStream log(m_msgSvc,"XMLCatalog"); 00244 log << MSG::FATAL << msg << endmsg; 00245 if ( rethrow ) { 00246 throw runtime_error("XMLFileCatalog> "+msg); 00247 } 00248 } 00249 // ---------------------------------------------------------------------------- 00250 void XMLFileCatalog::init() { 00251 string xmlFile = getfile(false); 00252 try{ 00253 if ( m_parser ) delete m_parser; 00254 m_parser = new XercesDOMParser; 00255 m_parser->setValidationScheme(XercesDOMParser::Val_Auto); 00256 m_parser->setDoNamespaces(false); 00257 DTDRedirect dtdinmem; 00258 m_parser->setEntityResolver(&dtdinmem); 00259 if ( ! m_errHdlr ) m_errHdlr = new ErrHandler(m_msgSvc); 00260 m_parser->setErrorHandler(m_errHdlr); 00261 if ( !xmlFile.empty() ) { 00262 m_parser->parse(xmlFile.c_str()); 00263 } 00264 else { 00265 const std::string& s = EmptyCatalog; 00266 MemBufInputSource src((const XMLByte*)s.c_str(),s.length(),"MemCatalog"); 00267 m_parser->parse(src); 00268 } 00269 m_doc = m_parser->getDocument(); 00270 } 00271 catch (const XMLException& e) { 00272 printError("XML parse error["+xmlFile+"]: "+_toString(e.getMessage())); 00273 } 00274 catch (const DOMException& e) { 00275 printError("XML parse error["+xmlFile+"]: "+_toString(e.getMessage())); 00276 } 00277 catch (...) { 00278 printError("UNKNOWN XML parse error in file "+xmlFile); 00279 } 00280 } 00281 // ---------------------------------------------------------------------------- 00282 string XMLFileCatalog::lookupFID(const std::string& fid) const { 00283 std::string result; 00284 DOMNode* e = element(fid,false); 00285 e = e ? e->getParentNode() : 0; // Mode up to <logical> 00286 e = e ? e->getParentNode() : 0; // Mode up to <File> 00287 if ( e ) { 00288 if ( e->getAttributes() ) { // Need to check this. The node may be no DOMElement 00289 char* nam = XMLString::transcode(((DOMElement*)e)->getAttribute(Attr_ID)); 00290 if ( nam ) result = nam; 00291 XMLString::release(&nam); 00292 } 00293 } 00294 return result; 00295 } 00296 // ---------------------------------------------------------------------------- 00297 void XMLFileCatalog::getFID(Strings& fids) const { 00298 fids.clear(); 00299 DOMNode* fde = getDoc(true)->getElementsByTagName(XMLStr("*"))->item(0); 00300 for(XMLCollection c(child(fde,"File"), false); c; ++c) 00301 fids.push_back(c.attr(Attr_ID)); 00302 } 00303 // ---------------------------------------------------------------------------- 00304 void XMLFileCatalog::getPFN(CSTR fid, Files& files) const { 00305 files.clear(); 00306 for(XMLCollection c(child(child(element(fid,false),PFNCOLL),PFNNODE), false); c; ++c) 00307 files.push_back(make_pair(c.attr(Attr_name),c.attr(Attr_ftype))); 00308 } 00309 // ---------------------------------------------------------------------------- 00310 void XMLFileCatalog::getLFN(CSTR fid, Files& files) const { 00311 files.clear(); 00312 for(XMLCollection c(child(child(element(fid,false),LFNCOLL),LFNNODE), false); c; ++c) 00313 files.push_back(make_pair(c.attr(Attr_name),fid)); 00314 } 00315 // ---------------------------------------------------------------------------- 00316 void XMLFileCatalog::getMetaData(CSTR fid, Attributes& attr) const { 00317 attr.clear(); 00318 for(XMLCollection c(child(element(fid),MetaNode), false); c; ++c) 00319 attr.push_back(make_pair(c.attr(Attr_metaName),c.attr(Attr_metaValue))); 00320 if ( attr.size() > 0 ) 00321 attr.push_back(make_pair("guid",fid)); 00322 } 00323 // ---------------------------------------------------------------------------- 00324 DOMNode* XMLFileCatalog::child(DOMNode* par,CSTR tag,CSTR attr,CSTR val) const { 00325 for(XMLCollection c(par); c; ++c ) { 00326 if( c.tag() == tag ) { 00327 if( !attr.empty() && c.attr(attr) != val) continue; 00328 return c; 00329 } 00330 } 00331 return 0; 00332 } 00333 // ---------------------------------------------------------------------------- 00334 void XMLFileCatalog::setMetaData(CSTR fid, CSTR attr, CSTR val) const { 00335 if ( !readOnly() ) { 00336 DOMNode* node = element(fid); 00337 DOMElement* mnod = (DOMElement*)child(node,MetaNode,Attr_metaName,attr); 00338 if (!mnod){ 00339 mnod = getDoc(true)->createElement(MetaNode); 00340 node->appendChild(mnod); 00341 mnod->setAttribute(Attr_metaName,XMLStr(attr)); 00342 } 00343 mnod->setAttribute(Attr_metaValue,XMLStr(val)); 00344 m_update = true; 00345 return; 00346 } 00347 printError("Cannot update readonly catalog!"); 00348 } 00349 // ---------------------------------------------------------------------------- 00350 string XMLFileCatalog::getMetaDataItem(CSTR fid,CSTR attr) const { 00351 XMLCollection c(child(getDoc(true)->getElementById(XMLStr(fid)),MetaNode,Attr_metaName,attr)); 00352 return c ? c.attr(attr) : string(""); 00353 } 00354 // ---------------------------------------------------------------------------- 00355 void XMLFileCatalog::dropMetaData(CSTR fid,CSTR attr) const { 00356 vector<DOMNode*> gbc; 00357 DOMNode* fn = getDoc(true)->getElementById(XMLStr(fid)); 00358 for(XMLCollection c(child(fn,MetaNode)); c; ++c) 00359 if ( attr[0]=='*' || !c.attr(attr).empty() ) gbc.push_back(c); 00360 for(vector<DOMNode*>::iterator i=gbc.begin(); i != gbc.end(); i++) 00361 fn->removeChild(*i); 00362 } 00363 // ---------------------------------------------------------------------------- 00364 DOMNode* XMLFileCatalog::element(CSTR element_name,bool print_err) const { 00365 DOMNode* node = getDoc(true)->getElementById(XMLStr(element_name)); 00366 if ( !node && print_err ) printError("Cannot find element:"+element_name); 00367 return node; 00368 } 00369 // ---------------------------------------------------------------------------- 00370 void XMLFileCatalog::deleteFID(CSTR fid) const { 00371 DOMNode *pn = 0, *fn = element(fid); 00372 if ( fn ) pn = fn->getParentNode(); 00373 if ( pn ) pn->removeChild(fn); 00374 } 00375 // ---------------------------------------------------------------------------- 00376 void XMLFileCatalog::registerFID(CSTR fid) const { 00377 if ( !fid.empty() ) { 00378 std::pair<DOMElement*, DOMElement*> res = i_registerFID(fid); 00379 if ( res.first == 0 || res.second == 0 ) { 00380 printError("Failed to register FID:"+fid); 00381 } 00382 return; 00383 } 00384 throw runtime_error("XMLFileCatalog> Cannot register LFN for invalid FID:"+fid); 00385 } 00386 // ---------------------------------------------------------------------------- 00387 std::pair<DOMElement*,DOMElement*> XMLFileCatalog::i_registerFID(CSTR fid) const { 00388 if ( !readOnly() ) { 00390 DOMElement *file = (DOMElement*)element(fid,false), *phyelem = 0, *logelem = 0; 00391 DOMDocument* doc = getDoc(true); 00392 if ( !file ) { 00393 DOMNode* fde = doc->getElementsByTagName(XMLStr("*"))->item(0); 00394 file = m_doc->createElement(XMLStr("File")); 00395 file->setAttribute(Attr_ID, XMLStr(fid)); 00396 file->setIdAttribute(Attr_ID); 00397 fde->appendChild(file); 00398 m_update = true; 00399 } 00400 for(XMLCollection c1(file); c1; ++c1 ) { 00401 char* nam = XMLString::transcode(c1->getNodeName()); 00402 if ( nam == PFNCOLL ) phyelem = c1; 00403 if ( nam == LFNCOLL ) logelem = c1; 00404 XMLString::release(&nam); 00405 } 00406 if ( !phyelem ) { 00407 phyelem = doc->createElement(PFNCOLL); 00408 file->appendChild(phyelem); 00409 m_update = true; 00410 } 00411 if ( !logelem ) { 00412 logelem = doc->createElement(LFNCOLL); 00413 file->appendChild(logelem); 00414 m_update = true; 00415 } 00416 return std::make_pair(logelem,phyelem); 00417 } 00418 printError("Cannot update readonly catalog!"); 00419 return std::pair<DOMElement*, DOMElement*>(0,0); 00420 } 00421 // ---------------------------------------------------------------------------- 00422 void XMLFileCatalog::registerPFN(CSTR fid, CSTR pfn, CSTR ftype) const { 00423 if ( !fid.empty() ) { 00424 std::pair<DOMElement*,DOMElement*> res = i_registerFID(fid); 00425 DOMElement* phyelem = res.second, *fnelem = 0; 00426 for(XMLCollection c(phyelem); c; ++c ) { 00427 char* nam = XMLString::transcode(c->getNodeName()); 00428 if ( nam == PFNNODE ) { 00429 XMLString::release(&nam); 00430 nam = XMLString::transcode(c->getAttribute(Attr_name)); 00431 if ( nam == pfn ) { 00432 XMLString::release(&nam); 00433 fnelem = c; 00434 break; 00435 } 00436 } 00437 XMLString::release(&nam); 00438 } 00439 if ( !fnelem ) { 00440 fnelem = getDoc(true)->createElement(PFNNODE); 00441 phyelem->appendChild(fnelem); 00442 fnelem->setAttribute(Attr_ftype,XMLStr(ftype)); 00443 fnelem->setAttribute(Attr_name,XMLStr(pfn)); 00444 fnelem->setIdAttribute(Attr_name); 00445 m_update = true; 00446 } 00447 return; 00448 } 00449 throw runtime_error("XMLFileCatalog> Cannot register PFN for invalid FID:"+fid); 00450 } 00451 // ---------------------------------------------------------------------------- 00452 void XMLFileCatalog::registerLFN(CSTR fid, CSTR lfn) const { 00453 if ( !fid.empty() ) { 00454 std::pair<DOMElement*, DOMElement*> res = i_registerFID(fid); 00455 DOMElement* logelem = res.first, *fnelem = 0; 00456 for(XMLCollection c(logelem); c; ++c ) { 00457 char* nam = XMLString::transcode(c->getNodeName()); 00458 if ( nam == LFNNODE ) { 00459 XMLString::release(&nam); 00460 nam = XMLString::transcode(c->getAttribute(Attr_name)); 00461 if ( nam == lfn ) { 00462 XMLString::release(&nam); 00463 fnelem = c; 00464 break; 00465 } 00466 } 00467 } 00468 if ( !fnelem ) { 00469 fnelem = getDoc(true)->createElement(LFNNODE); 00470 logelem->appendChild(fnelem); 00471 fnelem->setAttribute(Attr_name,XMLStr(lfn)); 00472 fnelem->setIdAttribute(Attr_name); 00473 m_update = true; 00474 } 00475 return; 00476 } 00477 throw runtime_error("XMLFileCatalog> Cannot register LFN for invalid FID:"+fid); 00478 } 00479 // ---------------------------------------------------------------------------- 00480 void XMLFileCatalog::commit() { 00481 try { 00482 if ( dirty() && !readOnly() ) { 00483 string xmlfile = getfile(true); 00484 XMLStr ii("LS"); 00485 DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii); 00486 DOMWriter *wr = ((DOMImplementationLS*)imp)->createDOMWriter(); 00487 XMLFormatTarget *tar = new LocalFileFormatTarget(xmlfile.c_str()); 00488 wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true); 00489 wr->writeNode(tar, *m_doc); 00490 wr->release(); 00491 delete tar; 00492 } 00493 } 00494 catch ( exception& e ) { 00495 printError(string("Cannot open output file:")+e.what()); 00496 } 00497 catch (...) { 00498 printError("Unknown IO rrror."); 00499 } 00500 } 00501 // ---------------------------------------------------------------------------- 00502 string XMLFileCatalog::getfile(bool create) { 00503 string protocol, path; 00504 XMLURL xerurl; 00505 try{ 00506 xerurl = (const XMLCh*)XMLStr(m_file); 00507 protocol = _toString(xerurl.getProtocolName()); 00508 path = _toString(xerurl.getPath()); 00509 } 00510 catch (const XMLException& e ) { 00511 printError(_toString(e.getMessage())); 00512 } 00513 if ( protocol.empty() ) { 00514 printError("Missing protocol."); 00515 } 00516 else if ( protocol == "http" || protocol == "ftp" ) { 00517 m_rdOnly = true; 00518 } 00519 else if ( protocol == "file" ) { 00520 m_rdOnly = false; 00521 struct stat buff; 00522 int exist = ::stat(path.c_str(),&buff) != -1; 00523 if ( create && !exist ) { 00524 MsgStream log(m_msgSvc,"XMLCatalog"); 00525 log << MSG::INFO << "File '" << path << "' does not exist. New file created." << endmsg; 00526 ofstream out(path.c_str()); 00527 if( !m_rdOnly && out.is_open() ) { 00528 out << (CSTR)EmptyCatalog << endl; 00529 } 00530 else { 00531 printError("Problem creating file "+path); 00532 } 00533 out.close(); 00534 } 00535 else if ( exist ) { 00536 return path; 00537 } 00538 else if ( !create ) { 00539 return ""; 00540 } 00541 } 00542 else { 00543 printError(protocol + ": protocol not supported."); 00544 } 00545 return path; 00546 }