| 27 | | static TrivialFileCatalog myTFC(eDest); |
|---|
| 28 | | eDest.Say("Copr. 2009 University of Nebraska-Lincoln TFC plugin v 1.0"); |
|---|
| 29 | | |
|---|
| 30 | | eDest.Say("Params: " << parms); |
|---|
| 31 | | |
|---|
| 32 | | return &myTFC; |
|---|
| 33 | | } |
|---|
| | 36 | TrivialFileCatalog *myTFC = new TrivialFileCatalog(eDest, "/tmp/test"); |
|---|
| | 37 | eDest->Say("Copr. 2009 University of Nebraska-Lincoln TFC plugin v 1.0"); |
|---|
| | 38 | |
|---|
| | 39 | eDest->Say("Params: "); |
|---|
| | 40 | eDest->Say(parms); |
|---|
| | 41 | |
|---|
| | 42 | return myTFC; |
|---|
| | 43 | } |
|---|
| | 44 | } |
|---|
| | 45 | |
|---|
| | 46 | typedef std::vector<std::string> StringVec; |
|---|
| | 47 | |
|---|
| | 48 | StringVec &split(const std::string &s, char delim, StringVec &elems) { |
|---|
| | 49 | std::stringstream ss(s); |
|---|
| | 50 | std::string item; |
|---|
| | 51 | while(std::getline(ss, item, delim)) { |
|---|
| | 52 | elems.push_back(item); |
|---|
| | 53 | } |
|---|
| | 54 | return elems; |
|---|
| | 55 | } |
|---|
| | 56 | |
|---|
| | 57 | |
|---|
| | 58 | StringVec split(const std::string &s, char delim) { |
|---|
| | 59 | StringVec elems; |
|---|
| | 60 | return split(s, delim, elems); |
|---|
| 46 | | XrdTfcCms::TrivialFileCatalog::TrivialFileCatalog () |
|---|
| 47 | | : m_connectionStatus (false), |
|---|
| 48 | | m_fileType ("ROOT_All"), |
|---|
| 49 | | m_destination ("any") |
|---|
| 50 | | { |
|---|
| 51 | | } |
|---|
| 52 | | |
|---|
| 53 | | XrdTfcCms::TrivialFileCatalog::~TrivialFileCatalog () |
|---|
| 54 | | { |
|---|
| | 73 | void XrdCmsTfc::TrivialFileCatalog::freeProtocolRules(ProtocolRules protRules) { |
|---|
| | 74 | ProtocolRules::iterator it; |
|---|
| | 75 | Rules::iterator it2; |
|---|
| | 76 | for (it = protRules.begin(); it != protRules.end(); it++) { |
|---|
| | 77 | Rules rules = (*it).second; |
|---|
| | 78 | for (it2 = rules.begin(); it2 != rules.end(); it2++) { |
|---|
| | 79 | if (it2->pathMatch != NULL) |
|---|
| | 80 | pcre_free(it2->pathMatch); |
|---|
| | 81 | } |
|---|
| | 82 | } |
|---|
| | 83 | } |
|---|
| | 84 | |
|---|
| | 85 | XrdCmsTfc::TrivialFileCatalog::~TrivialFileCatalog () |
|---|
| | 86 | { |
|---|
| | 87 | freeProtocolRules(m_directRules); |
|---|
| | 88 | freeProtocolRules(m_inverseRules); |
|---|
| 89 | | rule.pathMatch.setPattern (pathMatchRegexp); |
|---|
| 90 | | rule.pathMatch.compile (); |
|---|
| 91 | | rule.destinationMatch.setPattern (destinationMatchRegexp); |
|---|
| 92 | | rule.destinationMatch.compile (); |
|---|
| | 124 | const char *error; |
|---|
| | 125 | int erroffset; |
|---|
| | 126 | rule.pathMatch = NULL; |
|---|
| | 127 | rule.destinationMatch = NULL; |
|---|
| | 128 | rule.pathMatch = pcre_compile(pathMatchRegexp, 0, &error, &erroffset, NULL); |
|---|
| | 129 | if (rule.pathMatch == NULL) { |
|---|
| | 130 | char *err = (char *)malloc(BUFFSIZE*sizeof(char)); |
|---|
| | 131 | snprintf(err, BUFFSIZE, "PCRE compilation failed at offset %d: %s", erroffset, error); |
|---|
| | 132 | eDest->Say(err); |
|---|
| | 133 | free(err); |
|---|
| | 134 | return XRDCMSTFC_ERR_PARSERULE; |
|---|
| | 135 | } |
|---|
| | 136 | |
|---|
| | 137 | rule.destinationMatch = pcre_compile(destinationMatchRegexp, 0, &error, &erroffset, NULL); |
|---|
| | 138 | if (rule.destinationMatch == NULL) { |
|---|
| | 139 | char *err = (char *)malloc(BUFFSIZE*sizeof(char)); |
|---|
| | 140 | snprintf(err, BUFFSIZE, "PCRE compilation failed at offset %d: %s", erroffset, error); |
|---|
| | 141 | eDest->Say(err); |
|---|
| | 142 | free(err); |
|---|
| | 143 | return XRDCMSTFC_ERR_PARSERULE; |
|---|
| | 144 | } |
|---|
| 95 | | rules[protocol].push_back (rule); |
|---|
| 96 | | } |
|---|
| 97 | | |
|---|
| 98 | | void |
|---|
| 99 | | pool::TrivialFileCatalog::connect () |
|---|
| 100 | | { |
|---|
| 101 | | try |
|---|
| 102 | | { |
|---|
| 103 | | eDest.Say("Connecting to the catalog "); |
|---|
| 104 | | << m_url << coral::MessageStream::endmsg; |
|---|
| 105 | | |
|---|
| 106 | | if (m_url.find ("file:") != std::string::npos) |
|---|
| 107 | | { |
|---|
| 108 | | m_url = m_url.erase (0, |
|---|
| 109 | | m_url.find (":") + 1); |
|---|
| 110 | | } |
|---|
| 111 | | else |
|---|
| 112 | | { |
|---|
| 113 | | throw FCTransactionException |
|---|
| 114 | | ("TrivialFileCatalog::connect", |
|---|
| 115 | | ": Malformed url for file catalog configuration"); |
|---|
| 116 | | } |
|---|
| 117 | | |
|---|
| 118 | | lat::StringList tokens = lat::StringOps::split (m_url, "?"); |
|---|
| 119 | | m_filename = tokens[0]; |
|---|
| 120 | | |
|---|
| 121 | | if (tokens.size () == 2) |
|---|
| 122 | | { |
|---|
| 123 | | std::string options = tokens[1]; |
|---|
| 124 | | lat::StringList optionTokens = lat::StringOps::split (options, "&"); |
|---|
| 125 | | |
|---|
| 126 | | for (lat::StringList::iterator option = optionTokens.begin (); |
|---|
| 127 | | option != optionTokens.end (); |
|---|
| | 147 | rules[protocol].push_back (rule); |
|---|
| | 148 | return 0; |
|---|
| | 149 | } |
|---|
| | 150 | |
|---|
| | 151 | int |
|---|
| | 152 | XrdCmsTfc::TrivialFileCatalog::parse () |
|---|
| | 153 | { |
|---|
| | 154 | eDest->Say("Connecting to the catalog ", m_url.c_str()); |
|---|
| | 155 | |
|---|
| | 156 | if (m_url.find ("file:") != std::string::npos) { |
|---|
| | 157 | m_url = m_url.erase (0, m_url.find (":") + 1); |
|---|
| | 158 | } else { |
|---|
| | 159 | eDest->Say("TrivialFileCatalog::connect: Malformed url for file catalog configuration"); |
|---|
| | 160 | return XRDCMSTFC_ERR_URL; |
|---|
| | 161 | } |
|---|
| | 162 | |
|---|
| | 163 | m_filename = split(m_url, '?')[0]; |
|---|
| | 164 | |
|---|
| | 165 | size_t ques_pos = m_url.find("?"); |
|---|
| | 166 | if (ques_pos != std::string::npos) |
|---|
| | 167 | { |
|---|
| | 168 | m_filename = m_url.substr(0, ques_pos); |
|---|
| | 169 | std::string options = m_url.substr(ques_pos+1, std::string::npos); |
|---|
| | 170 | std::vector<std::string> optionTokens = split(options, '&'); |
|---|
| | 171 | |
|---|
| | 172 | for (StringVec::iterator option = optionTokens.begin(); |
|---|
| | 173 | option != optionTokens.end(); |
|---|
| 158 | | configFile.open (m_filename.c_str ()); |
|---|
| 159 | | |
|---|
| 160 | | |
|---|
| 161 | | trivialLog << coral::Info |
|---|
| 162 | | << "Using catalog configuration " |
|---|
| 163 | | << m_filename << coral::MessageStream::endmsg; |
|---|
| 164 | | |
|---|
| 165 | | if (!configFile.good () || !configFile.is_open ()) |
|---|
| 166 | | { |
|---|
| 167 | | m_transactionsta = 0; |
|---|
| 168 | | throw FCTransactionException |
|---|
| 169 | | ("TrivialFileCatalog::connect", |
|---|
| 170 | | ": Unable to open trivial file catalog " + m_filename); |
|---|
| 171 | | } |
|---|
| 172 | | |
|---|
| 173 | | configFile.close (); |
|---|
| | 206 | configFile.open(m_filename.c_str()); |
|---|
| | 207 | eDest->Say("Using catalog configuration", m_filename.c_str()); |
|---|
| | 208 | |
|---|
| | 209 | if (!configFile.good() || !configFile.is_open()) |
|---|
| | 210 | { |
|---|
| | 211 | eDest->Say("TrivialFileCatalog::parse: Unable to open trivial file catalog", m_filename.c_str()); |
|---|
| | 212 | return XRDCMSTFC_ERR_FILE; |
|---|
| | 213 | } |
|---|
| | 214 | |
|---|
| | 215 | configFile.close(); |
|---|
| 241 | | fid = applyRules (m_inverseRules, *protocol, m_destination, false, tmpPfn); |
|---|
| 242 | | if (! fid.empty ()) |
|---|
| 243 | | { |
|---|
| 244 | | return; |
|---|
| 245 | | } |
|---|
| 246 | | } |
|---|
| 247 | | } |
|---|
| 248 | | |
|---|
| 249 | | void |
|---|
| 250 | | pool::TrivialFileCatalog::lookupFileByLFN (const std::string& lfn, |
|---|
| 251 | | FileCatalog::FileID& fid) const |
|---|
| 252 | | { |
|---|
| 253 | | // return NULL id if the catalog is not connected. |
|---|
| 254 | | if (m_transactionsta == 0) { |
|---|
| 255 | | fid = FileCatalog::FileID(); |
|---|
| 256 | | return; |
|---|
| 257 | | } |
|---|
| 258 | | |
|---|
| 259 | | // GUID (FileID) and lfn are the same under TrivialFileCatalog |
|---|
| 260 | | fid = lfn; |
|---|
| 261 | | } |
|---|
| 262 | | |
|---|
| 263 | | std::string |
|---|
| 264 | | replaceWithRegexp (const lat::RegexpMatch matches, |
|---|
| | 272 | tmpLfn = applyRules(m_inverseRules, *protocol, m_destination, false, tmpPfn); |
|---|
| | 273 | if (!tmpLfn.empty()) |
|---|
| | 274 | { |
|---|
| | 275 | strncpy(buff, tmpLfn.c_str(), blen); |
|---|
| | 276 | return 0; |
|---|
| | 277 | } |
|---|
| | 278 | } |
|---|
| | 279 | eDest->Say("No pfn2lfn mapping for ", pfn); |
|---|
| | 280 | return XRDCMSTFC_ERR_NOPFN2LFN; |
|---|
| | 281 | } |
|---|
| | 282 | |
|---|
| | 283 | int |
|---|
| | 284 | XrdCmsTfc::TrivialFileCatalog::lfn2pfn(const char *lfn, char *buff, int blen) |
|---|
| | 285 | { |
|---|
| | 286 | std::string tmpPfn = ""; |
|---|
| | 287 | std::string tmpLfn = lfn; |
|---|
| | 288 | |
|---|
| | 289 | for (std::list<std::string>::iterator protocol = m_protocols.begin(); |
|---|
| | 290 | protocol != m_protocols.end(); |
|---|
| | 291 | protocol++) |
|---|
| | 292 | { |
|---|
| | 293 | tmpLfn = applyRules(m_directRules, *protocol, m_destination, false, tmpLfn); |
|---|
| | 294 | if (!tmpLfn.empty()) { |
|---|
| | 295 | strncpy(buff, tmpLfn.c_str(), blen); |
|---|
| | 296 | return 0; |
|---|
| | 297 | } |
|---|
| | 298 | } |
|---|
| | 299 | eDest->Say("No lfn2pfn mapping for ", lfn); |
|---|
| | 300 | return XRDCMSTFC_ERR_NOLFN2PFN; |
|---|
| | 301 | } |
|---|
| | 302 | |
|---|
| | 303 | |
|---|
| | 304 | |
|---|
| | 305 | std::string replace(const std::string inputString, pcre * re, std::string replacementString) { |
|---|
| | 306 | |
|---|
| | 307 | int ovector[OVECCOUNT], rc; |
|---|
| | 308 | std::string result; |
|---|
| | 309 | rc = pcre_exec(re, NULL, inputString.c_str(), inputString.length(), 0, 0, |
|---|
| | 310 | ovector, OVECCOUNT); |
|---|
| | 311 | |
|---|
| | 312 | if (rc <= 0) { |
|---|
| | 313 | return ""; |
|---|
| | 314 | } |
|---|
| | 315 | |
|---|
| | 316 | int substring_end = 0, substring_begin; |
|---|
| | 317 | for (int i = 0; i < rc; i++) { |
|---|
| | 318 | substring_begin = ovector[2*i]; |
|---|
| | 319 | result += inputString.substr(substring_end, substring_begin-substring_end) + replacementString; |
|---|
| | 320 | substring_end = ovector[2*i+1] + substring_begin; |
|---|
| | 321 | } |
|---|
| | 322 | |
|---|
| | 323 | return result; |
|---|
| | 324 | } |
|---|
| | 325 | |
|---|
| | 326 | std::string replaceWithRegexp (const int ovector[OVECCOUNT], const int rc, |
|---|
| 281 | | std::string matchResult = matches.matchString (inputString, i); |
|---|
| 282 | | |
|---|
| 283 | | lat::Regexp sustitutionToken (variableRegexp); |
|---|
| 284 | | |
|---|
| 285 | | //std::cerr << "Current match: " << matchResult << std::endl; |
|---|
| 286 | | |
|---|
| 287 | | result = lat::StringOps::replace (result, |
|---|
| 288 | | sustitutionToken, |
|---|
| 289 | | matchResult); |
|---|
| | 345 | |
|---|
| | 346 | substring_begin = ovector[2*i]; |
|---|
| | 347 | substring_length = ovector[2*i+1] - substring_begin; |
|---|
| | 348 | std::string matchResult = inputString.substr(substring_begin, substring_length); |
|---|
| | 349 | |
|---|
| | 350 | const char *error; |
|---|
| | 351 | int erroffset; |
|---|
| | 352 | pcre * substitutionToken = pcre_compile(variableRegexp.c_str(), |
|---|
| | 353 | 0, &error, &erroffset, NULL); |
|---|
| | 354 | if (substitutionToken == NULL) { |
|---|
| | 355 | pcre_free(substitutionToken); |
|---|
| | 356 | return ""; |
|---|
| | 357 | } |
|---|
| | 358 | std::cerr << "Current match: " << matchResult << std::endl; |
|---|
| | 359 | |
|---|
| | 360 | result = replace(result, substitutionToken, matchResult); |
|---|
| | 361 | |
|---|
| | 362 | pcre_free(substitutionToken); |
|---|
| 348 | | |
|---|
| 349 | | void |
|---|
| 350 | | XrdTfcCms::TrivialFileCatalog::lookupBestPFN (const FileCatalog::FileID& fid, |
|---|
| 351 | | const FileCatalog::FileOpenMode& /*omode*/, |
|---|
| 352 | | const FileCatalog::FileAccessPattern& /*amode*/, |
|---|
| 353 | | std::string& pfn, |
|---|
| 354 | | std::string& filetype) const |
|---|
| 355 | | { |
|---|
| 356 | | if (m_transactionsta == 0) |
|---|
| 357 | | throw FCconnectionException("TrivialFileCatalog::lookupBestPFN", |
|---|
| 358 | | "Catalog not connected"); |
|---|
| 359 | | filetype = m_fileType; |
|---|
| 360 | | |
|---|
| 361 | | pfn = ""; |
|---|
| 362 | | std::string lfn = fid; |
|---|
| 363 | | |
|---|
| 364 | | for (lat::StringList::const_iterator protocol = m_protocols.begin (); |
|---|
| 365 | | protocol != m_protocols.end (); |
|---|
| 366 | | protocol++) |
|---|
| 367 | | { |
|---|
| 368 | | pfn = applyRules (m_directRules, |
|---|
| 369 | | *protocol, |
|---|
| 370 | | m_destination, |
|---|
| 371 | | true, |
|---|
| 372 | | lfn); |
|---|
| 373 | | if (! pfn.empty ()) |
|---|
| 374 | | { |
|---|
| 375 | | return; |
|---|
| 376 | | } |
|---|
| 377 | | } |
|---|
| 378 | | } |
|---|
| 379 | | |
|---|
| 380 | | bool |
|---|
| 381 | | XrdCmsTfc::TrivialFileCatalog::retrievePFN (const std::string& query, |
|---|
| 382 | | FCBuf<PFNEntry>& buf, |
|---|
| 383 | | const size_t& /*start*/) |
|---|
| 384 | | { |
|---|
| 385 | | if (m_transactionsta == 0) |
|---|
| 386 | | throw FCconnectionException("TrivialFileCatalog::lookupBestPFN", |
|---|
| 387 | | "Catalog not connected"); |
|---|
| 388 | | // The only query supported is lfn='something' or pfn='something' |
|---|
| 389 | | // No spaces allowed in something. |
|---|
| 390 | | lat::Regexp grammar ("(lfname|guid)='(.*)'"); |
|---|
| 391 | | lat::RegexpMatch grammarMatches; |
|---|
| 392 | | |
|---|
| 393 | | grammar.match (query, 0, 0, &grammarMatches); |
|---|
| 394 | | |
|---|
| 395 | | if (grammarMatches.numMatches () != 3) |
|---|
| 396 | | { |
|---|
| 397 | | throw FCTransactionException |
|---|
| 398 | | ("TrivialFileCatalog::retrievePFN", |
|---|
| 399 | | "malformed query. the only supported one is lfname='something'" |
|---|
| 400 | | " or guid='something'"); |
|---|
| 401 | | } |
|---|
| 402 | | |
|---|
| 403 | | std::string lfn = grammarMatches.matchString (query, 2); |
|---|
| 404 | | |
|---|
| 405 | | for (lat::StringList::iterator protocol = m_protocols.begin (); |
|---|
| 406 | | protocol != m_protocols.end (); |
|---|
| 407 | | protocol++) |
|---|
| 408 | | { |
|---|
| 409 | | std::string pfn = applyRules (m_directRules, *protocol, m_destination, true, lfn); |
|---|
| 410 | | if (! pfn.empty ()) |
|---|
| 411 | | { |
|---|
| 412 | | buf.push_back (PFNEntry(pfn, |
|---|
| 413 | | lfn, |
|---|
| 414 | | m_fileType)); |
|---|
| 415 | | return true; |
|---|
| 416 | | } |
|---|
| 417 | | } |
|---|
| 418 | | |
|---|
| 419 | | |
|---|
| 420 | | |
|---|
| 421 | | buf.push_back (PFNEntry(lfn, |
|---|
| 422 | | lfn, |
|---|
| 423 | | m_fileType)); |
|---|
| 424 | | |
|---|
| 425 | | return false; |
|---|
| 426 | | } |
|---|
| 427 | | |
|---|
| 428 | | bool |
|---|
| 429 | | XrdCmsTfc::TrivialFileCatalog::retrieveLFN (const std::string& query, |
|---|
| 430 | | FCBuf<LFNEntry>& buf, |
|---|
| 431 | | const size_t& /*start*/) |
|---|
| 432 | | { |
|---|
| 433 | | if (m_transactionsta == 0) |
|---|
| 434 | | throw FCconnectionException("TrivialFileCatalog::lookupBestPFN", |
|---|
| 435 | | "Catalog not connected"); |
|---|
| 436 | | // The only query supported is lfn='something' or pfn='something' |
|---|
| 437 | | // No spaces allowed in something. |
|---|
| 438 | | |
|---|
| 439 | | lat::Regexp grammar ("(pfname|guid)='(.*)'"); |
|---|
| 440 | | lat::RegexpMatch grammarMatches; |
|---|
| 441 | | |
|---|
| 442 | | grammar.match (query, 0, 0, &grammarMatches); |
|---|
| 443 | | |
|---|
| 444 | | if (grammarMatches.numMatches () != 3) |
|---|
| 445 | | { |
|---|
| 446 | | throw FCTransactionException |
|---|
| 447 | | ("TrivialFileCatalog::retrieveLFN", |
|---|
| 448 | | "malformed query. the only supported one is pfname='something'" |
|---|
| 449 | | " or guid='something'"); |
|---|
| 450 | | } |
|---|
| 451 | | |
|---|
| 452 | | std::string selector = grammarMatches.matchString (query, 1); |
|---|
| 453 | | std::string pfn = grammarMatches.matchString (query, 2); |
|---|
| 454 | | |
|---|
| 455 | | |
|---|
| 456 | | if (selector == "guid") |
|---|
| 457 | | { |
|---|
| 458 | | buf.push_back (LFNEntry (pfn, |
|---|
| 459 | | pfn)); |
|---|
| 460 | | return true; |
|---|
| 461 | | } |
|---|
| 462 | | |
|---|
| 463 | | |
|---|
| 464 | | for (lat::StringList::iterator protocol = m_protocols.begin (); |
|---|
| 465 | | protocol != m_protocols.end (); |
|---|
| 466 | | protocol++) |
|---|
| 467 | | { |
|---|
| 468 | | std::string lfn = applyRules (m_inverseRules, *protocol, m_destination, false, pfn); |
|---|
| 469 | | // std::cerr << "LFN: " << lfn << std::endl; |
|---|
| 470 | | |
|---|
| 471 | | if (! lfn.empty ()) |
|---|
| 472 | | { |
|---|
| 473 | | buf.push_back (LFNEntry(lfn, |
|---|
| 474 | | lfn)); |
|---|
| 475 | | return true; |
|---|
| 476 | | } |
|---|
| 477 | | } |
|---|
| 478 | | |
|---|
| 479 | | |
|---|
| 480 | | |
|---|
| 481 | | buf.push_back (LFNEntry(pfn, |
|---|
| 482 | | pfn)); |
|---|
| 483 | | |
|---|
| 484 | | return false; |
|---|
| 485 | | } |
|---|
| 486 | | |
|---|
| 487 | | |
|---|