XrdSutPFile.cc

Go to the documentation of this file.
00001 // $Id: XrdSutPFile.cc 30949 2009-11-02 16:37:58Z ganis $
00002 
00003 const char *XrdSutPFileCVSID = "$Id: XrdSutPFile.cc 30949 2009-11-02 16:37:58Z ganis $";
00004 #include <stdio.h>
00005 #include <string.h>
00006 #include <unistd.h>
00007 #include <stdlib.h>
00008 #include <sys/types.h>
00009 #include <sys/stat.h>
00010 #include <fcntl.h>
00011 #include <errno.h>
00012 #include <time.h>
00013 
00014 #include "XrdSut/XrdSutAux.hh"
00015 #include "XrdSut/XrdSutPFEntry.hh"
00016 #include "XrdSut/XrdSutPFile.hh"
00017 #include "XrdSut/XrdSutTrace.hh"
00018 
00019 //_________________________________________________________________
00020 XrdSutPFEntInd::XrdSutPFEntInd(const char *n, kXR_int32 no,
00021                                kXR_int32 eo, kXR_int32 es)
00022 {
00023    // Constructor
00024 
00025    name = 0;
00026    if (n) {
00027       name = new char[strlen(n)+1];
00028       if (name)
00029          strcpy(name,n);
00030    }
00031    nxtofs = no;
00032    entofs = eo;
00033    entsiz = es;
00034 } 
00035 
00036 //_________________________________________________________________
00037 XrdSutPFEntInd::XrdSutPFEntInd(const XrdSutPFEntInd &ei)
00038 {
00039    //Copy constructor
00040 
00041    name = 0;
00042    if (ei.name) {
00043       name = new char[strlen(ei.name)+1];
00044       if (name)
00045          strcpy(name,ei.name);
00046    }
00047    nxtofs = ei.nxtofs;
00048    entofs = ei.entofs;
00049    entsiz = ei.entsiz;
00050 }
00051 
00052 //_________________________________________________________________
00053 void XrdSutPFEntInd::SetName(const char *n)
00054 {
00055    // Name setter
00056 
00057    if (name) {
00058       delete[] name;
00059       name = 0;
00060    }
00061    if (n) {
00062       name = new char[strlen(n)+1];
00063       if (name)
00064          strcpy(name,n);
00065    }
00066 }
00067 
00068 //______________________________________________________________________________
00069 XrdSutPFEntInd& XrdSutPFEntInd::operator=(const XrdSutPFEntInd ei)
00070 {
00071    // Assign index entry ei to local index entry.
00072 
00073    name = 0;
00074    if (ei.name) {
00075       name = new char[strlen(ei.name)+1];
00076       if (name)
00077          strcpy(name,ei.name);
00078    }
00079    nxtofs = ei.nxtofs;
00080    entofs = ei.entofs;
00081    entsiz = ei.entsiz;
00082 
00083    return *this;
00084 }
00085 
00086 //_________________________________________________________________
00087 XrdSutPFHeader::XrdSutPFHeader(const char *id, kXR_int32 v, kXR_int32 ct,
00088                            kXR_int32 it, kXR_int32 ent, kXR_int32 ofs)
00089 {
00090    // Constructor
00091 
00092    memset(fileID,0,kFileIDSize);
00093    if (id) {
00094       kXR_int32 lid = strlen(id); 
00095       if (lid  > kFileIDSize)
00096          lid = kFileIDSize; 
00097       memcpy(fileID,id,lid);
00098    }
00099    version = v;
00100    ctime = ct;
00101    itime = it;
00102    entries = ent;
00103    indofs = ofs;
00104    jnksiz = 0;     // At start everything is reachable
00105 } 
00106 
00107 //_________________________________________________________________
00108 XrdSutPFHeader::XrdSutPFHeader(const XrdSutPFHeader &fh)
00109 {
00110    // Copy constructor
00111 
00112    memcpy(fileID,fh.fileID,kFileIDSize); 
00113    version = fh.version;
00114    ctime = fh.ctime;
00115    itime = fh.itime;
00116    entries = fh.entries;
00117    indofs = fh.indofs;
00118    jnksiz = fh.jnksiz;
00119 }
00120 
00121 //_________________________________________________________________
00122 void XrdSutPFHeader::Print() const
00123 {
00124    // Header printout
00125 
00126    struct tm tst;
00127 
00128    // String form for time of last change
00129    char sctime[256] = {0};
00130    time_t ttmp = ctime;
00131    localtime_r(&ttmp,&tst);
00132    asctime_r(&tst,sctime);
00133    sctime[strlen(sctime)-1] = 0;
00134 
00135    // String form for time of last index change
00136    char sitime[256] = {0};
00137    ttmp = itime;
00138    localtime_r(&ttmp,&tst);
00139    asctime_r(&tst,sitime);
00140    sitime[strlen(sitime)-1] = 0;
00141 
00142    fprintf(stdout,
00143        "//------------------------------------"
00144                 "------------------------------//\n"
00145        "// \n"
00146        "//  File Header dump \n"
00147        "// \n"
00148        "//  File ID:          %s \n"
00149        "//  version:          %d \n"
00150        "//  last changed on:  %s (%d sec) \n"
00151        "//  index changed on: %s (%d sec) \n"
00152        "//  entries:          %d  \n"
00153        "//  unreachable:      %d  \n"
00154        "//  first ofs:        %d  \n"
00155        "// \n"
00156        "//------------------------------------"
00157                 "------------------------------//\n",
00158        fileID,version,sctime,ctime,sitime,itime,entries,jnksiz,indofs); 
00159 }
00160 
00161 //________________________________________________________________
00162 XrdSutPFile::XrdSutPFile(const char *n, kXR_int32 openmode,
00163                          kXR_int32 createmode, bool hashtab)
00164 {
00165    // Constructor
00166 
00167    name = 0; 
00168    if (n) {
00169       name = new char[strlen(n)+1];
00170       if (name)
00171          strcpy(name,n);
00172    }
00173    valid = 0;
00174    fFd = -1;
00175    fHTutime = -1;
00176    fHashTable = 0;
00177 
00178    valid = Init(n, openmode, createmode, hashtab);
00179 }
00180 
00181 //________________________________________________________________
00182 XrdSutPFile::XrdSutPFile(const XrdSutPFile &f)
00183 {
00184    // Copy constructor
00185 
00186    name = 0; 
00187    if (f.name) { 
00188       name = new char[strlen(f.name)+1];
00189       if (name)
00190          strcpy(name,f.name);
00191    }
00192    fFd = f.fFd ;
00193 }
00194 
00195 //________________________________________________________________
00196 XrdSutPFile::~XrdSutPFile()
00197 {
00198    // Destructor
00199 
00200    if (name)
00201       delete[] name;
00202    name = 0;
00203    if (fHashTable)
00204       delete fHashTable;
00205    fHashTable = 0;
00206 
00207    Close(); 
00208 }
00209 
00210 //________________________________________________________________
00211 bool XrdSutPFile::Init(const char *n, kXR_int32 openmode,
00212                        kXR_int32 createmode, bool hashtab)
00213 {
00214    // (re)initialize PFile
00215 
00216    // Make sure it is closed
00217    Close();
00218 
00219    // Reset members
00220    if (name)
00221       delete[] name;
00222    name = 0; 
00223    if (n) {
00224       name = new char[strlen(n)+1];
00225       if (name)
00226          strcpy(name,n);
00227    }
00228    valid = 0;
00229    fFd = -1;
00230    fHTutime = -1;
00231    if (fHashTable)
00232       delete fHashTable;
00233    fHashTable = 0;
00234 
00235    // If name is missing nothing can be done
00236    if (!name)
00237       return 0;
00238 
00239    // open modes
00240    bool create    = (openmode & kPFEcreate);
00241    bool leaveopen = (openmode & kPFEopen);
00242 
00243    // If file does not exists, create it with default header
00244    struct stat st;
00245    if (stat(name, &st) == -1) {
00246       if (errno == ENOENT) {
00247          if (create) {
00248             if (Open(1,0,0,createmode) > 0) {
00249                kXR_int32 ct = (kXR_int32)time(0);
00250                XrdSutPFHeader hdr(kDefFileID,kXrdIFVersion,ct,ct,0,0);
00251                WriteHeader(hdr);
00252                valid = 1;
00253                if (!leaveopen)
00254                   Close();
00255             }
00256          } else {
00257             Err(kPFErrNoFile,"Init",name);
00258          }
00259       }
00260    } else {
00261       // Fill the the hash table
00262       if (Open(1) > 0) {
00263          if (hashtab)
00264             UpdateHashTable();
00265          valid = 1;
00266          if (!leaveopen)
00267             Close();
00268       }
00269    }
00270    // We are done
00271    return valid;
00272 }
00273 
00274 //_________________________________________________________________
00275 kXR_int32 XrdSutPFile::Open(kXR_int32 opt, bool *wasopen,
00276                             const char *nam, kXR_int32 createmode)
00277 {
00278    // Open the stream, so defining fFd .
00279    // Valid options:
00280    //        0      read only
00281    //        1      read/write append
00282    //        2      read/write truncate
00283    // For options 1 and 2 the file is created, if not existing,
00284    // and permission set to createmode (default: 0600).
00285    // If the file name ends with 'XXXXXX' and it does not exist,
00286    // it is created as temporary using mkstemp.
00287    // The file is also exclusively locked.
00288    // If nam is defined it is used as file name
00289    // If the file is already open and wasopen is allocated, then *wasopen
00290    // is set to true
00291    // The file descriptor of the open file is returned
00292    XrdOucString copt(opt);
00293 
00294    // Reset was open flag
00295    if (wasopen) *wasopen = 0;
00296 
00297    // File name must be defined
00298    char *fnam = (char *)nam;
00299    if (!fnam)
00300       fnam = name;
00301    if (!fnam)
00302       return Err(kPFErrBadInputs,"Open");
00303 
00304    // If already open, do nothing
00305    if (!nam && fFd > -1) {
00306       if (opt > 0) {
00307          // Make sure that the write flag is set
00308          long omode = 0;
00309          if (fcntl(fFd, F_GETFL, &omode) != -1) {
00310             if (!(omode | O_WRONLY))
00311                return Err(kPFErrFileAlreadyOpen,"Open");
00312          }
00313       }
00314       if (wasopen) *wasopen = 1;
00315       return fFd;
00316    }
00317 
00318    // Ok, we have a file name ... check if it exists already
00319    bool newfile = 0;
00320    struct stat st;
00321    if (stat(fnam, &st) == -1) {
00322       if (errno != ENOENT) {
00323          return Err(kPFErrNoFile,"Open",fnam);
00324       } else {
00325          if (opt == 0)
00326             return Err(kPFErrStat,"Open",fnam);
00327          newfile = 1;
00328       }
00329    }
00330 
00331    // Now open it
00332    if (!nam)
00333       fFd = -1;
00334    kXR_int32 fd = -1;
00335    //
00336    // If we have to create a new file and the file name ends with
00337    // 'XXXXXX', make it temporary with mkstemp
00338    char *pn = strstr(fnam,"XXXXXX");
00339    if (pn && (pn == (fnam + strlen(fnam) - 6))) {
00340       if (opt > 0 && newfile) {
00341          fd = mkstemp(fnam);
00342          if (fd <= -1)
00343             return Err(kPFErrFileOpen,"Open",fnam);
00344       }
00345    }
00346    //
00347    // If normal file act according to requests
00348    if (fd <= -1) {
00349       kXR_int32 mode = 0;
00350       switch (opt) {
00351          case 2:
00352             //
00353             // Forcing truncation 
00354             mode |= O_TRUNC ;
00355          case 1:
00356             //
00357             // Read / Write
00358             mode |= O_RDWR ;
00359             if (newfile)
00360                mode |= O_CREAT ;
00361             break;
00362          case 0:
00363             //
00364             // Read only
00365             mode = O_RDONLY ;
00366             break;
00367          default:
00368             //
00369             // Unknown option
00370             return Err(kPFErrBadOp,"Open",copt.c_str());
00371       }
00372 
00373       // Open file (createmode is only used if O_CREAT is set)
00374       fd = open(fnam, mode, createmode);
00375       if (fd <= -1)
00376          return Err(kPFErrFileOpen,"Open",fnam);
00377    }
00378 
00379    //
00380    // Shared or exclusive lock of the whole file
00381    int lockmode = (opt > 0) ? (F_WRLCK | F_RDLCK) : F_RDLCK;
00382    int lck = kMaxLockTries;
00383    int rc = 0;
00384    while (lck && rc == -1) {
00385 #ifdef __macos__
00386       struct flock flck = {0, 0, 0, lockmode, SEEK_SET};
00387 #else
00388       struct flock flck = {lockmode, SEEK_SET, 0, 0};
00389 #endif
00390       if ((rc = fcntl(fd, F_SETLK, &flck)) == 0)
00391          break;
00392       struct timespec lftp, rqtp = {1, 0};
00393       while (nanosleep(&rqtp, &lftp) < 0 && errno == EINTR) {
00394          rqtp.tv_sec  = lftp.tv_sec;
00395          rqtp.tv_nsec = lftp.tv_nsec;
00396       }
00397    }
00398    if (rc == -1) {
00399       if (errno == EACCES || errno == EAGAIN) {
00400          // File locked by other process
00401          int pid = -1;
00402 #ifdef __macos__
00403          struct flock flck = {0, 0, 0, lockmode, SEEK_SET};
00404 #else
00405          struct flock flck = {lockmode, SEEK_SET, 0, 0};
00406 #endif
00407          if (fcntl(fd,F_GETLK,&flck) != -1)
00408             pid = flck.l_pid;
00409          close(fd);
00410          return Err(kPFErrFileLocked,"Open",fnam,(const char *)&pid);
00411       } else {
00412          // Error
00413          return Err(kPFErrLocking,"Open",fnam,(const char *)&fd);
00414       }
00415    }
00416 
00417    // Ok, we got the file open and locked
00418    if (!nam)
00419       fFd = fd;
00420    return fd;
00421 }
00422 
00423 //_________________________________________________________________
00424 kXR_int32 XrdSutPFile::Close(kXR_int32 fd)
00425 {
00426    // Close the open stream or descriptor fd, if > -1 .
00427    // The file is unlocked before.
00428 
00429    // If not open, do nothing
00430    if (fd < 0)
00431       fd = fFd;
00432    if (fd < 0)
00433    return 0;
00434 
00435    //
00436    // Unlock the file
00437 #ifdef __macos__
00438    struct flock flck = {0, 0, 0, F_UNLCK, SEEK_SET};
00439 #else
00440    struct flock flck = {F_UNLCK, SEEK_SET, 0, 0};
00441 #endif
00442    if (fcntl(fd, F_SETLK, &flck) == -1) {
00443       close(fd);
00444       return Err(kPFErrUnlocking,"Close",(const char *)&fd);
00445    }
00446 
00447    //
00448    // Close it
00449    close(fd);
00450 
00451    // Reset file descriptor
00452    if (fd == fFd)
00453       fFd = -1;
00454 
00455    return 0;
00456 }
00457 
00458 //_________________________________________________________________
00459 kXR_int32 XrdSutPFile::UpdateHeader(XrdSutPFHeader hd)
00460 {
00461    // Write/Update header to beginning of file
00462 
00463    //
00464    // Open the file
00465    if (Open(1) < 0)
00466       return -1;
00467 
00468    // Write
00469    kXR_int32 nw = WriteHeader(hd);
00470 
00471    // Close the file
00472    Close();
00473  
00474    return nw;
00475 }
00476 
00477 //_________________________________________________________________
00478 kXR_int32 XrdSutPFile::RetrieveHeader(XrdSutPFHeader &hd)
00479 {
00480    // Retrieve number of entries in the file
00481 
00482    //
00483    // Open the file
00484    bool wasopen = 0;
00485    if (Open(1, &wasopen) < 0)
00486       return -1;
00487 
00488    // Read header
00489    kXR_int32 rc = ReadHeader(hd);
00490 
00491    // Close the file
00492    if (!wasopen) Close();
00493  
00494    return rc;
00495 }
00496 
00497 //_________________________________________________________________
00498 kXR_int32 XrdSutPFile::WriteHeader(XrdSutPFHeader hd)
00499 {
00500    // Write/Update header to beginning of opne stream
00501 
00502    //
00503    // Build output buffer
00504    // Get total lenght needed
00505    kXR_int32 ltot = hd.Length();
00506    //
00507    // Allocate the buffer
00508    char *bout = new char[ltot];
00509    if (!bout)
00510       return Err(kPFErrOutOfMemory,"WriteHeader");
00511    //
00512    // Fill the buffer
00513    kXR_int32 lp = 0;
00514    // File ID
00515    memcpy(bout+lp,hd.fileID,kFileIDSize);
00516    lp += kFileIDSize;
00517    // version
00518    memcpy(bout+lp,&hd.version,sizeof(kXR_int32));
00519    lp += sizeof(kXR_int32);
00520    // change time
00521    memcpy(bout+lp,&hd.ctime,sizeof(kXR_int32));
00522    lp += sizeof(kXR_int32);
00523    // index change time
00524    memcpy(bout+lp,&hd.itime,sizeof(kXR_int32));
00525    lp += sizeof(kXR_int32);
00526    // entries
00527    memcpy(bout+lp,&hd.entries,sizeof(kXR_int32));
00528    lp += sizeof(kXR_int32);
00529    // offset of the first index entry
00530    memcpy(bout+lp,&hd.indofs,sizeof(kXR_int32));
00531    lp += sizeof(kXR_int32);
00532    // number of unused bytes
00533    memcpy(bout+lp,&hd.jnksiz,sizeof(kXR_int32));
00534    lp += sizeof(kXR_int32);
00535    // Check length
00536    if (lp != ltot) {
00537       if (bout) delete[] bout;
00538       return Err(kPFErrLenMismatch,"WriteHeader",
00539                  (const char *)&lp, (const char *)&ltot);
00540    }
00541    //
00542    // Ready to write: check we got the file
00543    if (fFd < 0)
00544       return Err(kPFErrFileNotOpen,"WriteHeader");
00545    //
00546    // Set the offset
00547    if (lseek(fFd, 0, SEEK_SET) == -1) {
00548       return Err(kPFErrSeek,"WriteHeader","SEEK_SET",(const char *)&fFd);
00549    }
00550 
00551    kXR_int32 nw = 0;
00552    // Now write the buffer to the stream
00553    while ((nw = write(fFd, bout, ltot)) < 0 && errno == EINTR)
00554       errno = 0;
00555  
00556    return nw;
00557 }
00558 
00559 //______________________________________________________________________
00560 kXR_int32 XrdSutPFile::WriteEntry(XrdSutPFEntry ent)
00561 {
00562    // Write entry to file
00563    // Look first if an entry with the same name exists: in such
00564    // case try to overwrite the allocated file region; if the space
00565    // is not enough, set the existing entry inactive and write
00566    // the new entry at the end of the file, updating all the
00567    // pointers.
00568    // File must be opened in read/write mode (O_RDWR).
00569 
00570    // Make sure that the entry is named (otherwise we can't do nothing)
00571    if (!ent.name)
00572       return Err(kPFErrBadInputs,"WriteEntry");
00573 
00574    //
00575    // Ready to write: open the file
00576    bool wasopen = 0;
00577    if (Open(1, &wasopen) < 0)
00578       return -1;
00579 
00580    kXR_int32 ofs = 0;
00581    kXR_int32 nw = 0;
00582    kXR_int32 indofs = 0;
00583    // Read the header
00584    XrdSutPFHeader header;
00585    if (ReadHeader(header) < 0) {
00586       if (!wasopen) Close();
00587       return -1;
00588    }
00589    if ((ofs = lseek(fFd, 0, SEEK_CUR)) == -1) {
00590       if (!wasopen) Close();
00591       return Err(kPFErrSeek,"WriteEntry","SEEK_CUR",(const char *)&fFd);
00592    }
00593 
00594    XrdSutPFEntInd ind;
00595    // If first entry, write it, update the info and return
00596    if (header.entries == 0) {
00597       if ((nw = WriteEnt(ofs, ent)) < 0) {
00598          if (!wasopen) Close();
00599          return -1;
00600       }
00601       ind.SetName(ent.name);
00602       ind.nxtofs = 0;
00603       ind.entofs = ofs;
00604       ind.entsiz = nw;
00605       indofs = ofs + nw;
00606       if (WriteInd(indofs, ind) < 0) {
00607          if (!wasopen) Close();
00608          return -1;
00609       }
00610       // Update header
00611       header.entries = 1;
00612       header.indofs  = indofs;
00613       header.ctime   = time(0);
00614       header.itime   = header.ctime;
00615       if (WriteHeader(header) < 0) {
00616          if (!wasopen) Close();
00617          return -1;
00618       }
00619       if (!wasopen) Close();
00620       return nw;
00621    }
00622 
00623    // First Localize existing entry, if any
00624    kXR_int32 nr = 1;
00625    bool found = 0;
00626    indofs = header.indofs;
00627    kXR_int32 lastindofs = indofs;
00628    while (!found && nr > 0 && indofs > 0) {
00629       nr = ReadInd(indofs, ind);
00630       if (nr) {
00631          if (ind.entofs > 0 && !strcmp(ent.name,ind.name)) {
00632             found = 1;
00633             break;
00634          }
00635          lastindofs = indofs;
00636          indofs = ind.nxtofs;
00637       }
00638    }
00639 
00640    //
00641    // If an entry already exists and there is enough space to
00642    // store the update, write the update at the already allocated
00643    // space; if not, add it at the end.
00644    if (found) {
00645       // Update 
00646       kXR_int32 ct = 0;
00647       if (ind.entsiz >= ent.Length()) {
00648          // The offset is set inside ...
00649          if ((nw = WriteEnt(ind.entofs, ent)) < 0) {
00650             if (!wasopen) Close();
00651             return -1;
00652          }
00653       } else {
00654          // Add it at the end
00655          kXR_int32 entofs = 0;
00656          if ((entofs = lseek(fFd, 0, SEEK_END)) == -1) {
00657             if (!wasopen) Close();
00658             return Err(kPFErrSeek,"WriteEntry",
00659                        "SEEK_END",(const char *)&fFd);
00660          }
00661          if ((nw = WriteEnt(entofs, ent)) < 0) {
00662             if (!wasopen) Close();
00663             return -1;
00664          }
00665          // Set existing entry inactive
00666          kXR_int32 wrtofs = ind.entofs;
00667          if (lseek(fFd, wrtofs, SEEK_SET) == -1) {
00668             if (!wasopen) Close();
00669             return Err(kPFErrSeek,"WriteEntry",
00670                        "SEEK_SET",(const char *)&fFd);
00671          }
00672          short status = kPFE_inactive;
00673          while (write(fFd, &status, sizeof(short)) < 0 &&
00674                 errno == EINTR) errno = 0;
00675          // Reset entry area
00676          if (Reset(wrtofs + sizeof(short), ind.entsiz - sizeof(short)) < 0) {
00677             if (!wasopen) Close();
00678             return -1;
00679          }
00680          // Count as unused bytes
00681          header.jnksiz += ind.entsiz;
00682          if (lseek(fFd, kOfsJnkSiz, SEEK_SET) == -1) {
00683             if (!wasopen) Close();
00684             return Err(kPFErrSeek,"WriteEntry",
00685                        "SEEK_SET",(const char *)&fFd);
00686          }
00687          while (write(fFd, &header.jnksiz, sizeof(kXR_int32)) < 0 &&
00688             errno == EINTR) errno = 0;
00689          // Update the entry index and new size
00690          wrtofs = indofs + 2*sizeof(kXR_int32);
00691          if (lseek(fFd, wrtofs, SEEK_SET) == -1) {
00692             if (!wasopen) Close();
00693             return Err(kPFErrSeek,"WriteEntry",
00694                        "SEEK_SET",(const char *)&fFd);
00695          }
00696          while (write(fFd, &entofs, sizeof(kXR_int32)) < 0 &&
00697                 errno == EINTR) errno = 0;
00698          while (write(fFd, &nw, sizeof(kXR_int32)) < 0 &&
00699                 errno == EINTR) errno = 0;
00700          // Update time of change of index
00701          ct   = (kXR_int32)time(0); 
00702          header.itime = ct; 
00703          if (lseek(fFd, kOfsItime, SEEK_SET) == -1) {
00704             if (!wasopen) Close();
00705             return Err(kPFErrSeek,"WriteEntry",
00706                        "SEEK_SET",(const char *)&fFd);
00707          }
00708          while (write(fFd, &header.itime, sizeof(kXR_int32)) < 0 &&
00709             errno == EINTR) errno = 0;
00710       }
00711       // Update time of change in header
00712       header.ctime = (ct > 0) ? ct : time(0); 
00713       if (lseek(fFd, kOfsCtime, SEEK_SET) == -1) {
00714          if (!wasopen) Close();
00715          return Err(kPFErrSeek,"WriteEntry",
00716                     "SEEK_SET",(const char *)&fFd);
00717       }
00718       while (write(fFd, &header.ctime, sizeof(kXR_int32)) < 0 &&
00719          errno == EINTR) errno = 0;
00720       if (!wasopen) Close();
00721       return nw;
00722    }
00723 
00724    //
00725    // If new name, add the entry at the end
00726    if ((ofs = lseek(fFd, 0, SEEK_END)) == -1) {
00727       if (!wasopen) Close();
00728       return Err(kPFErrSeek,"WriteEntry",
00729                           "SEEK_END",(const char *)&fFd);
00730    }
00731    if ((nw = WriteEnt(ofs, ent)) < 0) {
00732       if (!wasopen) Close();
00733       return -1;
00734    }
00735    //
00736    // Create new index entry
00737    XrdSutPFEntInd newind(ent.name, 0, ofs, nw);
00738    if (WriteInd(ofs+nw, newind) < 0) {
00739       if (!wasopen) Close();
00740       return -1;
00741    }
00742    //
00743    // Update previous index entry 
00744    ind.nxtofs = ofs + nw;
00745    kXR_int32 wrtofs = lastindofs + sizeof(kXR_int32);
00746    if (lseek(fFd, wrtofs, SEEK_SET) == -1) {
00747       if (!wasopen) Close();
00748       return Err(kPFErrSeek,"WriteEntry",
00749                           "SEEK_SET",(const char *)&fFd);
00750    }
00751    while (write(fFd, &ind.nxtofs, sizeof(kXR_int32)) < 0 &&
00752       errno == EINTR) errno = 0;
00753 
00754    // Update header
00755    header.entries += 1;
00756    header.ctime   = time(0);
00757    header.itime   = header.ctime;
00758    if (WriteHeader(header) < 0) {
00759       if (!wasopen) Close();
00760       return -1;
00761    }
00762 
00763    // Close the file
00764    if (!wasopen) Close();
00765 
00766    return nw;
00767 }
00768 
00769 //________________________________________________________________
00770 kXR_int32 XrdSutPFile::UpdateCount(const char *tag, int *cnt,
00771                                    int step, bool reset)
00772 {
00773    // Update counter for entry with 'tag', if any.
00774    // If reset is true, counter is firts reset.
00775    // The counter is updated by 'step'.
00776    // Default: no reset, increase by 1.
00777    // If cnt is defined, fill it with the updated counter.
00778    // Returns 0 or -1 in case of error
00779 
00780    // Make sure that we got a tag (otherwise we can't do nothing)
00781    if (!tag)
00782       return Err(kPFErrBadInputs,"UpdateCount");
00783 
00784    // Make sure we got an open stream
00785    if (Open(1) < 0)
00786       return -1;
00787 
00788    // Read the header
00789    XrdSutPFHeader header;
00790    if (ReadHeader(header) < 0) {
00791       Close();
00792       return -1;
00793    }
00794 
00795    // Check if the HashTable needs to be updated
00796    if (fHashTable && header.itime > fHTutime) {
00797       // Update the table
00798       if (UpdateHashTable() < 0) {
00799          Close();
00800          return -1;
00801       }
00802    }
00803    //
00804    // Get index entry associated with tag, if any
00805    XrdSutPFEntInd ind;
00806    bool found = 0;
00807    if (fHashTable) {
00808       kXR_int32 *refofs = fHashTable->Find(tag);
00809       if (*refofs > 0) {
00810          // Read it out
00811          if (ReadInd(*refofs, ind) < 0) {
00812             Close();
00813             return -1;
00814          }
00815          found = 1;
00816       }
00817    } else {
00818       // Get offset of the first index entry
00819       kXR_int32 indofs = header.indofs;
00820       while (indofs > 0) {
00821          // Read it out
00822          if (ReadInd(indofs, ind) < 0) {
00823             Close();
00824             return -1;
00825          }
00826          // Check compatibility
00827          if (strlen(ind.name) == strlen(tag)) {
00828             if (!strncmp(ind.name,tag,strlen(tag))) {
00829                found = 1;
00830                break;
00831             }
00832          }
00833          // Next index entry
00834          indofs = ind.nxtofs;
00835       }
00836    }
00837    //
00838    // Read the entry, if found
00839    XrdSutPFEntry ent;
00840    bool changed = 0;
00841    if (found) {
00842 
00843       // Read entry if active
00844       if (ind.entofs) {
00845          if (ReadEnt(ind.entofs, ent) < 0) {
00846             Close();
00847             return -1;
00848          }
00849          //
00850          // Reset counter if required
00851          if (reset && ent.cnt != 0) {
00852             changed = 1;
00853             ent.cnt = 0;
00854          }
00855          //
00856          // Update counter
00857          if (step != 0) {
00858             changed = 1;
00859             ent.cnt += step;
00860          }
00861          //
00862          // Update entry in file, if anything changed
00863          if (changed) {
00864             ent.mtime = (kXR_int32)time(0);
00865             if (WriteEnt(ind.entofs, ent) < 0) {
00866                Close();
00867                return -1;
00868             }
00869          }
00870          //
00871          // Fill output
00872          if (cnt)
00873             *cnt = ent.cnt;
00874       }
00875    }
00876 
00877    // Close the file
00878    Close();
00879 
00880    return 0;
00881 }
00882 
00883 //________________________________________________________________
00884 kXR_int32 XrdSutPFile::ReadEntry(const char *tag,
00885                                  XrdSutPFEntry &ent, int opt)
00886 {
00887    // Read entry with tag from file
00888    // If it does not exist, if opt == 1 search also for wild-card
00889    // matching entries; if more than 1 return the one that matches
00890    // the best, base on the number of characters matching.
00891    // If more wild-card entries have the same level of matching,
00892    // the first found is returned.
00893    ent.Reset();
00894 
00895    // Make sure that we got a tag (otherwise we can't do nothing)
00896    if (!tag)
00897       return Err(kPFErrBadInputs,"ReadEntry");
00898 
00899    // Make sure we got an open stream
00900    bool wasopen = 0;
00901    if (Open(1 &wasopen) < 0)
00902       return -1;
00903 
00904    // Read the header
00905    XrdSutPFHeader header;
00906    if (ReadHeader(header) < 0) {
00907       if (!wasopen) Close();
00908       return -1;
00909    }
00910 
00911    // Check if the HashTable needs to be updated
00912    if (fHashTable && header.itime > fHTutime) {
00913       // Update the table
00914       if (UpdateHashTable() < 0) {
00915          if (!wasopen) Close();
00916          return -1;
00917       }
00918    }
00919    //
00920    // Get index entry associated with tag, if any
00921    XrdSutPFEntInd ind;
00922    bool found = 0;
00923    if (fHashTable) {
00924       kXR_int32 *reftmp = fHashTable->Find(tag);
00925       kXR_int32 refofs = reftmp ? *reftmp : -1;
00926       if (refofs > 0) {
00927          // Read it out
00928          if (ReadInd(refofs, ind) < 0) {
00929             if (!wasopen) Close();
00930             return -1;
00931          }
00932          found = 1;
00933       }
00934    } else {
00935       // Get offset of the first index entry
00936       kXR_int32 indofs = header.indofs;
00937       while (indofs > 0) {
00938          // Read it out
00939          if (ReadInd(indofs, ind) < 0) {
00940             if (!wasopen) Close();
00941             return -1;
00942          }
00943          // Check compatibility
00944          if (strlen(ind.name) == strlen(tag)) {
00945             if (!strncmp(ind.name,tag,strlen(tag))) {
00946                found = 1;
00947                break;
00948             }
00949          }
00950          // Next index entry
00951          indofs = ind.nxtofs;
00952       }
00953    }
00954    //
00955    // If not found and requested, try also wild-cards
00956    if (!found && opt == 1) {
00957       //
00958       // If > 1 we will keep the best matching, i.e. the one
00959       // matching most of the chars in tag
00960       kXR_int32 refofs = -1;
00961       kXR_int32 nmmax = 0;
00962       kXR_int32 iofs = header.indofs;
00963       XrdOucString stag(tag);
00964       while (iofs) {
00965          //
00966          // Read it out
00967          if (ReadInd(iofs, ind) < 0) {
00968             if (!wasopen) Close();
00969             return -1;
00970          }
00971          //      
00972          // Check compatibility, if active
00973          if (ind.entofs > 0) {
00974             int match = stag.matches(ind.name);
00975             if (match > nmmax && ind.entofs > 0) {
00976                nmmax = match;
00977                refofs = iofs;
00978             }
00979          }
00980          //
00981          // Next index entry
00982          iofs = ind.nxtofs;
00983       }
00984       //
00985       // Read it out
00986       if (refofs > 0) {
00987          if (ReadInd(refofs, ind) < 0) {
00988             if (!wasopen) Close();
00989             return -1;
00990          }
00991          found = 1;
00992       }
00993    }
00994 
00995    // Read the entry, if found
00996    kXR_int32 nr = 0;
00997    if (found) {
00998 
00999       // Read entry if active
01000       if (ind.entofs) {
01001          if ((nr = ReadEnt(ind.entofs, ent)) < 0) {
01002             if (!wasopen) Close();
01003             return -1;
01004          }
01005          // Fill the name
01006          ent.SetName(ind.name);
01007       }
01008    }
01009 
01010    // Close the file
01011    if (!wasopen) Close();
01012 
01013    return nr;
01014 }
01015 
01016 //________________________________________________________________
01017 kXR_int32 XrdSutPFile::ReadEntry(kXR_int32 ofs, XrdSutPFEntry &ent)
01018 {
01019    // Read entry at ofs from file
01020 
01021    // Make sure that ofs makes sense
01022    if (ofs <= 0)
01023       return Err(kPFErrBadInputs,"ReadEntry");
01024 
01025    // Make sure we got an open stream
01026    bool wasopen = 0;
01027    if (Open(1, &wasopen) < 0)
01028       return -1;
01029 
01030    kXR_int32 nr = 0;
01031 
01032    // Read index entry out
01033    XrdSutPFEntInd ind;
01034    if (ReadInd(ofs, ind) < 0) {
01035       if (!wasopen) Close();
01036       return -1;
01037    }
01038 
01039    // Read entry
01040    if ((nr = ReadEnt(ind.entofs, ent)) < 0) {
01041       if (!wasopen) Close();
01042       return -1;
01043    }
01044 
01045    // Fill the name
01046    ent.SetName(ind.name);
01047 
01048    // Close the file
01049    if (!wasopen) Close();
01050 
01051    return nr;
01052 }
01053 
01054 //________________________________________________________________
01055 kXR_int32 XrdSutPFile::RemoveEntry(const char *tag)
01056 {
01057    // Remove entry with tag from file
01058    // The entry is set inactive, so that it is hidden and it will
01059    // be physically removed at next Trim 
01060 
01061    // Make sure that we got a tag (otherwise we can't do nothing)
01062    if (!tag || !strlen(tag))
01063       return Err(kPFErrBadInputs,"RemoveEntry");
01064 
01065    // Make sure we got an open stream
01066    if (Open(1) < 0)
01067       return -1;
01068 
01069    // Read the header
01070    XrdSutPFHeader header;
01071    if (ReadHeader(header) < 0) {
01072       Close();
01073       return -1;
01074    }
01075 
01076    // Check if the HashTable needs to be updated
01077    if (fHashTable && header.itime > fHTutime) {
01078       // Update the table
01079       if (UpdateHashTable() < 0) {
01080          Close();
01081          return -1;
01082       }
01083    }
01084 
01085    // Get offset of the index entry associated with tag, if any
01086    XrdSutPFEntInd ind;
01087    bool found = 0;
01088    kXR_int32 indofs = -1;
01089    if (fHashTable) {
01090       kXR_int32 *indtmp = fHashTable->Find(tag);
01091       indofs = indtmp ? *indtmp : indofs;
01092       if (indofs > 0) {
01093          // Read it out
01094          if (ReadInd(indofs, ind) < 0) {
01095             Close();
01096             return -1;
01097          }
01098          found = 1;
01099       }
01100    } else {
01101       // Get offset of the first index entry
01102       indofs = header.indofs;
01103       while (indofs > 0) {
01104          // Read it out
01105          if (ReadInd(indofs, ind) < 0) {
01106             Close();
01107             return -1;
01108          }
01109          // Check compatibility
01110          if (strlen(ind.name) == strlen(tag)) {
01111             if (!strncmp(ind.name,tag,strlen(tag))) {
01112                found = 1;
01113                break;
01114             }
01115          }
01116          // Next index entry
01117          indofs = ind.nxtofs;
01118       }
01119    }
01120    //
01121    // Get entry now, if index found
01122    if (found) {
01123       // Reset entry area
01124       short status = kPFE_inactive;
01125       if (lseek(fFd, ind.entofs, SEEK_SET) == -1) {
01126          Close();
01127          return Err(kPFErrSeek,"RemoveEntry",
01128                                "SEEK_SET",(const char *)&fFd);
01129       }
01130       while (write(fFd, &status, sizeof(short)) < 0 &&
01131              errno == EINTR) errno = 0;
01132       // Reset entry area
01133       if (Reset(ind.entofs + sizeof(short), ind.entsiz - sizeof(short)) < 0) {
01134          Close();
01135          return -1;
01136       }
01137       // Set entofs to null
01138       ind.entofs = 0;
01139       if (WriteInd(indofs, ind) < 0) {
01140          Close();
01141          return -1;
01142       }
01143       // Count as unused bytes
01144       header.jnksiz += ind.entsiz;
01145       // Decrease number of entries
01146       header.entries--;
01147       // Update times
01148       header.ctime = (kXR_int32)time(0);
01149       header.itime = header.ctime;
01150       // Update header
01151       if (WriteHeader(header) < 0) {
01152          Close();
01153          return -1;
01154       }
01155 
01156       // Ok: close the file and return
01157       Close();
01158       return 0;
01159    }
01160 
01161    // Close the file
01162    Close();
01163    // entry non-existing
01164    return -1;
01165 }
01166 
01167 //________________________________________________________________
01168 kXR_int32 XrdSutPFile::RemoveEntry(kXR_int32 ofs)
01169 {
01170    // Remove entry at entry index offset ofs from file
01171    // The entry is set inactive, so that it is hidden and it will
01172    // be physically removed at next Trim 
01173 
01174    // Make sure that we got a tag (otherwise we can't do nothing)
01175    if (ofs <= 0)
01176       return Err(kPFErrBadInputs,"RemoveEntry");
01177 
01178    // Make sure we got an open stream
01179    if (Open(1) < 0)
01180       return -1;
01181 
01182    // Read the header
01183    XrdSutPFHeader header;
01184    if (ReadHeader(header) < 0) {
01185       Close();
01186       return -1;
01187    }
01188 
01189    // Check if the HashTable needs to be updated
01190    if (header.itime > fHTutime) {
01191       // Update the table
01192       if (UpdateHashTable() < 0) {
01193          Close();
01194          return -1;
01195       }
01196    }
01197    //
01198    // Read it out
01199    XrdSutPFEntInd ind;
01200    if (ReadInd(ofs, ind) < 0) {
01201       Close();
01202       return -1;
01203    }
01204    //
01205    // Reset entry area
01206    short status = kPFE_inactive;
01207    if (lseek(fFd, ind.entofs, SEEK_SET) == -1) {
01208       Close();
01209       return Err(kPFErrSeek,"RemoveEntry",
01210                           "SEEK_SET",(const char *)&fFd);
01211    }
01212    while (write(fFd, &status, sizeof(short)) < 0 &&
01213           errno == EINTR) errno = 0;
01214    // Reset entry area
01215    if (Reset(ind.entofs + sizeof(short), ind.entsiz - sizeof(short)) < 0) {
01216       Close();
01217       return -1;
01218    }
01219    // Set entofs to null
01220    ind.entofs = 0;
01221    if (WriteInd(ofs, ind) < 0) {
01222       Close();
01223       return -1;
01224    }
01225    // Count as unused bytes
01226    header.jnksiz += ind.entsiz;
01227    // Decrease number of entries
01228    header.entries--;
01229    // Update times
01230    header.ctime = (kXR_int32)time(0);
01231    header.itime = header.ctime;
01232    // Update header
01233    if (WriteHeader(header) < 0) {
01234       Close();
01235       return -1;
01236    }
01237    //
01238    // Ok: close the file and return
01239    Close();
01240    return 0;
01241 }
01242 
01243 //_________________________________________________________________
01244 kXR_int32 XrdSutPFile::Reset(kXR_int32 ofs, kXR_int32 siz)
01245 {
01246    // Reset size bytes starting at ofs in the open stream 
01247 
01248    //
01249    // Set the offset
01250    if (lseek(fFd, ofs, SEEK_SET) == -1)
01251       return Err(kPFErrSeek,"Reset",
01252                           "SEEK_SET",(const char *)&fFd);
01253 
01254    kXR_int32 nrs = 0;
01255    // Now write the buffer to the stream
01256    while (nrs < siz) {
01257       char c = 0;
01258       while (write(fFd, &c, 1) < 0 && errno == EINTR)
01259          errno = 0;
01260       nrs++;
01261    }
01262 
01263    return nrs;
01264 }
01265 
01266 
01267 //__________________________________________________________________
01268 kXR_int32 XrdSutPFile::WriteInd(kXR_int32 ofs, XrdSutPFEntInd ind)
01269 {
01270    // Write entry index to open stream fFd
01271 
01272    // Make sure we got an open stream
01273    if (fFd < 0)
01274       return Err(kPFErrFileNotOpen,"WriteInd");
01275    //
01276    // Set the offset
01277    if (lseek(fFd, ofs, SEEK_SET) == -1)
01278       return Err(kPFErrSeek,"WriteInd",
01279                           "SEEK_SET",(const char *)&fFd);
01280    //
01281    // Build output buffer
01282    //
01283    // Get total lenght needed
01284    kXR_int32 ltot = ind.Length();
01285    //
01286    // Allocate the buffer
01287    char *bout = new char[ltot];
01288    if (!bout)
01289       return Err(kPFErrOutOfMemory,"WriteInd");
01290    //
01291    // Fill the buffer
01292    kXR_int32 lp = 0;
01293    // Name length
01294    kXR_int32 lnam = strlen(ind.name);
01295    memcpy(bout+lp,&lnam,sizeof(kXR_int32));
01296    lp += sizeof(kXR_int32);
01297    // Offset of next index entry
01298    memcpy(bout+lp,&ind.nxtofs,sizeof(kXR_int32));
01299    lp += sizeof(kXR_int32);
01300    // Offset of entry
01301    memcpy(bout+lp,&ind.entofs,sizeof(kXR_int32));
01302    lp += sizeof(kXR_int32);
01303    // Size allocated for entry
01304    memcpy(bout+lp,&ind.entsiz,sizeof(kXR_int32));
01305    lp += sizeof(kXR_int32);
01306    // name
01307    memcpy(bout+lp,ind.name,lnam);
01308    lp += lnam;
01309    // Check length
01310    if (lp != ltot) {
01311       if (bout) delete[] bout;
01312       return Err(kPFErrLenMismatch,"WriteInd",
01313                  (const char *)&lp, (const char *)&ltot);
01314    }
01315 
01316    kXR_int32 nw = 0;
01317    // Now write the buffer to the stream
01318    while ((nw = write(fFd, bout, ltot)) < 0 && errno == EINTR)
01319       errno = 0;
01320  
01321    return nw;
01322 }
01323 
01324 //__________________________________________________________________
01325 kXR_int32 XrdSutPFile::WriteEnt(kXR_int32 ofs, XrdSutPFEntry ent)
01326 {
01327    // Write ent to stream out
01328 
01329    // Make sure we got an open stream
01330    if (fFd < 0)
01331       return Err(kPFErrFileNotOpen,"WriteEnt");
01332    //
01333    // Set the offset
01334    if (lseek(fFd, ofs, SEEK_SET) == -1)
01335       return Err(kPFErrSeek,"WriteEnt",
01336                           "SEEK_SET",(const char *)&fFd);
01337    //
01338    // Build output buffer
01339    //
01340    // Get total lenght needed
01341    kXR_int32 ltot = ent.Length();
01342    //
01343    // Allocate the buffer
01344    char *bout = new char[ltot];
01345    if (!bout)
01346       return Err(kPFErrOutOfMemory,"WriteEnt");
01347    //
01348    // Fill the buffer
01349    kXR_int32 lp = 0;
01350    // status
01351    memcpy(bout+lp,&ent.status,sizeof(short));
01352    lp += sizeof(short);
01353    // count
01354    memcpy(bout+lp,&ent.cnt,sizeof(short));
01355    lp += sizeof(short);
01356    // time of modification / creation
01357    memcpy(bout+lp,&ent.mtime,sizeof(kXR_int32));
01358    lp += sizeof(kXR_int32);
01359    // length of first buffer
01360    memcpy(bout+lp,&ent.buf1.len,sizeof(kXR_int32));
01361    lp += sizeof(kXR_int32);
01362    // length of second buffer
01363    memcpy(bout+lp,&ent.buf2.len,sizeof(kXR_int32));
01364    lp += sizeof(kXR_int32);
01365    // length of third buffer
01366    memcpy(bout+lp,&ent.buf3.len,sizeof(kXR_int32));
01367    lp += sizeof(kXR_int32);
01368    // length of fourth buffer
01369    memcpy(bout+lp,&ent.buf4.len,sizeof(kXR_int32));
01370    lp += sizeof(kXR_int32);
01371    if (ent.buf1.len > 0) {
01372       // first buffer
01373       memcpy(bout+lp,ent.buf1.buf,ent.buf1.len);
01374       lp += ent.buf1.len;
01375    }
01376    if (ent.buf2.len > 0) {
01377       // second buffer
01378       memcpy(bout+lp,ent.buf2.buf,ent.buf2.len);
01379       lp += ent.buf2.len;
01380    }
01381    if (ent.buf3.len > 0) {
01382       // third buffer
01383       memcpy(bout+lp,ent.buf3.buf,ent.buf3.len);
01384       lp += ent.buf3.len;
01385    }
01386    if (ent.buf4.len > 0) {
01387       // third buffer
01388       memcpy(bout+lp,ent.buf4.buf,ent.buf4.len);
01389       lp += ent.buf4.len;
01390    }
01391    // Check length
01392    if (lp != ltot) {
01393       if (bout) delete[] bout;
01394       return Err(kPFErrLenMismatch,"WriteEnt",
01395                  (const char *)&lp, (const char *)&ltot);
01396    }
01397 
01398    kXR_int32 nw = 0;
01399    // Now write the buffer to the stream
01400    while ((nw = write(fFd, bout, ltot)) < 0 && errno == EINTR)
01401       errno = 0;
01402  
01403    return nw;
01404 }
01405 
01406 //__________________________________________________________________
01407 kXR_int32 XrdSutPFile::ReadHeader(XrdSutPFHeader &hd)
01408 {
01409    // Read header from beginning of stream 
01410 
01411    //
01412    // Make sure that we got an open file description
01413    if (fFd < 0)
01414       return Err(kPFErrFileNotOpen,"ReadHeader");
01415    //
01416    // Set the offset
01417    if (lseek(fFd, 0, SEEK_SET) == -1)
01418       return Err(kPFErrSeek,"ReadHeader",
01419                           "SEEK_SET",(const char *)&fFd);
01420 
01421    kXR_int32 nr = 0, nrdt = 0;
01422    //
01423    // Now read the information step by step:
01424    // the file ID ...
01425    if ((nr = read(fFd,hd.fileID,kFileIDSize)) != kFileIDSize)
01426       return Err(kPFErrRead,"ReadHeader",(const char *)&fFd);
01427    hd.fileID[kFileIDSize-1] = 0;
01428    nrdt += nr;
01429    // the version ...
01430    if ((nr = read(fFd,&hd.version,sizeof(kXR_int32))) != sizeof(kXR_int32))
01431       return Err(kPFErrRead,"ReadHeader",(const char *)&fFd);
01432    nrdt += nr;
01433    // the time of last change ...
01434    if ((nr = read(fFd,&hd.ctime,sizeof(kXR_int32))) != sizeof(kXR_int32))
01435       return Err(kPFErrRead,"ReadHeader",(const char *)&fFd);
01436    nrdt += nr;
01437    // the time of last index change ...
01438    if ((nr = read(fFd,&hd.itime,sizeof(kXR_int32))) != sizeof(kXR_int32))
01439       return Err(kPFErrRead,"ReadHeader",(const char *)&fFd);
01440    nrdt += nr;
01441    // the number of entries ...
01442    if ((nr = read(fFd,&hd.entries,sizeof(kXR_int32))) != sizeof(kXR_int32))
01443       return Err(kPFErrRead,"ReadHeader",(const char *)&fFd);
01444    nrdt += nr;
01445    // the offset of first index entry ...
01446    if ((nr = read(fFd,&hd.indofs,sizeof(kXR_int32))) != sizeof(kXR_int32))
01447       return Err(kPFErrRead,"ReadHeader",(const char *)&fFd);
01448    nrdt += nr;
01449    // the number of unused bytes ...
01450    if ((nr = read(fFd,&hd.jnksiz,sizeof(kXR_int32))) != sizeof(kXR_int32))
01451       return Err(kPFErrRead,"ReadHeader",(const char *)&fFd);
01452    nrdt += nr;
01453 
01454    return nrdt;
01455 }
01456 
01457 //_____________________________________________________________________
01458 kXR_int32 XrdSutPFile::ReadInd(kXR_int32 ofs, XrdSutPFEntInd &ind)
01459 {
01460    // Read entry index from offset ofs of open stream fFd
01461 
01462    //
01463    // Make sure that we got an open file description
01464    if (fFd < 0)
01465       return Err(kPFErrFileNotOpen,"ReadInd");
01466    //
01467    // Set the offset
01468    if (lseek(fFd, ofs, SEEK_SET) == -1)
01469       return Err(kPFErrSeek,"ReadInd",
01470                           "SEEK_SET",(const char *)&fFd);
01471 
01472    kXR_int32 nr = 0, nrdt = 0;
01473    //
01474    // Now read the information step by step:
01475    // the length of the name ...
01476    kXR_int32 lnam = 0;
01477    if ((nr = read(fFd,&lnam,sizeof(kXR_int32))) != sizeof(kXR_int32))
01478       return Err(kPFErrRead,"ReadInd",(const char *)&fFd);
01479    nrdt += nr;
01480    // the offset of next entry index ...
01481    if ((nr = read(fFd,&ind.nxtofs,sizeof(kXR_int32))) != sizeof(kXR_int32))
01482       return Err(kPFErrRead,"ReadInd",(const char *)&fFd);
01483    nrdt += nr;
01484    // the offset of the entry ...
01485    if ((nr = read(fFd,&ind.entofs,sizeof(kXR_int32))) != sizeof(kXR_int32))
01486       return Err(kPFErrRead,"ReadInd",(const char *)&fFd);
01487    nrdt += nr;
01488    // the size allocated for the entry ...
01489    if ((nr = read(fFd,&ind.entsiz,sizeof(kXR_int32))) != sizeof(kXR_int32))
01490       return Err(kPFErrRead,"ReadInd",(const char *)&fFd);
01491    nrdt += nr;
01492    // the name ... cleanup first
01493    if (ind.name) {
01494       delete[] ind.name;
01495       ind.name = 0;
01496    }
01497    if (lnam) {
01498       ind.name = new char[lnam+1];
01499       if (ind.name) {
01500          if ((nr = read(fFd,ind.name,lnam)) != lnam)
01501             return Err(kPFErrRead,"ReadInd",(const char *)&fFd);
01502          ind.name[lnam] = 0; // null-terminated
01503          nrdt += nr;
01504       } else 
01505          return Err(kPFErrOutOfMemory,"ReadInd");
01506    }
01507 
01508    return nrdt;
01509 }
01510 
01511 //____________________________________________________________________
01512 kXR_int32 XrdSutPFile::ReadEnt(kXR_int32 ofs, XrdSutPFEntry &ent)
01513 {
01514    // Read ent from current position at stream 
01515 
01516    //
01517    // Make sure that we got an open file description
01518    if (fFd < 0)
01519       return Err(kPFErrFileNotOpen,"ReadEnt");
01520    //
01521    // Set the offset
01522    if (lseek(fFd, ofs, SEEK_SET) == -1)
01523       return Err(kPFErrSeek,"ReadEnt",
01524                           "SEEK_SET",(const char *)&fFd);
01525 
01526    kXR_int32 nr = 0, nrdt = 0;
01527    //
01528    // Now read the information step by step:
01529    // the status ...
01530    if ((nr = read(fFd,&ent.status,sizeof(short))) != sizeof(short))
01531       return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01532    nrdt += nr;
01533    // the count var ...
01534    if ((nr = read(fFd,&ent.cnt,sizeof(short))) != sizeof(short))
01535       return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01536    nrdt += nr;
01537    // the the time of modification / creation ...
01538    if ((nr = read(fFd,&ent.mtime,sizeof(kXR_int32))) != sizeof(kXR_int32))
01539       return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01540    nrdt += nr;
01541    // the length of the first buffer ...
01542    if ((nr = read(fFd,&ent.buf1.len,sizeof(kXR_int32))) != sizeof(kXR_int32))
01543       return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01544    nrdt += nr;
01545    // the length of the second buffer ...
01546    if ((nr = read(fFd,&ent.buf2.len,sizeof(kXR_int32))) != sizeof(kXR_int32))
01547       return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01548    nrdt += nr;
01549    // the length of the third buffer ...
01550    if ((nr = read(fFd,&ent.buf3.len,sizeof(kXR_int32))) != sizeof(kXR_int32))
01551       return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01552    nrdt += nr;
01553    // the length of the fourth buffer ...
01554    if ((nr = read(fFd,&ent.buf4.len,sizeof(kXR_int32))) != sizeof(kXR_int32))
01555       return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01556    nrdt += nr;
01557    // Allocate space for the first buffer and read it (if any) ...
01558    if (ent.buf1.len) {
01559       ent.buf1.buf = new char[ent.buf1.len];
01560       if (!ent.buf1.buf)
01561          return Err(kPFErrOutOfMemory,"ReadEnt");
01562       if ((nr = read(fFd,ent.buf1.buf,ent.buf1.len)) != ent.buf1.len)
01563          return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01564       nrdt += nr;
01565    }
01566    // Allocate space for the second buffer and read it (if any) ...
01567    if (ent.buf2.len) {
01568       ent.buf2.buf = new char[ent.buf2.len];
01569       if (!ent.buf2.buf)
01570          return Err(kPFErrOutOfMemory,"ReadEnt");
01571       if ((nr = read(fFd,ent.buf2.buf,ent.buf2.len)) != ent.buf2.len)
01572          return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01573       nrdt += nr;
01574    }
01575    // Allocate space for the third buffer and read it (if any) ...
01576    if (ent.buf3.len) {
01577       ent.buf3.buf = new char[ent.buf3.len];
01578       if (!ent.buf3.buf)
01579          return Err(kPFErrOutOfMemory,"ReadEnt");
01580       if ((nr = read(fFd,ent.buf3.buf,ent.buf3.len)) != ent.buf3.len)
01581          return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01582       nrdt += nr;
01583    }
01584    // Allocate space for the fourth buffer and read it (if any) ...
01585    if (ent.buf4.len) {
01586       ent.buf4.buf = new char[ent.buf4.len];
01587       if (!ent.buf4.buf)
01588          return Err(kPFErrOutOfMemory,"ReadEnt");
01589       if ((nr = read(fFd,ent.buf4.buf,ent.buf4.len)) != ent.buf4.len)
01590          return Err(kPFErrRead,"ReadEnt",(const char *)&fFd);
01591       nrdt += nr;
01592    }
01593 
01594    return nrdt;
01595 }
01596 
01597 //________________________________________________________________
01598 kXR_int32 XrdSutPFile::Browse(void *oout)
01599 {
01600    // Display the content of the file
01601 
01602    // Make sure we got an open stream
01603    if (Open(1) < 0)
01604       return -1;
01605 
01606    // Read header
01607    XrdSutPFHeader hdr;
01608    if (ReadHeader(hdr) < 0) {
01609       Close();
01610       return -1;
01611    }
01612 
01613    // Time strings
01614    struct tm tst;
01615    char sctime[256] = {0};
01616    time_t ttmp = hdr.ctime;
01617    localtime_r(&ttmp,&tst);
01618    asctime_r(&tst,sctime);
01619    sctime[strlen(sctime)-1] = 0;
01620    char sitime[256] = {0};
01621    ttmp = hdr.itime;
01622    localtime_r(&ttmp,&tst);
01623    asctime_r(&tst,sitime);
01624    sitime[strlen(sitime)-1] = 0;
01625 
01626    // Default is stdout
01627    FILE *out = oout ? (FILE *)oout : stdout;
01628 
01629    fprintf(out,"//-----------------------------------------------------"
01630                                               "--------------------//\n");
01631    fprintf(out,"//\n");
01632    fprintf(out,"//  File:         %s\n",name);
01633    fprintf(out,"//  ID:           %s\n",hdr.fileID);
01634    fprintf(out,"//  Version:      %d\n",hdr.version);
01635    fprintf(out,"//  Last change : %s (%d sec)\n",sctime,hdr.ctime);
01636    fprintf(out,"//  Index change: %s (%d sec)\n",sitime,hdr.itime);
01637    fprintf(out,"//\n");
01638    fprintf(out,"//  Number of Entries: %d\n",hdr.entries);
01639    fprintf(out,"//  Bytes unreachable: %d\n",hdr.jnksiz);
01640    fprintf(out,"//\n");
01641 
01642    if (hdr.entries > 0) {
01643 
01644       // Special entries first, if any
01645       kXR_int32 ns = SearchSpecialEntries();
01646       if (ns > 0) {
01647          // Allocate space for offsets
01648          kXR_int32 *sofs = new kXR_int32[ns];
01649          if (sofs) {
01650             // Get offsets
01651             ns = SearchSpecialEntries(sofs,ns);
01652             fprintf(out,"//  Special entries (%d):\n",ns);
01653             int i = 0;
01654             for (; i<ns; i++) {
01655                
01656                // Read entry index at ofs
01657                XrdSutPFEntInd ind;
01658                if (ReadInd(sofs[i], ind) < 0) {
01659                   Close();
01660                   return -1;
01661                }
01662 
01663                if (ind.entofs) {
01664                   // Read entry
01665                   XrdSutPFEntry ent;
01666                   if (ReadEnt(ind.entofs, ent) < 0) {
01667                      Close();
01668                      return -1;
01669                   }
01670                   char smt[20] = {0};
01671                   XrdSutTimeString(ent.mtime,smt);
01672                   char buf[2048] = {0};
01673                   memset(buf,0,2048);
01674                   sprintf(buf,"// #%d mod:%s",i+1,smt);
01675                   sprintf(buf,"%s name:%s",buf,ind.name);
01676                   fprintf(out,"%s\n",buf);
01677                   sprintf(buf,"//    buf");
01678                   if (ent.cnt == 1) {
01679                      if (ent.buf1.len && ent.buf1.buf)
01680                         sprintf(buf,"%s: %.*s",buf,ent.buf1.len,ent.buf1.buf);
01681                      if (ent.buf2.len && ent.buf2.buf)
01682                         sprintf(buf,"%s: %.*s",buf,ent.buf2.len,ent.buf2.buf);
01683                      if (ent.buf3.len && ent.buf3.buf)
01684                         sprintf(buf,"%s: %.*s",buf,ent.buf3.len,ent.buf3.buf);
01685                      if (ent.buf4.len && ent.buf4.buf)
01686                         sprintf(buf,"%s: %.*s",buf,ent.buf4.len,ent.buf4.buf);
01687                   } else {
01688                      sprintf(buf,"%s:%d:%d:%d:%d",buf,
01689                                  ent.buf1.len,ent.buf2.len,ent.buf3.len,
01690                                  ent.buf4.len);
01691                      sprintf(buf,"%s (protected)",buf);
01692                   }
01693                   fprintf(out,"%s\n",buf);
01694                }
01695             }
01696             fprintf(out,"//\n");
01697             delete[] sofs;
01698          }
01699       }
01700 
01701       if (hdr.entries > ns)
01702          fprintf(out,"//  Normal entries (%d):\n",hdr.entries-ns);
01703 
01704       kXR_int32 nn = 0;
01705       kXR_int32 nxtofs = hdr.indofs;
01706       while (nxtofs) {
01707 
01708          // Read entry index at ofs
01709          XrdSutPFEntInd ind;
01710          if (ReadInd(nxtofs, ind) < 0) {
01711             Close();
01712             return -3;
01713          }
01714 
01715          if (ind.entofs) {
01716             // Read entry
01717             XrdSutPFEntry ent;
01718             if (ReadEnt(ind.entofs, ent) < 0) {
01719                Close();
01720                return -4;
01721             }
01722             if (ent.status != kPFE_special) {
01723                char smt[20] = {0};
01724                XrdSutTimeString(ent.mtime,smt);
01725                
01726                nn++;
01727                fprintf(out,
01728                    "// #:%d  st:%d cn:%d  buf:%d,%d,%d,%d mod:%s name:%s\n",
01729                    nn,ent.status,ent.cnt,ent.buf1.len,ent.buf2.len,ent.buf3.len,
01730                    ent.buf4.len,smt,ind.name);
01731             }
01732          }
01733 
01734          // Read next
01735          nxtofs = ind.nxtofs;
01736       }
01737       fprintf(out,"//\n");
01738    }
01739    fprintf(out,"//-----------------------------------------------------"
01740                                               "--------------------//\n");
01741 
01742    // Close the file
01743    Close();
01744 
01745    return 0;
01746 }
01747 
01748 //________________________________________________________________
01749 kXR_int32 XrdSutPFile::Trim(const char *fbak)
01750 {
01751    // Trim away unreachable entries from the file
01752    // Previous content is save in a file name fbak, the default
01753    // being 'name'.bak
01754    EPNAME("PFile::Trim");
01755 
01756    // Retrieve header, first, to check if there is anything to trim
01757    XrdSutPFHeader header;
01758    if (RetrieveHeader(header) < 0)
01759       return -1;
01760    if (header.jnksiz <= 0) {
01761       DEBUG("nothing to trim - return ");
01762       return -1;
01763    }
01764 
01765    // Get name of backup file
01766    char *nbak = (char *)fbak;
01767    if (!nbak) {
01768       // Use default
01769       nbak = new char[strlen(name)+5];
01770       if (!nbak)
01771          return Err(kPFErrOutOfMemory,"Trim");
01772       sprintf(nbak,"%s.bak",name);
01773       DEBUG("backup file: "<<nbak);
01774    }
01775 
01776    // Move file
01777    if (rename(name,nbak) == -1)
01778       return Err(kPFErrFileRename,"Trim",name,nbak);
01779 
01780    // Create new file
01781    int fdnew = Open(1);
01782    if (fdnew < 0)
01783       return -1;
01784 
01785    // Open backup file
01786    int fdbck = Open(1,0,nbak);
01787    if (fdbck < 0) {
01788       Close();
01789       return -1;
01790    }
01791 
01792    // Read the header from backup file
01793    fFd = fdbck;
01794    if (ReadHeader(header) < 0) {
01795       Close(fdnew); Close(fdbck);
01796       return -1;
01797    }
01798 
01799    // Copy it to new file
01800    fFd = fdnew;
01801    if (WriteHeader(header) < 0) {
01802       Close(fdnew); Close(fdbck);
01803       return -1;
01804    }
01805    kXR_int32 wrofs = lseek(fdnew, 0, SEEK_CUR);
01806    if (wrofs == -1) {
01807       Close(fdnew); Close(fdbck);
01808       return Err(kPFErrSeek,"Trim",
01809                           "SEEK_CUR",(const char *)&fdnew);
01810    }
01811 
01812    // Read active entries now and save them to new file
01813    bool firstind = 1;
01814    XrdSutPFEntInd ind, indlast;
01815    XrdSutPFEntry ent;
01816 
01817    kXR_int32 nxtofs = header.indofs;
01818    kXR_int32 lastofs = nxtofs;
01819 
01820    while (nxtofs) {
01821 
01822       // Read index entry
01823       fFd = fdbck;
01824       if (ReadInd(nxtofs,ind) < 0) {
01825          Close(fdnew); Close(fdbck);
01826          return -1;
01827       }
01828 
01829       // Get Next index entry before updating index entry
01830       nxtofs = ind.nxtofs;
01831       
01832       // Read entry, if active
01833       if (ind.entofs > 0) {
01834          fFd = fdbck;
01835          if (ReadEnt(ind.entofs,ent) < 0) {
01836             Close(fdnew); Close(fdbck);
01837             return -1;
01838          }
01839          // Update index entry
01840          ind.entofs = wrofs;
01841 
01842          // Write active entry
01843          fFd = fdnew;
01844          if (WriteEnt(wrofs,ent) < 0) {
01845             Close(fdnew); Close(fdbck);
01846             return -1;
01847          }
01848 
01849          // Update write offset
01850          if ((wrofs = lseek(fdnew, 0, SEEK_CUR)) == -1) {
01851             Close(fdnew); Close(fdbck);
01852             return Err(kPFErrSeek,"Trim",
01853                        "SEEK_CUR",(const char *)&fdnew);
01854          }
01855 
01856          if (firstind) {
01857             // Update header
01858             header.indofs = wrofs;
01859             firstind = 0;
01860          } else {
01861             // Update previous index entry
01862             indlast.nxtofs = wrofs;
01863             fFd = fdnew;
01864             if (WriteInd(lastofs,indlast) < 0) {
01865                Close(fdnew); Close(fdbck);
01866                return -1;
01867             }
01868          }
01869 
01870          // Save this index for later updates
01871          indlast = ind;
01872          lastofs = wrofs;
01873 
01874          // Last index entry, for now
01875          ind.nxtofs = 0;
01876 
01877          // Write active index entry
01878          fFd = fdnew;
01879          if (WriteInd(wrofs,ind) < 0) {
01880             Close(fdnew); Close(fdbck);
01881             return -1;
01882          }
01883 
01884          // Update write offset
01885          if ((wrofs = lseek(fdnew, 0, SEEK_CUR)) == -1) {
01886             Close(fdnew); Close(fdbck);
01887             return Err(kPFErrSeek,"Trim",
01888                        "SEEK_CUR",(const char *)&fdnew);
01889          }
01890       }
01891    }
01892 
01893    // Close backup file
01894    Close(fdbck);
01895    fFd = fdnew;
01896 
01897    // Update header
01898    header.ctime = (kXR_int32)time(0);
01899    header.itime = header.ctime;
01900    header.jnksiz = 0;
01901 
01902    // Copy it to new file
01903    if (WriteHeader(header) < 0) {
01904       Close();;
01905       return -1;
01906    }
01907 
01908    // Close the file
01909    Close();
01910 
01911    return 0;
01912 }
01913 
01914 //________________________________________________________________
01915 kXR_int32 XrdSutPFile::UpdateHashTable(bool force)
01916 {
01917    // Update hash table reflecting the index of the file
01918    // If force is .true. the table is recreated even if no recent 
01919    // change in the index has occured.
01920    // Returns the number of entries in the table.
01921 
01922    // The file must be open
01923    if (fFd < 0)
01924       return Err(kPFErrFileNotOpen,"UpdateHashTable");
01925 
01926    // Read the header
01927    XrdSutPFHeader header;
01928    if (ReadHeader(header) < 0)
01929       return -1;
01930 
01931    // If no recent changes and no force option, return
01932    if (!force && header.itime < fHTutime)
01933       return 0;
01934 
01935    // Clean up the table or create it
01936    if (fHashTable)
01937       fHashTable->Purge();
01938    else
01939       fHashTable = new XrdOucHash<kXR_int32>;
01940    // Make sure we have it
01941    if (!fHashTable)
01942       return Err(kPFErrOutOfMemory,"UpdateHashTable");
01943 
01944    // Read entries
01945    kXR_int32 ne = 0;
01946    if (header.entries > 0) {
01947       XrdSutPFEntInd ind;
01948       kXR_int32 nxtofs = header.indofs;
01949       while (nxtofs > 0) {
01950          if (ReadInd(nxtofs, ind) < 0)
01951             return -1;
01952          ne++;
01953          // Fill the table 
01954          kXR_int32 *key = new kXR_int32(nxtofs);
01955          fHashTable->Add(ind.name,key);
01956          // Go to next
01957          nxtofs = ind.nxtofs;
01958       }
01959    }
01960 
01961    // Update the time stamp
01962    fHTutime = (kXR_int32)time(0);
01963 
01964    return ne;
01965 }
01966 
01967 //________________________________________________________________
01968 kXR_int32 XrdSutPFile::RemoveEntries(const char *tag, char opt)
01969 {
01970    // Remove entries whose tag is compatible with 'tag', according
01971    // to compatibility option 'opt'.
01972    // For opt = 0 tags starting with 'tag'
01973    // for opt = 1 tags containing the wild card '*' are matched.
01974    // Return number of entries removed
01975    EPNAME("PFile::RemoveEntries");
01976 
01977    //
01978    // Get number of entries related
01979    int nm = SearchEntries(tag,opt);
01980    if (nm) {
01981       DEBUG("found "<<nm<<" entries for tag '"<<tag<<"'");
01982       //
01983       // Book vector for offsets
01984       int *ofs = new int[nm];
01985       //
01986       // Get number of entries related
01987       SearchEntries(tag,0,ofs,nm);
01988       //
01989       // Read entries now
01990       int i = 0;
01991       for (; i < nm ; i++) {
01992          if (RemoveEntry(ofs[i]) == 0) {
01993             DEBUG("entry for tag '"<<tag<<"' removed from file");
01994          } else {
01995             DEBUG("entry for tag '"<<tag<<"' not found in file");
01996          }
01997       }
01998    } else {
01999       DEBUG("no entry for tag '"<<tag<<"' found in file: "<<Name());
02000    }
02001    // We are done
02002    return nm;
02003 }
02004 
02005 //________________________________________________________________
02006 kXR_int32 XrdSutPFile::SearchEntries(const char *tag, char opt,
02007                                      kXR_int32 *ofs, kXR_int32 nofs)
02008 {
02009    // Get offsets of the first nofs entries whose tag is compatible
02010    // with 'tag', according to compatibility option 'opt'.
02011    // For opt = 0 tags starting with 'tag' are searched for;
02012    // For opt = 1 tags containing the wild card '*' matching tag
02013    // are searched for.
02014    // For opt = 2 tags matching tag are searched for; tag may contain
02015    // the wild card '*'.
02016    // The caller is responsible for memory pointed by 'ofs'.
02017    // Return number of entries found (<= nofs).
02018    // If ofs = 0, return total number of entries matching the
02019    // condition.
02020 
02021    // Make sure that we got a tag
02022    if (!tag)
02023       return Err(kPFErrBadInputs,"SearchEntries");
02024 
02025    // Make sure we got an open stream
02026    bool wasopen = 0;
02027    if (Open(1,&wasopen) < 0)
02028       return -1;
02029 
02030    // Read the header
02031    XrdSutPFHeader header;
02032    if (ReadHeader(header) < 0) {
02033       if (!wasopen) Close();
02034       return -1;
02035    }
02036 
02037    // Get offset of the first index entry
02038    kXR_int32 indofs = header.indofs;
02039 
02040    // Scan entries
02041    kXR_int32 no = 0;
02042    XrdOucString smatch;
02043    if (opt == 1)
02044       smatch.assign(tag, 0);
02045    while (indofs) {
02046 
02047       // Read it out
02048       XrdSutPFEntInd ind;
02049       if (ReadInd(indofs, ind) < 0) {
02050          if (!wasopen) Close();
02051          return -1;
02052       }
02053 
02054       // Check compatibility
02055       int match = 0;
02056       if (opt == 0) {
02057          if (!strncmp(ind.name,tag,strlen(tag)))
02058             match = 1;
02059       } else if (opt == 1) {
02060          match = smatch.matches(ind.name);
02061       } else if (opt == 2) {
02062          smatch.assign(ind.name, 0);
02063          match = smatch.matches(tag);
02064       }
02065 
02066       if (match > 0 && ind.entofs > 0) {
02067          no++;
02068          if (ofs) {
02069             ofs[no-1] = indofs;
02070             if (no == nofs) {
02071                // We are done
02072                break;
02073             }
02074          }
02075       }
02076 
02077       // Next index entry
02078       indofs = ind.nxtofs;
02079    }
02080 
02081    // Close the file
02082    if (!wasopen) Close();
02083 
02084    return no;
02085 }
02086 
02087 //________________________________________________________________
02088 kXR_int32 XrdSutPFile::SearchSpecialEntries(kXR_int32 *ofs,
02089                                             kXR_int32 nofs)
02090 {
02091    // Get offsets of the first nofs entries with status
02092    // kPFE_special.
02093    // The caller is responsible for memory pointed by 'ofs'.
02094    // Return number of entries found (<= nofs).
02095    // If ofs = 0, return total number of special entries.
02096 
02097    // Make sure we got an open stream
02098    bool wasopen = 0;
02099    if (Open(1,&wasopen) < 0)
02100       return -1;
02101 
02102    // Read the header
02103    XrdSutPFHeader header;
02104    if (ReadHeader(header) < 0) {
02105       if (!wasopen) Close();
02106       return -1;
02107    }
02108 
02109    // Get offset of the first index entry
02110    kXR_int32 indofs = header.indofs;
02111 
02112    // Scan entries
02113    kXR_int32 no = 0;
02114    while (indofs) {
02115 
02116       // Read index
02117       XrdSutPFEntInd ind;
02118       if (ReadInd(indofs, ind) < 0) {
02119          if (!wasopen) Close();
02120          return -1;
02121       }
02122 
02123       // If active ...
02124       if (ind.entofs > 0) {
02125 
02126          // Read entry out
02127          XrdSutPFEntry ent;
02128          if (ReadEnt(ind.entofs, ent) < 0) {
02129             if (!wasopen) Close();
02130             return -1;
02131          }
02132          // If special ...
02133          if (ent.status == kPFE_special) {
02134             // Record the offset ...
02135             no++;
02136             if (ofs) {
02137                ofs[no-1] = indofs;
02138                if (no == nofs) {
02139                   // We are done
02140                   break;
02141                }
02142             }
02143          }
02144       }
02145 
02146       // Next index entry
02147       indofs = ind.nxtofs;
02148    }
02149 
02150    // Close the file
02151    if (!wasopen) Close();
02152 
02153    return no;
02154 }
02155 
02156 //________________________________________________________________
02157 kXR_int32 XrdSutPFile::Err(kXR_int32 code, const char *loc,
02158                            const char *em1, const char *em2)
02159 {
02160    // Save code and, if requested, format and print an error
02161    // message
02162    EPNAME("PFile::Err");
02163 
02164    char buf[XrdSutMAXBUF];
02165    int fd = 0, lp = 0, lt = 0;
02166 
02167    // Save code for later use
02168    fError = code;
02169 
02170    // Build string following the error code
02171    char *errbuf = strerror(errno);
02172    switch (code) {
02173       case kPFErrBadInputs:
02174          snprintf(buf,XrdSutMAXBUF,
02175                   "XrdSutPFile::%s: bad input arguments",loc);
02176          break;
02177       case kPFErrFileAlreadyOpen:
02178          snprintf(buf,XrdSutMAXBUF,
02179                   "XrdSutPFile::%s: file already open"
02180                   " in incompatible mode",loc);
02181          break;
02182       case kPFErrNoFile:
02183          snprintf(buf,XrdSutMAXBUF,
02184                   "XrdSutPFile::%s: file %s does not exists",
02185                   loc,em1);
02186          break;
02187       case kPFErrFileRename:
02188          snprintf(buf,XrdSutMAXBUF,
02189                   "XrdSutPFile::%s: error renaming file %s to %s"
02190                   " (%s)",loc,em1,em2,errbuf);
02191          break;
02192       case kPFErrStat:
02193          snprintf(buf,XrdSutMAXBUF,
02194                   "XrdSutPFile::%s: cannot file %s (%s)",
02195                   loc,em1,errbuf);
02196          break;
02197       case kPFErrFileOpen:
02198          snprintf(buf,XrdSutMAXBUF,
02199                   "XrdSutPFile::%s: cannot open file %s (%s)",
02200                   loc,em1,errbuf);
02201          break;
02202       case kPFErrFileNotOpen:
02203          snprintf(buf,XrdSutMAXBUF,
02204                   "XrdSutPFile::%s: file is not open", loc);
02205          break;
02206       case kPFErrLocking:
02207          fd = *((int *)em1);
02208          snprintf(buf,XrdSutMAXBUF,
02209                   "XrdSutPFile::%s: cannot lock file descriptor %d (%s)",
02210                   loc,fd,errbuf);
02211          break;
02212       case kPFErrUnlocking:
02213          fd = *((int *)em1);
02214          snprintf(buf,XrdSutMAXBUF,
02215                   "XrdSutPFile::%s: cannot unlock file descriptor %d (%s)",
02216                   loc,fd,errbuf);
02217          break;
02218       case kPFErrFileLocked:
02219          fd = *((int *)em2);
02220          snprintf(buf,XrdSutMAXBUF,
02221                   "XrdSutPFile::%s: file %s is locked by process %d",
02222                   loc,em1,fd);
02223          break;
02224       case kPFErrSeek:
02225          fd = *((int *)em2);
02226          snprintf(buf,XrdSutMAXBUF,
02227                   "XrdSutPFile::%s: lseek %s error on descriptor %d (%s)",
02228                   loc,em1,fd,errbuf);
02229          break;
02230       case kPFErrRead:
02231          fd = *((int *)em1);
02232          snprintf(buf,XrdSutMAXBUF,
02233                   "XrdSutPFile::%s: read error on descriptor %d (%s)",
02234                   loc,fd,errbuf);
02235          break;
02236       case kPFErrOutOfMemory:
02237          snprintf(buf,XrdSutMAXBUF,
02238                   "XrdSutPFile::%s: out of memory (%s)",
02239                   loc,errbuf);
02240          break;
02241       case kPFErrLenMismatch:
02242          lp = *((int *)em1);
02243          lt = *((int *)em2);
02244          snprintf(buf,XrdSutMAXBUF,
02245                   "XrdSutPFile::%s: length mismatch: %d (expected: %d)",
02246                   loc,lp,lt);
02247          break;
02248       case kPFErrBadOp:
02249          snprintf(buf,XrdSutMAXBUF,
02250                   "XrdSutPFile::%s: bad option: %s", loc,em1);
02251          break;
02252       default:
02253          DEBUG("unknown error code: "<<code);
02254    }
02255 
02256    // Print error string if requested
02257    DEBUG(buf);
02258 
02259    // Save error string
02260    fErrStr = buf;
02261 
02262    return -1;
02263 }

Generated on Tue Jul 5 14:47:03 2011 for ROOT_528-00b_version by  doxygen 1.5.1