XrdOfs.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                             X r d O f s . c c                              */
00004 /*                                                                            */
00005 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*       All Rights Reserved. See XrdInfo.cc for complete License Terms       */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*               DE-AC03-76-SFO0515 with the Deprtment of Energy              */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdOfs.cc 38011 2011-02-08 18:35:57Z ganis $
00012 
00013 const char *XrdOfsCVSID = "$Id: XrdOfs.cc 38011 2011-02-08 18:35:57Z ganis $";
00014 
00015 /* Available compile-time define symbols:
00016 
00017    -DAIX       mangles some includes to accomodate AIX.
00018 
00019    -DNODEBUG   suppresses inline dbugging statement.
00020 
00021    -DNOSEC     suppresses security code generation.
00022 
00023    Note: This is a C++ mt-safe 64-bit clean program and must be compiled with:
00024 
00025          Solaris: -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_REENTRANT
00026 
00027          AIX:     -D_THREAD_SAFE
00028 */
00029 
00030 #include <unistd.h>
00031 #include <dirent.h>
00032 #include <errno.h>
00033 #include <fcntl.h>
00034 #include <memory.h>
00035 #include <string.h>
00036 #include <stdio.h>
00037 #include <time.h>
00038 #include <netdb.h>
00039 #include <stdlib.h>
00040 #include <sys/param.h>
00041 #include <sys/stat.h>
00042 #include <sys/time.h>
00043 #include <sys/types.h>
00044 
00045 #include "XrdVersion.hh"
00046 
00047 #include "XrdOfs/XrdOfs.hh"
00048 #include "XrdOfs/XrdOfsEvs.hh"
00049 #include "XrdOfs/XrdOfsPoscq.hh"
00050 #include "XrdOfs/XrdOfsTrace.hh"
00051 #include "XrdOfs/XrdOfsSecurity.hh"
00052 #include "XrdOfs/XrdOfsStats.hh"
00053 
00054 #include "XrdCms/XrdCmsClient.hh"
00055 
00056 #include "XrdOss/XrdOss.hh"
00057 
00058 #include "XrdNet/XrdNetDNS.hh"
00059 
00060 #include "XrdSys/XrdSysHeaders.hh"
00061 #include "XrdOuc/XrdOuca2x.hh"
00062 #include "XrdOuc/XrdOucEnv.hh"
00063 #include "XrdSys/XrdSysError.hh"
00064 #include "XrdOuc/XrdOucLock.hh"
00065 #include "XrdSys/XrdSysLogger.hh"
00066 #include "XrdOuc/XrdOucMsubs.hh"
00067 #include "XrdSys/XrdSysPlatform.hh"
00068 #include "XrdSys/XrdSysPthread.hh"
00069 #include "XrdOuc/XrdOucTList.hh"
00070 #include "XrdOuc/XrdOucTrace.hh"
00071 #include "XrdSec/XrdSecEntity.hh"
00072 #include "XrdSfs/XrdSfsAio.hh"
00073 #include "XrdSfs/XrdSfsInterface.hh"
00074 
00075 #ifdef AIX
00076 #include <sys/mode.h>
00077 #endif
00078 
00079 /******************************************************************************/
00080 /*                  E r r o r   R o u t i n g   O b j e c t                   */
00081 /******************************************************************************/
00082 
00083 XrdSysError      OfsEroute(0);
00084 
00085 XrdOucTrace      OfsTrace(&OfsEroute);
00086 
00087 /******************************************************************************/
00088 /*               S t a t i s t i c a l   D a t a   O b j e c t                */
00089 /******************************************************************************/
00090   
00091 XrdOfsStats      OfsStats;
00092 
00093 /******************************************************************************/
00094 /*                        S t a t i c   O b j e c t s                         */
00095 /******************************************************************************/
00096   
00097 XrdOfsHandle     *XrdOfs::dummyHandle;
00098 
00099 int               XrdOfs::MaxDelay = 60;
00100 int               XrdOfs::OSSDelay = 30;
00101 
00102 /******************************************************************************/
00103 /*                    F i l e   S y s t e m   O b j e c t                     */
00104 /******************************************************************************/
00105   
00106 extern XrdOfs XrdOfsFS;
00107 
00108 /******************************************************************************/
00109 /*                 S t o r a g e   S y s t e m   O b j e c t                  */
00110 /******************************************************************************/
00111   
00112 XrdOss *XrdOfsOss;
00113 
00114 /******************************************************************************/
00115 /*                    X r d O f s   C o n s t r u c t o r                     */
00116 /******************************************************************************/
00117 
00118 XrdOfs::XrdOfs()
00119 {
00120    unsigned int myIPaddr = 0;
00121    char buff[256], *bp;
00122    int i;
00123 
00124 // Establish defaults
00125 //
00126    Authorization = 0;
00127    Finder        = 0;
00128    Balancer      = 0;
00129    evsObject     = 0;
00130    myRole        = strdup("server");
00131    myPort        = 0;
00132 
00133 // Defaults for POSC
00134 //
00135    poscQ   = 0;
00136    poscLog = 0;
00137    poscHold= 10*60;
00138    poscAuto= 0;
00139 
00140 // Establish our hostname and IPV4 address
00141 //
00142    HostName      = XrdNetDNS::getHostName();
00143    if (!XrdNetDNS::Host2IP(HostName, &myIPaddr)) myIPaddr = 0x7f000001;
00144    strcpy(buff, "[::"); bp = buff+3;
00145    bp += XrdNetDNS::IP2String(myIPaddr, 0, bp, 128);
00146    *bp++ = ']'; *bp++ = ':';
00147    sprintf(bp, "%d", myPort);
00148    locResp = strdup(buff); locRlen = strlen(buff);
00149    for (i = 0; HostName[i] && HostName[i] != '.'; i++);
00150    HostName[i] = '\0';
00151    HostPref = strdup(HostName);
00152    HostName[i] = '.';
00153 
00154 // Set the configuration file name abd dummy handle
00155 //
00156    ConfigFN = 0;
00157    XrdOfsHandle::Alloc(&dummyHandle);
00158 }
00159   
00160 /******************************************************************************/
00161 /*                X r d O f s F i l e   C o n s t r u c t o r                 */
00162 /******************************************************************************/
00163 
00164 XrdOfsFile::XrdOfsFile(const char *user) : XrdSfsFile(user)
00165 {
00166    oh = XrdOfs::dummyHandle; 
00167    dorawio = 0;
00168    viaDel  = 0;
00169    tident = (user ? user : "");
00170 }
00171 
00172 /******************************************************************************/
00173 /*                                                                            */
00174 /*           D i r e c t o r y   O b j e c t   I n t e r f a c e s            */
00175 /*                                                                            */
00176 /******************************************************************************/
00177 /******************************************************************************/
00178 /*                                  o p e n                                   */
00179 /******************************************************************************/
00180 
00181 int XrdOfsDirectory::open(const char              *dir_path, // In
00182                           const XrdSecEntity      *client,   // In
00183                           const char              *info)      // In
00184 /*
00185   Function: Open the directory `path' and prepare for reading.
00186 
00187   Input:    path      - The fully qualified name of the directory to open.
00188             client    - Authentication credentials, if any.
00189             info      - Opaque information to be used as seen fit.
00190 
00191   Output:   Returns SFS_OK upon success, otherwise SFS_ERROR.
00192 
00193   Notes: 1. The code here assumes that directory file descriptors are never
00194             shared. Hence, no locks need to be obtained. It works out that
00195             lock overhead is worse than have a duplicate file descriptor for
00196             very short durations.
00197 */
00198 {
00199    EPNAME("opendir");
00200    XrdOucEnv Open_Env(info,0,client);
00201    int retc;
00202 
00203 // Trace entry
00204 //
00205    XTRACE(opendir, dir_path, "");
00206 
00207 // Verify that this object is not already associated with an open directory
00208 //
00209    if (dp) return
00210       XrdOfsFS.Emsg(epname, error, EADDRINUSE, "open directory", dir_path);
00211 
00212 // Apply security, as needed
00213 //
00214    AUTHORIZE(client,&Open_Env,AOP_Readdir,"open directory",dir_path,error);
00215 
00216 // Open the directory and allocate a handle for it
00217 //
00218    if (!(dp = XrdOfsOss->newDir(tident))) retc = -ENOMEM;
00219       else if (!(retc = dp->Opendir(dir_path)))
00220               {fname = strdup(dir_path);
00221                return SFS_OK;
00222               }
00223               else {delete dp; dp = 0;}
00224 
00225 // Encountered an error
00226 //
00227    return XrdOfsFS.Emsg(epname, error, retc, "open directory", dir_path);
00228 }
00229 
00230 /******************************************************************************/
00231 /*                             n e x t E n t r y                              */
00232 /******************************************************************************/
00233 
00234 const char *XrdOfsDirectory::nextEntry()
00235 /*
00236   Function: Read the next directory entry.
00237 
00238   Input:    n/a
00239 
00240   Output:   Upon success, returns the contents of the next directory entry as
00241             a null terminated string. Returns a null pointer upon EOF or an
00242             error. To differentiate the two cases, getErrorInfo will return
00243             0 upon EOF and an actual error code (i.e., not 0) on error.
00244 
00245   Notes: 1. The code here assumes that idle directory file descriptors are
00246             *not* closed. This needs to be the case because we need to return
00247             non-duplicate directory entries. Anyway, the xrootd readdir protocol
00248             is handled internally so directories should never be idle.
00249          2. The code here assumes that directory file descriptors are never
00250             shared. Hence, no locks need to be obtained. It works out that
00251             lock overhead is worse than have a duplicate file descriptor for
00252             very short durations.
00253 */
00254 {
00255    EPNAME("readdir");
00256    int retc;
00257 
00258 // Check if this directory is actually open
00259 //
00260    if (!dp) {XrdOfsFS.Emsg(epname, error, EBADF, "read directory");
00261              return 0;
00262             }
00263 
00264 // Check if we are at EOF (once there we stay there)
00265 //
00266    if (atEOF) return 0;
00267 
00268 // Read the next directory entry
00269 //
00270    if ((retc = dp->Readdir(dname, sizeof(dname))) < 0)
00271       {XrdOfsFS.Emsg(epname, error, retc, "read directory", fname);
00272        return 0;
00273       }
00274 
00275 // Check if we have reached end of file
00276 //
00277    if (!*dname)
00278       {atEOF = 1;
00279        error.clear();
00280        XTRACE(readdir, fname, "<eof>");
00281        return 0;
00282       }
00283 
00284 // Return the actual entry
00285 //
00286    XTRACE(readdir, fname, dname);
00287    return (const char *)(dname);
00288 }
00289 
00290 /******************************************************************************/
00291 /*                                 c l o s e                                  */
00292 /******************************************************************************/
00293   
00294 int XrdOfsDirectory::close()
00295 /*
00296   Function: Close the directory object.
00297 
00298   Input:    n/a
00299 
00300   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
00301 
00302   Notes: 1. The code here assumes that directory file descriptors are never
00303             shared. Hence, no locks need to be obtained. It works out that
00304             lock overhead is worse than have a duplicate file descriptor for
00305             very short durations.
00306 */
00307 {
00308    EPNAME("closedir");
00309    int retc;
00310 
00311 // Check if this directory is actually open
00312 //
00313    if (!dp) {XrdOfsFS.Emsg(epname, error, EBADF, "close directory");
00314              return SFS_ERROR;
00315             }
00316    XTRACE(closedir, fname, "");
00317 
00318 // Close this directory
00319 //
00320     if ((retc = dp->Close()))
00321        retc = XrdOfsFS.Emsg(epname, error, retc, "close", fname);
00322        else retc = SFS_OK;
00323 
00324 // All done
00325 //
00326    delete dp;
00327    dp = 0;
00328    free(fname);
00329    fname = 0;
00330    return retc;
00331 }
00332 
00333 /******************************************************************************/
00334 /*                                                                            */
00335 /*                F i l e   O b j e c t   I n t e r f a c e s                 */
00336 /*                                                                            */
00337 /******************************************************************************/
00338 /******************************************************************************/
00339 /*                                  o p e n                                   */
00340 /******************************************************************************/
00341 
00342 int XrdOfsFile::open(const char          *path,      // In
00343                      XrdSfsFileOpenMode   open_mode, // In
00344                      mode_t               Mode,      // In
00345                const XrdSecEntity        *client,    // In
00346                const char                *info)      // In
00347 /*
00348   Function: Open the file `path' in the mode indicated by `open_mode'.  
00349 
00350   Input:    path      - The fully qualified name of the file to open.
00351             open_mode - One of the following flag values:
00352                         SFS_O_RDONLY - Open file for reading.
00353                         SFS_O_WRONLY - Open file for writing.
00354                         SFS_O_RDWR   - Open file for update
00355                         SFS_O_REPLICA- Open file for replication
00356                         SFS_O_CREAT  - Create the file open in RW mode
00357                         SFS_O_TRUNC  - Trunc  the file open in RW mode
00358                         SFS_O_POSC   - Presist    file on successful close
00359             Mode      - The Posix access mode bits to be assigned to the file.
00360                         These bits correspond to the standard Unix permission
00361                         bits (e.g., 744 == "rwxr--r--"). Additionally, Mode
00362                         may contain SFS_O_MKPTH to force creation of the full
00363                         directory path if it does not exist. This parameter is
00364                         ignored unless open_mode = SFS_O_CREAT.
00365             client    - Authentication credentials, if any.
00366             info      - Opaque information to be used as seen fit.
00367 
00368   Output:   Returns SFS_OK upon success, otherwise SFS_ERROR is returned.
00369 */
00370 {
00371    EPNAME("open");
00372    static const int crMask = (SFS_O_CREAT  | SFS_O_TRUNC);
00373    static const int opMask = (SFS_O_RDONLY | SFS_O_WRONLY | SFS_O_RDWR);
00374 
00375    struct OpenHelper
00376          {const char   *Path;
00377           XrdOfsHandle *hP;
00378           XrdOssDF     *fP;
00379           int           poscNum;
00380 
00381           int           OK() {hP = 0; fP = 0; poscNum = 0; return SFS_OK;}
00382 
00383                         OpenHelper(const char *path)
00384                        : Path(path), hP(0), fP(0), poscNum(0) {}
00385 
00386                        ~OpenHelper()
00387                        {if (hP) hP->Retire();
00388                         if (fP) delete fP;
00389                         if (poscNum > 0) XrdOfsFS.poscQ->Del(Path, poscNum, 1);
00390                        }
00391          } oP(path);
00392 
00393    mode_t theMode = Mode & S_IAMB;
00394    int retc, isPosc = 0, crOpts = 0, isRW = 0, open_flag = 0;
00395    int find_flag = open_mode & (SFS_O_NOWAIT | SFS_O_RESET);
00396    XrdOucEnv Open_Env(info,0,client);
00397 
00398 // Trace entry
00399 //
00400    ZTRACE(open, std::hex <<open_mode <<"-" <<std::oct <<Mode <<std::dec <<" fn=" <<path);
00401 
00402 // Verify that this object is not already associated with an open file
00403 //
00404    XrdOfsFS.ocMutex.Lock();
00405    if (oh != XrdOfs::dummyHandle)
00406       {XrdOfsFS.ocMutex.UnLock();
00407        return XrdOfsFS.Emsg(epname,error,EADDRINUSE,"open file",path);
00408       }
00409    XrdOfsFS.ocMutex.UnLock();
00410 
00411 // Handle the open mode options
00412 //
00413    if (open_mode & crMask)
00414       {crOpts = (Mode & SFS_O_MKPTH ? XRDOSS_mkpath : 0);
00415        if (XrdOfsFS.poscQ && ((open_mode & SFS_O_POSC) ||
00416            XrdOfsFS.poscAuto || Open_Env.Get("ofs.posc")))
00417            {isPosc = 1; isRW = XrdOfsHandle::opPC;}
00418           else isRW = XrdOfsHandle::opRW;
00419        if (open_mode & SFS_O_CREAT)
00420           {open_flag   = O_RDWR     | O_CREAT  | O_EXCL;
00421            find_flag  |= SFS_O_RDWR | SFS_O_CREAT | (open_mode & SFS_O_REPLICA);
00422            crOpts     |= XRDOSS_new;
00423           } else {
00424            open_flag  |= O_RDWR     | O_CREAT  | O_TRUNC;
00425            find_flag  |= SFS_O_RDWR | SFS_O_TRUNC;
00426           }
00427       }
00428    else
00429    switch(open_mode & opMask)
00430   {case SFS_O_RDONLY: open_flag = O_RDONLY; find_flag |= SFS_O_RDONLY;
00431                       break;
00432    case SFS_O_WRONLY: open_flag = O_WRONLY; find_flag |= SFS_O_WRONLY;
00433                       isRW = XrdOfsHandle::opRW;
00434                       if (XrdOfsFS.poscQ && ((open_mode & SFS_O_POSC) ||
00435                           Open_Env.Get("ofs.posc"))) oP.poscNum = -1;
00436                       break;
00437    case SFS_O_RDWR:   open_flag = O_RDWR;   find_flag |= SFS_O_RDWR;
00438                       isRW = XrdOfsHandle::opRW;
00439                       if (XrdOfsFS.poscQ && ((open_mode & SFS_O_POSC) ||
00440                           Open_Env.Get("ofs.posc"))) oP.poscNum = -1;
00441                       break;
00442    default:           open_flag = O_RDONLY; find_flag |= SFS_O_RDONLY;
00443                       break;
00444   }
00445 
00446 
00447 // If we have a finder object, use it to direct the client. The final
00448 // destination will apply the security that is needed
00449 //
00450    if (XrdOfsFS.Finder && (retc = XrdOfsFS.Finder->Locate(error, path,
00451                                                    find_flag, &Open_Env)))
00452       return XrdOfsFS.fsError(error, retc);
00453 
00454 // Create the file if so requested o/w try to attach the file
00455 //
00456    if (open_flag & O_CREAT)
00457       {// Apply security, as needed
00458        //
00459        AUTHORIZE(client,&Open_Env,AOP_Create,"create",path,error);
00460        OOIDENTENV(client, Open_Env);
00461 
00462        // For ephemeral file, we must enter the file into the queue
00463        //
00464        if (isPosc && (oP.poscNum = XrdOfsFS.poscQ->Add(tident,path)) < 0)
00465           return XrdOfsFS.Emsg(epname, error, oP.poscNum, "pcreate", path);
00466 
00467        // Create the file. If ENOTSUP is returned, promote the creation to
00468        // the subsequent open. This is to accomodate proxy support.
00469        //
00470        if ((retc = XrdOfsOss->Create(tident, path, theMode, Open_Env,
00471                                      ((open_flag << 8) | crOpts))))
00472           {if (retc > 0) return XrdOfsFS.Stall(error, retc, path);
00473            if (retc == -EINPROGRESS)
00474               {XrdOfsFS.evrObject.Wait4Event(path,&error);
00475                return XrdOfsFS.fsError(error, retc);
00476               }
00477            if (retc != -ENOTSUP)
00478               {if (XrdOfsFS.Balancer) XrdOfsFS.Balancer->Removed(path);
00479                return XrdOfsFS.Emsg(epname, error, retc, "create", path);
00480               }
00481           } else {
00482             if (XrdOfsFS.Balancer) XrdOfsFS.Balancer->Added(path, isPosc);
00483             open_flag  = O_RDWR|O_TRUNC;
00484             if (XrdOfsFS.evsObject 
00485             &&  XrdOfsFS.evsObject->Enabled(XrdOfsEvs::Create))
00486                {XrdOfsEvsInfo evInfo(tident,path,info,&Open_Env,Mode);
00487                 XrdOfsFS.evsObject->Notify(XrdOfsEvs::Create, evInfo);
00488                }
00489           }
00490 
00491       } else {
00492 
00493        // Apply security, as needed
00494        //
00495        AUTHORIZE(client,&Open_Env,(isRW?AOP_Update:AOP_Read),"open",path,error);
00496        OOIDENTENV(client, Open_Env);
00497       }
00498 
00499 // Get a handle for this file.
00500 //
00501    if ((retc = XrdOfsHandle::Alloc(path, isRW, &oP.hP)))
00502       {if (retc > 0) return XrdOfsFS.Stall(error, retc, path);
00503        return XrdOfsFS.Emsg(epname, error, retc, "attach", path);
00504       }
00505 
00506 // Assign/transfer posc ownership. We may need to delay the client if the
00507 // file create ownership does not match and this is not a create request.
00508 //
00509    if (oP.hP->isRW == XrdOfsHandle::opPC)
00510       {if (!isRW) return XrdOfsFS.Stall(error, -1, path);
00511        if ((retc = oP.hP->PoscSet(tident, oP.poscNum, theMode)))
00512           {if (retc > 0) XrdOfsFS.poscQ->Del(path, retc);
00513               else return XrdOfsFS.Emsg(epname, error, retc, "access", path);
00514           }
00515       }
00516 
00517 // If this is a previously existing handle, we are almost done
00518 //
00519    if (!(oP.hP->Inactive()))
00520       {dorawio = (oh->isCompressed && open_mode & SFS_O_RAWIO ? 1 : 0);
00521        XrdOfsFS.ocMutex.Lock(); oh = oP.hP; XrdOfsFS.ocMutex.UnLock();
00522        FTRACE(open, "attach use=" <<oh->Usage());
00523        if (oP.poscNum > 0) XrdOfsFS.poscQ->Commit(path, oP.poscNum);
00524        oP.hP->UnLock(); 
00525        OfsStats.sdMutex.Lock();
00526        isRW ? OfsStats.Data.numOpenW++ : OfsStats.Data.numOpenR++;
00527        if (oP.poscNum > 0) OfsStats.Data.numOpenP++;
00528        OfsStats.sdMutex.UnLock();
00529        return oP.OK();
00530       }
00531 
00532 // Get a storage system object
00533 //
00534    if (!(oP.fP = XrdOfsOss->newFile(tident)))
00535       return XrdOfsFS.Emsg(epname, error, ENOMEM, "open", path);
00536 
00537 // Open the file
00538 //
00539    if ((retc = oP.fP->Open(path, open_flag, Mode, Open_Env)))
00540       {if (retc > 0) return XrdOfsFS.Stall(error, retc, path);
00541        if (retc == -EINPROGRESS)
00542           {XrdOfsFS.evrObject.Wait4Event(path,&error);
00543            return XrdOfsFS.fsError(error, retc);
00544           }
00545        if (retc == -ETXTBSY) return XrdOfsFS.Stall(error, -1, path);
00546        if (XrdOfsFS.Balancer) XrdOfsFS.Balancer->Removed(path);
00547        return XrdOfsFS.Emsg(epname, error, retc, "open", path);
00548       }
00549 
00550 // Verify that we can actually use this file
00551 //
00552    if (oP.poscNum > 0)
00553       {if ((retc = oP.fP->Fchmod(static_cast<mode_t>(theMode | S_ISUID))))
00554           return XrdOfsFS.Emsg(epname, error, retc, "fchmod", path);
00555        XrdOfsFS.poscQ->Commit(path, oP.poscNum);
00556       }
00557 
00558 // Set compression values and activate the handle
00559 //
00560    if (oP.fP->isCompressed())
00561       {oP.hP->isCompressed = 1;
00562        dorawio = (open_mode & SFS_O_RAWIO ? 1 : 0);
00563       }
00564    oP.hP->Activate(oP.fP);
00565    oP.hP->UnLock();
00566 
00567 // Send an open event if we must
00568 //
00569    if (XrdOfsFS.evsObject)
00570       {XrdOfsEvs::Event theEvent = (isRW ? XrdOfsEvs::Openw : XrdOfsEvs::Openr);
00571        if (XrdOfsFS.evsObject->Enabled(theEvent))
00572           {XrdOfsEvsInfo evInfo(tident, path, info, &Open_Env);
00573            XrdOfsFS.evsObject->Notify(theEvent, evInfo);
00574           }
00575       }
00576 
00577 // Maintain statistics
00578 //
00579    OfsStats.sdMutex.Lock();
00580    isRW ? OfsStats.Data.numOpenW++ : OfsStats.Data.numOpenR++;
00581    if (oP.poscNum > 0) OfsStats.Data.numOpenP++;
00582    OfsStats.sdMutex.UnLock();
00583 
00584 // All done
00585 //
00586    XrdOfsFS.ocMutex.Lock(); oh = oP.hP; XrdOfsFS.ocMutex.UnLock();
00587    return oP.OK();
00588 }
00589 
00590 /******************************************************************************/
00591 /*                                 c l o s e                                  */
00592 /******************************************************************************/
00593 
00594 int XrdOfsFile::close()  // In
00595 /*
00596   Function: Close the file object.
00597 
00598   Input:    n/a
00599 
00600   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
00601 */
00602 {
00603    EPNAME("close");
00604 
00605    class  CloseFH : public XrdOfsHanCB
00606          {public: void Retired(XrdOfsHandle *hP) {XrdOfsFS.Unpersist(hP);}};
00607    static XrdOfsHanCB *hCB = static_cast<XrdOfsHanCB *>(new CloseFH);
00608 
00609    XrdOfsHandle *hP;
00610    int   poscNum, retc;
00611    short theMode;
00612 
00613 // Trace the call
00614 //
00615     FTRACE(close, "use=" <<oh->Usage()); // Unreliable trace, no origin lock
00616 
00617 // Verify the handle (we briefly maintain a global lock)
00618 //
00619     XrdOfsFS.ocMutex.Lock();
00620     if (oh == XrdOfs::dummyHandle)
00621        {XrdOfsFS.ocMutex.UnLock(); return SFS_OK;}
00622     if ((oh->Inactive()))
00623        {XrdOfsFS.ocMutex.UnLock();
00624         return XrdOfsFS.Emsg(epname, error, EBADF, "close file");
00625        }
00626     hP = oh; oh = XrdOfs::dummyHandle;
00627     XrdOfsFS.ocMutex.UnLock();
00628     hP->Lock();
00629 
00630 // Maintain statistics
00631 //
00632    OfsStats.sdMutex.Lock();
00633    if (!(hP->isRW)) OfsStats.Data.numOpenR--;
00634       else {OfsStats.Data.numOpenW--;
00635             if (hP->isRW == XrdOfsHandle::opPC) OfsStats.Data.numOpenP--;
00636            }
00637    OfsStats.sdMutex.UnLock();
00638 
00639 // If this file was tagged as a POSC then we need to make sure it will persist
00640 // Note that we unpersist the file immediately when it's inactive or if no hold
00641 // time is allowed.  `Also, close events occur only for active handles.
00642 //
00643    if ((poscNum = hP->PoscGet(theMode, !viaDel)))
00644       {if (viaDel)
00645           {if (hP->Inactive() || !XrdOfsFS.poscHold)
00646               {XrdOfsFS.Unpersist(hP, !hP->Inactive()); hP->Retire();}
00647               else hP->Retire(hCB, XrdOfsFS.poscHold);
00648            return SFS_OK;
00649           }
00650        if ((retc = hP->Select().Fchmod(theMode)))
00651           XrdOfsFS.Emsg(epname, error, retc, "fchmod", hP->Name());
00652           else {XrdOfsFS.poscQ->Del(hP->Name(), poscNum);
00653                 if (XrdOfsFS.Balancer) XrdOfsFS.Balancer->Added(hP->Name());
00654                }
00655       }
00656 
00657 // We need to handle the cunudrum that an event may have to be sent upon
00658 // the final close. However, that would cause the path name to be destroyed.
00659 // So, we have two modes of logic where we copy out the pathname if a final
00660 // close actually occurs. The path is not copied if it's not final and we
00661 // don't bother with any of it if we need not generate an event.
00662 //
00663    if (XrdOfsFS.evsObject && tident
00664    &&  XrdOfsFS.evsObject->Enabled(hP->isRW ? XrdOfsEvs::Closew
00665                                             : XrdOfsEvs::Closer))
00666       {long long FSize, *retsz;
00667        char pathbuff[MAXPATHLEN+8];
00668        XrdOfsEvs::Event theEvent;
00669        if (hP->isRW) {theEvent = XrdOfsEvs::Closew; retsz = &FSize;}
00670           else {      theEvent = XrdOfsEvs::Closer; retsz = 0; FSize=0;}
00671        if (!(hP->Retire(retsz, pathbuff, sizeof(pathbuff))))
00672           {XrdOfsEvsInfo evInfo(tident, pathbuff, "" , 0, 0, FSize);
00673            XrdOfsFS.evsObject->Notify(theEvent, evInfo);
00674           } else hP->Retire();
00675       } else     hP->Retire();
00676 
00677 // All done
00678 //
00679     return SFS_OK;
00680 }
00681 
00682 /******************************************************************************/
00683 /*                                  f c t l                                   */
00684 /******************************************************************************/
00685   
00686 int            XrdOfsFile::fctl(const int               cmd,
00687                                 const char             *args,
00688                                       XrdOucErrInfo    &out_error)
00689 {
00690 // See if we can do this
00691 //
00692    if (cmd == SFS_FCTL_GETFD)
00693       {out_error.setErrCode(oh->Select().getFD());
00694        return SFS_OK;
00695       }
00696 
00697 // We don't support this
00698 //
00699    out_error.setErrInfo(EEXIST, "fctl operation not supported");
00700    return SFS_ERROR;
00701 }
00702 
00703 /******************************************************************************/
00704 /*                                  r e a d                                   */
00705 /******************************************************************************/
00706 
00707 int            XrdOfsFile::read(XrdSfsFileOffset  offset,    // In
00708                                 XrdSfsXferSize    blen)      // In
00709 /*
00710   Function: Preread `blen' bytes at `offset'
00711 
00712   Input:    offset    - The absolute byte offset at which to start the read.
00713             blen      - The amount to preread.
00714 
00715   Output:   Returns SFS_OK upon success and SFS_ERROR o/w.
00716 */
00717 {
00718    EPNAME("read");
00719    int retc;
00720 
00721 // Perform required tracing
00722 //
00723    FTRACE(read, "preread " <<blen <<"@" <<offset);
00724 
00725 // Make sure the offset is not too large
00726 //
00727 #if _FILE_OFFSET_BITS!=64
00728    if (offset >  0x000000007fffffff)
00729       return  XrdOfsFS.Emsg(epname, error, EFBIG, "read", oh->Name());
00730 #endif
00731 
00732 // Now preread the actual number of bytes
00733 //
00734    if ((retc = oh->Select().Read((off_t)offset, (size_t)blen)) < 0)
00735       return XrdOfsFS.Emsg(epname, error, (int)retc, "preread", oh->Name());
00736 
00737 // Return number of bytes read
00738 //
00739    return retc;
00740 }
00741   
00742 /******************************************************************************/
00743 /*                                  r e a d                                   */
00744 /******************************************************************************/
00745 
00746 XrdSfsXferSize XrdOfsFile::read(XrdSfsFileOffset  offset,    // In
00747                                 char             *buff,      // Out
00748                                 XrdSfsXferSize    blen)      // In
00749 /*
00750   Function: Read `blen' bytes at `offset' into 'buff' and return the actual
00751             number of bytes read.
00752 
00753   Input:    offset    - The absolute byte offset at which to start the read.
00754             buff      - Address of the buffer in which to place the data.
00755             blen      - The size of the buffer. This is the maximum number
00756                         of bytes that will be read from 'fd'.
00757 
00758   Output:   Returns the number of bytes read upon success and SFS_ERROR o/w.
00759 */
00760 {
00761    EPNAME("read");
00762    XrdSfsXferSize nbytes;
00763 
00764 // Perform required tracing
00765 //
00766    FTRACE(read, blen <<"@" <<offset);
00767 
00768 // Make sure the offset is not too large
00769 //
00770 #if _FILE_OFFSET_BITS!=64
00771    if (offset >  0x000000007fffffff)
00772       return  XrdOfsFS.Emsg(epname, error, EFBIG, "read", oh->Name());
00773 #endif
00774 
00775 // Now read the actual number of bytes
00776 //
00777    nbytes = (dorawio ?
00778             (XrdSfsXferSize)(oh->Select().ReadRaw((void *)buff,
00779                             (off_t)offset, (size_t)blen))
00780           : (XrdSfsXferSize)(oh->Select().Read((void *)buff,
00781                             (off_t)offset, (size_t)blen)));
00782    if (nbytes < 0)
00783       return XrdOfsFS.Emsg(epname, error, (int)nbytes, "read", oh->Name());
00784 
00785 // Return number of bytes read
00786 //
00787    return nbytes;
00788 }
00789   
00790 /******************************************************************************/
00791 /*                              r e a d   A I O                               */
00792 /******************************************************************************/
00793   
00794 /*
00795   Function: Read `blen' bytes at `offset' into 'buff' and return the actual
00796             number of bytes read using asynchronous I/O, if possible.
00797 
00798   Output:   Returns the 0 if successfullt queued, otherwise returns an error.
00799             The underlying implementation will convert the request to
00800             synchronous I/O is async mode is not possible.
00801 */
00802 
00803 int XrdOfsFile::read(XrdSfsAio *aiop)
00804 {
00805    EPNAME("aioread");
00806    int rc;
00807 
00808 // Async mode for compressed files is not supported.
00809 //
00810    if (oh->isCompressed)
00811       {aiop->Result = this->read((XrdSfsFileOffset)aiop->sfsAio.aio_offset,
00812                                            (char *)aiop->sfsAio.aio_buf,
00813                                    (XrdSfsXferSize)aiop->sfsAio.aio_nbytes);
00814        aiop->doneRead();
00815        return 0;
00816       }
00817 
00818 // Perform required tracing
00819 //
00820    FTRACE(aio, aiop->sfsAio.aio_nbytes <<"@" <<aiop->sfsAio.aio_offset);
00821 
00822 // Make sure the offset is not too large
00823 //
00824 #if _FILE_OFFSET_BITS!=64
00825    if (aiop->sfsAio.aio_offset >  0x000000007fffffff)
00826       return  XrdOfsFS.Emsg(epname, error, EFBIG, "read", oh->Name());
00827 #endif
00828 
00829 // Issue the read. Only true errors are returned here.
00830 //
00831    if ((rc = oh->Select().Read(aiop)) < 0)
00832       return XrdOfsFS.Emsg(epname, error, rc, "read", oh->Name());
00833 
00834 // All done
00835 //
00836    return SFS_OK;
00837 }
00838 
00839 /******************************************************************************/
00840 /*                                 w r i t e                                  */
00841 /******************************************************************************/
00842 
00843 XrdSfsXferSize XrdOfsFile::write(XrdSfsFileOffset  offset,    // In
00844                                  const char       *buff,      // Out
00845                                  XrdSfsXferSize    blen)      // In
00846 /*
00847   Function: Write `blen' bytes at `offset' from 'buff' and return the actual
00848             number of bytes written.
00849 
00850   Input:    offset    - The absolute byte offset at which to start the write.
00851             buff      - Address of the buffer from which to get the data.
00852             blen      - The size of the buffer. This is the maximum number
00853                         of bytes that will be written to 'fd'.
00854 
00855   Output:   Returns the number of bytes written upon success and SFS_ERROR o/w.
00856 
00857   Notes:    An error return may be delayed until the next write(), close(), or
00858             sync() call.
00859 */
00860 {
00861    EPNAME("write");
00862    XrdSfsXferSize nbytes;
00863 
00864 // Perform any required tracing
00865 //
00866    FTRACE(write, blen <<"@" <<offset);
00867 
00868 // Make sure the offset is not too large
00869 //
00870 #if _FILE_OFFSET_BITS!=64
00871    if (offset >  0x000000007fffffff)
00872       return  XrdOfsFS.Emsg(epname, error, EFBIG, "write", oh);
00873 #endif
00874 
00875 // Silly Castor stuff
00876 //
00877    if (XrdOfsFS.evsObject && !(oh->isChanged)
00878    &&  XrdOfsFS.evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
00879 
00880 // Write the requested bytes
00881 //
00882    oh->isPending = 1;
00883    nbytes = (XrdSfsXferSize)(oh->Select().Write((const void *)buff,
00884                             (off_t)offset, (size_t)blen));
00885    if (nbytes < 0)
00886       return XrdOfsFS.Emsg(epname, error, (int)nbytes, "write", oh);
00887 
00888 // Return number of bytes written
00889 //
00890    return nbytes;
00891 }
00892 
00893 /******************************************************************************/
00894 /*                             w r i t e   A I O                              */
00895 /******************************************************************************/
00896   
00897 // For now, this reverts to synchronous I/O
00898 //
00899 int XrdOfsFile::write(XrdSfsAio *aiop)
00900 {
00901    EPNAME("aiowrite");
00902    int rc;
00903 
00904 // Perform any required tracing
00905 //
00906    FTRACE(aio, aiop->sfsAio.aio_nbytes <<"@" <<aiop->sfsAio.aio_offset);
00907 
00908 // If this is a POSC file, we must convert the async call to a sync call as we
00909 // must trap any errors that unpersist the file. We can't do that via aio i/f.
00910 //
00911    if (oh->isRW == XrdOfsHandle::opPC)
00912       {aiop->Result = this->write(aiop->sfsAio.aio_offset,
00913                                   (const char *)aiop->sfsAio.aio_buf,
00914                                   aiop->sfsAio.aio_nbytes);
00915        aiop->doneWrite();
00916        return 0;
00917       }
00918 
00919 // Make sure the offset is not too large
00920 //
00921 #if _FILE_OFFSET_BITS!=64
00922    if (aiop->sfsAio.aio_offset >  0x000000007fffffff)
00923       return  XrdOfsFS.Emsg(epname, error, EFBIG, "write", oh->Name());
00924 #endif
00925 
00926 // Silly Castor stuff
00927 //
00928    if (XrdOfsFS.evsObject && !(oh->isChanged)
00929    &&  XrdOfsFS.evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
00930 
00931 // Write the requested bytes
00932 //
00933    oh->isPending = 1;
00934    if ((rc = oh->Select().Write(aiop)) < 0)
00935        return XrdOfsFS.Emsg(epname, error, rc, "write", oh->Name());
00936 
00937 // All done
00938 //
00939    return SFS_OK;
00940 }
00941 
00942 /******************************************************************************/
00943 /*                               g e t M m a p                                */
00944 /******************************************************************************/
00945 
00946 int XrdOfsFile::getMmap(void **Addr, off_t &Size)         // Out
00947 /*
00948   Function: Return memory mapping for file, if any.
00949 
00950   Output:   Addr        - Address of memory location
00951             Size        - Size of the file or zero if not memory mapped.
00952             Returns SFS_OK upon success and SFS_ERROR upon failure.
00953 */
00954 {
00955 
00956 // Perform the function
00957 //
00958    Size = oh->Select().getMmap(Addr);
00959 
00960    return SFS_OK;
00961 }
00962   
00963 /******************************************************************************/
00964 /*                                  s t a t                                   */
00965 /******************************************************************************/
00966 
00967 int XrdOfsFile::stat(struct stat     *buf)         // Out
00968 /*
00969   Function: Return file status information
00970 
00971   Input:    buf         - The stat structiure to hold the results
00972 
00973   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
00974 */
00975 {
00976    EPNAME("fstat");
00977    int retc;
00978 
00979 // Lock the handle and perform any required tracing
00980 //
00981    FTRACE(stat, "");
00982 
00983 // Perform the function
00984 //
00985    if ((retc = oh->Select().Fstat(buf)) < 0)
00986       return XrdOfsFS.Emsg(epname,error,retc,"get state for",oh->Name());
00987 
00988    return SFS_OK;
00989 }
00990 
00991 /******************************************************************************/
00992 /*                                  s y n c                                   */
00993 /******************************************************************************/
00994 
00995 int XrdOfsFile::sync()  // In
00996 /*
00997   Function: Commit all unwritten bytes to physical media.
00998 
00999   Input:    n/a
01000 
01001   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01002 */
01003 {
01004    EPNAME("sync");
01005    int retc;
01006 
01007 // Perform any required tracing
01008 //
01009    FTRACE(sync, "");
01010 
01011 // We can test the pendio flag w/o a lock because the person doing this
01012 // sync must have done the previous write. Causality is the synchronizer.
01013 //
01014    if (!(oh->isPending)) return SFS_OK;
01015 
01016 // We can also skip the sync if the file is closed. However, we need a file
01017 // object lock in order to test the flag. We can also reset the PENDIO flag.
01018 //
01019    oh->Lock();
01020    oh->isPending = 0;
01021    oh->UnLock();
01022 
01023 // Perform the function
01024 //
01025    if ((retc = oh->Select().Fsync()))
01026       {oh->isPending = 1;
01027        return XrdOfsFS.Emsg(epname, error, retc, "synchronize", oh);
01028       }
01029 
01030 // Indicate all went well
01031 //
01032    return SFS_OK;
01033 }
01034 
01035 /******************************************************************************/
01036 /*                              s y n c   A I O                               */
01037 /******************************************************************************/
01038   
01039 // For now, reverts to synchronous case. This must also be the case for POSC!
01040 //
01041 int XrdOfsFile::sync(XrdSfsAio *aiop)
01042 {
01043    aiop->Result = this->sync();
01044    aiop->doneWrite();
01045    return 0;
01046 }
01047 
01048 /******************************************************************************/
01049 /*                              t r u n c a t e                               */
01050 /******************************************************************************/
01051 
01052 int XrdOfsFile::truncate(XrdSfsFileOffset  flen)  // In
01053 /*
01054   Function: Set the length of the file object to 'flen' bytes.
01055 
01056   Input:    flen      - The new size of the file.
01057 
01058   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01059 
01060   Notes:    If 'flen' is smaller than the current size of the file, the file
01061             is made smaller and the data past 'flen' is discarded. If 'flen'
01062             is larger than the current size of the file, a hole is created
01063             (i.e., the file is logically extended by filling the extra bytes 
01064             with zeroes).
01065 */
01066 {
01067    EPNAME("trunc");
01068    int retc;
01069 
01070 // Lock the file handle and perform any tracing
01071 //
01072    FTRACE(truncate, "len=" <<flen);
01073 
01074 // Make sure the offset is not too large
01075 //
01076    if (sizeof(off_t) < sizeof(flen) && flen >  0x000000007fffffff)
01077       return  XrdOfsFS.Emsg(epname, error, EFBIG, "truncate", oh);
01078 
01079 // Silly Castor stuff
01080 //
01081    if (XrdOfsFS.evsObject && !(oh->isChanged)
01082    &&  XrdOfsFS.evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
01083 
01084 // Perform the function
01085 //
01086    oh->isPending = 1;
01087    if ((retc = oh->Select().Ftruncate(flen)))
01088       return XrdOfsFS.Emsg(epname, error, retc, "truncate", oh);
01089 
01090 // Indicate Success
01091 //
01092    return SFS_OK;
01093 }
01094 
01095 /******************************************************************************/
01096 /*                             g e t C X i n f o                              */
01097 /******************************************************************************/
01098   
01099 int XrdOfsFile::getCXinfo(char cxtype[4], int &cxrsz)
01100 /*
01101   Function: Set the length of the file object to 'flen' bytes.
01102 
01103   Input:    n/a
01104 
01105   Output:   cxtype - Compression algorithm code
01106             cxrsz  - Compression region size
01107 
01108             Returns SFS_OK upon success and SFS_ERROR upon failure.
01109 */
01110 {
01111 
01112 // Copy out the info
01113 //
01114    cxrsz = oh->Select().isCompressed(cxtype);
01115    return SFS_OK;
01116 }
01117 
01118 /******************************************************************************/
01119 /*                  P r i v a t e   F i l e   M e t h o d s                   */
01120 /******************************************************************************/
01121 /******************************************************************************/
01122 /* protected                  G e n F W E v e n t                             */
01123 /******************************************************************************/
01124   
01125 void XrdOfsFile::GenFWEvent()
01126 {
01127    int first_write;
01128 
01129 // This silly code is to generate a 1st write event which slows things down
01130 // but is needed by the one and only Castor. What a big sigh!
01131 //
01132    oh->Lock();
01133    if ((first_write = !(oh->isChanged))) oh->isChanged = 1;
01134    oh->UnLock();
01135    if (first_write)
01136       {XrdOfsEvsInfo evInfo(tident, oh->Name());
01137        XrdOfsFS.evsObject->Notify(XrdOfsEvs::Fwrite, evInfo);
01138       }
01139 }
01140 
01141 /******************************************************************************/
01142 /*                                                                            */
01143 /*         F i l e   S y s t e m   O b j e c t   I n t e r f a c e s          */
01144 /*                                                                            */
01145 /******************************************************************************/
01146 /******************************************************************************/
01147 /*                                 c h m o d                                  */
01148 /******************************************************************************/
01149 
01150 int XrdOfs::chmod(const char             *path,    // In
01151                         XrdSfsMode        Mode,    // In
01152                         XrdOucErrInfo    &einfo,   // Out
01153                   const XrdSecEntity     *client,  // In
01154                   const char             *info)    // In
01155 /*
01156   Function: Change the mode on a file or directory.
01157 
01158   Input:    path      - Is the fully qualified name of the file to be removed.
01159             einfo     - Error information object to hold error details.
01160             client    - Authentication credentials, if any.
01161             info      - Opaque information to be used as seen fit.
01162 
01163   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01164 */
01165 {
01166    EPNAME("chmod");
01167    mode_t acc_mode = Mode & S_IAMB;
01168    const char *tident = einfo.getErrUser();
01169    XrdOucEnv chmod_Env(info,0,client);
01170    int retc;
01171    XTRACE(chmod, path, "");
01172 
01173 // Apply security, as needed
01174 //
01175    AUTHORIZE(client,&chmod_Env,AOP_Chmod,"chmod",path,einfo);
01176 
01177 // Find out where we should chmod this file
01178 //
01179    if (Finder && Finder->isRemote())
01180       {if (fwdCHMOD.Cmd)
01181           {char buff[8];
01182            sprintf(buff, "%o", static_cast<int>(acc_mode));
01183            if (Forward(retc, einfo, fwdCHMOD, path, buff, info)) return retc;
01184           }
01185           else if ((retc = Finder->Locate(einfo,path,SFS_O_RDWR|SFS_O_META)))
01186                   return fsError(einfo, retc);
01187       }
01188 
01189 // Check if we should generate an event
01190 //
01191    if (evsObject && evsObject->Enabled(XrdOfsEvs::Chmod))
01192       {XrdOfsEvsInfo evInfo(tident, path, info, &chmod_Env, acc_mode);
01193        evsObject->Notify(XrdOfsEvs::Chmod, evInfo);
01194       }
01195 
01196 // Now try to find the file or directory
01197 //
01198    if (!(retc = XrdOfsOss->Chmod(path, acc_mode))) return SFS_OK;
01199 
01200 // An error occured, return the error info
01201 //
01202    return XrdOfsFS.Emsg(epname, einfo, retc, "change", path);
01203 }
01204 
01205 /******************************************************************************/
01206 /*                                e x i s t s                                 */
01207 /******************************************************************************/
01208 
01209 int XrdOfs::exists(const char                *path,        // In
01210                          XrdSfsFileExistence &file_exists, // Out
01211                          XrdOucErrInfo       &einfo,       // Out
01212                    const XrdSecEntity        *client,      // In
01213                    const char                *info)        // In
01214 /*
01215   Function: Determine if file 'path' actually exists.
01216 
01217   Input:    path        - Is the fully qualified name of the file to be tested.
01218             file_exists - Is the address of the variable to hold the status of
01219                           'path' when success is returned. The values may be:
01220                           XrdSfsFileExistsIsDirectory - file not found but path is valid.
01221                           XrdSfsFileExistsIsFile      - file found.
01222                           XrdSfsFileExistsIsNo        - neither file nor directory.
01223             einfo       - Error information object holding the details.
01224             client      - Authentication credentials, if any.
01225             info        - Opaque information to be used as seen fit.
01226 
01227   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01228 
01229   Notes:    When failure occurs, 'file_exists' is not modified.
01230 */
01231 {
01232    EPNAME("exists");
01233    struct stat fstat;
01234    int retc;
01235    const char *tident = einfo.getErrUser();
01236    XrdOucEnv stat_Env(info,0,client);
01237    XTRACE(exists, path, "");
01238 
01239 // Apply security, as needed
01240 //
01241    AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
01242 
01243 // Find out where we should stat this file
01244 //
01245    if (Finder && Finder->isRemote() 
01246    &&  (retc = Finder->Locate(einfo, path, SFS_O_RDONLY)))
01247       return fsError(einfo, retc);
01248 
01249 // Now try to find the file or directory
01250 //
01251    retc = XrdOfsOss->Stat(path, &fstat);
01252    if (!retc)
01253       {     if (S_ISDIR(fstat.st_mode)) file_exists=XrdSfsFileExistIsDirectory;
01254        else if (S_ISREG(fstat.st_mode)) file_exists=XrdSfsFileExistIsFile;
01255        else                             file_exists=XrdSfsFileExistNo;
01256        return SFS_OK;
01257       }
01258    if (retc == -ENOENT)
01259       {file_exists=XrdSfsFileExistNo;
01260        return SFS_OK;
01261       }
01262 
01263 // An error occured, return the error info
01264 //
01265    return XrdOfsFS.Emsg(epname, einfo, retc, "locate", path);
01266 }
01267 
01268 /******************************************************************************/
01269 /*                                 f s c t l                                  */
01270 /******************************************************************************/
01271 
01272 int XrdOfs::fsctl(const int               cmd,
01273                   const char             *args,
01274                   XrdOucErrInfo          &einfo,
01275                   const XrdSecEntity     *client)
01276 /*
01277   Function: Perform filesystem operations:
01278 
01279   Input:    cmd       - Operation command (currently supported):
01280                         SFS_FSCTL_LOCATE - locate file
01281                         SFS_FSCTL_STATFS - return file system info (physical)
01282                         SFS_FSCTL_STATLS - return file system info (logical)
01283                         SFS_FSCTL_STATXA - return file extended attributes
01284             arg       - Command dependent argument:
01285                       - Locate: The path whose location is wanted
01286             buf       - The stat structure to hold the results
01287             einfo     - Error/Response information structure.
01288             client    - Authentication credentials, if any.
01289 
01290   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01291 */
01292 {
01293    EPNAME("fsctl");
01294    static int PrivTab[]     = {XrdAccPriv_Delete, XrdAccPriv_Insert,
01295                                XrdAccPriv_Lock,   XrdAccPriv_Lookup,
01296                                XrdAccPriv_Rename, XrdAccPriv_Read,
01297                                XrdAccPriv_Write};
01298    static char PrivLet[]    = {'d',               'i',
01299                                'k',               'l',
01300                                'n',               'r',
01301                                'w'};
01302    static const int PrivNum = sizeof(PrivLet);
01303 
01304    int retc, find_flag = SFS_O_LOCATE | (cmd & (SFS_O_NOWAIT | SFS_O_RESET));
01305    int i, blen, privs, opcode = cmd & SFS_FSCTL_CMD;
01306    const char *tident = einfo.getErrUser();
01307    char *bP, *cP;
01308    XTRACE(fsctl, args, "");
01309 
01310 // Process the LOCATE request
01311 //
01312    if (opcode == SFS_FSCTL_LOCATE)
01313       {struct stat fstat;
01314        const char *Path, *locArg;
01315        char rType[3], *Resp[] = {rType, locResp};
01316             if (*args == '*')      {Path = args+1; locArg = args;}
01317        else if (cmd & SFS_O_TRUNC) {Path = args;   locArg = (char *)"*";}
01318        else                         Path = locArg = args;
01319        AUTHORIZE(client,0,AOP_Stat,"locate",Path,einfo);
01320        if (Finder && Finder->isRemote()
01321        &&  (retc = Finder->Locate(einfo, locArg, find_flag)))
01322           return fsError(einfo, retc);
01323        if ((retc = XrdOfsOss->Stat(Path, &fstat)))
01324           return XrdOfsFS.Emsg(epname, einfo, retc, "locate", Path);
01325        rType[0] = ((fstat.st_mode & S_IFBLK) == S_IFBLK ? 's' : 'S');
01326        rType[1] = (fstat.st_mode & S_IWUSR            ? 'w' : 'r');
01327        rType[2] = '\0';
01328        einfo.setErrInfo(locRlen+3, (const char **)Resp, 2);
01329        return SFS_DATA;
01330       }
01331 
01332 // Process the STATFS request
01333 //
01334    if (opcode == SFS_FSCTL_STATFS)
01335       {AUTHORIZE(client,0,AOP_Stat,"statfs",args,einfo);
01336        if (Finder && Finder->isRemote()
01337        &&  (retc = Finder->Space(einfo, args))) return fsError(einfo, retc);
01338        bP = einfo.getMsgBuff(blen);
01339        if ((retc = XrdOfsOss->StatFS(args, bP, blen)))
01340           return XrdOfsFS.Emsg(epname, einfo, retc, "statfs", args);
01341        einfo.setErrCode(blen+1);
01342        return SFS_DATA;
01343       }
01344 
01345 // Process the STATLS request
01346 //
01347    if (opcode == SFS_FSCTL_STATLS)
01348       {const char *path;
01349         char pbuff[1024], *opq = (char *) index(args, '?');
01350        XrdOucEnv statls_Env(opq ? opq+1 : 0,0,client);
01351        if (!opq) path = args;
01352           else {int plen = opq-args;
01353                 if (plen >= (int)sizeof(pbuff)) plen = sizeof(pbuff)-1;
01354                 strncpy(pbuff, args, plen);
01355                 path = pbuff;
01356                }
01357        AUTHORIZE(client,0,AOP_Stat,"statfs",path,einfo);
01358        if (Finder && Finder->isRemote()
01359        &&  (retc = Finder->Space(einfo, path))) return fsError(einfo, retc);
01360        bP = einfo.getMsgBuff(blen);
01361        if ((retc = XrdOfsOss->StatLS(statls_Env, path, bP, blen)))
01362           return XrdOfsFS.Emsg(epname, einfo, retc, "statls", path);
01363        einfo.setErrCode(blen+1);
01364        return SFS_DATA;
01365       }
01366 
01367 // Process the STATXA request
01368 //
01369    if (opcode == SFS_FSCTL_STATXA)
01370       {AUTHORIZE(client,0,AOP_Stat,"statxa",args,einfo);
01371        if (Finder && Finder->isRemote()
01372        && (retc = Finder->Locate(einfo, args, SFS_O_RDONLY|SFS_O_STAT)))
01373           return fsError(einfo, retc);
01374        bP = einfo.getMsgBuff(blen);
01375        if ((retc = XrdOfsOss->StatXA(args, bP, blen)))
01376           return XrdOfsFS.Emsg(epname, einfo, retc, "statxa", args);
01377        if (!client || !XrdOfsFS.Authorization) privs = XrdAccPriv_All;
01378           else privs = XrdOfsFS.Authorization->Access(client, args, AOP_Any);
01379        cP = bP + blen; strcpy(cP, "&ofs.ap="); cP += 8;
01380        if (privs == XrdAccPriv_All) *cP++ = 'a';
01381           else {for (i = 0; i < PrivNum; i++)
01382                     if (PrivTab[i] & privs) *cP++ = PrivLet[i];
01383                 if (cP == (bP + blen + 1)) *cP++ = '?';
01384                }
01385        *cP++ = '\0';
01386        einfo.setErrCode(cP-bP+1);
01387        return SFS_DATA;
01388       }
01389 
01390 // Operation is not supported
01391 //
01392    return XrdOfsFS.Emsg(epname, einfo, ENOTSUP, "fsctl", args);
01393 
01394 }
01395 
01396 /******************************************************************************/
01397 /*                              g e t S t a t s                               */
01398 /******************************************************************************/
01399 
01400 int XrdOfs::getStats(char *buff, int blen)
01401 {
01402    int n;
01403 
01404 // See if the size just wanted
01405 //
01406   if (!buff) return OfsStats.Report(0,0) + XrdOfsOss->Stats(0,0);
01407 
01408 // Report ofs info followed by the oss info
01409 //
01410    n = OfsStats.Report(buff, blen);
01411    buff += n; blen -= n;
01412    n += XrdOfsOss->Stats(buff, blen);
01413 
01414 // All done
01415 //
01416    return n;
01417 }
01418   
01419 /******************************************************************************/
01420 /*                            g e t V e r s i o n                             */
01421 /******************************************************************************/
01422   
01423 const char *XrdOfs::getVersion() {return XrdVSTRING;}
01424 
01425 /******************************************************************************/
01426 /*                                 m k d i r                                  */
01427 /******************************************************************************/
01428 
01429 int XrdOfs::mkdir(const char             *path,    // In
01430                         XrdSfsMode        Mode,    // In
01431                         XrdOucErrInfo    &einfo,   // Out
01432                   const XrdSecEntity     *client,  // In
01433                   const char             *info)    // In
01434 /*
01435   Function: Create a directory entry.
01436 
01437   Input:    path      - Is the fully qualified name of the file to be removed.
01438             Mode      - Is the POSIX mode value the directory is to have.
01439                         Additionally, Mode may contain SFS_O_MKPTH if the
01440                         full dircectory path should be created.
01441             einfo     - Error information object to hold error details.
01442             client    - Authentication credentials, if any.
01443             info      - Opaque information to be used as seen fit.
01444 
01445   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01446 */
01447 {
01448    EPNAME("mkdir");
01449    static const int LocOpts = SFS_O_RDWR | SFS_O_CREAT | SFS_O_META;
01450    mode_t acc_mode = Mode & S_IAMB;
01451    int retc, mkpath = Mode & SFS_O_MKPTH;
01452    const char *tident = einfo.getErrUser();
01453    XrdOucEnv mkdir_Env(info,0,client);
01454    XTRACE(mkdir, path, "");
01455 
01456 // Apply security, as needed
01457 //
01458    AUTHORIZE(client,&mkdir_Env,AOP_Mkdir,"mkdir",path,einfo);
01459 
01460 // Find out where we should remove this file
01461 //
01462    if (Finder && Finder->isRemote())
01463       {if (fwdMKDIR.Cmd)
01464           {char buff[8];
01465            sprintf(buff, "%o", static_cast<int>(acc_mode));
01466            if (Forward(retc, einfo, (mkpath ? fwdMKPATH:fwdMKDIR),
01467                        path, buff, info)) return retc;
01468           }
01469           else if ((retc = Finder->Locate(einfo,path,LocOpts)))
01470                   return fsError(einfo, retc);
01471       }
01472 
01473 // Perform the actual operation
01474 //
01475     if ((retc = XrdOfsOss->Mkdir(path, acc_mode, mkpath)))
01476        return XrdOfsFS.Emsg(epname, einfo, retc, "mkdir", path);
01477 
01478 // Check if we should generate an event
01479 //
01480    if (evsObject && evsObject->Enabled(XrdOfsEvs::Mkdir))
01481       {XrdOfsEvsInfo evInfo(tident, path, info, &mkdir_Env, acc_mode);
01482        evsObject->Notify(XrdOfsEvs::Mkdir, evInfo);
01483       }
01484 
01485     return SFS_OK;
01486 }
01487 
01488 /******************************************************************************/
01489 /*                               p r e p a r e                                */
01490 /******************************************************************************/
01491 
01492 int XrdOfs::prepare(      XrdSfsPrep       &pargs,      // In
01493                           XrdOucErrInfo    &out_error,  // Out
01494                     const XrdSecEntity     *client)     // In
01495 {
01496    EPNAME("prepare");
01497    XrdOucTList *tp = pargs.paths;
01498    int retc;
01499 
01500 // Run through the paths to make sure client can read each one
01501 //
01502    while(tp)
01503         {AUTHORIZE(client,0,AOP_Read,"prepare",tp->text,out_error);
01504          tp = tp->next;
01505         }
01506 
01507 // If we have a finder object, use it to prepare the paths. Otherwise,
01508 // ignore this prepare request (we may change this in the future).
01509 //
01510    if (XrdOfsFS.Finder && (retc = XrdOfsFS.Finder->Prepare(out_error, pargs)))
01511       return fsError(out_error, retc);
01512    return 0;
01513 }
01514   
01515 /******************************************************************************/
01516 /*                                r e m o v e                                 */
01517 /******************************************************************************/
01518 
01519 int XrdOfs::remove(const char              type,    // In
01520                    const char             *path,    // In
01521                          XrdOucErrInfo    &einfo,   // Out
01522                    const XrdSecEntity     *client,  // In
01523                    const char             *info)    // In
01524 /*
01525   Function: Delete a file from the namespace and release it's data storage.
01526 
01527   Input:    type      - 'f' for file and 'd' for directory.
01528             path      - Is the fully qualified name of the file to be removed.
01529             einfo     - Error information object to hold error details.
01530             client    - Authentication credentials, if any.
01531             info      - Opaque information to be used as seen fit.
01532 
01533   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01534 */
01535 {
01536    EPNAME("remove");
01537    int retc, Opt;
01538    const char *tident = einfo.getErrUser();
01539    XrdOucEnv rem_Env(info,0,client);
01540    XTRACE(remove, path, type);
01541 
01542 // Apply security, as needed
01543 //
01544    AUTHORIZE(client,&rem_Env,AOP_Delete,"remove",path,einfo);
01545 
01546 // Find out where we should remove this file
01547 //
01548    if (Finder && Finder->isRemote())
01549       {struct fwdOpt *fSpec = (type == 'd' ? &fwdRMDIR : &fwdRM);
01550        if (fSpec->Cmd)
01551           {if (Forward(retc, einfo, *fSpec, path, 0, info)) return retc;}
01552           else if ((retc = Finder->Locate(einfo,path,SFS_O_WRONLY|SFS_O_META)))
01553                   return fsError(einfo, retc);
01554       }
01555 
01556 // Check if we should generate an event
01557 //
01558    if (evsObject)
01559       {XrdOfsEvs::Event theEvent=(type == 'd' ? XrdOfsEvs::Rmdir:XrdOfsEvs::Rm);
01560        if (evsObject->Enabled(theEvent))
01561           {XrdOfsEvsInfo evInfo(tident, path, info, &rem_Env);
01562            evsObject->Notify(theEvent, evInfo);
01563           }
01564       }
01565 
01566 // Check if this is an online deletion only
01567 //
01568    Opt = (rem_Env.Get("ofs.lcl") ? XRDOSS_Online : 0);
01569 
01570 // Perform the actual deletion
01571 //
01572     retc = (type=='d' ? XrdOfsOss->Remdir(path) : XrdOfsOss->Unlink(path,Opt));
01573     if (retc) return XrdOfsFS.Emsg(epname, einfo, retc, "remove", path);
01574     if (type == 'f')
01575        {XrdOfsHandle::Hide(path);
01576         if (Balancer) Balancer->Removed(path);
01577        }
01578     return SFS_OK;
01579 }
01580 
01581 /******************************************************************************/
01582 /*                                r e n a m e                                 */
01583 /******************************************************************************/
01584 
01585 int XrdOfs::rename(const char             *old_name,  // In
01586                    const char             *new_name,  // In
01587                          XrdOucErrInfo    &einfo,     //Out
01588                    const XrdSecEntity     *client,    // In
01589                    const char             *infoO,     // In
01590                    const char             *infoN)     // In
01591 /*
01592   Function: Renames a file with name 'old_name' to 'new_name'.
01593 
01594   Input:    old_name  - Is the fully qualified name of the file to be renamed.
01595             new_name  - Is the fully qualified name that the file is to have.
01596             einfo     - Error information structure, if an error occurs.
01597             client    - Authentication credentials, if any.
01598             infoO     - old_name opaque information to be used as seen fit.
01599             infoN     - new_name opaque information to be used as seen fit.
01600 
01601   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01602 */
01603 {
01604    EPNAME("rename");
01605    int retc;
01606    const char *tident = einfo.getErrUser();
01607    XrdOucEnv old_Env(infoO,0,client);
01608    XrdOucEnv new_Env(infoN,0,client);
01609    XTRACE(rename, new_name, "old fn=" <<old_name <<" new ");
01610 
01611 // Apply security, as needed
01612 //
01613    AUTHORIZE2(client, einfo,
01614               AOP_Rename, "renaming",    old_name, &old_Env,
01615               AOP_Insert, "renaming to", new_name, &new_Env );
01616 
01617 // Find out where we should rename this file
01618 //
01619    if (Finder && Finder->isRemote())
01620       {if (fwdMV.Cmd)
01621           {if (Forward(retc, einfo, fwdMV, old_name, new_name, infoO, infoN))
01622               return retc;
01623           }
01624           else if ((retc = Finder->Locate(einfo,old_name,SFS_O_RDWR|SFS_O_META)))
01625                   return fsError(einfo, retc);
01626       }
01627 
01628 // Check if we should generate an event
01629 //
01630    if (evsObject && evsObject->Enabled(XrdOfsEvs::Mv))
01631       {XrdOfsEvsInfo evInfo(tident, old_name, infoO, &old_Env, 0, 0,
01632                                     new_name, infoN, &new_Env);
01633        evsObject->Notify(XrdOfsEvs::Mv, evInfo);
01634       }
01635 
01636 // Perform actual rename operation
01637 //
01638    if ((retc = XrdOfsOss->Rename(old_name, new_name)))
01639       return XrdOfsFS.Emsg(epname, einfo, retc, "rename", old_name);
01640    XrdOfsHandle::Hide(old_name);
01641    if (Balancer) {Balancer->Removed(old_name);
01642                   Balancer->Added(new_name);
01643                  }
01644    return SFS_OK;
01645 }
01646 
01647 /******************************************************************************/
01648 /*                                  s t a t                                   */
01649 /******************************************************************************/
01650 
01651 int XrdOfs::stat(const char             *path,        // In
01652                        struct stat      *buf,         // Out
01653                        XrdOucErrInfo    &einfo,       // Out
01654                  const XrdSecEntity     *client,      // In
01655                  const char             *info)        // In
01656 /*
01657   Function: Return file status information
01658 
01659   Input:    path      - The path for which status is wanted
01660             buf       - The stat structure to hold the results
01661             einfo     - Error information structure, if an error occurs.
01662             client    - Authentication credentials, if any.
01663             info      - opaque information to be used as seen fit.
01664 
01665   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01666 */
01667 {
01668    EPNAME("stat");
01669    int retc;
01670    const char *tident = einfo.getErrUser();
01671    XrdOucEnv stat_Env(info,0,client);
01672    XTRACE(stat, path, "");
01673 
01674 // Apply security, as needed
01675 //
01676    AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
01677 
01678 // Find out where we should stat this file
01679 //
01680    if (Finder && Finder->isRemote()
01681    &&  (retc = Finder->Locate(einfo, path, SFS_O_RDONLY|SFS_O_STAT, &stat_Env)))
01682       return fsError(einfo, retc);
01683 
01684 // Now try to find the file or directory
01685 //
01686    if ((retc = XrdOfsOss->Stat(path, buf)))
01687       return XrdOfsFS.Emsg(epname, einfo, retc, "locate", path);
01688    return SFS_OK;
01689 }
01690 
01691 /******************************************************************************/
01692 
01693 int XrdOfs::stat(const char             *path,        // In
01694                        mode_t           &mode,        // Out
01695                        XrdOucErrInfo    &einfo,       // Out
01696                  const XrdSecEntity     *client,      // In
01697                  const char             *info)        // In
01698 /*
01699   Function: Return file status information (resident files only)
01700 
01701   Input:    path      - The path for which status is wanted
01702             mode      - The stat mode entry (faked -- do not trust it)
01703             einfo     - Error information structure, if an error occurs.
01704             client    - Authentication credentials, if any.
01705             info      - opaque information to be used as seen fit.
01706 
01707   Output:   Always returns SFS_ERROR if a delay needs to be imposed. Otherwise,
01708             SFS_OK is returned and mode is appropriately, if inaccurately, set.
01709             If file residency cannot be determined, mode is set to -1.
01710 */
01711 {
01712    EPNAME("stat");
01713    struct stat buf;
01714    int retc;
01715    const char *tident = einfo.getErrUser();
01716    XrdOucEnv stat_Env(info,0,client);
01717    XTRACE(stat, path, "");
01718 
01719 // Apply security, as needed
01720 //
01721    AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
01722    mode = (mode_t)-1;
01723 
01724 // Find out where we should stat this file
01725 //
01726    if (Finder && Finder->isRemote()
01727    &&  (retc = Finder->Locate(einfo,path,SFS_O_NOWAIT|SFS_O_RDONLY|SFS_O_STAT,
01728                               &stat_Env)))
01729       return fsError(einfo, retc);
01730 
01731 // Now try to find the file or directory
01732 //
01733    if (!(retc = XrdOfsOss->Stat(path, &buf, XRDOSS_resonly))) mode=buf.st_mode;
01734       else if ((-ENOMSG) != retc) return XrdOfsFS.Emsg(epname, einfo, retc,
01735                                                     "locate", path);
01736    return SFS_OK;
01737 }
01738 
01739 /******************************************************************************/
01740 /*                              t r u n c a t e                               */
01741 /******************************************************************************/
01742 
01743 int XrdOfs::truncate(const char             *path,    // In
01744                            XrdSfsFileOffset  Size,    // In
01745                            XrdOucErrInfo    &einfo,   // Out
01746                      const XrdSecEntity     *client,  // In
01747                      const char             *info)    // In
01748 /*
01749   Function: Change the mode on a file or directory.
01750 
01751   Input:    path      - Is the fully qualified name of the file to be removed.
01752             Size      - the size the file should have.
01753             einfo     - Error information object to hold error details.
01754             client    - Authentication credentials, if any.
01755             info      - Opaque information to be used as seen fit.
01756 
01757   Output:   Returns SFS_OK upon success and SFS_ERROR upon failure.
01758 */
01759 {
01760    EPNAME("truncate");
01761    const char *tident = einfo.getErrUser();
01762    XrdOucEnv trunc_Env(info,0,client);
01763    int retc;
01764    XTRACE(truncate, path, "");
01765 
01766 // Apply security, as needed
01767 //
01768    AUTHORIZE(client,&trunc_Env,AOP_Update,"truncate",path,einfo);
01769 
01770 // Find out where we should chmod this file
01771 //
01772    if (Finder && Finder->isRemote())
01773       {if (fwdTRUNC.Cmd)
01774           {char xSz[32];
01775            sprintf(xSz, "%lld", static_cast<long long>(Size));
01776            if (Forward(retc, einfo, fwdTRUNC, path, xSz, info)) return retc;
01777           }
01778           else if ((retc = Finder->Locate(einfo,path,SFS_O_RDWR)))
01779                   return fsError(einfo, retc);
01780       }
01781 
01782 // Check if we should generate an event
01783 //
01784    if (evsObject && evsObject->Enabled(XrdOfsEvs::Trunc))
01785       {XrdOfsEvsInfo evInfo(tident, path, info, &trunc_Env, 0, Size);
01786        evsObject->Notify(XrdOfsEvs::Trunc, evInfo);
01787       }
01788 
01789 // Now try to find the file or directory
01790 //
01791    if (!(retc = XrdOfsOss->Truncate(path, Size))) return SFS_OK;
01792 
01793 // An error occured, return the error info
01794 //
01795    return XrdOfsFS.Emsg(epname, einfo, retc, "trunc", path);
01796 }
01797 
01798 /******************************************************************************/
01799 /*                                  E m s g                                   */
01800 /******************************************************************************/
01801 
01802 int XrdOfs::Emsg(const char    *pfx,    // Message prefix value
01803                  XrdOucErrInfo &einfo,  // Place to put text & error code
01804                  int            ecode,  // The error code
01805                  const char    *op,     // Operation being performed
01806                  XrdOfsHandle  *hP)     // The target handle
01807 {
01808    int rc;
01809 
01810 // First issue the error message so if we have to unpersist it makes sense
01811 //
01812    if ((rc = Emsg(pfx, einfo, ecode, op, hP->Name())) != SFS_ERROR) return rc;
01813 
01814 // If this is a POSC file then we need to unpersist it. Note that we are always
01815 // called with the handle **unlocked**
01816 //
01817    if (hP->isRW == XrdOfsHandle::opPC)
01818       {hP->Lock();
01819        XrdOfsFS.Unpersist(hP);
01820        hP->UnLock();
01821       }
01822 
01823 // Now return the error
01824 //
01825    return SFS_ERROR;
01826 }
01827 
01828 /******************************************************************************/
01829 
01830 int XrdOfs::Emsg(const char    *pfx,    // Message prefix value
01831                  XrdOucErrInfo &einfo,  // Place to put text & error code
01832                  int            ecode,  // The error code
01833                  const char    *op,     // Operation being performed
01834                  const char    *target) // The target (e.g., fname)
01835 {
01836    char *etext, buffer[MAXPATHLEN+80], unkbuff[64];
01837 
01838 // If the error is EBUSY then we just need to stall the client. This is
01839 // a hack in order to provide for proxy support
01840 //
01841     if (ecode < 0) ecode = -ecode;
01842     if (ecode == EBUSY) return 5;  // A hack for proxy support
01843 
01844 // Check for timeout conditions that require a client delay
01845 //
01846    if (ecode == ETIMEDOUT) return OSSDelay;
01847 
01848 // Get the reason for the error
01849 //
01850    if (!(etext = OfsEroute.ec2text(ecode))) 
01851       {sprintf(unkbuff, "reason unknown (%d)", ecode); etext = unkbuff;}
01852 
01853 // Format the error message
01854 //
01855     snprintf(buffer,sizeof(buffer),"Unable to %s %s; %s", op, target, etext);
01856 
01857 // Print it out if debugging is enabled
01858 //
01859 #ifndef NODEBUG
01860     OfsEroute.Emsg(pfx, einfo.getErrUser(), buffer);
01861 #endif
01862 
01863 // Place the error message in the error object and return
01864 //
01865     einfo.setErrInfo(ecode, buffer);
01866     return SFS_ERROR;
01867 }
01868 
01869 /******************************************************************************/
01870 /*                     P R I V A T E    S E C T I O N                         */
01871 /******************************************************************************/
01872 
01873 /******************************************************************************/
01874 /*                                 F n a m e                                  */
01875 /******************************************************************************/
01876 
01877 const char *XrdOfs::Fname(const char *path)
01878 {
01879    int i = strlen(path)-1;
01880    while(i) if (path[i] == '/') return &path[i+1];
01881                else i--;
01882    return path;
01883 }
01884 
01885 /******************************************************************************/
01886 /*                               F o r w a r d                                */
01887 /******************************************************************************/
01888   
01889 int XrdOfs::Forward(int &Result, XrdOucErrInfo &Resp, struct fwdOpt &Fwd,
01890                     const char *arg1, const char *arg2,
01891                     const char *arg3, const char *arg4)
01892 {
01893    int retc;
01894 
01895    if ((retc = Finder->Forward(Resp, Fwd.Cmd, arg1, arg2, arg3, arg4)))
01896       {Result = fsError(Resp, retc);
01897        return 1;
01898       }
01899 
01900    if (Fwd.Port <= 0)
01901       {Result = SFS_OK;
01902        return (Fwd.Port ? 0 : 1);
01903       }
01904 
01905    Resp.setErrInfo(Fwd.Port, Fwd.Host);
01906    Result = SFS_REDIRECT;
01907    return 1;
01908 }
01909 
01910 /******************************************************************************/
01911 /*                               f s E r r o r                                */
01912 /******************************************************************************/
01913   
01914 int XrdOfs::fsError(XrdOucErrInfo &myError, int rc)
01915 {
01916 
01917 // Translate the error code (update statistics w/o a lock for speed!)
01918 //
01919    if (rc == -EREMOTE)     {OfsStats.Data.numRedirect++; return SFS_REDIRECT;}
01920    if (rc == -EINPROGRESS) {OfsStats.Data.numStarted++;  return SFS_STARTED; }
01921    if (rc > 0)             {OfsStats.Data.numDelays++;   return rc;          }
01922    if (rc == -EALREADY)    {OfsStats.Data.numReplies++;  return SFS_DATA;    }
01923                            {OfsStats.Data.numErrors++;   return SFS_ERROR;   }
01924 }
01925 
01926 /******************************************************************************/
01927 /*                                 S t a l l                                  */
01928 /******************************************************************************/
01929   
01930 int XrdOfs::Stall(XrdOucErrInfo   &einfo, // Error text & code
01931                   int              stime, // Seconds to stall
01932                   const char      *path)  // The path to stall on
01933 {
01934     const char *msgfmt = "File %s is being %s; "
01935                          "estimated time to completion %s";
01936     EPNAME("Stall")
01937 #ifndef NODEBUG
01938     const char *tident = "";
01939 #endif
01940     char Mbuff[2048], Tbuff[32];
01941     const char *What = "staged";
01942 
01943 // Check why the stall is occurring
01944 //
01945    if (stime < 0) {stime = 60; What = "created";}
01946 
01947 // Format the stall message
01948 //
01949     snprintf(Mbuff, sizeof(Mbuff)-1, msgfmt,
01950              Fname(path), What, WaitTime(stime, Tbuff, sizeof(Tbuff)));
01951     ZTRACE(delay, "Stall " <<stime <<": " <<Mbuff <<" for " <<path);
01952 
01953 // Place the error message in the error object and return
01954 //
01955     einfo.setErrInfo(0, Mbuff);
01956 
01957 // All done
01958 //
01959    return (stime > MaxDelay ? MaxDelay : stime);
01960 }
01961 
01962 /******************************************************************************/
01963 /*                             U n p e r s i s t                              */
01964 /******************************************************************************/
01965   
01966 void XrdOfs::Unpersist(XrdOfsHandle *oh, int xcev)
01967 {
01968    EPNAME("Unpersist");
01969    const char *tident = oh->PoscUsr();
01970    int   poscNum, retc;
01971    short theMode;
01972 
01973 // Trace the call
01974 //
01975     FTRACE(close, "use=0");
01976 
01977 // Generate a proper close event as one has not yet been generated
01978 //
01979    if (xcev && XrdOfsFS.evsObject && *tident != '?'
01980    &&  XrdOfsFS.evsObject->Enabled(XrdOfsEvs::Closew))
01981        {XrdOfsEvsInfo evInfo(tident, oh->Name());
01982         XrdOfsFS.evsObject->Notify(XrdOfsEvs::Closew, evInfo);
01983        }
01984 
01985 // Now generate a removal event
01986 //
01987    if (XrdOfsFS.Balancer) XrdOfsFS.Balancer->Removed(oh->Name());
01988    if (XrdOfsFS.evsObject && XrdOfsFS.evsObject->Enabled(XrdOfsEvs::Rm))
01989       {XrdOfsEvsInfo evInfo(tident, oh->Name());
01990        XrdOfsFS.evsObject->Notify(XrdOfsEvs::Rm, evInfo);
01991       }
01992 
01993 // Count this
01994 //
01995    OfsStats.Add(OfsStats.Data.numUnpsist);
01996 
01997 // Now unpersist the file
01998 //
01999    OfsEroute.Emsg(epname, "Unpersisting", tident, oh->Name());
02000    if ((poscNum = oh->PoscGet(theMode))) poscQ->Del(oh->Name(), poscNum, 1);
02001        else if ((retc = XrdOfsOss->Unlink(oh->Name())))
02002                OfsEroute.Emsg(epname, retc, "unpersist", oh->Name());
02003 }
02004   
02005 /******************************************************************************/
02006 /*                              W a i t T i m e                               */
02007 /******************************************************************************/
02008 
02009 char *XrdOfs::WaitTime(int stime, char *buff, int blen)
02010 {
02011    int mlen, hr, min, sec;
02012 
02013 // Compute hours, minutes, and seconds
02014 //
02015    min = stime / 60;
02016    sec = stime % 60;
02017    hr  = min   / 60;
02018    min = min   % 60;
02019 
02020 // Now format the message based on time duration
02021 //
02022         if (!hr && !min)
02023            mlen = snprintf(buff,blen,"%d second%s",sec,(sec > 1 ? "s" : ""));
02024    else if (!hr)
02025           {if (sec > 10) min++;
02026            mlen = snprintf(buff,blen,"%d minute%s",min,(min > 1 ? "s" : ""));
02027           }
02028    else   {if (hr == 1)
02029               if (min <= 30)
02030                       mlen = snprintf(buff,blen,"%d minutes",min+60);
02031                  else mlen = snprintf(buff,blen,"%d hour and %d minutes",hr,min);
02032               else {if (min > 30) hr++;
02033                       mlen = snprintf(buff,blen,"%d hours",hr);
02034                    }
02035           }
02036 
02037 // Complete the message
02038 //
02039    buff[blen-1] = '\0';
02040    return buff;
02041 }

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