XRootD
Loading...
Searching...
No Matches
XrdOfs.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d O f s . c c */
4/* */
5/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Andrew Hanushevsky for Stanford University under contract */
7/* DE-AC02-76-SFO0515 with the Deprtment of Energy */
8/* */
9/* This file is part of the XRootD software suite. */
10/* */
11/* XRootD is free software: you can redistribute it and/or modify it under */
12/* the terms of the GNU Lesser General Public License as published by the */
13/* Free Software Foundation, either version 3 of the License, or (at your */
14/* option) any later version. */
15/* */
16/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19/* License for more details. */
20/* */
21/* You should have received a copy of the GNU Lesser General Public License */
22/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24/* */
25/* The copyright holder's institutional names and contributor's names may not */
26/* be used to endorse or promote products derived from this software without */
27/* specific prior written permission of the institution or contributor. */
28/******************************************************************************/
29
30#include <unistd.h>
31#include <dirent.h>
32#include <cerrno>
33#include <fcntl.h>
34#include <memory.h>
35#include <cstring>
36#include <cstdio>
37#include <ctime>
38#include <netdb.h>
39#include <cstdlib>
40#include <memory>
41#include <sys/param.h>
42#include <sys/stat.h>
43#include <sys/time.h>
44#include <sys/types.h>
45
47
48#include "XrdCks/XrdCks.hh"
49#include "XrdCks/XrdCksCalc.hh"
51#include "XrdCks/XrdCksData.hh"
52
53#include "XrdNet/XrdNetAddr.hh"
54#include "XrdNet/XrdNetIF.hh"
55#include "XrdNet/XrdNetUtils.hh"
56
57#include "XrdOfs/XrdOfs.hh"
61#include "XrdOfs/XrdOfsEvs.hh"
63#include "XrdOfs/XrdOfsPoscq.hh"
65#include "XrdOfs/XrdOfsTrace.hh"
67#include "XrdOfs/XrdOfsStats.hh"
68#include "XrdOfs/XrdOfsTPC.hh"
69
71
72#include "XrdOss/XrdOss.hh"
73
74#include "XrdSys/XrdSysError.hh"
80
81#include "XrdOuc/XrdOuca2x.hh"
82#include "XrdOuc/XrdOucEnv.hh"
84#include "XrdOuc/XrdOucLock.hh"
85#include "XrdOuc/XrdOucMsubs.hh"
87#include "XrdOuc/XrdOucTList.hh"
88#include "XrdOuc/XrdOucTPC.hh"
91#include "XrdSfs/XrdSfsAio.hh"
92#include "XrdSfs/XrdSfsFlags.hh"
94
95#ifdef AIX
96#include <sys/mode.h>
97#endif
98
99#ifndef O_DIRECT
100#define O_DIRECT 0
101#endif
102
103/******************************************************************************/
104/* E r r o r R o u t i n g O b j e c t */
105/******************************************************************************/
106
108
110
111/******************************************************************************/
112/* S t a t i s t i c a l D a t a O b j e c t */
113/******************************************************************************/
114
116
117/******************************************************************************/
118/* L o c a l F u n c t i o n s */
119/******************************************************************************/
120
121namespace
122{
123bool VerPgw(const char *buf, ssize_t off, size_t len, const uint32_t* csv,
124 XrdOfsHandle *oh, XrdOucErrInfo &error)
125{
126 EPNAME("VerPgw");
127 XrdOucPgrwUtils::dataInfo dInfo(buf, csv, off, len);
128 off_t badoff;
129 int badlen;
130
131// Verify incoming checksums
132//
133 if (!XrdOucPgrwUtils::csVer(dInfo, badoff, badlen))
134 {char eMsg[512];
135 int n;
136 n = snprintf(eMsg, sizeof(eMsg), "Checksum error at offset %lld.", (long long) badoff);
137 error.setErrInfo(EDOM, eMsg);
138 eMsg[n-1] = 0;
139 OfsEroute.Emsg(epname, eMsg, "aborted pgwrite to", oh->Name());
140 return false;
141 }
142 return true;
143}
144}
145
146/******************************************************************************/
147/* S t a t i c O b j e c t s */
148/******************************************************************************/
149
150XrdOfsHandle *XrdOfs::dummyHandle;
151
152int XrdOfs::MaxDelay = 60;
153int XrdOfs::OSSDelay = 30;
154
155/******************************************************************************/
156/* F i l e S y s t e m O b j e c t */
157/******************************************************************************/
158
159extern XrdOfs* XrdOfsFS;
160
161/******************************************************************************/
162/* S t o r a g e S y s t e m O b j e c t */
163/******************************************************************************/
164
166
167/******************************************************************************/
168/* X r d O f s C o n s t r u c t o r */
169/*****************************************************************************/
170
171XrdOfs::XrdOfs() : dMask{0000,0775}, fMask{0000,0775}, // Legacy
173{
174 const char *bp;
175
176// Establish defaults
177//
178 ofsConfig = 0;
179 FSctl_PC = 0;
180 FSctl_PI = 0;
181 Authorization = 0;
182 Finder = 0;
183 Balancer = 0;
184 evsObject = 0;
185 ossRPList = 0;
186 myRole = strdup("server");
187 OssIsProxy = 0;
188 ossRW =' ';
189 ossFeatures = 0;
190
191// Obtain port number we will be using. Note that the constructor must occur
192// after the port number is known (i.e., this cannot be a global static).
193//
194 myPort = (bp = getenv("XRDPORT")) ? strtol(bp, (char **)NULL, 10) : 0;
195
196// Defaults for POSC
197//
198 poscQ = 0;
199 poscLog = 0;
200 poscHold= 10*60;
201 poscAuto= 0;
202 poscSync= 1;
203
204// Set the configuration file name and dummy handle
205//
206 ConfigFN = 0;
207 XrdOfsHandle::Alloc(&dummyHandle);
208
209// Set checksum pointers
210//
211 CksRTCalc = 0;
212 CksRTName = 0;
213 Cks = 0;
214 CksPfn = true;
215 CksRdr = true;
216 CksRTCgi = 0;
217
218// Prepare handling
219//
220 prepHandler = 0;
221 prepAuth = true;
222
223// Eextended attribute limits
224//
225 usxMaxNsz = kXR_faMaxNlen;
226 usxMaxVsz = kXR_faMaxVlen;
227
228// Other options
229//
230 DirRdr = false;
231 reProxy = false;
232 OssHasPGrw= false;
233 tryXERT = false;
234}
235
236/******************************************************************************/
237/* */
238/* 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 */
239/* */
240/******************************************************************************/
241/******************************************************************************/
242/* o p e n */
243/******************************************************************************/
244
245int XrdOfsDirectory::open(const char *dir_path, // In
246 const XrdSecEntity *client, // In
247 const char *info) // In
248/*
249 Function: Open the directory `path' and prepare for reading.
250
251 Input: path - The fully qualified name of the directory to open.
252 client - Authentication credentials, if any.
253 info - Opaque information to be used as seen fit.
254
255 Output: Returns SFS_OK upon success, otherwise SFS_ERROR.
256
257 Notes: 1. The code here assumes that directory file descriptors are never
258 shared. Hence, no locks need to be obtained. It works out that
259 lock overhead is worse than have a duplicate file descriptor for
260 very short durations.
261*/
262{
263 EPNAME("opendir");
264 static const int od_mode = SFS_O_RDONLY|SFS_O_META;
265 XrdOucEnv Open_Env(info,0,client);
266 int retc;
267
268// Trace entry
269//
270 XTRACE(opendir, dir_path, "");
271
272// Verify that this object is not already associated with an open directory
273//
274 if (dp) return
275 XrdOfsFS->Emsg(epname, error, EADDRINUSE, "open directory", dir_path);
276
277// Apply security, as needed
278//
279 AUTHORIZE(client,&Open_Env,AOP_Readdir,"open directory",dir_path,error);
280
281// Find out where we should open this directory
282//
283 if (XrdOfsFS->DirRdr && XrdOfsFS->Finder && XrdOfsFS->Finder->isRemote()
284 && (retc = XrdOfsFS->Finder->Locate(error, dir_path, od_mode, &Open_Env)))
285 return XrdOfsFS->fsError(error, retc);
286
287// Open the directory and allocate a handle for it
288//
289 if (!(dp = XrdOfsOss->newDir(tident))) retc = -ENOMEM;
290 else if (!(retc = dp->Opendir(dir_path, Open_Env)))
291 {fname = strdup(dir_path);
292 return SFS_OK;
293 }
294
295// Handle extended error information
296//
297 std::string eText;
298 const char* etP = 0;
299 if (dp && XrdOfsFS->tryXERT)
300 {if (dp->getErrMsg(eText)) etP = eText.c_str();
301 delete dp; dp = 0;
302 }
303
304// Encountered an error
305//
306 return XrdOfsFS->Emsg(epname, error, retc, "open directory", dir_path, etP);
307}
308
309/******************************************************************************/
310/* n e x t E n t r y */
311/******************************************************************************/
312
314/*
315 Function: Read the next directory entry.
316
317 Input: n/a
318
319 Output: Upon success, returns the contents of the next directory entry as
320 a null terminated string. Returns a null pointer upon EOF or an
321 error. To differentiate the two cases, getErrorInfo will return
322 0 upon EOF and an actual error code (i.e., not 0) on error.
323
324 Notes: 1. The code here assumes that idle directory file descriptors are
325 *not* closed. This needs to be the case because we need to return
326 non-duplicate directory entries. Anyway, the xrootd readdir protocol
327 is handled internally so directories should never be idle.
328 2. The code here assumes that directory file descriptors are never
329 shared. Hence, no locks need to be obtained. It works out that
330 lock overhead is worse than have a duplicate file descriptor for
331 very short durations.
332*/
333{
334 EPNAME("readdir");
335 int retc;
336
337// Check if this directory is actually open
338//
339 if (!dp) {XrdOfsFS->Emsg(epname, error, EBADF, "read directory");
340 return 0;
341 }
342
343// Check if we are at EOF (once there we stay there)
344//
345 if (atEOF) return 0;
346
347// Read the next directory entry
348//
349 if ((retc = dp->Readdir(dname, sizeof(dname))) < 0)
350 {std::string eText;
351 const char* etP = 0;
352 if (XrdOfsFS->tryXERT && dp->getErrMsg(eText)) etP = eText.c_str();
353 XrdOfsFS->Emsg(epname, error, retc, "read directory", fname, etP);
354 return 0;
355 }
356
357// Check if we have reached end of file
358//
359 if (!*dname)
360 {atEOF = 1;
361 error.clear();
362 XTRACE(readdir, fname, "<eof>");
363 return 0;
364 }
365
366// Return the actual entry
367//
369 return (const char *)(dname);
370}
371
372/******************************************************************************/
373/* c l o s e */
374/******************************************************************************/
375
377/*
378 Function: Close the directory object.
379
380 Input: n/a
381
382 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
383
384 Notes: 1. The code here assumes that directory file descriptors are never
385 shared. Hence, no locks need to be obtained. It works out that
386 lock overhead is worse than have a duplicate file descriptor for
387 very short durations.
388*/
389{
390 EPNAME("closedir");
391 int retc;
392
393// Check if this directory is actually open
394//
395 if (!dp) {XrdOfsFS->Emsg(epname, error, EBADF, "close directory");
396 return SFS_ERROR;
397 }
398 XTRACE(closedir, fname, "");
399
400// Close this directory
401//
402 if ((retc = dp->Close()))
403 {std::string eText;
404 const char* etP = 0;
405 if (XrdOfsFS->tryXERT && dp->getErrMsg(eText)) etP = eText.c_str();
406 retc = XrdOfsFS->Emsg(epname, error, retc, "close", fname, etP);
407 } else retc = SFS_OK;
408
409// All done
410//
411 delete dp;
412 dp = 0;
413 free(fname);
414 fname = 0;
415 return retc;
416}
417
418/******************************************************************************/
419/* a u t o S t a t */
420/******************************************************************************/
421
423/*
424 Function: Set stat buffer to automaticaly return stat information
425
426 Input: Pointer to stat buffer which will be filled in on each
427 nextEntry() and represent stat information for that entry.
428
429 Output: Upon success, returns zero. Upon error returns SFS_ERROR and sets
430 the error object to contain the reason.
431
432 Notes: 1. If autoStat() is not supported he caller will need to follow up
433 with a manual stat() call for the full path, a slow and tedious
434 process. The autoStat function significantly reduces overhead by
435 automatically providing stat information for the entry read.
436*/
437{
438 EPNAME("autoStat");
439 int retc;
440
441// Check if this directory is actually open
442//
443 if (!dp) {XrdOfsFS->Emsg(epname, error, EBADF, "autostat directory");
444 return SFS_ERROR;
445 }
446
447// Set the stat buffer in the storage system directory but don't complain.
448//
449 if ((retc = dp->StatRet(buf))) return retc;
450 return SFS_OK;
451}
452
453/******************************************************************************/
454/* */
455/* F i l e O b j e c t I n t e r f a c e s */
456/* */
457/******************************************************************************/
458/******************************************************************************/
459/* X r d O f s F i l e C o n s t r u c t o r */
460/******************************************************************************/
461
462XrdOfsFile::XrdOfsFile(XrdOucErrInfo &eInfo, const char *user)
463 : XrdSfsFile(eInfo), tident(user ? user : ""),
464 oh(XrdOfs::dummyHandle), myTPC(0), myCKP(0),
465 dorawio(0), viaDel(false), ckpBad(false) {}
466
467/******************************************************************************/
468/* o p e n */
469/******************************************************************************/
470
471int XrdOfsFile::open(const char *path, // In
472 XrdSfsFileOpenMode open_mode, // In
473 mode_t Mode, // In
474 const XrdSecEntity *client, // In
475 const char *info) // In
476/*
477 Function: Open the file `path' in the mode indicated by `open_mode'.
478
479 Input: path - The fully qualified name of the file to open.
480 open_mode - One of the following flag values:
481 SFS_O_RDONLY - Open file for reading.
482 SFS_O_WRONLY - Open file for writing.
483 SFS_O_RDWR - Open file for update
484 SFS_O_NOTPC - Disallow TPC opens
485 SFS_O_REPLICA- Open file for replication
486 SFS_O_CREAT - Create the file open in RW mode
487 SFS_O_CREATAT- As above but with colocation.
488 SFS_O_TRUNC - Trunc the file open in RW mode
489 SFS_O_POSC - Presist file on successful close
490 SFS_O_SEQIO - Primarily sequential I/O (e.g. xrdcp)
491 Mode - The Posix access mode bits to be assigned to the file.
492 These bits correspond to the standard Unix permission
493 bits (e.g., 744 == "rwxr--r--"). Additionally, Mode
494 may contain SFS_O_MKPTH to force creation of the full
495 directory path if it does not exist. This parameter is
496 ignored unless open_mode = SFS_O_CREAT.
497 client - Authentication credentials, if any.
498 info - Opaque information to be used as seen fit.
499
500 Output: Returns SFS_OK upon success, otherwise SFS_ERROR is returned.
501*/
502{
503 EPNAME("open");
504 static const int crMask = (SFS_O_CREAT | SFS_O_TRUNC);
505 static const int opMask = (SFS_O_RDONLY | SFS_O_WRONLY | SFS_O_RDWR);
506
507 struct OpenHelper
508 {const char *Path;
509 XrdOfsHandle *hP;
510 XrdOssDF *fP;
511 XrdCksCalc *cP;
512 int poscNum;
513
514 int OK() {hP=0; fP=0; cP=0; poscNum=0; return SFS_OK;}
515
516 OpenHelper(const char *path)
517 : Path(path), hP(0), fP(0), cP(0), poscNum(0) {}
518
519 ~OpenHelper()
520 {int retc;
521 if (hP) hP->Retire(retc);
522 if (fP) delete fP;
523 if (cP) cP->Recycle();
524 if (poscNum > 0) XrdOfsFS->poscQ->Del(Path, poscNum, 1);
525 }
526 } oP(path);
527
528 mode_t theMode = (Mode | XrdOfsFS->fMask[0]) & XrdOfsFS->fMask[1];
529 const char *tpcKey;
530 int retc, isPosc = 0, crOpts = 0, isRW = 0, open_flag = 0;
531 int find_flag = open_mode & (SFS_O_NOWAIT | SFS_O_RESET | SFS_O_MULTIW);
532 XrdOucEnv Open_Env(info,0,client);
533
534// Trace entry
535//
536 ZTRACE(open, Xrd::hex1 <<open_mode <<"-" <<Xrd::oct1 <<Mode <<" ("
537 <<Xrd::oct1 <<theMode <<") fn=" <<path);
538
539// Verify that this object is not already associated with an open file
540//
541 XrdOfsFS->ocMutex.Lock();
542 if (oh != XrdOfs::dummyHandle)
543 {XrdOfsFS->ocMutex.UnLock();
544 return XrdOfsFS->Emsg(epname,error,EADDRINUSE,"open file",path);
545 }
546 XrdOfsFS->ocMutex.UnLock();
547
548// Handle the open mode options
549//
550 if (open_mode & crMask)
551 {crOpts = (Mode & SFS_O_MKPTH ? XRDOSS_mkpath : 0);
552 if (XrdOfsFS->poscQ && ((open_mode & SFS_O_POSC) ||
553 XrdOfsFS->poscAuto || Open_Env.Get("ofs.posc")))
554 {isPosc = 1; isRW = XrdOfsHandle::opPC;}
555 else isRW = XrdOfsHandle::opRW;
556 if (open_mode & SFS_O_CREAT)
557 {open_flag = O_RDWR | O_CREAT | O_EXCL;
558 find_flag |= SFS_O_RDWR | SFS_O_CREAT | (open_mode & SFS_O_REPLICA);
559 crOpts |= XRDOSS_new;
560 } else {
561 open_flag |= O_RDWR | O_CREAT | O_TRUNC;
562 find_flag |= SFS_O_RDWR | SFS_O_TRUNC;
563 }
564 if (XrdOfsFS->WantCksRT())
565 {const char* cipher = 0;
566 if ((retc = XrdOfsFS->SetupCksRT(oP.cP, Open_Env, cipher)))
567 {char eBuff[80];
568 snprintf(eBuff, sizeof(eBuff), "setup real-time %s checksum",
569 (cipher ? cipher : "unknown"));
570 return XrdOfsFS->Emsg(epname, error, retc, eBuff, path);
571 }
572 }
573 }
574 else
575 switch(open_mode & opMask)
576 {case SFS_O_RDONLY: open_flag = O_RDONLY; find_flag |= SFS_O_RDONLY;
577 break;
578 case SFS_O_WRONLY: open_flag = O_WRONLY; find_flag |= SFS_O_WRONLY;
579 isRW = XrdOfsHandle::opRW;
580 if (XrdOfsFS->poscQ && ((open_mode & SFS_O_POSC) ||
581 Open_Env.Get("ofs.posc"))) oP.poscNum = -1;
582 break;
583 case SFS_O_RDWR: open_flag = O_RDWR; find_flag |= SFS_O_RDWR;
584 isRW = XrdOfsHandle::opRW;
585 if (XrdOfsFS->poscQ && ((open_mode & SFS_O_POSC) ||
586 Open_Env.Get("ofs.posc"))) oP.poscNum = -1;
587 break;
588 default: open_flag = O_RDONLY; find_flag |= SFS_O_RDONLY;
589 break;
590 }
591
592// Preset TPC handling
593//
594 tpcKey = Open_Env.Get(XrdOucTPC::tpcKey);
595
596// Check if we will be redirecting the tpc request
597//
598 if (tpcKey && isRW && (XrdOfsFS->Options & XrdOfs::RdrTPC))
599 {const char *dOn = Open_Env.Get(XrdOucTPC::tpcDlgOn);
600 int k = ((dOn && *dOn == '1') || strcmp(tpcKey, "delegate") ? 1 : 0);
601 if (XrdOfsFS->tpcRdrHost[k])
602 {error.setErrInfo(XrdOfsFS->tpcRdrPort[k], XrdOfsFS->tpcRdrHost[k]);
603 return SFS_REDIRECT;
604 }
605 }
606
607// If we have a finder object, use it to direct the client. The final
608// destination will apply the security that is needed
609//
610 if (XrdOfsFS->Finder && (retc = XrdOfsFS->Finder->Locate(error, path,
611 find_flag, &Open_Env)))
612 return XrdOfsFS->fsError(error, retc);
613
614// Preset TPC handling and if not allowed, complain
615//
616 if (tpcKey && (open_mode & SFS_O_NOTPC))
617 return XrdOfsFS->Emsg(epname, error, EPROTOTYPE, "tpc", path,
618 "+TPC prohibited due to security configuration");
619
620// Create the file if so requested o/w try to attach the file
621//
622 if (open_flag & O_CREAT)
623 {// Apply security, as needed
624 //
625 // If we aren't requesting O_EXCL, one needs AOP_Create
626 bool overwrite_permitted = true;
627 if (!(open_flag & O_EXCL))
628 {if (client && XrdOfsFS->Authorization &&
629 !XrdOfsFS->Authorization->Access(client, path, AOP_Create, &Open_Env))
630 { // We don't have the ability to create a file without O_EXCL. If we have AOP_Excl_Create,
631 // then manipulate the open flags and see if we're successful with it.
632 AUTHORIZE(client,&Open_Env,AOP_Excl_Create,"create",path,error);
633 overwrite_permitted = false;
634 open_flag |= O_EXCL;
635 open_flag &= ~O_TRUNC;
636 }
637 }
638 // If we are in O_EXCL mode, then we accept either AOP_Excl_Create or AOP_Create
639 else if (client && XrdOfsFS->Authorization &&
640 !XrdOfsFS->Authorization->Access(client, path, AOP_Create, &Open_Env))
641 {AUTHORIZE(client,&Open_Env,AOP_Excl_Create,"create",path,error);
642 // In this case, we don't have AOP_Create but we do have AOP_Excl_Create; note that
643 // overwrites are not permitted (this is later used to correct an error code).
644 overwrite_permitted = false;
645 }
646
647 OOIDENTENV(client, Open_Env);
648
649 // For ephemeral file, we must enter the file into the queue
650 //
651 if (isPosc)
652 {bool isNew = (open_mode & SFS_O_TRUNC) == 0;
653 if ((oP.poscNum = XrdOfsFS->poscQ->Add(tident, path, isNew)) < 0)
654 return XrdOfsFS->Emsg(epname, error, oP.poscNum, "pcreate", path,
655 "+ofs_open: failed to enter file into posc queue");
656 }
657
658 // If placement information is present provide a hint to the oss plugin
659 //
660 if ((open_mode & ~SFS_O_CREAT) & SFS_O_CREATAT) crOpts |= XRDOSS_coloc;
661
662 // Create the file. If ENOTSUP is returned, promote the creation to
663 // the subsequent open. This is to accomodate proxy support.
664 //
665 if ((retc = XrdOfsOss->Create(tident, path, theMode, Open_Env,
666 ((open_flag << 8) | crOpts))))
667 {if (retc > 0) return XrdOfsFS->Stall(error, retc, path);
668 if (retc == -EINPROGRESS)
669 {XrdOfsFS->evrObject.Wait4Event(path,&error);
670 return XrdOfsFS->fsError(error, SFS_STARTED);
671 }
672 if (retc != -ENOTSUP)
673 {// If we tried to overwrite an existing file but do not have the AOP_Create
674 // privilege, then ensure we generate a 'permission denied' instead of 'exists'
675 if ((open_flag & O_EXCL) && retc == -EEXIST && !overwrite_permitted)
676 {retc = -EACCES;}
677 if (XrdOfsFS->Balancer) XrdOfsFS->Balancer->Removed(path);
678 return XrdOfsFS->Emsg(epname, error, retc, "create", path);
679 }
680 } else {
681 if (XrdOfsFS->Balancer) XrdOfsFS->Balancer->Added(path, isPosc);
682 open_flag = O_RDWR|O_TRUNC;
683 if (XrdOfsFS->evsObject
684 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Create))
685 {XrdOfsEvsInfo evInfo(tident,path,info,&Open_Env,Mode);
686 XrdOfsFS->evsObject->Notify(XrdOfsEvs::Create, evInfo);
687 }
688 }
689
690 } else {
691
692 // Apply security, as needed
693 //
694 if (tpcKey && !isRW)
695 {XrdOfsTPC::Facts Args(client, &error, &Open_Env, tpcKey, path);
696 if ((retc = XrdOfsTPC::Authorize(&myTPC, Args))) return retc;
697 } else {AUTHORIZE(client, &Open_Env, (isRW?AOP_Update:AOP_Read),
698 "open", path, error);
699 }
700 OOIDENTENV(client, Open_Env);
701 }
702
703// Get a handle for this file.
704//
705 if ((retc = XrdOfsHandle::Alloc(path, isRW, &oP.hP)))
706 {if (retc > 0) return XrdOfsFS->Stall(error, retc, path);
707 return XrdOfsFS->Emsg(epname, error, retc, "attach", path);
708 }
709
710// If this is a third party copy and we are the destination, then validate
711// specification at this point and setup to transfer. Note that if the
712// call fails and auto removal is enabled, the file we created will be deleted.
713//
714 if (tpcKey && isRW)
715 {char pfnbuff[MAXPATHLEN+8]; const char *pfnP;
716 if (!(pfnP = XrdOfsOss->Lfn2Pfn(path, pfnbuff, MAXPATHLEN, retc)))
717 return XrdOfsFS->Emsg(epname, error, retc, "open", path,
718 "+ofs_open: mapping tpc target lfn to pfn failed");
719 XrdOfsTPC::Facts Args(client, &error, &Open_Env, tpcKey, path, pfnP);
720 if ((retc = XrdOfsTPC::Validate(&myTPC, Args))) return retc;
721 }
722
723// Assign/transfer posc ownership. We may need to delay the client if the
724// file create ownership does not match and this is not a create request.
725//
726 if (oP.hP->isRW == XrdOfsHandle::opPC)
727 {if (!isRW) return XrdOfsFS->Stall(error, -1, path);
728 if ((retc = oP.hP->PoscSet(tident, oP.poscNum, theMode)))
729 {if (retc > 0) XrdOfsFS->poscQ->Del(path, retc);
730 else return XrdOfsFS->Emsg(epname, error, retc, "access", path,
731 "+ofs_open: posc mode initiation failed");
732 }
733 }
734
735// If this is a previously existing handle, we are almost done. If this is
736// the target of a third party copy request, fail it now. We don't support
737// multiple writers in tpc mode (this should really never happen).
738//
739 if (!(oP.hP->Inactive()))
740 {dorawio = (oh->isCompressed && open_mode & SFS_O_RAWIO ? 1 : 0);
741 if (tpcKey && isRW)
742 return XrdOfsFS->Emsg(epname, error, EALREADY, "tpc", path,
743 "+ofs_open: this tpc is already in progress");
744 XrdOfsFS->ocMutex.Lock(); oh = oP.hP; XrdOfsFS->ocMutex.UnLock();
745 FTRACE(open, "attach use=" <<oh->Usage());
746 if (oP.poscNum > 0) XrdOfsFS->poscQ->Commit(path, oP.poscNum);
747 oP.hP->UnLock();
748 OfsStats.sdMutex.Lock();
749 isRW ? OfsStats.Data.numOpenW++ : OfsStats.Data.numOpenR++;
750 if (oP.poscNum > 0) OfsStats.Data.numOpenP++;
751 OfsStats.sdMutex.UnLock();
752 return oP.OK();
753 }
754
755// Get a storage system object
756//
757 if (!(oP.fP = XrdOfsOss->newFile(tident)))
758 return XrdOfsFS->Emsg(epname, error, ENOMEM, "open", path);
759
760// We need to make special provisions for proxy servers in the presence of
761// the TPC option and possibly cache as it's handled differently in this case.
762//
763 if (XrdOfsFS->OssIsProxy)
764 {if (myTPC) open_flag |= O_NOFOLLOW;
765 if (error.getUCap() & XrdOucEI::uUrlOK &&
766 error.getUCap() & XrdOucEI::uLclF) open_flag |= O_DIRECT;
767 }
768
769// If we are doing real-time checksums, wrap the Oss file with a Cks file
770//
771 if (oP.cP)
772 {XrdOfsCksFile* cfP = new XrdOfsCksFile(tident,path,oP.fP,oP.cP,viaDel);
773 oP.fP = static_cast<XrdOssDF*>(cfP);
774 oP.cP = 0;
775 }
776
777// Open the file
778//
779 if ((retc = oP.fP->Open(path, open_flag, theMode, Open_Env)))
780 {if (retc > 0) return XrdOfsFS->Stall(error, retc, path);
781 if (retc == -EINPROGRESS)
782 {XrdOfsFS->evrObject.Wait4Event(path,&error);
783 return XrdOfsFS->fsError(error, SFS_STARTED);
784 }
785 if (retc == -ETXTBSY) return XrdOfsFS->Stall(error, -1, path);
786 if (retc == -EDESTADDRREQ)
787 {char *url = Open_Env.Get("FileURL");
788 if (url) {error.setErrInfo(-1, url); return SFS_REDIRECT;}
789 }
790 if (XrdOfsFS->Balancer && retc == -ENOENT)
791 XrdOfsFS->Balancer->Removed(path);
792 const char* etP = 0;
793 std::string eText;
794 if (XrdOfsFS->tryXERT && oP.fP->getErrMsg(eText)) etP = eText.c_str();
795 return XrdOfsFS->Emsg(epname, error, retc, "open", path, etP);
796 }
797
798// Verify that we can actually use this file
799//
800 if (oP.poscNum > 0)
801 {if ((retc = oP.fP->Fchmod(static_cast<mode_t>(theMode|XRDSFS_POSCPEND))))
802 return XrdOfsFS->Emsg(epname, error, retc, "fchmod", path,
803 "+ofs_open: POSC file designation failed");
804 XrdOfsFS->poscQ->Commit(path, oP.poscNum);
805 }
806
807// Set compression values and activate the handle
808//
809 if (oP.fP->isCompressed() > 0)
810 {oP.hP->isCompressed = 1;
811 dorawio = (open_mode & SFS_O_RAWIO ? 1 : 0);
812 }
813 oP.hP->Activate(oP.fP);
814 oP.hP->UnLock();
815
816// If this is being opened for sequential I/O advise the filesystem about it.
817//
818#if defined(__linux__) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
819 if (!(XrdOfsFS->OssIsProxy) && open_mode & SFS_O_SEQIO)
820 {static RAtomic_int fadFails(0);
821 int theFD = oP.fP->getFD();
822 if (theFD >= 0 && fadFails < 4096)
823 if (posix_fadvise(theFD, 0, 0, POSIX_FADV_SEQUENTIAL) < 0)
824 {OfsEroute.Emsg(epname, errno, "fadvise for sequential I/O.");
825 fadFails++;
826 }
827 }
828#endif
829
830// Send an open event if we must
831//
832 if (XrdOfsFS->evsObject)
834 if (XrdOfsFS->evsObject->Enabled(theEvent))
835 {XrdOfsEvsInfo evInfo(tident, path, info, &Open_Env);
836 XrdOfsFS->evsObject->Notify(theEvent, evInfo);
837 }
838 }
839
840// Maintain statistics
841//
842 OfsStats.sdMutex.Lock();
843 isRW ? OfsStats.Data.numOpenW++ : OfsStats.Data.numOpenR++;
844 if (oP.poscNum > 0) OfsStats.Data.numOpenP++;
845 OfsStats.sdMutex.UnLock();
846
847// All done
848//
849 XrdOfsFS->ocMutex.Lock(); oh = oP.hP; XrdOfsFS->ocMutex.UnLock();
850 return oP.OK();
851}
852
853/******************************************************************************/
854/* C l o n e */
855/******************************************************************************/
856/*
857 Function: Clone the file object from another file object.
858
859 Input: n/a
860
861 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
862*/
863
865{
866 EPNAME("Clone");
867 XrdOfsFile& ofsFile = static_cast<XrdOfsFile&>(srcFile);
868 int rc = oh->Select().Clone(ofsFile.oh->Select());
869
870 if (rc < 0)
871 {char etxt[4096];
872 snprintf(etxt,sizeof(etxt),"%s from %s",oh->Name(),ofsFile.oh->Name());
873 return XrdOfsFS->Emsg(epname, error, rc, "clone", etxt);
874 }
875
876 return SFS_OK;
877}
878
879/******************************************************************************/
880
881int XrdOfsFile::Clone(const std::vector<XrdOucCloneSeg> &cVec)
882{
883 EPNAME("Clone");
884 int rc = oh->Select().Clone(cVec);
885
886 if (rc < 0)
887 {char etxt[4096];
888 snprintf(etxt,sizeof(etxt),"%s from file ranges",oh->Name());
889 return XrdOfsFS->Emsg(epname, error, rc, "clone", etxt);
890 }
891
892 return SFS_OK;
893}
894
895/******************************************************************************/
896/* c l o s e */
897/******************************************************************************/
898
900/*
901 Function: Close the file object.
902
903 Input: n/a
904
905 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
906*/
907{
908 EPNAME("close");
909
910 class CloseFH : public XrdOfsHanCB
911 {public: void Retired(XrdOfsHandle *hP) {XrdOfsFS->Unpersist(hP);}};
912 static XrdOfsHanCB *hCB = static_cast<XrdOfsHanCB *>(new CloseFH);
913
914 XrdOfsHandle *hP;
915 int poscNum, retc, cRetc = 0;
916 short theMode;
917
918// Trace the call
919//
920 FTRACE(close, "use=" <<oh->Usage()); // Unreliable trace, no origin lock
921
922// Verify the handle (we briefly maintain a global lock)
923//
924 XrdOfsFS->ocMutex.Lock();
925 if (oh == XrdOfs::dummyHandle)
926 {XrdOfsFS->ocMutex.UnLock(); return SFS_OK;}
927 if ((oh->Inactive()))
928 {XrdOfsFS->ocMutex.UnLock();
929 return XrdOfsFS->Emsg(epname, error, EBADF, "close file");
930 }
931 hP = oh; oh = XrdOfs::dummyHandle;
932 XrdOfsFS->ocMutex.UnLock();
933 hP->Lock();
934
935// Delete the tpc object, if any
936//
937 if (myTPC) {myTPC->Del(); myTPC = 0;}
938
939// Maintain statistics
940//
941 OfsStats.sdMutex.Lock();
942 if (!(hP->isRW)) OfsStats.Data.numOpenR--;
943 else {OfsStats.Data.numOpenW--;
944 if (hP->isRW == XrdOfsHandle::opPC) OfsStats.Data.numOpenP--;
945 }
946 OfsStats.sdMutex.UnLock();
947
948// If this file was tagged as a POSC then we need to make sure it will persist
949// Note that we unpersist the file immediately when it's inactive or if no hold
950// time is allowed. Also, close events occur only for active handles. If the
951// entry was via delete then we ignore the close return code as there is no
952// one to handle it on the other side.
953//
954 if ((poscNum = hP->PoscGet(theMode, !viaDel)))
955 {if (viaDel)
956 {if (hP->Inactive() || !XrdOfsFS->poscHold)
957 {XrdOfsFS->Unpersist(hP, !hP->Inactive()); hP->Retire(cRetc);}
958 else hP->Retire(hCB, XrdOfsFS->poscHold);
959 return SFS_OK;
960 }
961 if ((retc = hP->Select().Fchmod(theMode)))
962 XrdOfsFS->Emsg(epname, error, retc, "fchmod", hP->Name());
963 else {XrdOfsFS->poscQ->Del(hP->Name(), poscNum);
964 if (XrdOfsFS->Balancer) XrdOfsFS->Balancer->Added(hP->Name());
965 }
966 }
967
968// Handle any oustanding checkpoint
969//
970 if (myCKP)
971 {retc = myCKP->Restore();
972 if (retc) XrdOfsFS->Emsg(epname,error,retc,"restore chkpnt",hP->Name());
973 myCKP->Finished();
974 myCKP = 0;
975 }
976
977// We need to handle the cunudrum that an event may have to be sent upon
978// the final close. However, that would cause the path name to be destroyed.
979// So, we have two modes of logic where we copy out the pathname if a final
980// close actually occurs. The path is not copied if it's not final and we
981// don't bother with any of it if we need not generate an event.
982//
983 if (XrdOfsFS->evsObject && tident
984 && XrdOfsFS->evsObject->Enabled(hP->isRW ? XrdOfsEvs::Closew
986 {long long FSize, *retsz;
987 char pathbuff[MAXPATHLEN+8];
988 XrdOfsEvs::Event theEvent;
989 if (hP->isRW) {theEvent = XrdOfsEvs::Closew; retsz = &FSize;}
990 else { theEvent = XrdOfsEvs::Closer; retsz = 0; FSize=0;}
991 if (!(hP->Retire(cRetc, retsz, pathbuff, sizeof(pathbuff))))
992 {XrdOfsEvsInfo evInfo(tident, pathbuff, "" , 0, 0, FSize);
993 XrdOfsFS->evsObject->Notify(theEvent, evInfo);
994 }
995 } else hP->Retire(cRetc);
996
997// All done
998//
999 return (cRetc ? XrdOfsFS->Emsg(epname, error, cRetc, "close file") : SFS_OK);
1000}
1001
1002/******************************************************************************/
1003/* c h e c k p o i n t */
1004/******************************************************************************/
1005
1006int XrdOfsFile::checkpoint(XrdSfsFile::cpAct act, struct iov *range, int n)
1007{
1008 EPNAME("chkpnt");
1009 const char *ckpName;
1010 int rc;
1011 bool readok;
1012
1013// Make sure we are active
1014//
1015 if (oh->Inactive()) return XrdOfsFS->Emsg(epname, error, EBADF,
1016 "handle checkpoint", (const char *)0);
1017
1018// If checkpointing is disabled, the don't accept this request.
1019//
1020 if (!XrdOfsConfigCP::Enabled) return XrdOfsFS->Emsg(epname, error, ENOTSUP,
1021 "handle disabled checkpoint", (const char *)0);
1022
1023// If this checkpoint is bad then only a delete, query or restore is allowed.
1024//
1025 if (ckpBad && (act == XrdSfsFile::cpTrunc || act == XrdSfsFile::cpWrite))
1026 return XrdOfsFS->Emsg(epname, error, EIDRM, "extend checkpoint "
1027 "(only delete or restore possible) for", oh->Name());
1028
1029// Handle the request
1030//
1031 switch(act)
1033 ckpName = "create checkpoint for";
1034 if ((rc = CreateCKP())) return rc;
1035 if ((rc = myCKP->Create())) {myCKP->Finished(); myCKP = 0;}
1036 break;
1038 ckpName = "delete checkpoint for";
1039 if (!myCKP) rc = ENOENT;
1040 else {rc = myCKP->Delete();
1041 myCKP->Finished();
1042 myCKP = 0;
1043 ckpBad = false;
1044 }
1045 break;
1047 ckpName = "query checkpoint for";
1048 if (!range || n <= 0)
1049 return XrdOfsFS->Emsg(epname, error, EINVAL,
1050 "query checkpoint limits for", oh->Name());
1051 rc = (myCKP ? myCKP->Query(*range) : ENOENT);
1052 break;
1054 ckpName = "restore checkpoint for";
1055 if (!myCKP) rc = ENOENT;
1056 else {if (!(rc = myCKP->Restore(&readok)))
1057 {myCKP->Finished();
1058 myCKP = 0;
1059 ckpBad = false;
1060 } else {
1061 if (!(oh->Select().DFType() & XrdOssDF::DF_isProxy))
1062 oh->Suppress((readok ? 0 : -EDOM));
1063 ckpBad = true;
1064 }
1065 }
1066 break;
1068 ckpName = "checkpoint truncate";
1069 if (!range) rc = EINVAL;
1070 else if (!myCKP) rc = ENOENT;
1071 else if ((rc = myCKP->Truncate(range))) ckpBad = true;
1072 break;
1074 ckpName = "checkpoint write";
1075 if (!range || n <= 0) rc = EINVAL;
1076 else if (!myCKP) rc = ENOENT;
1077 else if ((rc = myCKP->Write(range, n))) ckpBad = true;
1078 break;
1079
1080 default: return XrdOfsFS->Emsg(epname, error, EINVAL,
1081 "decode checkpoint request for", oh->Name());
1082 };
1083
1084// Complete as needed
1085//
1086 if (rc) return XrdOfsFS->Emsg(epname, error, rc, ckpName, oh->Name());
1087
1088// Trace success and return
1089//
1090 FTRACE(chkpnt, ckpName);
1091 return SFS_OK;
1092}
1093
1094/******************************************************************************/
1095/* Private: C r e a t e C K P */
1096/******************************************************************************/
1097
1098int XrdOfsFile::CreateCKP()
1099{
1100
1101// Verify that a checkpoint does not exist
1102//
1103 if (myCKP) return XrdOfsFS->Emsg("CreateCKP", error, EEXIST,
1104 "create checkpoint for", oh->Name());
1105
1106// Verify that this file is open r/w mode
1107//
1108 if (!(oh->isRW)) return XrdOfsFS->Emsg("CreateCKP", error, ENOTTY,
1109 "create checkpoint for R/O", oh->Name(),
1110 "+ofs_CreateCKP: file is not open in r/w mode");
1111
1112// POSC and checkpoints are mutally exclusive
1113//
1114 if (oh->isRW == XrdOfsHandle::opPC)
1115 return XrdOfsFS->Emsg("CreateCKP", error, ENOTTY,
1116 "create checkpoint for POSC file", oh->Name(),
1117 "+ofs_CreateCKP: POSC file cannot be checkpointed");
1118
1119// Get a new checkpoint object
1120//
1121 if (XrdOfsFS->OssIsProxy)
1122 {char *resp;
1123 int rc = oh->Select().Fctl(XrdOssDF::Fctl_ckpObj, 0, 0, &resp);
1124 if (rc) return XrdOfsFS->Emsg("CreateCKP", error, rc,
1125 "create proxy checkpoint");
1126 myCKP = (XrdOucChkPnt *)resp;
1127 } else myCKP = new XrdOfsChkPnt(oh->Select(), oh->Name());
1128
1129// All done
1130//
1131 return 0;
1132}
1133
1134/******************************************************************************/
1135/* f c t l */
1136/******************************************************************************/
1137
1138int XrdOfsFile::fctl(const int cmd,
1139 const char *args,
1140 XrdOucErrInfo &out_error)
1141{
1142// See if we can do this
1143//
1144 if (cmd == SFS_FCTL_GETFD)
1145 {out_error.setErrCode(oh->Select().getFD());
1146 return SFS_OK;
1147 }
1148
1149// We don't support this
1150//
1151 out_error.setErrInfo(ENOTSUP, "fctl operation not supported");
1152
1153// Return
1154//
1155 return SFS_ERROR;
1156}
1157
1158/******************************************************************************/
1159
1160int XrdOfsFile::fctl(const int cmd, int alen, const char *args,
1161 const XrdSecEntity *client)
1162{ // 12345678901234
1163 EPNAME("fctl");
1164 static const char *fctlArg = "ofs.tpc cancel";
1165 static const int fctlAsz = 15;
1166
1167// For QFINFO we simply pass it to the Oss layer
1168//
1169 if (cmd == SFS_FCTL_QFINFO)
1170 {char* resp = 0;;
1171 int rc = oh->Select().Fctl(XrdOssDF::Fctl_QFinfo, alen, args, &resp);
1172 if (rc < 0)
1173 {if (resp) delete[] resp;
1174 return XrdOfsFS->Emsg(epname,error,rc,"fctl",oh,false,false);
1175 }
1176 if (resp)
1177 {if ((rc = strlen(resp)))
1178 {error.setErrInfo(rc, resp);
1179 delete[] resp;
1180 return SFS_DATA;
1181 }
1182 delete[] resp;
1183 }
1184 return SFS_OK;
1185 }
1186
1187// See if the is a tpc cancellation (the only thing we support here)
1188//
1189 if (cmd != SFS_FCTL_SPEC1 || !args || alen < fctlAsz || strcmp(fctlArg,args))
1190 return XrdOfsFS->FSctl(*this, cmd, alen, args, client);
1191
1192// Check if we have a tpc operation in progress
1193//
1194 if (!myTPC)
1195 {error.setErrInfo(ESRCH, "tpc operation not found");
1196 return SFS_ERROR;
1197 }
1198
1199// Cancel the tpc
1200//
1201 myTPC->Del();
1202 myTPC = 0;
1203 return SFS_OK;
1204}
1205
1206/******************************************************************************/
1207/* p g R e a d */
1208/******************************************************************************/
1209
1211 char *buffer,
1212 XrdSfsXferSize rdlen,
1213 uint32_t *csvec,
1214 uint64_t opts)
1215{
1216 EPNAME("pgRead");
1217 XrdSfsXferSize nbytes;
1218 uint64_t pgOpts;
1219
1220// If the oss plugin does not support pgRead and we doing rawio then simulate
1221// the pgread. As this is relatively common we skip the vtable. This means
1222// this class cannot be a inherited to override the read() method.
1223//
1224 if (!XrdOfsFS->OssHasPGrw || dorawio)
1225 {if ((nbytes = XrdOfsFile::read(offset, buffer, rdlen)) > 0)
1226 XrdOucPgrwUtils::csCalc(buffer, offset, nbytes, csvec);
1227 return nbytes;
1228 }
1229
1230// Perform required tracing
1231//
1232 FTRACE(read, rdlen <<"@" <<offset);
1233
1234// Make sure the offset is not too large
1235//
1236#if _FILE_OFFSET_BITS!=64
1237 if (offset > 0x000000007fffffff)
1238 return XrdOfsFS->Emsg(epname, error, EFBIG, "pgRead", oh->Name());
1239#endif
1240
1241// Pass through any flags of interest
1242//
1244 else pgOpts = 0;
1245
1246// Now read the actual number of bytes
1247//
1248 nbytes = (XrdSfsXferSize)(oh->Select().pgRead((void *)buffer,
1249 (off_t)offset, (size_t)rdlen, csvec, pgOpts));
1250 if (nbytes < 0)
1251 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"pgRead",oh,false,false);
1252
1253// Return number of bytes read
1254//
1255 return nbytes;
1256}
1257
1258/******************************************************************************/
1259
1261{
1262 EPNAME("aiopgread");
1263 uint64_t pgOpts;
1264 int rc;
1265
1266// If the oss plugin does not support pgRead or if we are doing rawio or the
1267// file is compressed then revert to using a standard async read. Note that
1268// the standard async read will generate checksums if a vector is present.
1269// Note: we set cksVec in the request to nil to indicate simulation!
1270//
1271 if (!XrdOfsFS->OssHasPGrw || dorawio || oh->isCompressed)
1272 {aioparm->cksVec = 0;
1273 return XrdOfsFile::read(aioparm);
1274 }
1275
1276// Perform required tracing
1277//
1278 FTRACE(aio, aioparm->sfsAio.aio_nbytes <<"@" <<aioparm->sfsAio.aio_offset);
1279
1280// Make sure the offset is not too large
1281//
1282#if _FILE_OFFSET_BITS!=64
1283 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1284 return XrdOfsFS->Emsg(epname,error,-EFBIG,"pgRead",oh->Name(),0,false);
1285#endif
1286
1287// Pass through any flags of interest
1288//
1290 else pgOpts = 0;
1291
1292// Issue the read. Only true errors are returned here.
1293//
1294 if ((rc = oh->Select().pgRead(aioparm, pgOpts)) < 0)
1295 return XrdOfsFS->Emsg(epname, error, rc, "pgRead", oh, false, false);
1296
1297// All done
1298//
1299 return SFS_OK;
1300}
1301
1302/******************************************************************************/
1303/* p g W r i t e */
1304/******************************************************************************/
1305
1307 char *buffer,
1308 XrdSfsXferSize wrlen,
1309 uint32_t *csvec,
1310 uint64_t opts)
1311{
1312 EPNAME("pgWrite");
1313 XrdSfsXferSize nbytes;
1314 uint64_t pgOpts;
1315
1316// If the oss plugin does not support pgWrite revert to using a standard write.
1317//
1318 if (!XrdOfsFS->OssHasPGrw)
1319 {if ((opts & XrdSfsFile::Verify)
1320 && !VerPgw(buffer, offset, wrlen, csvec, oh, error)) return SFS_ERROR;
1321 return XrdOfsFile::write(offset, buffer, wrlen);
1322 }
1323
1324// Perform any required tracing
1325//
1326 FTRACE(write, wrlen <<"@" <<offset);
1327
1328// Make sure the offset is not too large
1329//
1330#if _FILE_OFFSET_BITS!=64
1331 if (offset > 0x000000007fffffff)
1332 return XrdOfsFS->Emsg(epname, error, -EFBIG, "pgwrite", oh, true, false);
1333#endif
1334
1335// Silly Castor stuff
1336//
1337 if (XrdOfsFS->evsObject && !(oh->isChanged)
1338 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1339
1340// Pass through any flags of interest
1341//
1343 else pgOpts = 0;
1344
1345// Write the requested bytes
1346//
1347 oh->isPending = 1;
1348 nbytes = (XrdSfsXferSize)(oh->Select().pgWrite((void *)buffer,
1349 (off_t)offset, (size_t)wrlen, csvec, pgOpts));
1350 if (nbytes < 0)
1351 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"pgwrite",oh,true,false);
1352
1353// Return number of bytes written
1354//
1355 return nbytes;
1356}
1357
1358/******************************************************************************/
1359
1361{
1362 EPNAME("aiopgWrite");
1363 uint64_t pgOpts;
1364 int rc;
1365
1366// If the oss plugin does not support pgWrite revert to using a standard write.
1367//
1368 if (!XrdOfsFS->OssHasPGrw)
1369 {if ((opts & XrdSfsFile::Verify)
1370 && !VerPgw((char *)aioparm->sfsAio.aio_buf,
1371 aioparm->sfsAio.aio_offset,
1372 aioparm->sfsAio.aio_nbytes,
1373 aioparm->cksVec, oh, error)) return SFS_ERROR;
1374 return XrdOfsFile::write(aioparm);
1375 }
1376
1377// If this is a POSC file, we must convert the async call to a sync call as we
1378// must trap any errors that unpersist the file. We can't do that via aio i/f.
1379//
1380 if (oh->isRW == XrdOfsHandle::opPC)
1381 {aioparm->Result = XrdOfsFile::pgWrite(aioparm->sfsAio.aio_offset,
1382 (char *)aioparm->sfsAio.aio_buf,
1383 aioparm->sfsAio.aio_nbytes,
1384 aioparm->cksVec, opts);
1385 aioparm->doneWrite();
1386 return SFS_OK;
1387 }
1388
1389// Perform any required tracing
1390//
1391 FTRACE(aio, aioparm->sfsAio.aio_nbytes <<"@" <<aioparm->sfsAio.aio_offset);
1392
1393// Make sure the offset is not too large
1394//
1395#if _FILE_OFFSET_BITS!=64
1396 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1397 return XrdOfsFS->Emsg(epname, error, -EFBIG, "pgwrite", oh, true, false);
1398#endif
1399
1400// Silly Castor stuff
1401//
1402 if (XrdOfsFS->evsObject && !(oh->isChanged)
1403 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1404
1405// Pass through any flags of interest
1406//
1408 else pgOpts = 0;
1409
1410// Write the requested bytes
1411//
1412 oh->isPending = 1;
1413 if ((rc = oh->Select().pgWrite(aioparm, pgOpts)) < 0)
1414 return XrdOfsFS->Emsg(epname, error, rc, "pgwrite", oh, true, false);
1415
1416// All done
1417//
1418 return SFS_OK;
1419}
1420
1421/******************************************************************************/
1422/* r e a d */
1423/******************************************************************************/
1424
1426 XrdSfsXferSize blen) // In
1427/*
1428 Function: Preread `blen' bytes at `offset'
1429
1430 Input: offset - The absolute byte offset at which to start the read.
1431 blen - The amount to preread.
1432
1433 Output: Returns SFS_OK upon success and SFS_ERROR o/w.
1434*/
1435{
1436 EPNAME("read");
1437 int retc;
1438
1439// Perform required tracing
1440//
1441 FTRACE(read, "preread " <<blen <<"@" <<offset);
1442
1443// Make sure the offset is not too large
1444//
1445#if _FILE_OFFSET_BITS!=64
1446 if (offset > 0x000000007fffffff)
1447 return XrdOfsFS->Emsg(epname,error,-EFBIG,"read",oh->Name(),0,false);
1448#endif
1449
1450// Now preread the actual number of bytes
1451//
1452 if ((retc = oh->Select().Read((off_t)offset, (size_t)blen)) < 0)
1453 return XrdOfsFS->Emsg(epname, error, (int)retc, "preread", oh, 0, false);
1454
1455// Return number of bytes read
1456//
1457 return retc;
1458}
1459
1460/******************************************************************************/
1461/* r e a d */
1462/******************************************************************************/
1463
1465 char *buff, // Out
1466 XrdSfsXferSize blen) // In
1467/*
1468 Function: Read `blen' bytes at `offset' into 'buff' and return the actual
1469 number of bytes read.
1470
1471 Input: offset - The absolute byte offset at which to start the read.
1472 buff - Address of the buffer in which to place the data.
1473 blen - The size of the buffer. This is the maximum number
1474 of bytes that will be read from 'fd'.
1475
1476 Output: Returns the number of bytes read upon success and SFS_ERROR o/w.
1477*/
1478{
1479 EPNAME("read");
1480 XrdSfsXferSize nbytes;
1481
1482// Perform required tracing
1483//
1484 FTRACE(read, blen <<"@" <<offset);
1485
1486// Make sure the offset is not too large
1487//
1488#if _FILE_OFFSET_BITS!=64
1489 if (offset > 0x000000007fffffff)
1490 return XrdOfsFS->Emsg(epname,error,-EFBIG,"read",oh->Name(),0,false);
1491#endif
1492
1493// Now read the actual number of bytes
1494//
1495 nbytes = (dorawio ?
1496 (XrdSfsXferSize)(oh->Select().ReadRaw((void *)buff,
1497 (off_t)offset, (size_t)blen))
1498 : (XrdSfsXferSize)(oh->Select().Read((void *)buff,
1499 (off_t)offset, (size_t)blen)));
1500 if (nbytes < 0)
1501 return XrdOfsFS->Emsg(epname, error, (int)nbytes, "read", oh, 0, false);
1502
1503// Return number of bytes read
1504//
1505 return nbytes;
1506}
1507
1508/******************************************************************************/
1509/* r e a d v */
1510/******************************************************************************/
1511
1513 int readCount) // In
1514/*
1515 Function: Perform all the reads specified in the readV vector.
1516
1517 Input: readV - A description of the reads to perform; includes the
1518 absolute offset, the size of the read, and the buffer
1519 to place the data into.
1520 readCount - The size of the readV vector.
1521
1522 Output: Returns the number of bytes read upon success and SFS_ERROR o/w.
1523 If the number of bytes read is less than requested, it is considered
1524 an error.
1525*/
1526{
1527 EPNAME("readv");
1528
1529 XrdSfsXferSize nbytes = oh->Select().ReadV(readV, readCount);
1530 if (nbytes < 0)
1531 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"readv",oh,false,false);
1532
1533 return nbytes;
1534
1535}
1536
1537/******************************************************************************/
1538/* r e a d A I O */
1539/******************************************************************************/
1540
1541/*
1542 Function: Read `blen' bytes at `offset' into 'buff' and return the actual
1543 number of bytes read using asynchronous I/O, if possible.
1544
1545 Output: Returns the 0 if successfullt queued, otherwise returns an error.
1546 The underlying implementation will convert the request to
1547 synchronous I/O is async mode is not possible.
1548*/
1549
1551{
1552 EPNAME("aioread");
1553 int rc;
1554
1555// Async mode for compressed files is not supported.
1556//
1557 if (oh->isCompressed)
1558 {aiop->Result = this->read((XrdSfsFileOffset)aiop->sfsAio.aio_offset,
1559 (char *)aiop->sfsAio.aio_buf,
1561 aiop->doneRead();
1562 return 0;
1563 }
1564
1565// Perform required tracing
1566//
1567 FTRACE(aio, aiop->sfsAio.aio_nbytes <<"@" <<aiop->sfsAio.aio_offset);
1568
1569// Make sure the offset is not too large
1570//
1571#if _FILE_OFFSET_BITS!=64
1572 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1573 return XrdOfsFS->Emsg(epname,error,-EFBIG,"read",oh->Name(),0,false);
1574#endif
1575
1576// Issue the read. Only true errors are returned here.
1577//
1578 if ((rc = oh->Select().Read(aiop)) < 0)
1579 return XrdOfsFS->Emsg(epname, error, rc, "read", oh, false, false);
1580
1581// All done
1582//
1583 return SFS_OK;
1584}
1585
1586/******************************************************************************/
1587/* w r i t e */
1588/******************************************************************************/
1589
1591 const char *buff, // Out
1592 XrdSfsXferSize blen) // In
1593/*
1594 Function: Write `blen' bytes at `offset' from 'buff' and return the actual
1595 number of bytes written.
1596
1597 Input: offset - The absolute byte offset at which to start the write.
1598 buff - Address of the buffer from which to get the data.
1599 blen - The size of the buffer. This is the maximum number
1600 of bytes that will be written to 'fd'.
1601
1602 Output: Returns the number of bytes written upon success and SFS_ERROR o/w.
1603
1604 Notes: An error return may be delayed until the next write(), close(), or
1605 sync() call.
1606*/
1607{
1608 EPNAME("write");
1609 XrdSfsXferSize nbytes;
1610
1611// Perform any required tracing
1612//
1613 FTRACE(write, blen <<"@" <<offset);
1614
1615// Make sure the offset is not too large
1616//
1617#if _FILE_OFFSET_BITS!=64
1618 if (offset > 0x000000007fffffff)
1619 return XrdOfsFS->Emsg(epname,error,-EFBIG,"write",oh,true,false);
1620#endif
1621
1622// Silly Castor stuff
1623//
1624 if (XrdOfsFS->evsObject && !(oh->isChanged)
1625 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1626
1627// Write the requested bytes
1628//
1629 oh->isPending = 1;
1630 nbytes = (XrdSfsXferSize)(oh->Select().Write((const void *)buff,
1631 (off_t)offset, (size_t)blen));
1632 if (nbytes < 0)
1633 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"write",oh,true,false);
1634
1635// Return number of bytes written
1636//
1637 return nbytes;
1638}
1639
1640/******************************************************************************/
1641/* w r i t e A I O */
1642/******************************************************************************/
1643
1644// For now, this reverts to synchronous I/O
1645//
1647{
1648 EPNAME("aiowrite");
1649 int rc;
1650
1651// Perform any required tracing
1652//
1653 FTRACE(aio, aiop->sfsAio.aio_nbytes <<"@" <<aiop->sfsAio.aio_offset);
1654
1655// If this is a POSC file, we must convert the async call to a sync call as we
1656// must trap any errors that unpersist the file. We can't do that via aio i/f.
1657//
1658 if (oh->isRW == XrdOfsHandle::opPC)
1659 {aiop->Result = this->write(aiop->sfsAio.aio_offset,
1660 (const char *)aiop->sfsAio.aio_buf,
1661 aiop->sfsAio.aio_nbytes);
1662 aiop->doneWrite();
1663 return 0;
1664 }
1665
1666// Make sure the offset is not too large
1667//
1668#if _FILE_OFFSET_BITS!=64
1669 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1670 return XrdOfsFS->Emsg(epname, error, -EFBIG, "write", oh, true, false);
1671#endif
1672
1673// Silly Castor stuff
1674//
1675 if (XrdOfsFS->evsObject && !(oh->isChanged)
1676 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1677
1678// Write the requested bytes
1679//
1680 oh->isPending = 1;
1681 if ((rc = oh->Select().Write(aiop)) < 0)
1682 return XrdOfsFS->Emsg(epname, error, rc, "write", oh, true, false);
1683
1684// All done
1685//
1686 return SFS_OK;
1687}
1688
1689/******************************************************************************/
1690/* g e t M m a p */
1691/******************************************************************************/
1692
1693int XrdOfsFile::getMmap(void **Addr, off_t &Size) // Out
1694/*
1695 Function: Return memory mapping for file, if any.
1696
1697 Output: Addr - Address of memory location
1698 Size - Size of the file or zero if not memory mapped.
1699 Returns SFS_OK upon success and SFS_ERROR upon failure.
1700*/
1701{
1702
1703// Perform the function
1704//
1705 Size = oh->Select().getMmap(Addr);
1706
1707 return SFS_OK;
1708}
1709
1710/******************************************************************************/
1711/* s t a t */
1712/******************************************************************************/
1713
1714int XrdOfsFile::stat(struct stat *buf) // Out
1715/*
1716 Function: Return file status information
1717
1718 Input: buf - The stat structiure to hold the results
1719
1720 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1721*/
1722{
1723 EPNAME("fstat");
1724 int retc;
1725
1726// Perform any required tracing
1727//
1728 FTRACE(stat, "");
1729
1730// Perform the function
1731//
1732 if ((retc = oh->Select().Fstat(buf)) < 0)
1733 return XrdOfsFS->Emsg(epname,error,retc,"get state for",oh);
1734
1735 return SFS_OK;
1736}
1737
1738/******************************************************************************/
1739/* s y n c */
1740/******************************************************************************/
1741
1743/*
1744 Function: Commit all unwritten bytes to physical media.
1745
1746 Input: n/a
1747
1748 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1749*/
1750{
1751 EPNAME("sync");
1752 int retc;
1753
1754// Perform any required tracing
1755//
1756 FTRACE(sync, "");
1757
1758// If we have a tpc object hanging about, we need to dispatch that first
1759//
1760 if (myTPC && (retc = myTPC->Sync(&error))) return retc;
1761
1762// We can test the pendio flag w/o a lock because the person doing this
1763// sync must have done the previous write. Causality is the synchronizer.
1764//
1765 if (!(oh->isPending)) return SFS_OK;
1766
1767// We can also skip the sync if the file is closed. However, we need a file
1768// object lock in order to test the flag. We can also reset the PENDIO flag.
1769//
1770 oh->Lock();
1771 oh->isPending = 0;
1772 oh->UnLock();
1773
1774// Perform the function
1775//
1776 if ((retc = oh->Select().Fsync()))
1777 {oh->isPending = 1;
1778 return XrdOfsFS->Emsg(epname, error, retc, "synchronize", oh, true);
1779 }
1780
1781// Indicate all went well
1782//
1783 return SFS_OK;
1784}
1785
1786/******************************************************************************/
1787/* s y n c A I O */
1788/******************************************************************************/
1789
1790// For now, reverts to synchronous case. This must also be the case for POSC!
1791//
1793{
1794 aiop->Result = this->sync();
1795 aiop->doneWrite();
1796 return 0;
1797}
1798
1799/******************************************************************************/
1800/* t r u n c a t e */
1801/******************************************************************************/
1802
1804/*
1805 Function: Set the length of the file object to 'flen' bytes.
1806
1807 Input: flen - The new size of the file.
1808
1809 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1810
1811 Notes: If 'flen' is smaller than the current size of the file, the file
1812 is made smaller and the data past 'flen' is discarded. If 'flen'
1813 is larger than the current size of the file, a hole is created
1814 (i.e., the file is logically extended by filling the extra bytes
1815 with zeroes).
1816*/
1817{
1818 EPNAME("trunc");
1819 int retc;
1820
1821// Lock the file handle and perform any tracing
1822//
1823 FTRACE(truncate, "len=" <<flen);
1824
1825// Make sure the offset is not too large
1826//
1827 if (sizeof(off_t) < sizeof(flen) && flen > 0x000000007fffffff)
1828 return XrdOfsFS->Emsg(epname, error, EFBIG, "truncate", oh, true);
1829
1830// Silly Castor stuff
1831//
1832 if (XrdOfsFS->evsObject && !(oh->isChanged)
1833 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1834
1835// Perform the function
1836//
1837 oh->isPending = 1;
1838 if ((retc = oh->Select().Ftruncate(flen)))
1839 return XrdOfsFS->Emsg(epname, error, retc, "truncate", oh, true);
1840
1841// Indicate Success
1842//
1843 return SFS_OK;
1844}
1845
1846/******************************************************************************/
1847/* g e t C X i n f o */
1848/******************************************************************************/
1849
1850int XrdOfsFile::getCXinfo(char cxtype[4], int &cxrsz)
1851/*
1852 Function: Set the length of the file object to 'flen' bytes.
1853
1854 Input: n/a
1855
1856 Output: cxtype - Compression algorithm code
1857 cxrsz - Compression region size
1858
1859 Returns SFS_OK upon success and SFS_ERROR upon failure.
1860*/
1861{
1862
1863// Copy out the info
1864//
1865 cxrsz = oh->Select().isCompressed(cxtype);
1866 return SFS_OK;
1867}
1868
1869/******************************************************************************/
1870/* P r i v a t e F i l e M e t h o d s */
1871/******************************************************************************/
1872/******************************************************************************/
1873/* protected G e n F W E v e n t */
1874/******************************************************************************/
1875
1876void XrdOfsFile::GenFWEvent()
1877{
1878 int first_write;
1879
1880// This silly code is to generate a 1st write event which slows things down
1881// but is needed by the one and only Castor. What a big sigh!
1882//
1883 oh->Lock();
1884 if ((first_write = !(oh->isChanged))) oh->isChanged = 1;
1885 oh->UnLock();
1886 if (first_write)
1887 {XrdOfsEvsInfo evInfo(tident, oh->Name());
1888 XrdOfsFS->evsObject->Notify(XrdOfsEvs::Fwrite, evInfo);
1889 }
1890}
1891
1892/******************************************************************************/
1893/* */
1894/* 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 */
1895/* */
1896/******************************************************************************/
1897/******************************************************************************/
1898/* c h k s u m */
1899/******************************************************************************/
1900
1901int XrdOfs::chksum( csFunc Func, // In
1902 const char *csName, // In
1903 const char *Path, // In
1904 XrdOucErrInfo &einfo, // Out
1905 const XrdSecEntity *client, // In
1906 const char *opaque) // In
1907/*
1908 Function: Compute and return file checksum.
1909
1910 Input: Func - Function to be performed:
1911 csCalc - Return precomputed or computed checksum.
1912 csGet - Return precomputed checksum.
1913 csSize - Verify csName and get its size.
1914 Path - Pathname of file for csCalc and csSize.
1915 einfo - Error information object to hold error details.
1916 client - Authentication credentials, if any.
1917 opaque - Opaque information to be used as seen fit.
1918
1919 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1920*/
1921{
1922 EPNAME("chksum");
1923 XrdOucEnv cksEnv(opaque,0,client);
1924 XrdCksData cksData;
1925 const char *tident = einfo.getErrUser();
1926 char buff[MAXPATHLEN+8];
1927 int rc;
1928
1929// Check if we support checksumming
1930//
1931 if (!Cks)
1932 {einfo.setErrInfo(ENOTSUP, "Checksums are not supported.");
1933 return SFS_ERROR;
1934 }
1935
1936// A csSize request is issued usually once to verify everything is working. We
1937// take this opportunity to also verify the checksum name.
1938//
1939 rc = cksData.Set(csName);
1940 if (!rc || Func == XrdSfsFileSystem::csSize)
1941 {if (rc && (rc = Cks->Size(csName)))
1942 {einfo.setErrCode(rc); return SFS_OK;}
1943 strcpy(buff, csName); strcat(buff, " checksum not supported.");
1944 einfo.setErrInfo(ENOTSUP, buff);
1945 return SFS_ERROR;
1946 }
1947
1948// Everything else requires a path
1949//
1950 if (!Path)
1951 {strcpy(buff, csName);
1952 strcat(buff, " checksum path not specified.");
1953 einfo.setErrInfo(EINVAL, buff);
1954 return SFS_ERROR;
1955 }
1956
1957// Apply security, as needed
1958//
1959 XTRACE(stat, Path, csName);
1960 AUTHORIZE(client,&cksEnv,AOP_Stat,"checksum",Path,einfo);
1961
1962// If we are a menager then we need to redirect the client to where the file is
1963//
1964 if (CksRdr && Finder && Finder->isRemote()
1965 && (rc = Finder->Locate(einfo, Path, SFS_O_RDONLY, &cksEnv)))
1966 return fsError(einfo, rc);
1967
1968// At this point we need to convert the lfn to a pfn
1969//
1970 if (CksPfn && !(Path = XrdOfsOss->Lfn2Pfn(Path, buff, MAXPATHLEN, rc)))
1971 return Emsg(epname, einfo, rc, "checksum", Path,
1972 "+ofs_chksum: lfn to pfn mapping failed");
1973
1974// Originally we only passed he env pointer for proxy servers. Due to popular
1975// demand, we always pass the env as it points to the SecEntity object unless
1976// we don't have it then we pass the caller's environment.
1977//
1979 {if (client) cksData.envP = &cksEnv;
1980 else cksData.envP = (einfo.getEnv() ? einfo.getEnv() : &cksEnv);
1981 }
1982
1983// Now determine what to do
1984//
1985 if (Func == XrdSfsFileSystem::csCalc) rc = Cks->Calc(Path, cksData);
1986 else if (Func == XrdSfsFileSystem::csGet) rc = Cks->Get( Path, cksData);
1987 else {einfo.setErrInfo(EINVAL, "Invalid checksum function.");
1988 return SFS_ERROR;
1989 }
1990
1991// See if all went well
1992//
1993#ifdef ENOATTR
1994 if (rc >= 0 || rc == -ENOATTR || rc == -ESTALE || rc == -ESRCH)
1995#else
1996 if (rc >= 0 || rc == -ENODATA || rc == -ESTALE || rc == -ESRCH)
1997#endif
1998 {if (rc >= 0) {cksData.Get(buff, MAXPATHLEN); rc = 0;}
1999 else {*buff = 0; rc = -rc;}
2000 einfo.setErrInfo(rc, buff);
2001 return SFS_OK;
2002 }
2003
2004// We failed
2005//
2006 return Emsg(epname, einfo, rc, "checksum", Path, "?");
2007}
2008
2009/******************************************************************************/
2010/* c h m o d */
2011/******************************************************************************/
2012
2013int XrdOfs::chmod(const char *path, // In
2014 XrdSfsMode Mode, // In
2015 XrdOucErrInfo &einfo, // Out
2016 const XrdSecEntity *client, // In
2017 const char *info) // In
2018/*
2019 Function: Change the mode on a file or directory.
2020
2021 Input: path - Is the fully qualified name of the file to be removed.
2022 einfo - Error information object to hold error details.
2023 client - Authentication credentials, if any.
2024 info - Opaque information to be used as seen fit.
2025
2026 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2027*/
2028{
2029 EPNAME("chmod");
2030 static const int locFlags = SFS_O_RDWR|SFS_O_META;
2031 struct stat Stat;
2032 mode_t acc_mode = Mode & S_IAMB;
2033 const char *tident = einfo.getErrUser();
2034 XrdOucEnv chmod_Env(info,0,client);
2035 int retc;
2036 XTRACE(chmod, path, "");
2037
2038// Apply security, as needed
2039//
2040 AUTHORIZE(client,&chmod_Env,AOP_Chmod,"chmod",path,einfo);
2041
2042// Find out where we should chmod this file
2043//
2044 if (Finder && Finder->isRemote())
2045 {if (fwdCHMOD.Cmd)
2046 {char buff[8];
2047 sprintf(buff, "%o", static_cast<int>(acc_mode));
2048 if (Forward(retc,einfo,fwdCHMOD,path,buff,&chmod_Env)) return retc;
2049 }
2050 else if ((retc = Finder->Locate(einfo, path, locFlags, &chmod_Env)))
2051 return fsError(einfo, retc);
2052 }
2053
2054// We need to adjust the mode based on whether this is a file or directory.
2055//
2056 if ((retc = XrdOfsOss->Stat(path, &Stat, 0, &chmod_Env)))
2057 return XrdOfsFS->Emsg(epname, einfo, retc, "stat", path, "?");
2058 if (S_ISDIR(Stat.st_mode)) acc_mode = (acc_mode | dMask[0]) & dMask[1];
2059 else acc_mode = (acc_mode | fMask[0]) & fMask[1];
2060
2061// Check if we should generate an event
2062//
2063 if (evsObject && evsObject->Enabled(XrdOfsEvs::Chmod))
2064 {XrdOfsEvsInfo evInfo(tident, path, info, &chmod_Env, acc_mode);
2065 evsObject->Notify(XrdOfsEvs::Chmod, evInfo);
2066 }
2067
2068// Now try to find the file or directory
2069//
2070 if (!(retc = XrdOfsOss->Chmod(path, acc_mode, &chmod_Env))) return SFS_OK;
2071
2072// An error occurred, return the error info
2073//
2074 return XrdOfsFS->Emsg(epname, einfo, retc, "chmod", path, "?");
2075}
2076
2077/******************************************************************************/
2078/* C o n n e c t */
2079/******************************************************************************/
2080
2082{
2083 XrdOucEnv myEnv(0, 0, client);
2084
2085// Pass this call along
2086//
2087 XrdOfsOss->Connect(myEnv);
2088}
2089
2090/******************************************************************************/
2091/* D i s c */
2092/******************************************************************************/
2093
2094void XrdOfs::Disc(const XrdSecEntity *client)
2095{
2096 XrdOucEnv myEnv(0, 0, client);
2097
2098// Pass this call along
2099//
2100 XrdOfsOss->Disc(myEnv);
2101}
2102
2103/******************************************************************************/
2104/* e x i s t s */
2105/******************************************************************************/
2106
2107int XrdOfs::exists(const char *path, // In
2108 XrdSfsFileExistence &file_exists, // Out
2109 XrdOucErrInfo &einfo, // Out
2110 const XrdSecEntity *client, // In
2111 const char *info) // In
2112/*
2113 Function: Determine if file 'path' actually exists.
2114
2115 Input: path - Is the fully qualified name of the file to be tested.
2116 file_exists - Is the address of the variable to hold the status of
2117 'path' when success is returned. The values may be:
2118 XrdSfsFileExistsIsDirectory - file not found but path is valid.
2119 XrdSfsFileExistsIsFile - file found.
2120 XrdSfsFileExistsIsNo - neither file nor directory.
2121 einfo - Error information object holding the details.
2122 client - Authentication credentials, if any.
2123 info - Opaque information to be used as seen fit.
2124
2125 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2126
2127 Notes: When failure occurs, 'file_exists' is not modified.
2128*/
2129{
2130 EPNAME("exists");
2131 struct stat fstat;
2132 int retc;
2133 const char *tident = einfo.getErrUser();
2134 XrdOucEnv stat_Env(info,0,client);
2135 XTRACE(exists, path, "");
2136
2137// Apply security, as needed
2138//
2139 AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
2140
2141// Find out where we should stat this file
2142//
2143 if (Finder && Finder->isRemote()
2144 && (retc = Finder->Locate(einfo, path, SFS_O_RDONLY, &stat_Env)))
2145 return fsError(einfo, retc);
2146
2147// Now try to find the file or directory
2148//
2149 retc = XrdOfsOss->Stat(path, &fstat, 0, &stat_Env);
2150 if (!retc)
2151 { if (S_ISDIR(fstat.st_mode)) file_exists=XrdSfsFileExistIsDirectory;
2152 else if (S_ISREG(fstat.st_mode)) file_exists=XrdSfsFileExistIsFile;
2153 else file_exists=XrdSfsFileExistNo;
2154 return SFS_OK;
2155 }
2156 if (retc == -ENOENT)
2157 {file_exists=XrdSfsFileExistNo;
2158 return SFS_OK;
2159 }
2160
2161// An error occurred, return the error info
2162//
2163 return XrdOfsFS->Emsg(epname, einfo, retc, "locate", path, "?");
2164}
2165
2166/******************************************************************************/
2167/* g e t S t a t s */
2168/******************************************************************************/
2169
2170int XrdOfs::getStats(char *buff, int blen)
2171{
2172 int n;
2173
2174// See if the size just wanted
2175//
2176 if (!buff) return OfsStats.Report(0,0) + XrdOfsOss->Stats(0,0);
2177
2178// Report ofs info followed by the oss info
2179//
2180 n = OfsStats.Report(buff, blen);
2181 buff += n; blen -= n;
2182 n += XrdOfsOss->Stats(buff, blen);
2183
2184// All done
2185//
2186 return n;
2187}
2188
2189/******************************************************************************/
2190/* m k d i r */
2191/******************************************************************************/
2192
2193int XrdOfs::mkdir(const char *path, // In
2194 XrdSfsMode Mode, // In
2195 XrdOucErrInfo &einfo, // Out
2196 const XrdSecEntity *client, // In
2197 const char *info) // In
2198/*
2199 Function: Create a directory entry.
2200
2201 Input: path - Is the fully qualified name of the file to be removed.
2202 Mode - Is the POSIX mode value the directory is to have.
2203 Additionally, Mode may contain SFS_O_MKPTH if the
2204 full dircectory path should be created.
2205 einfo - Error information object to hold error details.
2206 client - Authentication credentials, if any.
2207 info - Opaque information to be used as seen fit.
2208
2209 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2210*/
2211{
2212 EPNAME("mkdir");
2213 static const int LocOpts = SFS_O_RDWR | SFS_O_CREAT | SFS_O_META;
2214 mode_t acc_mode = (Mode | dMask[0]) & dMask[1];
2215 int retc, mkpath = Mode & SFS_O_MKPTH;
2216 const char *tident = einfo.getErrUser();
2217 XrdOucEnv mkdir_Env(info,0,client);
2218 XTRACE(mkdir, path, "");
2219
2220// Apply security, as needed
2221//
2222 AUTHORIZE(client,&mkdir_Env,AOP_Mkdir,"mkdir",path,einfo);
2223
2224// Find out where we should remove this file
2225//
2226 if (Finder && Finder->isRemote())
2227 {if (fwdMKDIR.Cmd)
2228 {char buff[8];
2229 sprintf(buff, "%o", static_cast<int>(acc_mode));
2230 if (Forward(retc, einfo, (mkpath ? fwdMKPATH:fwdMKDIR),
2231 path, buff, &mkdir_Env)) return retc;
2232 }
2233 else if ((retc = Finder->Locate(einfo,path,LocOpts,&mkdir_Env)))
2234 return fsError(einfo, retc);
2235 }
2236
2237// Perform the actual operation
2238//
2239 if ((retc = XrdOfsOss->Mkdir(path, acc_mode, mkpath, &mkdir_Env)))
2240 return XrdOfsFS->Emsg(epname, einfo, retc, "mkdir", path, "?");
2241
2242// Check if we should generate an event
2243//
2244 if (evsObject && evsObject->Enabled(XrdOfsEvs::Mkdir))
2245 {XrdOfsEvsInfo evInfo(tident, path, info, &mkdir_Env, acc_mode);
2246 evsObject->Notify(XrdOfsEvs::Mkdir, evInfo);
2247 }
2248
2249// If we have a redirector, tell it that we now have this path
2250//
2251 if (Balancer)
2252 {if (!mkpath) Balancer->Added(path);
2253 else {char *slash, *myPath = strdup(path);
2254 do {Balancer->Added(myPath);
2255 if ((slash = rindex(myPath, '/'))) *slash = 0;
2256 } while(slash && slash != myPath);
2257 free(myPath);
2258 }
2259 }
2260
2261 return SFS_OK;
2262}
2263
2264/******************************************************************************/
2265/* p r e p a r e */
2266/******************************************************************************/
2267
2268int XrdOfs::prepare( XrdSfsPrep &pargs, // In
2269 XrdOucErrInfo &out_error, // Out
2270 const XrdSecEntity *client) // In
2271{
2272 EPNAME("prepare");
2273 XrdOucEnv prep_Env(0,0,client);
2274 XrdOucTList *tp = pargs.paths;
2275 int retc;
2276
2277// Run through the paths to make sure client can read each one unless we aren't
2278// supposed to apply authorization.
2279//
2280 if (prepAuth)
2281 while(tp)
2282 {AUTHORIZE(client,0,AOP_Read,"prepare",tp->text,out_error);
2283 tp = tp->next;
2284 }
2285
2286// If there is a prepare plugin, invoke it and return the result.
2287//
2288 if (prepHandler)
2289 {if (pargs.opts & Prep_QUERY)
2290 return prepHandler->query(pargs, out_error, client);
2291 if (pargs.opts & Prep_CANCEL)
2292 return prepHandler->cancel(pargs, out_error, client);
2293
2294 return prepHandler->begin(pargs, out_error, client);
2295 }
2296
2297// If we have a finder object, use it to prepare the paths. Otherwise,
2298// ignore this prepare request (we may change this in the future).
2299//
2300 if (XrdOfsFS->Finder
2301 && (retc = XrdOfsFS->Finder->Prepare(out_error, pargs, &prep_Env)))
2302 return fsError(out_error, retc);
2303 return 0;
2304}
2305
2306/******************************************************************************/
2307/* r e m o v e */
2308/******************************************************************************/
2309
2310int XrdOfs::remove(const char type, // In
2311 const char *path, // In
2312 XrdOucErrInfo &einfo, // Out
2313 const XrdSecEntity *client, // In
2314 const char *info) // In
2315/*
2316 Function: Delete a file from the namespace and release it's data storage.
2317
2318 Input: type - 'f' for file and 'd' for directory.
2319 path - Is the fully qualified name of the file to be removed.
2320 einfo - Error information object to hold error details.
2321 client - Authentication credentials, if any.
2322 info - Opaque information to be used as seen fit.
2323
2324 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2325*/
2326{
2327 EPNAME("remove");
2328 static const int LocOpts = SFS_O_WRONLY|SFS_O_META;
2329 int retc, Opt;
2330 const char *tident = einfo.getErrUser();
2331 XrdOucEnv rem_Env(info,0,client);
2332 XTRACE(remove, path, type);
2333
2334// Apply security, as needed
2335//
2336 AUTHORIZE(client,&rem_Env,AOP_Delete,"remove",path,einfo);
2337
2338// Find out where we should remove this file
2339//
2340 if (Finder && Finder->isRemote())
2341 {struct fwdOpt *fSpec = (type == 'd' ? &fwdRMDIR : &fwdRM);
2342 if (fSpec->Cmd)
2343 {if (Forward(retc, einfo, *fSpec, path, 0, &rem_Env)) return retc;}
2344 else if ((retc = Finder->Locate(einfo, path, LocOpts, &rem_Env)))
2345 return fsError(einfo, retc);
2346 }
2347
2348// Check if we should generate an event
2349//
2350 if (evsObject)
2351 {XrdOfsEvs::Event theEvent=(type == 'd' ? XrdOfsEvs::Rmdir:XrdOfsEvs::Rm);
2352 if (evsObject->Enabled(theEvent))
2353 {XrdOfsEvsInfo evInfo(tident, path, info, &rem_Env);
2354 evsObject->Notify(theEvent, evInfo);
2355 }
2356 }
2357
2358// Check if this is an online deletion only
2359//
2360 Opt = (rem_Env.Get("ofs.lcl") ? XRDOSS_Online : 0);
2361
2362// Perform the actual deletion
2363//
2364 retc = (type=='d' ? XrdOfsOss->Remdir(path, 0, &rem_Env)
2365 : XrdOfsOss->Unlink(path, Opt, &rem_Env));
2366 if (retc) return XrdOfsFS->Emsg(epname, einfo, retc, "remove", path, "?");
2367 if (type == 'f') XrdOfsHandle::Hide(path);
2368 if (Balancer) Balancer->Removed(path);
2369 return SFS_OK;
2370}
2371
2372/******************************************************************************/
2373/* r e n a m e */
2374/******************************************************************************/
2375
2376int XrdOfs::rename(const char *old_name, // In
2377 const char *new_name, // In
2378 XrdOucErrInfo &einfo, //Out
2379 const XrdSecEntity *client, // In
2380 const char *infoO, // In
2381 const char *infoN) // In
2382/*
2383 Function: Renames a file with name 'old_name' to 'new_name'.
2384
2385 Input: old_name - Is the fully qualified name of the file to be renamed.
2386 new_name - Is the fully qualified name that the file is to have.
2387 einfo - Error information structure, if an error occurs.
2388 client - Authentication credentials, if any.
2389 infoO - old_name opaque information to be used as seen fit.
2390 infoN - new_name opaque information to be used as seen fit.
2391
2392 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2393*/
2394{
2395 EPNAME("rename");
2396 static const int LocOpts = SFS_O_RDWR|SFS_O_META;
2397 int retc;
2398 const char *tident = einfo.getErrUser();
2399 XrdOucEnv old_Env(infoO,0,client);
2400 XrdOucEnv new_Env(infoN,0,client);
2401 XTRACE(rename, new_name, "old fn=" <<old_name <<" new ");
2402
2403// Apply security, as needed
2404//
2405 AUTHORIZE(client, &old_Env, AOP_Rename, "renaming", old_name, einfo);
2406
2407// The above authorization may mutate the XrdSecEntity by putting a mapped name
2408// into the extended attributes. This mapped name will affect the subsequent
2409// authorization check below, giving the client access that may not be permitted.
2410// Hence, we delete this attribute to reset the object back to "pristine" state.
2411// If there was a way to make a copy of the XrdSecEntity, we could avoid this
2412// hack-y reach inside the extended attributes.
2413 if (client) client->eaAPI->Add("request.name", "", true);
2414
2415// If we do not have full-blown insert authorization, we'll need to test for
2416// destination existence
2417 bool cannot_overwrite = false;
2418 if (client && XrdOfsFS->Authorization &&
2419 !XrdOfsFS->Authorization->Access(client, new_name, AOP_Insert, &new_Env))
2420 {cannot_overwrite = true;
2421 AUTHORIZE(client, &new_Env, AOP_Excl_Insert,
2422 "rename to existing file (overwrite disallowed)", new_name, einfo);
2423 }
2424
2425// Find out where we should rename this file
2426//
2427 if (Finder && Finder->isRemote())
2428 {if (fwdMV.Cmd)
2429 {if (Forward(retc,einfo,fwdMV,old_name,new_name,&old_Env,&new_Env))
2430 return retc;
2431 }
2432 else if ((retc = Finder->Locate(einfo, old_name, LocOpts, &old_Env)))
2433 return fsError(einfo, retc);
2434 }
2435
2436// Check if we should generate an event
2437//
2438 if (evsObject && evsObject->Enabled(XrdOfsEvs::Mv))
2439 {XrdOfsEvsInfo evInfo(tident, old_name, infoO, &old_Env, 0, 0,
2440 new_name, infoN, &new_Env);
2441 evsObject->Notify(XrdOfsEvs::Mv, evInfo);
2442 }
2443
2444// If we cannot overwrite, we must test for existence first. This will test whether
2445// we will destroy data in the rename (without actually destroying data).
2446// Note there's an obvious race condition here; it was seen as the lesser-of-evils
2447// compared to creating an exclusive file and potentially leaking it in the event
2448// of a crash.
2449//
2450 if (cannot_overwrite)
2451 {XrdSfsFileExistence exists_flag;
2452 if (SFS_OK != exists(new_name, exists_flag, einfo, client, infoN))
2453 {// File existence check itself failed; we can't prove that data won't
2454 // be overwritten so we return an error.
2455 return fsError(einfo, -einfo.getErrInfo());
2456 }
2457 if (exists_flag != XrdSfsFileExistNo)
2458 {// EPERM mimics the error code set by Linux when you invoke rename()
2459 // but cannot overwrite the destination file.
2460 einfo.setErrInfo(EPERM, "Overwrite of existing data not permitted");
2461 return fsError(einfo, -EPERM);
2462 }
2463 }
2464
2465// Perform actual rename operation
2466//
2467 if ((retc = XrdOfsOss->Rename(old_name, new_name, &old_Env, &new_Env)))
2468 {return XrdOfsFS->Emsg(epname, einfo, retc, "rename", old_name, "?");
2469 }
2470 XrdOfsHandle::Hide(old_name);
2471 if (Balancer) {Balancer->Removed(old_name);
2472 Balancer->Added(new_name);
2473 }
2474 return SFS_OK;
2475}
2476
2477/******************************************************************************/
2478/* s t a t */
2479/******************************************************************************/
2480
2481int XrdOfs::stat(const char *path, // In
2482 struct stat *buf, // Out
2483 XrdOucErrInfo &einfo, // Out
2484 const XrdSecEntity *client, // In
2485 const char *info) // In
2486/*
2487 Function: Return file status information
2488
2489 Input: path - The path for which status is wanted
2490 buf - The stat structure to hold the results
2491 einfo - Error information structure, if an error occurs.
2492 client - Authentication credentials, if any.
2493 info - opaque information to be used as seen fit.
2494
2495 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2496*/
2497{
2498 EPNAME("stat");
2499 int retc;
2500 const char *tident = einfo.getErrUser();
2501 XrdOucEnv stat_Env(info,0,client);
2502 XTRACE(stat, path, "");
2503
2504// Apply security, as needed
2505//
2506 AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
2507
2508// Find out where we should stat this file
2509//
2510 if (Finder && Finder->isRemote()
2511 && (retc = Finder->Locate(einfo, path, SFS_O_RDONLY|SFS_O_STAT, &stat_Env)))
2512 return fsError(einfo, retc);
2513
2514// Now try to find the file or directory
2515//
2516 if ((retc = XrdOfsOss->Stat(path, buf, 0, &stat_Env)))
2517 return XrdOfsFS->Emsg(epname, einfo, retc, "locate", path, "?");
2518 return SFS_OK;
2519}
2520
2521/******************************************************************************/
2522
2523int XrdOfs::stat(const char *path, // In
2524 mode_t &mode, // Out
2525 XrdOucErrInfo &einfo, // Out
2526 const XrdSecEntity *client, // In
2527 const char *info) // In
2528/*
2529 Function: Return file status information (resident files only)
2530
2531 Input: path - The path for which status is wanted
2532 mode - The stat mode entry (faked -- do not trust it)
2533 einfo - Error information structure, if an error occurs.
2534 client - Authentication credentials, if any.
2535 info - opaque information to be used as seen fit.
2536
2537 Output: Always returns SFS_ERROR if a delay needs to be imposed. Otherwise,
2538 SFS_OK is returned and mode is appropriately, if inaccurately, set.
2539 If file residency cannot be determined, mode is set to -1.
2540*/
2541{
2542 EPNAME("stat");
2543 struct stat buf;
2544 int retc;
2545 const char *tident = einfo.getErrUser();
2546 XrdOucEnv stat_Env(info,0,client);
2547 XTRACE(stat, path, "");
2548
2549// Apply security, as needed
2550//
2551 AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
2552 mode = (mode_t)-1;
2553
2554// Find out where we should stat this file
2555//
2556 if (Finder && Finder->isRemote()
2557 && (retc = Finder->Locate(einfo,path,SFS_O_NOWAIT|SFS_O_RDONLY|SFS_O_STAT,
2558 &stat_Env)))
2559 return fsError(einfo, retc);
2560
2561// Now try to find the file or directory
2562//
2563 if (!(retc = XrdOfsOss->Stat(path, &buf, XRDOSS_resonly, &stat_Env)))
2564 mode=buf.st_mode;
2565 else if ((-ENOMSG) != retc)
2566 return XrdOfsFS->Emsg(epname, einfo, retc, "locate", path, "?");
2567 return SFS_OK;
2568}
2569
2570/******************************************************************************/
2571/* t r u n c a t e */
2572/******************************************************************************/
2573
2574int XrdOfs::truncate(const char *path, // In
2575 XrdSfsFileOffset Size, // In
2576 XrdOucErrInfo &einfo, // Out
2577 const XrdSecEntity *client, // In
2578 const char *info) // In
2579/*
2580 Function: Change the mode on a file or directory.
2581
2582 Input: path - Is the fully qualified name of the file to be removed.
2583 Size - the size the file should have.
2584 einfo - Error information object to hold error details.
2585 client - Authentication credentials, if any.
2586 info - Opaque information to be used as seen fit.
2587
2588 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2589*/
2590{
2591 EPNAME("truncate");
2592 const char *tident = einfo.getErrUser();
2593 XrdOucEnv trunc_Env(info,0,client);
2594 int retc;
2595 XTRACE(truncate, path, "");
2596
2597// Apply security, as needed
2598//
2599 AUTHORIZE(client,&trunc_Env,AOP_Update,"truncate",path,einfo);
2600
2601// Find out where we should chmod this file
2602//
2603 if (Finder && Finder->isRemote())
2604 {if (fwdTRUNC.Cmd)
2605 {char xSz[32];
2606 sprintf(xSz, "%lld", static_cast<long long>(Size));
2607 if (Forward(retc,einfo,fwdTRUNC,path,xSz,&trunc_Env)) return retc;
2608 }
2609 else if ((retc = Finder->Locate(einfo,path,SFS_O_RDWR,&trunc_Env)))
2610 return fsError(einfo, retc);
2611 }
2612
2613// Check if we should generate an event
2614//
2615 if (evsObject && evsObject->Enabled(XrdOfsEvs::Trunc))
2616 {XrdOfsEvsInfo evInfo(tident, path, info, &trunc_Env, 0, Size);
2617 evsObject->Notify(XrdOfsEvs::Trunc, evInfo);
2618 }
2619
2620// Now try to find the file or directory
2621//
2622 if (!(retc = XrdOfsOss->Truncate(path, Size, &trunc_Env))) return SFS_OK;
2623
2624// An error occurred, return the error info
2625//
2626 return XrdOfsFS->Emsg(epname, einfo, retc, "trunc", path, "?");
2627}
2628
2629/******************************************************************************/
2630/* E m s g */
2631/******************************************************************************/
2632
2633int XrdOfs::Emsg(const char *pfx, // Message prefix value
2634 XrdOucErrInfo &einfo, // Place to put text & error code
2635 int ecode, // The error code
2636 const char *op, // Operation being performed
2637 XrdOfsHandle *hP, // The target handle
2638 bool posChk, // Unpersist if in posc mode
2639 bool chkType)// Check for type of error & subclass
2640{
2641 const char* etP = 0;
2642 int rc;
2643
2644// Screen out non-errors
2645//
2646 if (chkType && (rc = EmsgType(ecode)) != SFS_ERROR) return rc;
2647
2648// Get any extended information
2649//
2650 std::string eText;
2651 if (XrdOfsFS->tryXERT && hP->Select().getErrMsg(eText)) etP = eText.c_str();
2652
2653// First issue the error message so if we have to unpersist it makes sense
2654//
2655 rc = Emsg(pfx, einfo, ecode, op, hP->Name(), etP);
2656
2657// If this is a POSC file then we need to unpersist it. Note that we are always
2658// called with the handle **unlocked**
2659//
2660 if (posChk && hP->isRW == XrdOfsHandle::opPC)
2661 {hP->Lock();
2662 XrdOfsFS->Unpersist(hP);
2663 hP->UnLock();
2664 }
2665
2666// Now return the error
2667//
2668 return rc;
2669}
2670
2671/******************************************************************************/
2672
2673int XrdOfs::Emsg(const char *pfx, // Message prefix value
2674 XrdOucErrInfo &einfo, // Place to put text & error code
2675 int ecode, // The error code
2676 const char *op, // Operation being performed
2677 const char *target, // The target (e.g., fname)
2678 const char *xtra, // Optional extra error information
2679 bool chkType)// Check for type of error & subclass
2680{
2681 char* buffer;
2682 int buflen, rc;
2683 bool msgDone = false;
2684
2685// Screen out non-errors
2686//
2687 if (chkType && (rc = EmsgType(ecode)) != SFS_ERROR) return rc;
2688
2689// Setup message handling
2690//
2691 if (einfo.extData()) einfo.Reset();
2692 buffer = einfo.getMsgBuff(buflen);
2693 std::string eText;
2694
2695 // Translate ecode to corresponding errno
2696 int rcode = OfsEroute.ec2errno(ecode);
2697
2698// Check for extended information
2699//
2700 if (xtra)
2701 switch(*xtra)
2702 {case '?': xtra = 0;
2703 if (XrdOfsFS->tryXERT && XrdOfsOss->getErrMsg(eText))
2704 {if (eText.find("Unable") != std::string::npos)
2705 {einfo.setErrInfo(rcode, eText.c_str());
2706 msgDone = true;
2707 } else xtra = eText.c_str();
2708 }
2709 break;
2710 case '+': xtra++;
2711 break;
2712 default: einfo.setErrInfo(rcode, xtra);
2713 msgDone = true;
2714 break;
2715 }
2716
2717// Format the error message if it has not been already set
2718//
2719 if (!msgDone)
2720 {XrdOucERoute::Format(buffer, buflen, ecode, op, target, xtra);
2721 einfo.setErrCode(rcode);
2722 }
2723
2724// Print it out
2725//
2726 OfsEroute.Emsg(pfx, einfo.getErrUser(), buffer);
2727
2728// Return an error
2729//
2730 return SFS_ERROR;
2731}
2732
2733/******************************************************************************/
2734/* E m s g T y p e */
2735/******************************************************************************/
2736
2737int XrdOfs::EmsgType(int ecode) // The error code
2738{
2739
2740// If the error is EBUSY then we just need to stall the client. This is
2741// a hack in order to provide for proxy support
2742//
2743 if (ecode < 0) ecode = -ecode;
2744 if (ecode == EBUSY) return 5; // A hack for proxy support
2745
2746// Check for timeout conditions that require a client delay
2747//
2748 if (ecode == ETIMEDOUT) return OSSDelay;
2749
2750// This is a real error
2751//
2752 return SFS_ERROR;
2753}
2754
2755/******************************************************************************/
2756/* S e t u p C k s R T */
2757/******************************************************************************/
2758
2759int XrdOfs::SetupCksRT(XrdCksCalc*& cP, XrdOucEnv& Env,const char*& cT)
2760{
2761// Check if the cipher can come from the environment
2762//
2763 if (CksRTCgi && (cT = Env.Get("cks.type")))
2764 return (ValidCST(cT) && (cP=Cks->Object(cT)) ? 0 : -ENOTSUP);
2765
2766// Set of auto real-time is enabled
2767//
2768 if (CksRTCalc)
2769 {cP = CksRTCalc->New();
2770 cT = CksRTName;
2771 }
2772
2773// All done
2774//
2775 return 0;
2776}
2777
2778/******************************************************************************/
2779/* P R I V A T E S E C T I O N */
2780/******************************************************************************/
2781/******************************************************************************/
2782/* F n a m e */
2783/******************************************************************************/
2784
2785const char *XrdOfs::Fname(const char *path)
2786{
2787 int i = strlen(path)-1;
2788 while(i) if (path[i] == '/') return &path[i+1];
2789 else i--;
2790 return path;
2791}
2792
2793/******************************************************************************/
2794/* F o r w a r d */
2795/******************************************************************************/
2796
2797int XrdOfs::Forward(int &Result, XrdOucErrInfo &Resp, struct fwdOpt &Fwd,
2798 const char *arg1, const char *arg2,
2799 XrdOucEnv *Env1, XrdOucEnv *Env2)
2800{
2801 int retc;
2802
2803 if ((retc = Finder->Forward(Resp, Fwd.Cmd, arg1, arg2, Env1, Env2)))
2804 {Result = fsError(Resp, retc);
2805 return 1;
2806 }
2807
2808 if (Fwd.Port <= 0)
2809 {Result = SFS_OK;
2810 return (Fwd.Port ? 0 : 1);
2811 }
2812
2813 Resp.setErrInfo(Fwd.Port, Fwd.Host);
2814 Result = SFS_REDIRECT;
2816 return 1;
2817}
2818
2819/******************************************************************************/
2820/* f s E r r o r */
2821/******************************************************************************/
2822
2823int XrdOfs::fsError(XrdOucErrInfo &myError, int rc)
2824{
2825
2826// Screen the error code (update statistics w/o a lock for speed!)
2827//
2828 if (rc == SFS_REDIRECT) {OfsStats.Data.numRedirect++; return SFS_REDIRECT;}
2829 if (rc == SFS_STARTED) {OfsStats.Data.numStarted++; return SFS_STARTED; }
2830 if (rc > 0) {OfsStats.Data.numDelays++; return rc; }
2831 if (rc == SFS_DATA) {OfsStats.Data.numReplies++; return SFS_DATA; }
2832 {OfsStats.Data.numErrors++; return SFS_ERROR; }
2833}
2834
2835/******************************************************************************/
2836/* R e f o r m a t */
2837/******************************************************************************/
2838
2839int XrdOfs::Reformat(XrdOucErrInfo &myError)
2840{
2841 static const char *fmt = "oss.cgroup=all&oss.space=%llu&oss.free=%llu"
2842 "&oss.maxf=%llu&oss.used=%llu&oss.quota=-1";
2843 char qsFmt, *bP;
2844 unsigned long long totSpace, totFree, maxFree;
2845 int n, blen;
2846
2847// Get the buffer
2848//
2849 bP = myError.getMsgBuff(blen);
2850
2851// Scan out the values
2852//
2853 n = sscanf(bP, "%c %llu %llu %llu", &qsFmt, &totSpace, &totFree, &maxFree);
2854
2855// Validate the response. The response will be invalid for older cmsd's
2856//
2857 if (n != 4 || qsFmt != 'A')
2858 {myError.setErrInfo(ENOTSUP,"space fctl operation not supported by cmsd");
2859 return SFS_ERROR;
2860 }
2861
2862// Change megabyte values to actual bytes
2863//
2864 totSpace = totSpace << 20LL;
2865 totFree = totFree << 20LL;
2866 maxFree = maxFree << 20LL;
2867
2868// Reformat the result
2869//
2870 blen = snprintf(bP,blen,fmt,totSpace,totFree,maxFree,(totSpace-totFree));
2871
2872 myError.setErrCode(blen);
2873 return SFS_DATA;
2874}
2875
2876/******************************************************************************/
2877/* S p l i t */
2878/******************************************************************************/
2879
2880const char * XrdOfs::Split(const char *Args, const char **Opq,
2881 char *Path, int Plen)
2882{
2883 int xlen;
2884 *Opq = index(Args, '?');
2885 if (!(*Opq)) return Args;
2886 xlen = (*Opq)-Args;
2887 if (xlen >= Plen) xlen = Plen-1;
2888 strncpy(Path, Args, xlen);
2889 Path[xlen] = 0;
2890 return Path;
2891}
2892
2893/******************************************************************************/
2894/* S t a l l */
2895/******************************************************************************/
2896
2897int XrdOfs::Stall(XrdOucErrInfo &einfo, // Error text & code
2898 int stime, // Seconds to stall
2899 const char *path) // The path to stall on
2900{
2901 const char *msgfmt = "File %s is being %s; "
2902 "estimated time to completion %s";
2903 EPNAME("Stall")
2904#ifndef NODEBUG
2905 const char *tident = "";
2906#endif
2907 char Mbuff[2048], Tbuff[32];
2908 const char *What = "staged";
2909
2910// Check why the stall is occurring
2911//
2912 if (stime < 0) {stime = 60; What = "created";}
2913
2914// Format the stall message
2915//
2916 snprintf(Mbuff, sizeof(Mbuff)-1, msgfmt,
2917 Fname(path), What, WaitTime(stime, Tbuff, sizeof(Tbuff)));
2918 ZTRACE(delay, "Stall " <<stime <<": " <<Mbuff <<" for " <<path);
2919
2920// Place the error message in the error object and return
2921//
2922 einfo.setErrInfo(0, Mbuff);
2923
2924// All done
2925//
2926 return (stime > MaxDelay ? MaxDelay : stime);
2927}
2928
2929/******************************************************************************/
2930/* U n p e r s i s t */
2931/******************************************************************************/
2932
2934{
2935 EPNAME("Unpersist");
2936 const char *tident = oh->PoscUsr();
2937 int poscNum, retc;
2938 short theMode;
2939
2940// Trace the call
2941//
2942 FTRACE(close, "use=0");
2943
2944// Generate a proper close event as one has not yet been generated
2945//
2946 if (xcev && XrdOfsFS->evsObject && *tident != '?'
2947 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Closew))
2948 {XrdOfsEvsInfo evInfo(tident, oh->Name());
2949 XrdOfsFS->evsObject->Notify(XrdOfsEvs::Closew, evInfo);
2950 }
2951
2952// Now generate a removal event
2953//
2954 if (XrdOfsFS->Balancer) XrdOfsFS->Balancer->Removed(oh->Name());
2955 if (XrdOfsFS->evsObject && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Rm))
2956 {XrdOfsEvsInfo evInfo(tident, oh->Name());
2957 XrdOfsFS->evsObject->Notify(XrdOfsEvs::Rm, evInfo);
2958 }
2959
2960// Count this
2961//
2962 OfsStats.Add(OfsStats.Data.numUnpsist);
2963
2964// Now unpersist the file
2965//
2966 OfsEroute.Emsg(epname, "Unpersisting", tident, oh->Name());
2967 if ((poscNum = oh->PoscGet(theMode))) poscQ->Del(oh->Name(), poscNum, 1);
2968 else if ((retc = XrdOfsOss->Unlink(oh->Name())))
2969 OfsEroute.Emsg(epname, retc, "unpersist", oh->Name());
2970}
2971
2972/******************************************************************************/
2973/* W a i t T i m e */
2974/******************************************************************************/
2975
2976char *XrdOfs::WaitTime(int stime, char *buff, int blen)
2977{
2978 int hr, min, sec;
2979
2980// Compute hours, minutes, and seconds
2981//
2982 min = stime / 60;
2983 sec = stime % 60;
2984 hr = min / 60;
2985 min = min % 60;
2986
2987// Now format the message based on time duration
2988//
2989 if (!hr && !min)
2990 snprintf(buff,blen,"%d second%s",sec,(sec > 1 ? "s" : ""));
2991 else if (!hr)
2992 {if (sec > 10) min++;
2993 snprintf(buff,blen,"%d minute%s",min,(min > 1 ? "s" : ""));
2994 }
2995 else {if (hr == 1)
2996 if (min <= 30)
2997 snprintf(buff,blen,"%d minutes",min+60);
2998 else snprintf(buff,blen,"%d hour and %d minutes",hr,min);
2999 else {if (min > 30) hr++;
3000 snprintf(buff,blen,"%d hours",hr);
3001 }
3002 }
3003
3004// Complete the message
3005//
3006 buff[blen-1] = '\0';
3007 return buff;
3008}
#define ENOATTR
@ kXR_faMaxVlen
Definition XProtocol.hh:312
@ kXR_faMaxNlen
Definition XProtocol.hh:311
@ AOP_Delete
rm() or rmdir()
@ AOP_Mkdir
mkdir()
@ AOP_Update
open() r/w or append
@ AOP_Create
open() with create
@ AOP_Readdir
opendir()
@ AOP_Chmod
chmod()
@ AOP_Stat
exists(), stat()
@ AOP_Rename
mv() for source
@ AOP_Read
open() r/o, prepare()
@ AOP_Excl_Create
open() with O_EXCL|O_CREAT
@ AOP_Insert
mv() for target
@ AOP_Excl_Insert
mv() where destination doesn't exist.
#define tident
#define EPNAME(x)
#define FTRACE(act, x)
#define ZTRACE(act, x)
#define XTRACE(act, target, x)
struct stat Stat
Definition XrdCks.cc:49
#define S_IAMB
Definition XrdConfig.cc:163
#define O_DIRECT
Definition XrdCrc32c.cc:51
#define ENODATA
#define OOIDENTENV(usr, env)
#define AUTHORIZE(usr, env, optype, action, pathp, edata)
XrdSysError OfsEroute(0)
XrdSysTrace OfsTrace("ofs")
XrdOss * XrdOfsOss
Definition XrdOfs.cc:165
XrdOfsStats OfsStats
Definition XrdOfs.cc:115
XrdOfs * XrdOfsFS
Definition XrdOfsFS.cc:47
#define XRDOSS_coloc
Definition XrdOss.hh:529
#define XRDOSS_Online
Definition XrdOss.hh:528
#define XRDOSS_new
Definition XrdOss.hh:527
#define XRDOSS_mkpath
Definition XrdOss.hh:526
#define XRDOSS_resonly
Definition XrdOss.hh:548
#define close(a)
Definition XrdPosix.hh:48
#define fstat(a, b)
Definition XrdPosix.hh:62
#define write(a, b, c)
Definition XrdPosix.hh:121
#define opendir(a)
Definition XrdPosix.hh:82
#define closedir(a)
Definition XrdPosix.hh:50
#define stat(a, b)
Definition XrdPosix.hh:105
#define readdir(a)
Definition XrdPosix.hh:90
#define read(a, b, c)
Definition XrdPosix.hh:86
int Mode
XrdOucString Path
#define eMsg(x)
struct myOpts opts
off_t aio_offset
Definition XrdSfsAio.hh:49
size_t aio_nbytes
Definition XrdSfsAio.hh:48
void * aio_buf
Definition XrdSfsAio.hh:47
#define XRDSFS_POSCPEND
int XrdSfsMode
#define SFS_DATA
#define Prep_CANCEL
#define SFS_O_RESET
#define SFS_O_CREATAT
#define SFS_O_STAT
#define Prep_QUERY
XrdOucTList * paths
List of paths.
#define SFS_O_META
#define SFS_ERROR
XrdSfsFileExistence
@ XrdSfsFileExistIsFile
@ XrdSfsFileExistNo
@ XrdSfsFileExistIsDirectory
#define SFS_O_SEQIO
#define SFS_O_NOTPC
#define SFS_O_POSC
#define SFS_FCTL_QFINFO
#define SFS_REDIRECT
#define SFS_O_MKPTH
#define SFS_O_RDONLY
#define SFS_STARTED
#define SFS_O_MULTIW
#define SFS_O_WRONLY
#define SFS_FCTL_GETFD
#define SFS_O_CREAT
#define SFS_O_RAWIO
#define SFS_O_RDWR
int XrdSfsFileOpenMode
#define SFS_FCTL_SPEC1
#define SFS_OK
long long XrdSfsFileOffset
#define SFS_O_NOWAIT
int opts
Prep_xxx.
#define SFS_O_REPLICA
#define SFS_O_TRUNC
int XrdSfsXferSize
< Prepare parameters
XrdSys::RAtomic< int > RAtomic_int
virtual void Recycle()
Recycle the checksum object as it is no longer needed. A default is given.
virtual XrdCksCalc * New()=0
int Set(const char *csName)
Definition XrdCksData.hh:81
int Get(char *Buff, int Blen)
Definition XrdCksData.hh:69
virtual int isRemote()
static bool Enabled
char dname[MAXNAMLEN]
Definition XrdOfs.hh:92
const char * nextEntry()
Definition XrdOfs.cc:313
const char * tident
Definition XrdOfs.hh:88
int autoStat(struct stat *buf)
Definition XrdOfs.cc:422
char * fname
Definition XrdOfs.hh:89
XrdOssDF * dp
Definition XrdOfs.hh:90
int open(const char *dirName, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:245
XrdOfsFile(XrdOucErrInfo &eInfo, const char *user)
Definition XrdOfs.cc:462
int getCXinfo(char cxtype[4], int &cxrsz)
Definition XrdOfs.cc:1850
bool viaDel
Definition XrdOfs.hh:206
int checkpoint(XrdSfsFile::cpAct act, struct iov *range=0, int n=0)
Definition XrdOfs.cc:1006
XrdSfsXferSize pgWrite(XrdSfsFileOffset offset, char *buffer, XrdSfsXferSize wrlen, uint32_t *csvec, uint64_t opts=0)
Definition XrdOfs.cc:1306
XrdSfsXferSize write(XrdSfsFileOffset fileOffset, const char *buffer, XrdSfsXferSize buffer_size)
Definition XrdOfs.cc:1590
int truncate(XrdSfsFileOffset fileOffset)
Definition XrdOfs.cc:1803
int Clone(XrdSfsFile &srcFile)
Definition XrdOfs.cc:864
int read(XrdSfsFileOffset fileOffset, XrdSfsXferSize amount)
Definition XrdOfs.cc:1425
int fctl(const int cmd, const char *args, XrdOucErrInfo &out_error)
Definition XrdOfs.cc:1138
XrdSfsXferSize readv(XrdOucIOVec *readV, int readCount)
Definition XrdOfs.cc:1512
int open(const char *fileName, XrdSfsFileOpenMode openMode, mode_t createMode, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:471
XrdSfsXferSize pgRead(XrdSfsFileOffset offset, char *buffer, XrdSfsXferSize rdlen, uint32_t *csvec, uint64_t opts=0)
Definition XrdOfs.cc:1210
int getMmap(void **Addr, off_t &Size)
Definition XrdOfs.cc:1693
int close()
Definition XrdOfs.cc:899
const char * tident
Definition XrdOfs.hh:201
int sync()
Definition XrdOfs.cc:1742
XrdOfsHandle * oh
Definition XrdOfs.hh:202
int dorawio
Definition XrdOfs.hh:205
XrdOucChkPnt * myCKP
Definition XrdOfs.hh:204
bool ckpBad
Definition XrdOfs.hh:207
XrdOfsTPC * myTPC
Definition XrdOfs.hh:203
int stat(struct stat *buf)
Definition XrdOfs.cc:1714
int Retire(int &retc, long long *retsz=0, char *buff=0, int blen=0)
static void Hide(const char *thePath)
static const int opRW
int PoscGet(short &Mode, int Done=0)
static const int opPC
static int Alloc(const char *thePath, int Opts, XrdOfsHandle **Handle)
const char * PoscUsr()
XrdOssDF & Select(void)
const char * Name()
struct XrdOfsStats::StatsData Data
static int Authorize(XrdOfsTPC **theTPC, Facts &Args, int isPLE=0)
Definition XrdOfsTPC.cc:221
static int Validate(XrdOfsTPC **theTPC, Facts &Args)
Definition XrdOfsTPC.cc:550
void Connect(const XrdSecEntity *client=0)
Definition XrdOfs.cc:2081
int chmod(const char *Name, XrdSfsMode Mode, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2013
int truncate(const char *Name, XrdSfsFileOffset fileOffset, XrdOucErrInfo &out_error, const XrdSecEntity *client=0, const char *opaque=0)
Definition XrdOfs.cc:2574
struct fwdOpt fwdTRUNC
Definition XrdOfs.hh:425
void Disc(const XrdSecEntity *client=0)
Definition XrdOfs.cc:2094
int prepare(XrdSfsPrep &pargs, XrdOucErrInfo &out_error, const XrdSecEntity *client=0)
Definition XrdOfs.cc:2268
mode_t dMask[2]
Definition XrdOfs.hh:394
const char * Split(const char *Args, const char **Opq, char *Path, int Plen)
Definition XrdOfs.cc:2880
int myPort
Definition XrdOfs.hh:390
XrdCmsClient * Finder
Definition XrdOfs.hh:439
mode_t fMask[2]
Definition XrdOfs.hh:395
static int EmsgType(int ecode)
Definition XrdOfs.cc:2737
char * WaitTime(int, char *, int)
Definition XrdOfs.cc:2976
struct fwdOpt fwdRMDIR
Definition XrdOfs.hh:424
static int OSSDelay
Definition XrdOfs.hh:428
char * ConfigFN
Definition XrdOfs.hh:430
int tpcRdrPort[2]
Definition XrdOfs.hh:400
int mkdir(const char *dirName, XrdSfsMode Mode, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2193
struct fwdOpt fwdMKPATH
Definition XrdOfs.hh:421
XrdOfs()
Definition XrdOfs.cc:171
char * tpcRdrHost[2]
Definition XrdOfs.hh:399
int chksum(csFunc Func, const char *csName, const char *Path, XrdOucErrInfo &out_error, const XrdSecEntity *client=0, const char *opaque=0)
Definition XrdOfs.cc:1901
int rename(const char *oldFileName, const char *newFileName, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *infoO=0, const char *infoN=0)
Definition XrdOfs.cc:2376
struct fwdOpt fwdMKDIR
Definition XrdOfs.hh:420
static int MaxDelay
Definition XrdOfs.hh:427
struct fwdOpt fwdMV
Definition XrdOfs.hh:422
static int Emsg(const char *, XrdOucErrInfo &, int, const char *x, XrdOfsHandle *hP, bool posChk=false, bool chktype=true)
Definition XrdOfs.cc:2633
static int fsError(XrdOucErrInfo &myError, int rc)
Definition XrdOfs.cc:2823
int stat(const char *Name, struct stat *buf, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2481
struct fwdOpt fwdRM
Definition XrdOfs.hh:423
int SetupCksRT(XrdCksCalc *&, XrdOucEnv &, const char *&)
Definition XrdOfs.cc:2759
bool ValidCST(const char *cst)
int getStats(char *buff, int blen)
Definition XrdOfs.cc:2170
struct fwdOpt fwdCHMOD
Definition XrdOfs.hh:419
int Stall(XrdOucErrInfo &, int, const char *)
Definition XrdOfs.cc:2897
@ RdrTPC
Definition XrdOfs.hh:386
int exists(const char *fileName, XrdSfsFileExistence &exists_flag, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2107
void Unpersist(XrdOfsHandle *hP, int xcev=1)
Definition XrdOfs.cc:2933
static const uint64_t Verify
all: Verify checksums
Definition XrdOss.hh:251
virtual int Fctl(int cmd, int alen, const char *args, char **resp=0)
Definition XrdOss.cc:150
virtual int Fchmod(mode_t mode)
Definition XrdOss.hh:148
static const int Fctl_ckpObj
Definition XrdOss.hh:458
static const uint16_t DF_isProxy
Object is a proxy object.
Definition XrdOss.hh:434
virtual bool getErrMsg(std::string &eText)
Definition XrdOss.hh:478
static const int Fctl_QFinfo
Definition XrdOss.hh:461
virtual int Remdir(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
virtual int Unlink(const char *path, int Opts=0, XrdOucEnv *envP=0)=0
static int Format(char *buff, int blen, int ecode, const char *etxt1, const char *etxt2=0, const char *xtra=0)
char * Get(const char *varname)
Definition XrdOucEnv.hh:69
const char * getErrUser()
XrdOucEnv * getEnv()
char * getMsgBuff(int &mblen)
int setErrInfo(int code, const char *emsg)
void Reset()
Reset object to no message state. Call this method to release appendages.
int setErrCode(int code)
static void csCalc(const char *data, off_t offs, size_t count, uint32_t *csval)
static bool csVer(dataInfo &dInfo, off_t &bado, int &badc)
XrdOucTList * next
static const char * tpcDlgOn
Definition XrdOucTPC.hh:68
static const char * tpcKey
Definition XrdOucTPC.hh:58
bool Add(XrdSecAttr &attr)
XrdSecEntityAttr * eaAPI
non-const API to attributes
uint32_t * cksVec
Definition XrdSfsAio.hh:63
ssize_t Result
Definition XrdSfsAio.hh:65
virtual void doneRead()=0
struct aiocb sfsAio
Definition XrdSfsAio.hh:62
virtual void doneWrite()=0
XrdOucErrInfo & error
static const uint64_t Verify
Options for pgRead() and pgWrite() as noted below.
XrdOucErrInfo & error
@ cpTrunc
Truncate a file within checkpoint.
@ cpDelete
Delete an existing checkpoint.
@ cpRestore
Restore an active checkpoint and delete it.
@ cpWrite
Add data to an existing checkpoint.
@ cpQuery
Return checkpoint limits.
@ cpCreate
Create a checkpoint, one must not be active.
XrdSfsFile(const char *user=0, int MonID=0)
static const int uUrlOK
ucap: Supports async responses
static const int uLclF
ucap: Client is on a private net