00001 #include "Utilities/XrdAdaptor/src/XrdFile.h"
00002 #include "FWCore/Utilities/interface/EDMException.h"
00003 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00004 #include <vector>
00005 #include <sstream>
00006
00007 XrdFile::XrdFile (void)
00008 : m_client (0),
00009 m_offset (0),
00010 m_stat(),
00011 m_close (false),
00012 m_name()
00013 {
00014 memset(&m_stat, 0, sizeof (m_stat));
00015 }
00016
00017 XrdFile::XrdFile (const char *name,
00018 int flags ,
00019 int perms )
00020 : m_client (0),
00021 m_offset (0),
00022 m_stat(),
00023 m_close (false),
00024 m_name()
00025 {
00026 memset(&m_stat, 0, sizeof (m_stat));
00027 open (name, flags, perms);
00028 }
00029
00030 XrdFile::XrdFile (const std::string &name,
00031 int flags ,
00032 int perms )
00033 : m_client (0),
00034 m_offset (0),
00035 m_stat(),
00036 m_close (false),
00037 m_name()
00038 {
00039 memset(&m_stat, 0, sizeof (m_stat));
00040 open (name.c_str (), flags, perms);
00041 }
00042
00043 XrdFile::~XrdFile (void)
00044 {
00045 if (m_close)
00046 edm::LogError("XrdFileError")
00047 << "Destructor called on XROOTD file '" << m_name
00048 << "' but the file is still open";
00049 }
00050
00052 void
00053 XrdFile::create (const char *name,
00054 bool exclusive ,
00055 int perms )
00056 {
00057 open (name,
00058 (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00059 | (exclusive ? IOFlags::OpenExclusive : 0)),
00060 perms);
00061 }
00062
00063 void
00064 XrdFile::create (const std::string &name,
00065 bool exclusive ,
00066 int perms )
00067 {
00068 open (name.c_str (),
00069 (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00070 | (exclusive ? IOFlags::OpenExclusive : 0)),
00071 perms);
00072 }
00073
00074 void
00075 XrdFile::open (const std::string &name,
00076 int flags ,
00077 int perms )
00078 { open (name.c_str (), flags, perms); }
00079
00080 void
00081 XrdFile::open (const char *name,
00082 int flags ,
00083 int perms )
00084 {
00085
00086 if ((name == 0) || (*name == 0)) {
00087 edm::Exception ex(edm::errors::FileOpenError);
00088 ex << "Cannot open a file without a name";
00089 ex.addContext("Calling XrdFile::open()");
00090 throw ex;
00091 }
00092 if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0) {
00093 edm::Exception ex(edm::errors::FileOpenError);
00094 ex << "Must open file '" << name << "' at least for read or write";
00095 ex.addContext("Calling XrdFile::open()");
00096 throw ex;
00097 }
00098
00099 if (m_client && m_close)
00100 close();
00101 else
00102 abort();
00103
00104
00105 int openflags = 0;
00106
00107 if (flags & IOFlags::OpenWrite)
00108 openflags |= kXR_open_updt;
00109 else if (flags & IOFlags::OpenRead)
00110 openflags |= kXR_open_read;
00111
00112 if (flags & IOFlags::OpenAppend) {
00113 edm::Exception ex(edm::errors::FileOpenError);
00114 ex << "Opening file '" << name << "' in append mode not supported";
00115 ex.addContext("Calling XrdFile::open()");
00116 throw ex;
00117 }
00118
00119 if (flags & IOFlags::OpenCreate)
00120 {
00121 if (! (flags & IOFlags::OpenExclusive))
00122 openflags |= kXR_delete;
00123 openflags |= kXR_new;
00124 openflags |= kXR_mkpath;
00125 }
00126
00127 if ((flags & IOFlags::OpenTruncate) && (flags & IOFlags::OpenWrite))
00128 openflags |= kXR_delete;
00129
00130 m_name = name;
00131 m_client = new XrdClient(name);
00132 if (! m_client->Open(perms, openflags)
00133 || m_client->LastServerResp()->status != kXR_ok) {
00134 edm::Exception ex(edm::errors::FileOpenError);
00135 ex << "XrdClient::Open(name='" << name
00136 << "', flags=0x" << std::hex << openflags
00137 << ", permissions=0" << std::oct << perms << std::dec
00138 << ") => error '" << m_client->LastServerError()->errmsg
00139 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00140 ex.addContext("Calling XrdFile::open()");
00141 addConnection(ex);
00142 throw ex;
00143 }
00144 if (! m_client->Stat(&m_stat)) {
00145 edm::Exception ex(edm::errors::FileOpenError);
00146 ex << "XrdClient::Stat(name='" << name
00147 << ") => error '" << m_client->LastServerError()->errmsg
00148 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00149 ex.addContext("Calling XrdFile::open()");
00150 addConnection(ex);
00151 throw ex;
00152 }
00153 m_offset = 0;
00154 m_close = true;
00155 edm::LogInfo("XrdFileInfo") << "Opened " << m_name;
00156
00157 XrdClientConn *conn = m_client->GetClientConn();
00158 edm::LogInfo("XrdFileInfo") << "Connection URL " << conn->GetCurrentUrl().GetUrl().c_str();
00159 }
00160
00161 void
00162 XrdFile::close (void)
00163 {
00164 if (! m_client)
00165 {
00166 edm::LogError("XrdFileError")
00167 << "XrdFile::close(name='" << m_name
00168 << "') called but the file is not open";
00169 m_close = false;
00170 return;
00171 }
00172
00173 if (! m_client->Close())
00174 edm::LogWarning("XrdFileWarning")
00175 << "XrdFile::close(name='" << m_name
00176 << "') failed with error '" << m_client->LastServerError()->errmsg
00177 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00178 delete m_client;
00179 m_client = 0;
00180
00181 m_close = false;
00182 m_offset = 0;
00183 memset(&m_stat, 0, sizeof (m_stat));
00184 edm::LogInfo("XrdFileInfo") << "Closed " << m_name;
00185 }
00186
00187 void
00188 XrdFile::abort (void)
00189 {
00190 delete m_client;
00191 m_client = 0;
00192 m_close = false;
00193 m_offset = 0;
00194 memset(&m_stat, 0, sizeof (m_stat));
00195 }
00196
00198 IOSize
00199 XrdFile::read (void *into, IOSize n)
00200 {
00201 if (n > 0x7fffffff) {
00202 edm::Exception ex(edm::errors::FileReadError);
00203 ex << "XrdFile::read(name='" << m_name << "', n=" << n
00204 << ") too many bytes, limit is 0x7fffffff";
00205 ex.addContext("Calling XrdFile::read()");
00206 addConnection(ex);
00207 throw ex;
00208 }
00209 int s = m_client->Read(into, m_offset, n);
00210 if (s < 0) {
00211 edm::Exception ex(edm::errors::FileReadError);
00212 ex << "XrdClient::Read(name='" << m_name
00213 << "', offset=" << m_offset << ", n=" << n
00214 << ") failed with error '" << m_client->LastServerError()->errmsg
00215 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00216 ex.addContext("Calling XrdFile::read()");
00217 addConnection(ex);
00218 throw ex;
00219 }
00220 m_offset += s;
00221 return s;
00222 }
00223
00224 IOSize
00225 XrdFile::read (void *into, IOSize n, IOOffset pos)
00226 {
00227 if (n > 0x7fffffff) {
00228 edm::Exception ex(edm::errors::FileReadError);
00229 ex << "XrdFile::read(name='" << m_name << "', n=" << n
00230 << ") exceeds read size limit 0x7fffffff";
00231 ex.addContext("Calling XrdFile::read()");
00232 addConnection(ex);
00233 throw ex;
00234 }
00235 int s = m_client->Read(into, pos, n);
00236 if (s < 0) {
00237 edm::Exception ex(edm::errors::FileReadError);
00238 ex << "XrdClient::Read(name='" << m_name
00239 << "', offset=" << m_offset << ", n=" << n
00240 << ") failed with error '" << m_client->LastServerError()->errmsg
00241 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00242 ex.addContext("Calling XrdFile::read()");
00243 addConnection(ex);
00244 throw ex;
00245 }
00246 return s;
00247 }
00248
00249 IOSize
00250 XrdFile::readv (IOBuffer *into, IOSize n)
00251 {
00252
00253
00254
00255
00256
00257
00258
00259 IOOffset pos = m_offset;
00260 std::vector<long long> offsets (n);
00261 std::vector<int> lengths (n);
00262 for (IOSize i = 0; i < n; ++i)
00263 {
00264 IOSize len = into[i].size();
00265 if (len > 0x7fffffff) {
00266 edm::Exception ex(edm::errors::FileReadError);
00267 ex << "XrdFile::readv(name='" << m_name << "')[" << i
00268 << "].size=" << len << " exceeds read size limit 0x7fffffff";
00269 ex.addContext("Calling XrdFile::readv()");
00270 addConnection(ex);
00271 throw ex;
00272 }
00273 offsets[i] = pos;
00274 lengths[i] = len;
00275 pos += len;
00276 }
00277
00278
00279 if (m_client->ReadV(0, &offsets[0], &lengths[0], n) < 0) {
00280 edm::Exception ex(edm::errors::FileReadError);
00281 ex << "XrdClient::ReadV(name='" << m_name
00282 << "') failed with error '" << m_client->LastServerError()->errmsg
00283 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00284 ex.addContext("Calling XrdFile::readv()");
00285 addConnection(ex);
00286 throw ex;
00287 }
00288
00289
00290 IOSize total = 0;
00291 for (IOSize i = 0; i < n; ++i)
00292 {
00293 int s = m_client->Read(into[i].data(), offsets[i], lengths[i]);
00294 if (s < 0)
00295 {
00296 if (i > 0)
00297 break;
00298 edm::Exception ex(edm::errors::FileReadError);
00299 ex << "XrdClient::Read(name='" << m_name
00300 << "', offset=" << offsets[i] << ", n=" << lengths[i]
00301 << ") failed with error '" << m_client->LastServerError()->errmsg
00302 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00303 ex.addContext("Calling XrdFile::readv()");
00304 addConnection(ex);
00305 throw ex;
00306 }
00307 total += s;
00308 m_offset += s;
00309 }
00310
00311 return total;
00312 }
00313
00314 IOSize
00315 XrdFile::readv (IOPosBuffer *into, IOSize n)
00316 {
00317
00318 std::vector<long long> offsets (n);
00319 std::vector<int> lengths (n);
00320 for (IOSize i = 0; i < n; ++i)
00321 {
00322 IOSize len = into[i].size();
00323 if (len > 0x7fffffff) {
00324 edm::Exception ex(edm::errors::FileReadError);
00325 ex << "XrdFile::readv(name='" << m_name << "')[" << i
00326 << "].size=" << len << " exceeds read size limit 0x7fffffff";
00327 ex.addContext("Calling XrdFile::readv()");
00328 addConnection(ex);
00329 throw ex;
00330 }
00331 offsets[i] = into[i].offset();
00332 lengths[i] = len;
00333 }
00334
00335
00336 if (m_client->ReadV(0, &offsets[0], &lengths[0], n) < 0) {
00337 edm::Exception ex(edm::errors::FileReadError);
00338 ex << "XrdClient::ReadV(name='" << m_name
00339 << "') failed with error '" << m_client->LastServerError()->errmsg
00340 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00341 ex.addContext("Calling XrdFile::readv()");
00342 addConnection(ex);
00343 throw ex;
00344 }
00345
00346 IOSize total = 0;
00347 for (IOSize i = 0; i < n; ++i)
00348 {
00349 int s = m_client->Read(into[i].data(), offsets[i], lengths[i]);
00350 if (s < 0)
00351 {
00352 if (i > 0)
00353 break;
00354 edm::Exception ex(edm::errors::FileReadError);
00355 ex << "XrdClient::Read(name='" << m_name
00356 << "', offset=" << offsets[i] << ", n=" << lengths[i]
00357 << ") failed with error '" << m_client->LastServerError()->errmsg
00358 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00359 ex.addContext("Calling XrdFile::readv()");
00360 addConnection(ex);
00361 throw ex;
00362 }
00363 total += s;
00364 }
00365
00366 return total;
00367 }
00368
00369 IOSize
00370 XrdFile::write (const void *from, IOSize n)
00371 {
00372 if (n > 0x7fffffff) {
00373 cms::Exception ex("FileWriteError");
00374 ex << "XrdFile::write(name='" << m_name << "', n=" << n
00375 << ") too many bytes, limit is 0x7fffffff";
00376 ex.addContext("Calling XrdFile::write()");
00377 addConnection(ex);
00378 throw ex;
00379 }
00380 ssize_t s = m_client->Write(from, m_offset, n);
00381 if (s < 0) {
00382 cms::Exception ex("FileWriteError");
00383 ex << "XrdFile::write(name='" << m_name << "', n=" << n
00384 << ") failed with error '" << m_client->LastServerError()->errmsg
00385 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00386 ex.addContext("Calling XrdFile::write()");
00387 addConnection(ex);
00388 throw ex;
00389 }
00390 m_offset += s;
00391 if (m_offset > m_stat.size)
00392 m_stat.size = m_offset;
00393
00394 return s;
00395 }
00396
00397 IOSize
00398 XrdFile::write (const void *from, IOSize n, IOOffset pos)
00399 {
00400 if (n > 0x7fffffff) {
00401 cms::Exception ex("FileWriteError");
00402 ex << "XrdFile::write(name='" << m_name << "', n=" << n
00403 << ") too many bytes, limit is 0x7fffffff";
00404 ex.addContext("Calling XrdFile::write()");
00405 addConnection(ex);
00406 throw ex;
00407 }
00408 ssize_t s = m_client->Write(from, pos, n);
00409 if (s < 0) {
00410 cms::Exception ex("FileWriteError");
00411 ex << "XrdFile::write(name='" << m_name << "', n=" << n
00412 << ") failed with error '" << m_client->LastServerError()->errmsg
00413 << "' (errno=" << m_client->LastServerError()->errnum << ")";
00414 ex.addContext("Calling XrdFile::write()");
00415 addConnection(ex);
00416 throw ex;
00417 }
00418 if (pos + s > m_stat.size)
00419 m_stat.size = pos + s;
00420
00421 return s;
00422 }
00423
00424 bool
00425 XrdFile::prefetch (const IOPosBuffer *what, IOSize n)
00426 {
00427 std::vector<long long> offsets; offsets.resize(n);
00428 std::vector<int> lens; lens.resize(n);
00429 kXR_int64 total = 0;
00430 for (IOSize i = 0; i < n; ++i) {
00431 offsets[i] = what[i].offset();
00432 lens[i] = what[i].size();
00433 total += what[i].size();
00434 }
00435
00436 kXR_int64 r = m_client->ReadV(NULL, &offsets[0], &lens[0], n);
00437 return r == total;
00438 }
00439
00443 IOOffset
00444 XrdFile::position (IOOffset offset, Relative whence )
00445 {
00446 if (! m_client) {
00447 cms::Exception ex("FilePositionError");
00448 ex << "XrdFile::position() called on a closed file";
00449 ex.addContext("Calling XrdFile::position()");
00450 addConnection(ex);
00451 throw ex;
00452 }
00453 switch (whence)
00454 {
00455 case SET:
00456 m_offset = offset;
00457 break;
00458
00459 case CURRENT:
00460 m_offset += offset;
00461 break;
00462
00463 case END:
00464 m_offset = m_stat.size + offset;
00465 break;
00466
00467 default:
00468 cms::Exception ex("FilePositionError");
00469 ex << "XrdFile::position() called with incorrect 'whence' parameter";
00470 ex.addContext("Calling XrdFile::position()");
00471 addConnection(ex);
00472 throw ex;
00473 }
00474
00475 if (m_offset < 0)
00476 m_offset = 0;
00477 if (m_offset > m_stat.size)
00478 m_stat.size = m_offset;
00479
00480 return m_offset;
00481 }
00482
00483 void
00484 XrdFile::resize (IOOffset )
00485 {
00486 cms::Exception ex("FileResizeError");
00487 ex << "XrdFile::resize(name='" << m_name << "') not implemented";
00488 ex.addContext("Calling XrdFile::resize()");
00489 addConnection(ex);
00490 throw ex;
00491 }
00492
00493 void
00494 XrdFile::addConnection (cms::Exception &ex)
00495 {
00496 XrdClientConn *conn = m_client->GetClientConn();
00497 if (conn) {
00498 std::stringstream ss;
00499 ss << "Current server connection: " << conn->GetCurrentUrl().GetUrl().c_str();
00500 ex.addAdditionalInfo(ss.str());
00501 }
00502 }
00503