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)
300 {if (XrdOfsFS->tryXERT && 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// Do an fsync() on this file prior to closing if it was open r/w
949//
950 if (ocFsync && hP->isRW) hP->Select().Fsync(); // Ignore errors
951
952// If this file was tagged as a POSC then we need to make sure it will persist
953// Note that we unpersist the file immediately when it's inactive or if no hold
954// time is allowed. Also, close events occur only for active handles. If the
955// entry was via delete then we ignore the close return code as there is no
956// one to handle it on the other side.
957//
958 if ((poscNum = hP->PoscGet(theMode, !viaDel)))
959 {if (viaDel)
960 {if (hP->Inactive() || !XrdOfsFS->poscHold)
961 {XrdOfsFS->Unpersist(hP, !hP->Inactive()); hP->Retire(cRetc);}
962 else hP->Retire(hCB, XrdOfsFS->poscHold);
963 return SFS_OK;
964 }
965 if ((retc = hP->Select().Fchmod(theMode)))
966 XrdOfsFS->Emsg(epname, error, retc, "fchmod", hP->Name());
967 else {XrdOfsFS->poscQ->Del(hP->Name(), poscNum);
968 if (XrdOfsFS->Balancer) XrdOfsFS->Balancer->Added(hP->Name());
969 }
970 }
971
972// Handle any oustanding checkpoint
973//
974 if (myCKP)
975 {retc = myCKP->Restore();
976 if (retc) XrdOfsFS->Emsg(epname,error,retc,"restore chkpnt",hP->Name());
977 myCKP->Finished();
978 myCKP = 0;
979 }
980
981// We need to handle the cunudrum that an event may have to be sent upon
982// the final close. However, that would cause the path name to be destroyed.
983// So, we have two modes of logic where we copy out the pathname if a final
984// close actually occurs. The path is not copied if it's not final and we
985// don't bother with any of it if we need not generate an event.
986//
987 if (XrdOfsFS->evsObject && tident
988 && XrdOfsFS->evsObject->Enabled(hP->isRW ? XrdOfsEvs::Closew
990 {long long FSize, *retsz;
991 char pathbuff[MAXPATHLEN+8];
992 XrdOfsEvs::Event theEvent;
993 if (hP->isRW) {theEvent = XrdOfsEvs::Closew; retsz = &FSize;}
994 else { theEvent = XrdOfsEvs::Closer; retsz = 0; FSize=0;}
995 if (!(hP->Retire(cRetc, retsz, pathbuff, sizeof(pathbuff))))
996 {XrdOfsEvsInfo evInfo(tident, pathbuff, "" , 0, 0, FSize);
997 XrdOfsFS->evsObject->Notify(theEvent, evInfo);
998 }
999 } else hP->Retire(cRetc);
1000
1001// All done
1002//
1003 return (cRetc ? XrdOfsFS->Emsg(epname, error, cRetc, "close file") : SFS_OK);
1004}
1005
1006/******************************************************************************/
1007/* c h e c k p o i n t */
1008/******************************************************************************/
1009
1010int XrdOfsFile::checkpoint(XrdSfsFile::cpAct act, struct iov *range, int n)
1011{
1012 EPNAME("chkpnt");
1013 const char *ckpName;
1014 int rc;
1015 bool readok;
1016
1017// Make sure we are active
1018//
1019 if (oh->Inactive()) return XrdOfsFS->Emsg(epname, error, EBADF,
1020 "handle checkpoint", (const char *)0);
1021
1022// If checkpointing is disabled, the don't accept this request.
1023//
1024 if (!XrdOfsConfigCP::Enabled) return XrdOfsFS->Emsg(epname, error, ENOTSUP,
1025 "handle disabled checkpoint", (const char *)0);
1026
1027// If this checkpoint is bad then only a delete, query or restore is allowed.
1028//
1029 if (ckpBad && (act == XrdSfsFile::cpTrunc || act == XrdSfsFile::cpWrite))
1030 return XrdOfsFS->Emsg(epname, error, EIDRM, "extend checkpoint "
1031 "(only delete or restore possible) for", oh->Name());
1032
1033// Handle the request
1034//
1035 switch(act)
1037 ckpName = "create checkpoint for";
1038 if ((rc = CreateCKP())) return rc;
1039 if ((rc = myCKP->Create())) {myCKP->Finished(); myCKP = 0;}
1040 break;
1042 ckpName = "delete checkpoint for";
1043 if (!myCKP) rc = ENOENT;
1044 else {rc = myCKP->Delete();
1045 myCKP->Finished();
1046 myCKP = 0;
1047 ckpBad = false;
1048 }
1049 break;
1051 ckpName = "query checkpoint for";
1052 if (!range || n <= 0)
1053 return XrdOfsFS->Emsg(epname, error, EINVAL,
1054 "query checkpoint limits for", oh->Name());
1055 rc = (myCKP ? myCKP->Query(*range) : ENOENT);
1056 break;
1058 ckpName = "restore checkpoint for";
1059 if (!myCKP) rc = ENOENT;
1060 else {if (!(rc = myCKP->Restore(&readok)))
1061 {myCKP->Finished();
1062 myCKP = 0;
1063 ckpBad = false;
1064 } else {
1065 if (!(oh->Select().DFType() & XrdOssDF::DF_isProxy))
1066 oh->Suppress((readok ? 0 : -EDOM));
1067 ckpBad = true;
1068 }
1069 }
1070 break;
1072 ckpName = "checkpoint truncate";
1073 if (!range) rc = EINVAL;
1074 else if (!myCKP) rc = ENOENT;
1075 else if ((rc = myCKP->Truncate(range))) ckpBad = true;
1076 break;
1078 ckpName = "checkpoint write";
1079 if (!range || n <= 0) rc = EINVAL;
1080 else if (!myCKP) rc = ENOENT;
1081 else if ((rc = myCKP->Write(range, n))) ckpBad = true;
1082 break;
1083
1084 default: return XrdOfsFS->Emsg(epname, error, EINVAL,
1085 "decode checkpoint request for", oh->Name());
1086 };
1087
1088// Complete as needed
1089//
1090 if (rc) return XrdOfsFS->Emsg(epname, error, rc, ckpName, oh->Name());
1091
1092// Trace success and return
1093//
1094 FTRACE(chkpnt, ckpName);
1095 return SFS_OK;
1096}
1097
1098/******************************************************************************/
1099/* Private: C r e a t e C K P */
1100/******************************************************************************/
1101
1102int XrdOfsFile::CreateCKP()
1103{
1104
1105// Verify that a checkpoint does not exist
1106//
1107 if (myCKP) return XrdOfsFS->Emsg("CreateCKP", error, EEXIST,
1108 "create checkpoint for", oh->Name());
1109
1110// Verify that this file is open r/w mode
1111//
1112 if (!(oh->isRW)) return XrdOfsFS->Emsg("CreateCKP", error, ENOTTY,
1113 "create checkpoint for R/O", oh->Name(),
1114 "+ofs_CreateCKP: file is not open in r/w mode");
1115
1116// POSC and checkpoints are mutally exclusive
1117//
1118 if (oh->isRW == XrdOfsHandle::opPC)
1119 return XrdOfsFS->Emsg("CreateCKP", error, ENOTTY,
1120 "create checkpoint for POSC file", oh->Name(),
1121 "+ofs_CreateCKP: POSC file cannot be checkpointed");
1122
1123// Get a new checkpoint object
1124//
1125 if (XrdOfsFS->OssIsProxy)
1126 {char *resp;
1127 int rc = oh->Select().Fctl(XrdOssDF::Fctl_ckpObj, 0, 0, &resp);
1128 if (rc) return XrdOfsFS->Emsg("CreateCKP", error, rc,
1129 "create proxy checkpoint");
1130 myCKP = (XrdOucChkPnt *)resp;
1131 } else myCKP = new XrdOfsChkPnt(oh->Select(), oh->Name());
1132
1133// All done
1134//
1135 return 0;
1136}
1137
1138/******************************************************************************/
1139/* f c t l */
1140/******************************************************************************/
1141
1142int XrdOfsFile::fctl(const int cmd,
1143 const char *args,
1144 XrdOucErrInfo &out_error)
1145{
1146// See if we can do this
1147//
1148 if (cmd == SFS_FCTL_GETFD)
1149 {out_error.setErrCode(oh->Select().getFD());
1150 return SFS_OK;
1151 }
1152
1153// We don't support this
1154//
1155 out_error.setErrInfo(ENOTSUP, "fctl operation not supported");
1156
1157// Return
1158//
1159 return SFS_ERROR;
1160}
1161
1162/******************************************************************************/
1163
1164int XrdOfsFile::fctl(const int cmd, int alen, const char *args,
1165 const XrdSecEntity *client)
1166{ // 12345678901234
1167 EPNAME("fctl");
1168 static const char *fctlArg = "ofs.tpc cancel";
1169 static const int fctlAsz = 15;
1170
1171// For QFINFO we simply pass it to the Oss layer
1172//
1173 if (cmd == SFS_FCTL_QFINFO)
1174 {char* resp = 0;;
1175 int rc = oh->Select().Fctl(XrdOssDF::Fctl_QFinfo, alen, args, &resp);
1176 if (rc < 0)
1177 {if (resp) delete[] resp;
1178 return XrdOfsFS->Emsg(epname,error,rc,"fctl",oh,false,false);
1179 }
1180 if (resp)
1181 {if ((rc = strlen(resp)))
1182 {error.setErrInfo(rc, resp);
1183 delete[] resp;
1184 return SFS_DATA;
1185 }
1186 delete[] resp;
1187 }
1188 return SFS_OK;
1189 }
1190
1191// See if the is a tpc cancellation (the only thing we support here)
1192//
1193 if (cmd != SFS_FCTL_SPEC1 || !args || alen < fctlAsz || strcmp(fctlArg,args))
1194 return XrdOfsFS->FSctl(*this, cmd, alen, args, client);
1195
1196// Check if we have a tpc operation in progress
1197//
1198 if (!myTPC)
1199 {error.setErrInfo(ESRCH, "tpc operation not found");
1200 return SFS_ERROR;
1201 }
1202
1203// Cancel the tpc
1204//
1205 myTPC->Del();
1206 myTPC = 0;
1207 return SFS_OK;
1208}
1209
1210/******************************************************************************/
1211/* p g R e a d */
1212/******************************************************************************/
1213
1215 char *buffer,
1216 XrdSfsXferSize rdlen,
1217 uint32_t *csvec,
1218 uint64_t opts)
1219{
1220 EPNAME("pgRead");
1221 XrdSfsXferSize nbytes;
1222 uint64_t pgOpts;
1223
1224// If the oss plugin does not support pgRead and we doing rawio then simulate
1225// the pgread. As this is relatively common we skip the vtable. This means
1226// this class cannot be a inherited to override the read() method.
1227//
1228 if (!XrdOfsFS->OssHasPGrw || dorawio)
1229 {if ((nbytes = XrdOfsFile::read(offset, buffer, rdlen)) > 0)
1230 XrdOucPgrwUtils::csCalc(buffer, offset, nbytes, csvec);
1231 return nbytes;
1232 }
1233
1234// Perform required tracing
1235//
1236 FTRACE(read, rdlen <<"@" <<offset);
1237
1238// Make sure the offset is not too large
1239//
1240#if _FILE_OFFSET_BITS!=64
1241 if (offset > 0x000000007fffffff)
1242 return XrdOfsFS->Emsg(epname, error, EFBIG, "pgRead", oh->Name());
1243#endif
1244
1245// Pass through any flags of interest
1246//
1248 else pgOpts = 0;
1249
1250// Now read the actual number of bytes
1251//
1252 nbytes = (XrdSfsXferSize)(oh->Select().pgRead((void *)buffer,
1253 (off_t)offset, (size_t)rdlen, csvec, pgOpts));
1254 if (nbytes < 0)
1255 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"pgRead",oh,false,false);
1256
1257// Return number of bytes read
1258//
1259 return nbytes;
1260}
1261
1262/******************************************************************************/
1263
1265{
1266 EPNAME("aiopgread");
1267 uint64_t pgOpts;
1268 int rc;
1269
1270// If the oss plugin does not support pgRead or if we are doing rawio or the
1271// file is compressed then revert to using a standard async read. Note that
1272// the standard async read will generate checksums if a vector is present.
1273// Note: we set cksVec in the request to nil to indicate simulation!
1274//
1275 if (!XrdOfsFS->OssHasPGrw || dorawio || oh->isCompressed)
1276 {aioparm->cksVec = 0;
1277 return XrdOfsFile::read(aioparm);
1278 }
1279
1280// Perform required tracing
1281//
1282 FTRACE(aio, aioparm->sfsAio.aio_nbytes <<"@" <<aioparm->sfsAio.aio_offset);
1283
1284// Make sure the offset is not too large
1285//
1286#if _FILE_OFFSET_BITS!=64
1287 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1288 return XrdOfsFS->Emsg(epname,error,-EFBIG,"pgRead",oh->Name(),0,false);
1289#endif
1290
1291// Pass through any flags of interest
1292//
1294 else pgOpts = 0;
1295
1296// Issue the read. Only true errors are returned here.
1297//
1298 if ((rc = oh->Select().pgRead(aioparm, pgOpts)) < 0)
1299 return XrdOfsFS->Emsg(epname, error, rc, "pgRead", oh, false, false);
1300
1301// All done
1302//
1303 return SFS_OK;
1304}
1305
1306/******************************************************************************/
1307/* p g W r i t e */
1308/******************************************************************************/
1309
1311 char *buffer,
1312 XrdSfsXferSize wrlen,
1313 uint32_t *csvec,
1314 uint64_t opts)
1315{
1316 EPNAME("pgWrite");
1317 XrdSfsXferSize nbytes;
1318 uint64_t pgOpts;
1319
1320// If the oss plugin does not support pgWrite revert to using a standard write.
1321//
1322 if (!XrdOfsFS->OssHasPGrw)
1323 {if ((opts & XrdSfsFile::Verify)
1324 && !VerPgw(buffer, offset, wrlen, csvec, oh, error)) return SFS_ERROR;
1325 return XrdOfsFile::write(offset, buffer, wrlen);
1326 }
1327
1328// Perform any required tracing
1329//
1330 FTRACE(write, wrlen <<"@" <<offset);
1331
1332// Make sure the offset is not too large
1333//
1334#if _FILE_OFFSET_BITS!=64
1335 if (offset > 0x000000007fffffff)
1336 return XrdOfsFS->Emsg(epname, error, -EFBIG, "pgwrite", oh, true, false);
1337#endif
1338
1339// Silly Castor stuff
1340//
1341 if (XrdOfsFS->evsObject && !(oh->isChanged)
1342 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1343
1344// Pass through any flags of interest
1345//
1347 else pgOpts = 0;
1348
1349// Write the requested bytes
1350//
1351 oh->isPending = 1;
1352 nbytes = (XrdSfsXferSize)(oh->Select().pgWrite((void *)buffer,
1353 (off_t)offset, (size_t)wrlen, csvec, pgOpts));
1354 if (nbytes < 0)
1355 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"pgwrite",oh,true,false);
1356
1357// Return number of bytes written
1358//
1359 return nbytes;
1360}
1361
1362/******************************************************************************/
1363
1365{
1366 EPNAME("aiopgWrite");
1367 uint64_t pgOpts;
1368 int rc;
1369
1370// If the oss plugin does not support pgWrite revert to using a standard write.
1371//
1372 if (!XrdOfsFS->OssHasPGrw)
1373 {if ((opts & XrdSfsFile::Verify)
1374 && !VerPgw((char *)aioparm->sfsAio.aio_buf,
1375 aioparm->sfsAio.aio_offset,
1376 aioparm->sfsAio.aio_nbytes,
1377 aioparm->cksVec, oh, error)) return SFS_ERROR;
1378 return XrdOfsFile::write(aioparm);
1379 }
1380
1381// If this is a POSC file, we must convert the async call to a sync call as we
1382// must trap any errors that unpersist the file. We can't do that via aio i/f.
1383//
1384 if (oh->isRW == XrdOfsHandle::opPC)
1385 {aioparm->Result = XrdOfsFile::pgWrite(aioparm->sfsAio.aio_offset,
1386 (char *)aioparm->sfsAio.aio_buf,
1387 aioparm->sfsAio.aio_nbytes,
1388 aioparm->cksVec, opts);
1389 aioparm->doneWrite();
1390 return SFS_OK;
1391 }
1392
1393// Perform any required tracing
1394//
1395 FTRACE(aio, aioparm->sfsAio.aio_nbytes <<"@" <<aioparm->sfsAio.aio_offset);
1396
1397// Make sure the offset is not too large
1398//
1399#if _FILE_OFFSET_BITS!=64
1400 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1401 return XrdOfsFS->Emsg(epname, error, -EFBIG, "pgwrite", oh, true, false);
1402#endif
1403
1404// Silly Castor stuff
1405//
1406 if (XrdOfsFS->evsObject && !(oh->isChanged)
1407 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1408
1409// Pass through any flags of interest
1410//
1412 else pgOpts = 0;
1413
1414// Write the requested bytes
1415//
1416 oh->isPending = 1;
1417 if ((rc = oh->Select().pgWrite(aioparm, pgOpts)) < 0)
1418 return XrdOfsFS->Emsg(epname, error, rc, "pgwrite", oh, true, false);
1419
1420// All done
1421//
1422 return SFS_OK;
1423}
1424
1425/******************************************************************************/
1426/* r e a d */
1427/******************************************************************************/
1428
1430 XrdSfsXferSize blen) // In
1431/*
1432 Function: Preread `blen' bytes at `offset'
1433
1434 Input: offset - The absolute byte offset at which to start the read.
1435 blen - The amount to preread.
1436
1437 Output: Returns SFS_OK upon success and SFS_ERROR o/w.
1438*/
1439{
1440 EPNAME("read");
1441 int retc;
1442
1443// Perform required tracing
1444//
1445 FTRACE(read, "preread " <<blen <<"@" <<offset);
1446
1447// Make sure the offset is not too large
1448//
1449#if _FILE_OFFSET_BITS!=64
1450 if (offset > 0x000000007fffffff)
1451 return XrdOfsFS->Emsg(epname,error,-EFBIG,"read",oh->Name(),0,false);
1452#endif
1453
1454// Now preread the actual number of bytes
1455//
1456 if ((retc = oh->Select().Read((off_t)offset, (size_t)blen)) < 0)
1457 return XrdOfsFS->Emsg(epname, error, (int)retc, "preread", oh, 0, false);
1458
1459// Return number of bytes read
1460//
1461 return retc;
1462}
1463
1464/******************************************************************************/
1465/* r e a d */
1466/******************************************************************************/
1467
1469 char *buff, // Out
1470 XrdSfsXferSize blen) // In
1471/*
1472 Function: Read `blen' bytes at `offset' into 'buff' and return the actual
1473 number of bytes read.
1474
1475 Input: offset - The absolute byte offset at which to start the read.
1476 buff - Address of the buffer in which to place the data.
1477 blen - The size of the buffer. This is the maximum number
1478 of bytes that will be read from 'fd'.
1479
1480 Output: Returns the number of bytes read upon success and SFS_ERROR o/w.
1481*/
1482{
1483 EPNAME("read");
1484 XrdSfsXferSize nbytes;
1485
1486// Perform required tracing
1487//
1488 FTRACE(read, blen <<"@" <<offset);
1489
1490// Make sure the offset is not too large
1491//
1492#if _FILE_OFFSET_BITS!=64
1493 if (offset > 0x000000007fffffff)
1494 return XrdOfsFS->Emsg(epname,error,-EFBIG,"read",oh->Name(),0,false);
1495#endif
1496
1497// Now read the actual number of bytes
1498//
1499 nbytes = (dorawio ?
1500 (XrdSfsXferSize)(oh->Select().ReadRaw((void *)buff,
1501 (off_t)offset, (size_t)blen))
1502 : (XrdSfsXferSize)(oh->Select().Read((void *)buff,
1503 (off_t)offset, (size_t)blen)));
1504 if (nbytes < 0)
1505 return XrdOfsFS->Emsg(epname, error, (int)nbytes, "read", oh, 0, false);
1506
1507// Return number of bytes read
1508//
1509 return nbytes;
1510}
1511
1512/******************************************************************************/
1513/* r e a d v */
1514/******************************************************************************/
1515
1517 int readCount) // In
1518/*
1519 Function: Perform all the reads specified in the readV vector.
1520
1521 Input: readV - A description of the reads to perform; includes the
1522 absolute offset, the size of the read, and the buffer
1523 to place the data into.
1524 readCount - The size of the readV vector.
1525
1526 Output: Returns the number of bytes read upon success and SFS_ERROR o/w.
1527 If the number of bytes read is less than requested, it is considered
1528 an error.
1529*/
1530{
1531 EPNAME("readv");
1532
1533 XrdSfsXferSize nbytes = oh->Select().ReadV(readV, readCount);
1534 if (nbytes < 0)
1535 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"readv",oh,false,false);
1536
1537 return nbytes;
1538
1539}
1540
1541/******************************************************************************/
1542/* r e a d A I O */
1543/******************************************************************************/
1544
1545/*
1546 Function: Read `blen' bytes at `offset' into 'buff' and return the actual
1547 number of bytes read using asynchronous I/O, if possible.
1548
1549 Output: Returns the 0 if successfullt queued, otherwise returns an error.
1550 The underlying implementation will convert the request to
1551 synchronous I/O is async mode is not possible.
1552*/
1553
1555{
1556 EPNAME("aioread");
1557 int rc;
1558
1559// Async mode for compressed files is not supported.
1560//
1561 if (oh->isCompressed)
1562 {aiop->Result = this->read((XrdSfsFileOffset)aiop->sfsAio.aio_offset,
1563 (char *)aiop->sfsAio.aio_buf,
1565 aiop->doneRead();
1566 return 0;
1567 }
1568
1569// Perform required tracing
1570//
1571 FTRACE(aio, aiop->sfsAio.aio_nbytes <<"@" <<aiop->sfsAio.aio_offset);
1572
1573// Make sure the offset is not too large
1574//
1575#if _FILE_OFFSET_BITS!=64
1576 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1577 return XrdOfsFS->Emsg(epname,error,-EFBIG,"read",oh->Name(),0,false);
1578#endif
1579
1580// Issue the read. Only true errors are returned here.
1581//
1582 if ((rc = oh->Select().Read(aiop)) < 0)
1583 return XrdOfsFS->Emsg(epname, error, rc, "read", oh, false, false);
1584
1585// All done
1586//
1587 return SFS_OK;
1588}
1589
1590/******************************************************************************/
1591/* w r i t e */
1592/******************************************************************************/
1593
1595 const char *buff, // Out
1596 XrdSfsXferSize blen) // In
1597/*
1598 Function: Write `blen' bytes at `offset' from 'buff' and return the actual
1599 number of bytes written.
1600
1601 Input: offset - The absolute byte offset at which to start the write.
1602 buff - Address of the buffer from which to get the data.
1603 blen - The size of the buffer. This is the maximum number
1604 of bytes that will be written to 'fd'.
1605
1606 Output: Returns the number of bytes written upon success and SFS_ERROR o/w.
1607
1608 Notes: An error return may be delayed until the next write(), close(), or
1609 sync() call.
1610*/
1611{
1612 EPNAME("write");
1613 XrdSfsXferSize nbytes;
1614
1615// Perform any required tracing
1616//
1617 FTRACE(write, blen <<"@" <<offset);
1618
1619// Make sure the offset is not too large
1620//
1621#if _FILE_OFFSET_BITS!=64
1622 if (offset > 0x000000007fffffff)
1623 return XrdOfsFS->Emsg(epname,error,-EFBIG,"write",oh,true,false);
1624#endif
1625
1626// Silly Castor stuff
1627//
1628 if (XrdOfsFS->evsObject && !(oh->isChanged)
1629 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1630
1631// Write the requested bytes
1632//
1633 oh->isPending = 1;
1634 nbytes = (XrdSfsXferSize)(oh->Select().Write((const void *)buff,
1635 (off_t)offset, (size_t)blen));
1636 if (nbytes < 0)
1637 return XrdOfsFS->Emsg(epname,error,(int)nbytes,"write",oh,true,false);
1638
1639// Return number of bytes written
1640//
1641 return nbytes;
1642}
1643
1644/******************************************************************************/
1645/* w r i t e A I O */
1646/******************************************************************************/
1647
1648// For now, this reverts to synchronous I/O
1649//
1651{
1652 EPNAME("aiowrite");
1653 int rc;
1654
1655// Perform any required tracing
1656//
1657 FTRACE(aio, aiop->sfsAio.aio_nbytes <<"@" <<aiop->sfsAio.aio_offset);
1658
1659// If this is a POSC file, we must convert the async call to a sync call as we
1660// must trap any errors that unpersist the file. We can't do that via aio i/f.
1661//
1662 if (oh->isRW == XrdOfsHandle::opPC)
1663 {aiop->Result = this->write(aiop->sfsAio.aio_offset,
1664 (const char *)aiop->sfsAio.aio_buf,
1665 aiop->sfsAio.aio_nbytes);
1666 aiop->doneWrite();
1667 return 0;
1668 }
1669
1670// Make sure the offset is not too large
1671//
1672#if _FILE_OFFSET_BITS!=64
1673 if (aiop->sfsAio.aio_offset > 0x000000007fffffff)
1674 return XrdOfsFS->Emsg(epname, error, -EFBIG, "write", oh, true, false);
1675#endif
1676
1677// Silly Castor stuff
1678//
1679 if (XrdOfsFS->evsObject && !(oh->isChanged)
1680 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1681
1682// Write the requested bytes
1683//
1684 oh->isPending = 1;
1685 if ((rc = oh->Select().Write(aiop)) < 0)
1686 return XrdOfsFS->Emsg(epname, error, rc, "write", oh, true, false);
1687
1688// All done
1689//
1690 return SFS_OK;
1691}
1692
1693/******************************************************************************/
1694/* g e t M m a p */
1695/******************************************************************************/
1696
1697int XrdOfsFile::getMmap(void **Addr, off_t &Size) // Out
1698/*
1699 Function: Return memory mapping for file, if any.
1700
1701 Output: Addr - Address of memory location
1702 Size - Size of the file or zero if not memory mapped.
1703 Returns SFS_OK upon success and SFS_ERROR upon failure.
1704*/
1705{
1706
1707// Perform the function
1708//
1709 Size = oh->Select().getMmap(Addr);
1710
1711 return SFS_OK;
1712}
1713
1714/******************************************************************************/
1715/* s t a t */
1716/******************************************************************************/
1717
1718int XrdOfsFile::stat(struct stat *buf) // Out
1719/*
1720 Function: Return file status information
1721
1722 Input: buf - The stat structiure to hold the results
1723
1724 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1725*/
1726{
1727 EPNAME("fstat");
1728 int retc;
1729
1730// Perform any required tracing
1731//
1732 FTRACE(stat, "");
1733
1734// Perform the function
1735//
1736 if ((retc = oh->Select().Fstat(buf)) < 0)
1737 return XrdOfsFS->Emsg(epname,error,retc,"get state for",oh);
1738
1739 return SFS_OK;
1740}
1741
1742/******************************************************************************/
1743/* s y n c */
1744/******************************************************************************/
1745
1747/*
1748 Function: Commit all unwritten bytes to physical media.
1749
1750 Input: n/a
1751
1752 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1753*/
1754{
1755 EPNAME("sync");
1756 int retc;
1757
1758// Perform any required tracing
1759//
1760 FTRACE(sync, "");
1761
1762// If we have a tpc object hanging about, we need to dispatch that first
1763//
1764 if (myTPC && (retc = myTPC->Sync(&error))) return retc;
1765
1766// We can test the pendio flag w/o a lock because the person doing this
1767// sync must have done the previous write. Causality is the synchronizer.
1768//
1769 if (!(oh->isPending)) return SFS_OK;
1770
1771// We can also skip the sync if the file is closed. However, we need a file
1772// object lock in order to test the flag. We can also reset the PENDIO flag.
1773//
1774 oh->Lock();
1775 oh->isPending = 0;
1776 oh->UnLock();
1777
1778// Perform the function
1779//
1780 if ((retc = oh->Select().Fsync()))
1781 {oh->isPending = 1;
1782 return XrdOfsFS->Emsg(epname, error, retc, "synchronize", oh, true);
1783 }
1784
1785// Indicate all went well
1786//
1787 return SFS_OK;
1788}
1789
1790/******************************************************************************/
1791/* s y n c A I O */
1792/******************************************************************************/
1793
1794// For now, reverts to synchronous case. This must also be the case for POSC!
1795//
1797{
1798 aiop->Result = this->sync();
1799 aiop->doneWrite();
1800 return 0;
1801}
1802
1803/******************************************************************************/
1804/* t r u n c a t e */
1805/******************************************************************************/
1806
1808/*
1809 Function: Set the length of the file object to 'flen' bytes.
1810
1811 Input: flen - The new size of the file.
1812
1813 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1814
1815 Notes: If 'flen' is smaller than the current size of the file, the file
1816 is made smaller and the data past 'flen' is discarded. If 'flen'
1817 is larger than the current size of the file, a hole is created
1818 (i.e., the file is logically extended by filling the extra bytes
1819 with zeroes).
1820*/
1821{
1822 EPNAME("trunc");
1823 int retc;
1824
1825// Lock the file handle and perform any tracing
1826//
1827 FTRACE(truncate, "len=" <<flen);
1828
1829// Make sure the offset is not too large
1830//
1831 if (sizeof(off_t) < sizeof(flen) && flen > 0x000000007fffffff)
1832 return XrdOfsFS->Emsg(epname, error, EFBIG, "truncate", oh, true);
1833
1834// Silly Castor stuff
1835//
1836 if (XrdOfsFS->evsObject && !(oh->isChanged)
1837 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Fwrite)) GenFWEvent();
1838
1839// Perform the function
1840//
1841 oh->isPending = 1;
1842 if ((retc = oh->Select().Ftruncate(flen)))
1843 return XrdOfsFS->Emsg(epname, error, retc, "truncate", oh, true);
1844
1845// Indicate Success
1846//
1847 return SFS_OK;
1848}
1849
1850/******************************************************************************/
1851/* g e t C X i n f o */
1852/******************************************************************************/
1853
1854int XrdOfsFile::getCXinfo(char cxtype[4], int &cxrsz)
1855/*
1856 Function: Set the length of the file object to 'flen' bytes.
1857
1858 Input: n/a
1859
1860 Output: cxtype - Compression algorithm code
1861 cxrsz - Compression region size
1862
1863 Returns SFS_OK upon success and SFS_ERROR upon failure.
1864*/
1865{
1866
1867// Copy out the info
1868//
1869 cxrsz = oh->Select().isCompressed(cxtype);
1870 return SFS_OK;
1871}
1872
1873/******************************************************************************/
1874/* P r i v a t e F i l e M e t h o d s */
1875/******************************************************************************/
1876/******************************************************************************/
1877/* protected G e n F W E v e n t */
1878/******************************************************************************/
1879
1880void XrdOfsFile::GenFWEvent()
1881{
1882 int first_write;
1883
1884// This silly code is to generate a 1st write event which slows things down
1885// but is needed by the one and only Castor. What a big sigh!
1886//
1887 oh->Lock();
1888 if ((first_write = !(oh->isChanged))) oh->isChanged = 1;
1889 oh->UnLock();
1890 if (first_write)
1891 {XrdOfsEvsInfo evInfo(tident, oh->Name());
1892 XrdOfsFS->evsObject->Notify(XrdOfsEvs::Fwrite, evInfo);
1893 }
1894}
1895
1896/******************************************************************************/
1897/* */
1898/* 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 */
1899/* */
1900/******************************************************************************/
1901/******************************************************************************/
1902/* c h k s u m */
1903/******************************************************************************/
1904
1905int XrdOfs::chksum( csFunc Func, // In
1906 const char *csName, // In
1907 const char *Path, // In
1908 XrdOucErrInfo &einfo, // Out
1909 const XrdSecEntity *client, // In
1910 const char *opaque) // In
1911/*
1912 Function: Compute and return file checksum.
1913
1914 Input: Func - Function to be performed:
1915 csCalc - Return precomputed or computed checksum.
1916 csGet - Return precomputed checksum.
1917 csSize - Verify csName and get its size.
1918 Path - Pathname of file for csCalc and csSize.
1919 einfo - Error information object to hold error details.
1920 client - Authentication credentials, if any.
1921 opaque - Opaque information to be used as seen fit.
1922
1923 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
1924*/
1925{
1926 EPNAME("chksum");
1927 XrdOucEnv cksEnv(opaque,0,client);
1928 XrdCksData cksData;
1929 const char *tident = einfo.getErrUser();
1930 char buff[MAXPATHLEN+8];
1931 int rc;
1932
1933// Check if we support checksumming
1934//
1935 if (!Cks)
1936 {einfo.setErrInfo(ENOTSUP, "Checksums are not supported.");
1937 return SFS_ERROR;
1938 }
1939
1940// A csSize request is issued usually once to verify everything is working. We
1941// take this opportunity to also verify the checksum name.
1942//
1943 rc = cksData.Set(csName);
1944 if (!rc || Func == XrdSfsFileSystem::csSize)
1945 {if (rc && (rc = Cks->Size(csName)))
1946 {einfo.setErrCode(rc); return SFS_OK;}
1947 strcpy(buff, csName); strcat(buff, " checksum not supported.");
1948 einfo.setErrInfo(ENOTSUP, buff);
1949 return SFS_ERROR;
1950 }
1951
1952// Everything else requires a path
1953//
1954 if (!Path)
1955 {strcpy(buff, csName);
1956 strcat(buff, " checksum path not specified.");
1957 einfo.setErrInfo(EINVAL, buff);
1958 return SFS_ERROR;
1959 }
1960
1961// Apply security, as needed
1962//
1963 XTRACE(stat, Path, csName);
1964 AUTHORIZE(client,&cksEnv,AOP_Stat,"checksum",Path,einfo);
1965
1966// If we are a menager then we need to redirect the client to where the file is
1967//
1968 if (CksRdr && Finder && Finder->isRemote()
1969 && (rc = Finder->Locate(einfo, Path, SFS_O_RDONLY, &cksEnv)))
1970 return fsError(einfo, rc);
1971
1972// At this point we need to convert the lfn to a pfn
1973//
1974 if (CksPfn && !(Path = XrdOfsOss->Lfn2Pfn(Path, buff, MAXPATHLEN, rc)))
1975 return Emsg(epname, einfo, rc, "checksum", Path,
1976 "+ofs_chksum: lfn to pfn mapping failed");
1977
1978// Originally we only passed he env pointer for proxy servers. Due to popular
1979// demand, we always pass the env as it points to the SecEntity object unless
1980// we don't have it then we pass the caller's environment.
1981//
1983 {if (client) cksData.envP = &cksEnv;
1984 else cksData.envP = (einfo.getEnv() ? einfo.getEnv() : &cksEnv);
1985 }
1986
1987// Now determine what to do
1988//
1989 if (Func == XrdSfsFileSystem::csCalc) rc = Cks->Calc(Path, cksData);
1990 else if (Func == XrdSfsFileSystem::csGet) rc = Cks->Get( Path, cksData);
1991 else {einfo.setErrInfo(EINVAL, "Invalid checksum function.");
1992 return SFS_ERROR;
1993 }
1994
1995// See if all went well
1996//
1997#ifdef ENOATTR
1998 if (rc >= 0 || rc == -ENOATTR || rc == -ESTALE || rc == -ESRCH)
1999#else
2000 if (rc >= 0 || rc == -ENODATA || rc == -ESTALE || rc == -ESRCH)
2001#endif
2002 {if (rc >= 0) {cksData.Get(buff, MAXPATHLEN); rc = 0;}
2003 else {*buff = 0; rc = -rc;}
2004 einfo.setErrInfo(rc, buff);
2005 return SFS_OK;
2006 }
2007
2008// We failed
2009//
2010 return Emsg(epname, einfo, rc, "checksum", Path, "?");
2011}
2012
2013/******************************************************************************/
2014/* c h m o d */
2015/******************************************************************************/
2016
2017int XrdOfs::chmod(const char *path, // In
2018 XrdSfsMode Mode, // In
2019 XrdOucErrInfo &einfo, // Out
2020 const XrdSecEntity *client, // In
2021 const char *info) // In
2022/*
2023 Function: Change the mode on a file or directory.
2024
2025 Input: path - Is the fully qualified name of the file to be removed.
2026 einfo - Error information object to hold error details.
2027 client - Authentication credentials, if any.
2028 info - Opaque information to be used as seen fit.
2029
2030 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2031*/
2032{
2033 EPNAME("chmod");
2034 static const int locFlags = SFS_O_RDWR|SFS_O_META;
2035 struct stat Stat;
2036 mode_t acc_mode = Mode & S_IAMB;
2037 const char *tident = einfo.getErrUser();
2038 XrdOucEnv chmod_Env(info,0,client);
2039 int retc;
2040 XTRACE(chmod, path, "");
2041
2042// Apply security, as needed
2043//
2044 AUTHORIZE(client,&chmod_Env,AOP_Chmod,"chmod",path,einfo);
2045
2046// Find out where we should chmod this file
2047//
2048 if (Finder && Finder->isRemote())
2049 {if (fwdCHMOD.Cmd)
2050 {char buff[8];
2051 sprintf(buff, "%o", static_cast<int>(acc_mode));
2052 if (Forward(retc,einfo,fwdCHMOD,path,buff,&chmod_Env)) return retc;
2053 }
2054 else if ((retc = Finder->Locate(einfo, path, locFlags, &chmod_Env)))
2055 return fsError(einfo, retc);
2056 }
2057
2058// We need to adjust the mode based on whether this is a file or directory.
2059//
2060 if ((retc = XrdOfsOss->Stat(path, &Stat, 0, &chmod_Env)))
2061 return XrdOfsFS->Emsg(epname, einfo, retc, "stat", path, "?");
2062 if (S_ISDIR(Stat.st_mode)) acc_mode = (acc_mode | dMask[0]) & dMask[1];
2063 else acc_mode = (acc_mode | fMask[0]) & fMask[1];
2064
2065// Check if we should generate an event
2066//
2067 if (evsObject && evsObject->Enabled(XrdOfsEvs::Chmod))
2068 {XrdOfsEvsInfo evInfo(tident, path, info, &chmod_Env, acc_mode);
2069 evsObject->Notify(XrdOfsEvs::Chmod, evInfo);
2070 }
2071
2072// Now try to find the file or directory
2073//
2074 if (!(retc = XrdOfsOss->Chmod(path, acc_mode, &chmod_Env))) return SFS_OK;
2075
2076// An error occurred, return the error info
2077//
2078 return XrdOfsFS->Emsg(epname, einfo, retc, "chmod", path, "?");
2079}
2080
2081/******************************************************************************/
2082/* C o n n e c t */
2083/******************************************************************************/
2084
2086{
2087 XrdOucEnv myEnv(0, 0, client);
2088
2089// Pass this call along
2090//
2091 XrdOfsOss->Connect(myEnv);
2092}
2093
2094/******************************************************************************/
2095/* D i s c */
2096/******************************************************************************/
2097
2098void XrdOfs::Disc(const XrdSecEntity *client)
2099{
2100 XrdOucEnv myEnv(0, 0, client);
2101
2102// Pass this call along
2103//
2104 XrdOfsOss->Disc(myEnv);
2105}
2106
2107/******************************************************************************/
2108/* e x i s t s */
2109/******************************************************************************/
2110
2111int XrdOfs::exists(const char *path, // In
2112 XrdSfsFileExistence &file_exists, // Out
2113 XrdOucErrInfo &einfo, // Out
2114 const XrdSecEntity *client, // In
2115 const char *info) // In
2116/*
2117 Function: Determine if file 'path' actually exists.
2118
2119 Input: path - Is the fully qualified name of the file to be tested.
2120 file_exists - Is the address of the variable to hold the status of
2121 'path' when success is returned. The values may be:
2122 XrdSfsFileExistsIsDirectory - file not found but path is valid.
2123 XrdSfsFileExistsIsFile - file found.
2124 XrdSfsFileExistsIsNo - neither file nor directory.
2125 einfo - Error information object holding the details.
2126 client - Authentication credentials, if any.
2127 info - Opaque information to be used as seen fit.
2128
2129 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2130
2131 Notes: When failure occurs, 'file_exists' is not modified.
2132*/
2133{
2134 EPNAME("exists");
2135 struct stat fstat;
2136 int retc;
2137 const char *tident = einfo.getErrUser();
2138 XrdOucEnv stat_Env(info,0,client);
2139 XTRACE(exists, path, "");
2140
2141// Apply security, as needed
2142//
2143 AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
2144
2145// Find out where we should stat this file
2146//
2147 if (Finder && Finder->isRemote()
2148 && (retc = Finder->Locate(einfo, path, SFS_O_RDONLY, &stat_Env)))
2149 return fsError(einfo, retc);
2150
2151// Now try to find the file or directory
2152//
2153 retc = XrdOfsOss->Stat(path, &fstat, 0, &stat_Env);
2154 if (!retc)
2155 { if (S_ISDIR(fstat.st_mode)) file_exists=XrdSfsFileExistIsDirectory;
2156 else if (S_ISREG(fstat.st_mode)) file_exists=XrdSfsFileExistIsFile;
2157 else file_exists=XrdSfsFileExistNo;
2158 return SFS_OK;
2159 }
2160 if (retc == -ENOENT)
2161 {file_exists=XrdSfsFileExistNo;
2162 return SFS_OK;
2163 }
2164
2165// An error occurred, return the error info
2166//
2167 return XrdOfsFS->Emsg(epname, einfo, retc, "locate", path, "?");
2168}
2169
2170/******************************************************************************/
2171/* g e t S t a t s */
2172/******************************************************************************/
2173
2174int XrdOfs::getStats(char *buff, int blen)
2175{
2176 int n;
2177
2178// See if the size just wanted
2179//
2180 if (!buff) return OfsStats.Report(0,0) + XrdOfsOss->Stats(0,0);
2181
2182// Report ofs info followed by the oss info
2183//
2184 n = OfsStats.Report(buff, blen);
2185 buff += n; blen -= n;
2186 n += XrdOfsOss->Stats(buff, blen);
2187
2188// All done
2189//
2190 return n;
2191}
2192
2193/******************************************************************************/
2194/* m k d i r */
2195/******************************************************************************/
2196
2197int XrdOfs::mkdir(const char *path, // In
2198 XrdSfsMode Mode, // In
2199 XrdOucErrInfo &einfo, // Out
2200 const XrdSecEntity *client, // In
2201 const char *info) // In
2202/*
2203 Function: Create a directory entry.
2204
2205 Input: path - Is the fully qualified name of the file to be removed.
2206 Mode - Is the POSIX mode value the directory is to have.
2207 Additionally, Mode may contain SFS_O_MKPTH if the
2208 full dircectory path should be created.
2209 einfo - Error information object to hold error details.
2210 client - Authentication credentials, if any.
2211 info - Opaque information to be used as seen fit.
2212
2213 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2214*/
2215{
2216 EPNAME("mkdir");
2217 static const int LocOpts = SFS_O_RDWR | SFS_O_CREAT | SFS_O_META;
2218 mode_t acc_mode = (Mode | dMask[0]) & dMask[1];
2219 int retc, mkpath = Mode & SFS_O_MKPTH;
2220 const char *tident = einfo.getErrUser();
2221 XrdOucEnv mkdir_Env(info,0,client);
2222 XTRACE(mkdir, path, "");
2223
2224// Apply security, as needed
2225//
2226 AUTHORIZE(client,&mkdir_Env,AOP_Mkdir,"mkdir",path,einfo);
2227
2228// Find out where we should remove this file
2229//
2230 if (Finder && Finder->isRemote())
2231 {if (fwdMKDIR.Cmd)
2232 {char buff[8];
2233 sprintf(buff, "%o", static_cast<int>(acc_mode));
2234 if (Forward(retc, einfo, (mkpath ? fwdMKPATH:fwdMKDIR),
2235 path, buff, &mkdir_Env)) return retc;
2236 }
2237 else if ((retc = Finder->Locate(einfo,path,LocOpts,&mkdir_Env)))
2238 return fsError(einfo, retc);
2239 }
2240
2241// Perform the actual operation
2242//
2243 if ((retc = XrdOfsOss->Mkdir(path, acc_mode, mkpath, &mkdir_Env)))
2244 return XrdOfsFS->Emsg(epname, einfo, retc, "mkdir", path, "?");
2245
2246// Check if we should generate an event
2247//
2248 if (evsObject && evsObject->Enabled(XrdOfsEvs::Mkdir))
2249 {XrdOfsEvsInfo evInfo(tident, path, info, &mkdir_Env, acc_mode);
2250 evsObject->Notify(XrdOfsEvs::Mkdir, evInfo);
2251 }
2252
2253// If we have a redirector, tell it that we now have this path
2254//
2255 if (Balancer)
2256 {if (!mkpath) Balancer->Added(path);
2257 else {char *slash, *myPath = strdup(path);
2258 do {Balancer->Added(myPath);
2259 if ((slash = rindex(myPath, '/'))) *slash = 0;
2260 } while(slash && slash != myPath);
2261 free(myPath);
2262 }
2263 }
2264
2265 return SFS_OK;
2266}
2267
2268/******************************************************************************/
2269/* p r e p a r e */
2270/******************************************************************************/
2271
2272int XrdOfs::prepare( XrdSfsPrep &pargs, // In
2273 XrdOucErrInfo &out_error, // Out
2274 const XrdSecEntity *client) // In
2275{
2276 EPNAME("prepare");
2277 XrdOucEnv prep_Env(0,0,client);
2278 XrdOucTList *tp = pargs.paths;
2279 int retc;
2280
2281// Run through the paths to make sure client can read each one unless we aren't
2282// supposed to apply authorization.
2283//
2284 if (prepAuth)
2285 while(tp)
2286 {AUTHORIZE(client,0,AOP_Read,"prepare",tp->text,out_error);
2287 tp = tp->next;
2288 }
2289
2290// If there is a prepare plugin, invoke it and return the result.
2291//
2292 if (prepHandler)
2293 {if (pargs.opts & Prep_QUERY)
2294 return prepHandler->query(pargs, out_error, client);
2295 if (pargs.opts & Prep_CANCEL)
2296 return prepHandler->cancel(pargs, out_error, client);
2297
2298 return prepHandler->begin(pargs, out_error, client);
2299 }
2300
2301// If we have a finder object, use it to prepare the paths. Otherwise,
2302// ignore this prepare request (we may change this in the future).
2303//
2304 if (XrdOfsFS->Finder
2305 && (retc = XrdOfsFS->Finder->Prepare(out_error, pargs, &prep_Env)))
2306 return fsError(out_error, retc);
2307 return 0;
2308}
2309
2310/******************************************************************************/
2311/* r e m o v e */
2312/******************************************************************************/
2313
2314int XrdOfs::remove(const char type, // In
2315 const char *path, // In
2316 XrdOucErrInfo &einfo, // Out
2317 const XrdSecEntity *client, // In
2318 const char *info) // In
2319/*
2320 Function: Delete a file from the namespace and release it's data storage.
2321
2322 Input: type - 'f' for file and 'd' for directory.
2323 path - Is the fully qualified name of the file to be removed.
2324 einfo - Error information object to hold error details.
2325 client - Authentication credentials, if any.
2326 info - Opaque information to be used as seen fit.
2327
2328 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2329*/
2330{
2331 EPNAME("remove");
2332 static const int LocOpts = SFS_O_WRONLY|SFS_O_META;
2333 int retc, Opt;
2334 const char *tident = einfo.getErrUser();
2335 XrdOucEnv rem_Env(info,0,client);
2336 XTRACE(remove, path, type);
2337
2338// Apply security, as needed
2339//
2340 AUTHORIZE(client,&rem_Env,AOP_Delete,"remove",path,einfo);
2341
2342// Find out where we should remove this file
2343//
2344 if (Finder && Finder->isRemote())
2345 {struct fwdOpt *fSpec = (type == 'd' ? &fwdRMDIR : &fwdRM);
2346 if (fSpec->Cmd)
2347 {if (Forward(retc, einfo, *fSpec, path, 0, &rem_Env)) return retc;}
2348 else if ((retc = Finder->Locate(einfo, path, LocOpts, &rem_Env)))
2349 return fsError(einfo, retc);
2350 }
2351
2352// Check if we should generate an event
2353//
2354 if (evsObject)
2355 {XrdOfsEvs::Event theEvent=(type == 'd' ? XrdOfsEvs::Rmdir:XrdOfsEvs::Rm);
2356 if (evsObject->Enabled(theEvent))
2357 {XrdOfsEvsInfo evInfo(tident, path, info, &rem_Env);
2358 evsObject->Notify(theEvent, evInfo);
2359 }
2360 }
2361
2362// Check if this is an online deletion only
2363//
2364 Opt = (rem_Env.Get("ofs.lcl") ? XRDOSS_Online : 0);
2365
2366// Perform the actual deletion
2367//
2368 retc = (type=='d' ? XrdOfsOss->Remdir(path, 0, &rem_Env)
2369 : XrdOfsOss->Unlink(path, Opt, &rem_Env));
2370 if (retc) return XrdOfsFS->Emsg(epname, einfo, retc, "remove", path, "?");
2371 if (type == 'f') XrdOfsHandle::Hide(path);
2372 if (Balancer) Balancer->Removed(path);
2373 return SFS_OK;
2374}
2375
2376/******************************************************************************/
2377/* r e n a m e */
2378/******************************************************************************/
2379
2380int XrdOfs::rename(const char *old_name, // In
2381 const char *new_name, // In
2382 XrdOucErrInfo &einfo, //Out
2383 const XrdSecEntity *client, // In
2384 const char *infoO, // In
2385 const char *infoN) // In
2386/*
2387 Function: Renames a file with name 'old_name' to 'new_name'.
2388
2389 Input: old_name - Is the fully qualified name of the file to be renamed.
2390 new_name - Is the fully qualified name that the file is to have.
2391 einfo - Error information structure, if an error occurs.
2392 client - Authentication credentials, if any.
2393 infoO - old_name opaque information to be used as seen fit.
2394 infoN - new_name opaque information to be used as seen fit.
2395
2396 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2397*/
2398{
2399 EPNAME("rename");
2400 static const int LocOpts = SFS_O_RDWR|SFS_O_META;
2401 int retc;
2402 const char *tident = einfo.getErrUser();
2403 XrdOucEnv old_Env(infoO,0,client);
2404 XrdOucEnv new_Env(infoN,0,client);
2405 XTRACE(rename, new_name, "old fn=" <<old_name <<" new ");
2406
2407// Apply security, as needed
2408//
2409 AUTHORIZE(client, &old_Env, AOP_Rename, "renaming", old_name, einfo);
2410
2411// The above authorization may mutate the XrdSecEntity by putting a mapped name
2412// into the extended attributes. This mapped name will affect the subsequent
2413// authorization check below, giving the client access that may not be permitted.
2414// Hence, we delete this attribute to reset the object back to "pristine" state.
2415// If there was a way to make a copy of the XrdSecEntity, we could avoid this
2416// hack-y reach inside the extended attributes.
2417 if (client) client->eaAPI->Add("request.name", "", true);
2418
2419// If we do not have full-blown insert authorization, we'll need to test for
2420// destination existence
2421 bool cannot_overwrite = false;
2422 if (client && XrdOfsFS->Authorization &&
2423 !XrdOfsFS->Authorization->Access(client, new_name, AOP_Insert, &new_Env))
2424 {cannot_overwrite = true;
2425 AUTHORIZE(client, &new_Env, AOP_Excl_Insert,
2426 "rename to existing file (overwrite disallowed)", new_name, einfo);
2427 }
2428
2429// Find out where we should rename this file
2430//
2431 if (Finder && Finder->isRemote())
2432 {if (fwdMV.Cmd)
2433 {if (Forward(retc,einfo,fwdMV,old_name,new_name,&old_Env,&new_Env))
2434 return retc;
2435 }
2436 else if ((retc = Finder->Locate(einfo, old_name, LocOpts, &old_Env)))
2437 return fsError(einfo, retc);
2438 }
2439
2440// Check if we should generate an event
2441//
2442 if (evsObject && evsObject->Enabled(XrdOfsEvs::Mv))
2443 {XrdOfsEvsInfo evInfo(tident, old_name, infoO, &old_Env, 0, 0,
2444 new_name, infoN, &new_Env);
2445 evsObject->Notify(XrdOfsEvs::Mv, evInfo);
2446 }
2447
2448// If we cannot overwrite, we must test for existence first. This will test whether
2449// we will destroy data in the rename (without actually destroying data).
2450// Note there's an obvious race condition here; it was seen as the lesser-of-evils
2451// compared to creating an exclusive file and potentially leaking it in the event
2452// of a crash.
2453//
2454 if (cannot_overwrite)
2456 if (SFS_OK != exists(new_name, exists_flag, einfo, client, infoN))
2457 {// File existence check itself failed; we can't prove that data won't
2458 // be overwritten so we return an error.
2459 return fsError(einfo, -einfo.getErrInfo());
2460 }
2461 if (exists_flag != XrdSfsFileExistNo)
2462 {// EPERM mimics the error code set by Linux when you invoke rename()
2463 // but cannot overwrite the destination file.
2464 einfo.setErrInfo(EPERM, "Overwrite of existing data not permitted");
2465 return fsError(einfo, -EPERM);
2466 }
2467 }
2468
2469// Perform actual rename operation
2470//
2471 if ((retc = XrdOfsOss->Rename(old_name, new_name, &old_Env, &new_Env)))
2472 {return XrdOfsFS->Emsg(epname, einfo, retc, "rename", old_name, "?");
2473 }
2474 XrdOfsHandle::Hide(old_name);
2475 if (Balancer) {Balancer->Removed(old_name);
2476 Balancer->Added(new_name);
2477 }
2478 return SFS_OK;
2479}
2480
2481/******************************************************************************/
2482/* s t a t */
2483/******************************************************************************/
2484
2485int XrdOfs::stat(const char *path, // In
2486 struct stat *buf, // Out
2487 XrdOucErrInfo &einfo, // Out
2488 const XrdSecEntity *client, // In
2489 const char *info) // In
2490/*
2491 Function: Return file status information
2492
2493 Input: path - The path for which status is wanted
2494 buf - The stat structure to hold the results
2495 einfo - Error information structure, if an error occurs.
2496 client - Authentication credentials, if any.
2497 info - opaque information to be used as seen fit.
2498
2499 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2500*/
2501{
2502 EPNAME("stat");
2503 int retc;
2504 const char *tident = einfo.getErrUser();
2505 XrdOucEnv stat_Env(info,0,client);
2506 XTRACE(stat, path, "");
2507
2508// Apply security, as needed
2509//
2510 AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
2511
2512// Find out where we should stat this file
2513//
2514 if (Finder && Finder->isRemote()
2515 && (retc = Finder->Locate(einfo, path, SFS_O_RDONLY|SFS_O_STAT, &stat_Env)))
2516 return fsError(einfo, retc);
2517
2518// Now try to find the file or directory
2519//
2520 if ((retc = XrdOfsOss->Stat(path, buf, 0, &stat_Env)))
2521 return XrdOfsFS->Emsg(epname, einfo, retc, "locate", path, "?");
2522 return SFS_OK;
2523}
2524
2525/******************************************************************************/
2526
2527int XrdOfs::stat(const char *path, // In
2528 mode_t &mode, // Out
2529 XrdOucErrInfo &einfo, // Out
2530 const XrdSecEntity *client, // In
2531 const char *info) // In
2532/*
2533 Function: Return file status information (resident files only)
2534
2535 Input: path - The path for which status is wanted
2536 mode - The stat mode entry (faked -- do not trust it)
2537 einfo - Error information structure, if an error occurs.
2538 client - Authentication credentials, if any.
2539 info - opaque information to be used as seen fit.
2540
2541 Output: Always returns SFS_ERROR if a delay needs to be imposed. Otherwise,
2542 SFS_OK is returned and mode is appropriately, if inaccurately, set.
2543 If file residency cannot be determined, mode is set to -1.
2544*/
2545{
2546 EPNAME("stat");
2547 struct stat buf;
2548 int retc;
2549 const char *tident = einfo.getErrUser();
2550 XrdOucEnv stat_Env(info,0,client);
2551 XTRACE(stat, path, "");
2552
2553// Apply security, as needed
2554//
2555 AUTHORIZE(client,&stat_Env,AOP_Stat,"locate",path,einfo);
2556 mode = (mode_t)-1;
2557
2558// Find out where we should stat this file
2559//
2560 if (Finder && Finder->isRemote()
2561 && (retc = Finder->Locate(einfo,path,SFS_O_NOWAIT|SFS_O_RDONLY|SFS_O_STAT,
2562 &stat_Env)))
2563 return fsError(einfo, retc);
2564
2565// Now try to find the file or directory
2566//
2567 if (!(retc = XrdOfsOss->Stat(path, &buf, XRDOSS_resonly, &stat_Env)))
2568 mode=buf.st_mode;
2569 else if ((-ENOMSG) != retc)
2570 return XrdOfsFS->Emsg(epname, einfo, retc, "locate", path, "?");
2571 return SFS_OK;
2572}
2573
2574/******************************************************************************/
2575/* t r u n c a t e */
2576/******************************************************************************/
2577
2578int XrdOfs::truncate(const char *path, // In
2579 XrdSfsFileOffset Size, // In
2580 XrdOucErrInfo &einfo, // Out
2581 const XrdSecEntity *client, // In
2582 const char *info) // In
2583/*
2584 Function: Change the mode on a file or directory.
2585
2586 Input: path - Is the fully qualified name of the file to be removed.
2587 Size - the size the file should have.
2588 einfo - Error information object to hold error details.
2589 client - Authentication credentials, if any.
2590 info - Opaque information to be used as seen fit.
2591
2592 Output: Returns SFS_OK upon success and SFS_ERROR upon failure.
2593*/
2594{
2595 EPNAME("truncate");
2596 const char *tident = einfo.getErrUser();
2597 XrdOucEnv trunc_Env(info,0,client);
2598 int retc;
2599 XTRACE(truncate, path, "");
2600
2601// Apply security, as needed
2602//
2603 AUTHORIZE(client,&trunc_Env,AOP_Update,"truncate",path,einfo);
2604
2605// Find out where we should chmod this file
2606//
2607 if (Finder && Finder->isRemote())
2608 {if (fwdTRUNC.Cmd)
2609 {char xSz[32];
2610 sprintf(xSz, "%lld", static_cast<long long>(Size));
2611 if (Forward(retc,einfo,fwdTRUNC,path,xSz,&trunc_Env)) return retc;
2612 }
2613 else if ((retc = Finder->Locate(einfo,path,SFS_O_RDWR,&trunc_Env)))
2614 return fsError(einfo, retc);
2615 }
2616
2617// Check if we should generate an event
2618//
2619 if (evsObject && evsObject->Enabled(XrdOfsEvs::Trunc))
2620 {XrdOfsEvsInfo evInfo(tident, path, info, &trunc_Env, 0, Size);
2621 evsObject->Notify(XrdOfsEvs::Trunc, evInfo);
2622 }
2623
2624// Now try to find the file or directory
2625//
2626 if (!(retc = XrdOfsOss->Truncate(path, Size, &trunc_Env))) return SFS_OK;
2627
2628// An error occurred, return the error info
2629//
2630 return XrdOfsFS->Emsg(epname, einfo, retc, "trunc", path, "?");
2631}
2632
2633/******************************************************************************/
2634/* E m s g */
2635/******************************************************************************/
2636
2637int XrdOfs::Emsg(const char *pfx, // Message prefix value
2638 XrdOucErrInfo &einfo, // Place to put text & error code
2639 int ecode, // The error code
2640 const char *op, // Operation being performed
2641 XrdOfsHandle *hP, // The target handle
2642 bool posChk, // Unpersist if in posc mode
2643 bool chkType)// Check for type of error & subclass
2644{
2645 const char* etP = 0;
2646 int rc;
2647
2648// Screen out non-errors
2649//
2650 if (chkType && (rc = EmsgType(ecode)) != SFS_ERROR) return rc;
2651
2652// Get any extended information
2653//
2654 std::string eText;
2655 if (XrdOfsFS->tryXERT && hP->Select().getErrMsg(eText)) etP = eText.c_str();
2656
2657// First issue the error message so if we have to unpersist it makes sense
2658//
2659 rc = Emsg(pfx, einfo, ecode, op, hP->Name(), etP);
2660
2661// If this is a POSC file then we need to unpersist it. Note that we are always
2662// called with the handle **unlocked**
2663//
2664 if (posChk && hP->isRW == XrdOfsHandle::opPC)
2665 {hP->Lock();
2666 XrdOfsFS->Unpersist(hP);
2667 hP->UnLock();
2668 }
2669
2670// Now return the error
2671//
2672 return rc;
2673}
2674
2675/******************************************************************************/
2676
2677int XrdOfs::Emsg(const char *pfx, // Message prefix value
2678 XrdOucErrInfo &einfo, // Place to put text & error code
2679 int ecode, // The error code
2680 const char *op, // Operation being performed
2681 const char *target, // The target (e.g., fname)
2682 const char *xtra, // Optional extra error information
2683 bool chkType)// Check for type of error & subclass
2684{
2685 char* buffer;
2686 int buflen, rc;
2687 bool msgDone = false;
2688
2689// Screen out non-errors
2690//
2691 if (chkType && (rc = EmsgType(ecode)) != SFS_ERROR) return rc;
2692
2693// Setup message handling
2694//
2695 if (einfo.extData()) einfo.Reset();
2696 buffer = einfo.getMsgBuff(buflen);
2697 std::string eText;
2698
2699 // Translate ecode to corresponding errno
2700 int rcode = OfsEroute.ec2errno(ecode);
2701
2702// Check for extended information
2703//
2704 if (xtra)
2705 switch(*xtra)
2706 {case '?': xtra = 0;
2707 if (XrdOfsFS->tryXERT && XrdOfsOss->getErrMsg(eText))
2708 {if (eText.find("Unable") != std::string::npos)
2709 {einfo.setErrInfo(rcode, eText.c_str());
2710 msgDone = true;
2711 } else xtra = eText.c_str();
2712 }
2713 break;
2714 case '+': xtra++;
2715 break;
2716 default: einfo.setErrInfo(rcode, xtra);
2717 msgDone = true;
2718 break;
2719 }
2720
2721// Format the error message if it has not been already set
2722//
2723 if (!msgDone)
2724 {XrdOucERoute::Format(buffer, buflen, ecode, op, target, xtra);
2725 einfo.setErrCode(rcode);
2726 }
2727
2728// Print it out
2729//
2730 OfsEroute.Emsg(pfx, einfo.getErrUser(), buffer);
2731
2732// Return an error
2733//
2734 return SFS_ERROR;
2735}
2736
2737/******************************************************************************/
2738/* E m s g T y p e */
2739/******************************************************************************/
2740
2741int XrdOfs::EmsgType(int ecode) // The error code
2742{
2743
2744// If the error is EBUSY then we just need to stall the client. This is
2745// a hack in order to provide for proxy support
2746//
2747 if (ecode < 0) ecode = -ecode;
2748 if (ecode == EBUSY) return 5; // A hack for proxy support
2749
2750// Check for timeout conditions that require a client delay
2751//
2752 if (ecode == ETIMEDOUT) return OSSDelay;
2753
2754// This is a real error
2755//
2756 return SFS_ERROR;
2757}
2758
2759/******************************************************************************/
2760/* S e t u p C k s R T */
2761/******************************************************************************/
2762
2763int XrdOfs::SetupCksRT(XrdCksCalc*& cP, XrdOucEnv& Env,const char*& cT)
2764{
2765// Check if the cipher can come from the environment
2766//
2767 if (CksRTCgi && (cT = Env.Get("cks.type")))
2768 {if (!strcmp("default", cT))
2769 {int csLen;
2770 cT = CksRTCalc->Type(csLen);
2771 cP = CksRTCalc->New();
2772 return 0;
2773 }
2774 return (ValidCST(cT) && (cP=Cks->Object(cT)) ? 0 : -ENOTSUP);
2775 }
2776
2777// Set if auto real-time is enabled
2778//
2779 if (CksRTName)
2780 {cP = CksRTCalc->New();
2781 cT = CksRTName;
2782 return 0;
2783 }
2784
2785// All done
2786//
2787 cP = 0;
2788 cT = 0;
2789 return 0;
2790}
2791
2792/******************************************************************************/
2793/* P R I V A T E S E C T I O N */
2794/******************************************************************************/
2795/******************************************************************************/
2796/* F n a m e */
2797/******************************************************************************/
2798
2799const char *XrdOfs::Fname(const char *path)
2800{
2801 int i = strlen(path)-1;
2802 while(i) if (path[i] == '/') return &path[i+1];
2803 else i--;
2804 return path;
2805}
2806
2807/******************************************************************************/
2808/* F o r w a r d */
2809/******************************************************************************/
2810
2811int XrdOfs::Forward(int &Result, XrdOucErrInfo &Resp, struct fwdOpt &Fwd,
2812 const char *arg1, const char *arg2,
2813 XrdOucEnv *Env1, XrdOucEnv *Env2)
2814{
2815 int retc;
2816
2817 if ((retc = Finder->Forward(Resp, Fwd.Cmd, arg1, arg2, Env1, Env2)))
2818 {Result = fsError(Resp, retc);
2819 return 1;
2820 }
2821
2822 if (Fwd.Port <= 0)
2823 {Result = SFS_OK;
2824 return (Fwd.Port ? 0 : 1);
2825 }
2826
2827 Resp.setErrInfo(Fwd.Port, Fwd.Host);
2828 Result = SFS_REDIRECT;
2830 return 1;
2831}
2832
2833/******************************************************************************/
2834/* f s E r r o r */
2835/******************************************************************************/
2836
2837int XrdOfs::fsError(XrdOucErrInfo &myError, int rc)
2838{
2839
2840// Screen the error code (update statistics w/o a lock for speed!)
2841//
2842 if (rc == SFS_REDIRECT) {OfsStats.Data.numRedirect++; return SFS_REDIRECT;}
2843 if (rc == SFS_STARTED) {OfsStats.Data.numStarted++; return SFS_STARTED; }
2844 if (rc > 0) {OfsStats.Data.numDelays++; return rc; }
2845 if (rc == SFS_DATA) {OfsStats.Data.numReplies++; return SFS_DATA; }
2846 {OfsStats.Data.numErrors++; return SFS_ERROR; }
2847}
2848
2849/******************************************************************************/
2850/* R e f o r m a t */
2851/******************************************************************************/
2852
2853int XrdOfs::Reformat(XrdOucErrInfo &myError)
2854{
2855 static const char *fmt = "oss.cgroup=all&oss.space=%llu&oss.free=%llu"
2856 "&oss.maxf=%llu&oss.used=%llu&oss.quota=-1";
2857 char qsFmt, *bP;
2858 unsigned long long totSpace, totFree, maxFree;
2859 int n, blen;
2860
2861// Get the buffer
2862//
2863 bP = myError.getMsgBuff(blen);
2864
2865// Scan out the values
2866//
2867 n = sscanf(bP, "%c %llu %llu %llu", &qsFmt, &totSpace, &totFree, &maxFree);
2868
2869// Validate the response. The response will be invalid for older cmsd's
2870//
2871 if (n != 4 || qsFmt != 'A')
2872 {myError.setErrInfo(ENOTSUP,"space fctl operation not supported by cmsd");
2873 return SFS_ERROR;
2874 }
2875
2876// Change megabyte values to actual bytes
2877//
2878 totSpace = totSpace << 20LL;
2879 totFree = totFree << 20LL;
2880 maxFree = maxFree << 20LL;
2881
2882// Reformat the result
2883//
2884 blen = snprintf(bP,blen,fmt,totSpace,totFree,maxFree,(totSpace-totFree));
2885
2886 myError.setErrCode(blen);
2887 return SFS_DATA;
2888}
2889
2890/******************************************************************************/
2891/* S p l i t */
2892/******************************************************************************/
2893
2894const char * XrdOfs::Split(const char *Args, const char **Opq,
2895 char *Path, int Plen)
2896{
2897 int xlen;
2898 *Opq = index(Args, '?');
2899 if (!(*Opq)) return Args;
2900 xlen = (*Opq)-Args;
2901 if (xlen >= Plen) xlen = Plen-1;
2902 strncpy(Path, Args, xlen);
2903 Path[xlen] = 0;
2904 return Path;
2905}
2906
2907/******************************************************************************/
2908/* S t a l l */
2909/******************************************************************************/
2910
2911int XrdOfs::Stall(XrdOucErrInfo &einfo, // Error text & code
2912 int stime, // Seconds to stall
2913 const char *path) // The path to stall on
2914{
2915 const char *msgfmt = "File %s is being %s; "
2916 "estimated time to completion %s";
2917 EPNAME("Stall")
2918#ifndef NODEBUG
2919 const char *tident = "";
2920#endif
2921 char Mbuff[2048], Tbuff[32];
2922 const char *What = "staged";
2923
2924// Check why the stall is occurring
2925//
2926 if (stime < 0) {stime = 60; What = "created";}
2927
2928// Format the stall message
2929//
2930 snprintf(Mbuff, sizeof(Mbuff)-1, msgfmt,
2931 Fname(path), What, WaitTime(stime, Tbuff, sizeof(Tbuff)));
2932 ZTRACE(delay, "Stall " <<stime <<": " <<Mbuff <<" for " <<path);
2933
2934// Place the error message in the error object and return
2935//
2936 einfo.setErrInfo(0, Mbuff);
2937
2938// All done
2939//
2940 return (stime > MaxDelay ? MaxDelay : stime);
2941}
2942
2943/******************************************************************************/
2944/* U n p e r s i s t */
2945/******************************************************************************/
2946
2948{
2949 EPNAME("Unpersist");
2950 const char *tident = oh->PoscUsr();
2951 int poscNum, retc;
2952 short theMode;
2953
2954// Trace the call
2955//
2956 FTRACE(close, "use=0");
2957
2958// Generate a proper close event as one has not yet been generated
2959//
2960 if (xcev && XrdOfsFS->evsObject && *tident != '?'
2961 && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Closew))
2962 {XrdOfsEvsInfo evInfo(tident, oh->Name());
2963 XrdOfsFS->evsObject->Notify(XrdOfsEvs::Closew, evInfo);
2964 }
2965
2966// Now generate a removal event
2967//
2968 if (XrdOfsFS->Balancer) XrdOfsFS->Balancer->Removed(oh->Name());
2969 if (XrdOfsFS->evsObject && XrdOfsFS->evsObject->Enabled(XrdOfsEvs::Rm))
2970 {XrdOfsEvsInfo evInfo(tident, oh->Name());
2971 XrdOfsFS->evsObject->Notify(XrdOfsEvs::Rm, evInfo);
2972 }
2973
2974// Count this
2975//
2976 OfsStats.Add(OfsStats.Data.numUnpsist);
2977
2978// Now unpersist the file
2979//
2980 OfsEroute.Emsg(epname, "Unpersisting", tident, oh->Name());
2981 if ((poscNum = oh->PoscGet(theMode))) poscQ->Del(oh->Name(), poscNum, 1);
2982 else if ((retc = XrdOfsOss->Unlink(oh->Name())))
2983 OfsEroute.Emsg(epname, retc, "unpersist", oh->Name());
2984}
2985
2986/******************************************************************************/
2987/* W a i t T i m e */
2988/******************************************************************************/
2989
2990char *XrdOfs::WaitTime(int stime, char *buff, int blen)
2991{
2992 int hr, min, sec;
2993
2994// Compute hours, minutes, and seconds
2995//
2996 min = stime / 60;
2997 sec = stime % 60;
2998 hr = min / 60;
2999 min = min % 60;
3000
3001// Now format the message based on time duration
3002//
3003 if (!hr && !min)
3004 snprintf(buff,blen,"%d second%s",sec,(sec > 1 ? "s" : ""));
3005 else if (!hr)
3006 {if (sec > 10) min++;
3007 snprintf(buff,blen,"%d minute%s",min,(min > 1 ? "s" : ""));
3008 }
3009 else {if (hr == 1)
3010 if (min <= 30)
3011 snprintf(buff,blen,"%d minutes",min+60);
3012 else snprintf(buff,blen,"%d hour and %d minutes",hr,min);
3013 else {if (min > 30) hr++;
3014 snprintf(buff,blen,"%d hours",hr);
3015 }
3016 }
3017
3018// Complete the message
3019//
3020 buff[blen-1] = '\0';
3021 return buff;
3022}
#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:1854
bool viaDel
Definition XrdOfs.hh:208
int checkpoint(XrdSfsFile::cpAct act, struct iov *range=0, int n=0)
Definition XrdOfs.cc:1010
XrdSfsXferSize pgWrite(XrdSfsFileOffset offset, char *buffer, XrdSfsXferSize wrlen, uint32_t *csvec, uint64_t opts=0)
Definition XrdOfs.cc:1310
XrdSfsXferSize write(XrdSfsFileOffset fileOffset, const char *buffer, XrdSfsXferSize buffer_size)
Definition XrdOfs.cc:1594
static bool ocFsync
Definition XrdOfs.hh:199
int truncate(XrdSfsFileOffset fileOffset)
Definition XrdOfs.cc:1807
int Clone(XrdSfsFile &srcFile)
Definition XrdOfs.cc:864
int read(XrdSfsFileOffset fileOffset, XrdSfsXferSize amount)
Definition XrdOfs.cc:1429
int fctl(const int cmd, const char *args, XrdOucErrInfo &out_error)
Definition XrdOfs.cc:1142
XrdSfsXferSize readv(XrdOucIOVec *readV, int readCount)
Definition XrdOfs.cc:1516
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:1214
int getMmap(void **Addr, off_t &Size)
Definition XrdOfs.cc:1697
int close()
Definition XrdOfs.cc:899
const char * tident
Definition XrdOfs.hh:203
int sync()
Definition XrdOfs.cc:1746
XrdOfsHandle * oh
Definition XrdOfs.hh:204
int dorawio
Definition XrdOfs.hh:207
XrdOucChkPnt * myCKP
Definition XrdOfs.hh:206
bool ckpBad
Definition XrdOfs.hh:209
XrdOfsTPC * myTPC
Definition XrdOfs.hh:205
int stat(struct stat *buf)
Definition XrdOfs.cc:1718
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:2085
int chmod(const char *Name, XrdSfsMode Mode, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2017
int truncate(const char *Name, XrdSfsFileOffset fileOffset, XrdOucErrInfo &out_error, const XrdSecEntity *client=0, const char *opaque=0)
Definition XrdOfs.cc:2578
struct fwdOpt fwdTRUNC
Definition XrdOfs.hh:427
void Disc(const XrdSecEntity *client=0)
Definition XrdOfs.cc:2098
int prepare(XrdSfsPrep &pargs, XrdOucErrInfo &out_error, const XrdSecEntity *client=0)
Definition XrdOfs.cc:2272
mode_t dMask[2]
Definition XrdOfs.hh:396
const char * Split(const char *Args, const char **Opq, char *Path, int Plen)
Definition XrdOfs.cc:2894
int myPort
Definition XrdOfs.hh:392
XrdCmsClient * Finder
Definition XrdOfs.hh:441
mode_t fMask[2]
Definition XrdOfs.hh:397
static int EmsgType(int ecode)
Definition XrdOfs.cc:2741
char * WaitTime(int, char *, int)
Definition XrdOfs.cc:2990
struct fwdOpt fwdRMDIR
Definition XrdOfs.hh:426
static int OSSDelay
Definition XrdOfs.hh:430
char * ConfigFN
Definition XrdOfs.hh:432
int tpcRdrPort[2]
Definition XrdOfs.hh:402
int mkdir(const char *dirName, XrdSfsMode Mode, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2197
struct fwdOpt fwdMKPATH
Definition XrdOfs.hh:423
XrdOfs()
Definition XrdOfs.cc:171
char * tpcRdrHost[2]
Definition XrdOfs.hh:401
int chksum(csFunc Func, const char *csName, const char *Path, XrdOucErrInfo &out_error, const XrdSecEntity *client=0, const char *opaque=0)
Definition XrdOfs.cc:1905
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:2380
struct fwdOpt fwdMKDIR
Definition XrdOfs.hh:422
static int MaxDelay
Definition XrdOfs.hh:429
struct fwdOpt fwdMV
Definition XrdOfs.hh:424
static int Emsg(const char *, XrdOucErrInfo &, int, const char *x, XrdOfsHandle *hP, bool posChk=false, bool chktype=true)
Definition XrdOfs.cc:2637
static int fsError(XrdOucErrInfo &myError, int rc)
Definition XrdOfs.cc:2837
int stat(const char *Name, struct stat *buf, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2485
struct fwdOpt fwdRM
Definition XrdOfs.hh:425
int SetupCksRT(XrdCksCalc *&, XrdOucEnv &, const char *&)
Definition XrdOfs.cc:2763
bool ValidCST(const char *cst)
int getStats(char *buff, int blen)
Definition XrdOfs.cc:2174
struct fwdOpt fwdCHMOD
Definition XrdOfs.hh:421
int Stall(XrdOucErrInfo &, int, const char *)
Definition XrdOfs.cc:2911
@ RdrTPC
Definition XrdOfs.hh:388
int exists(const char *fileName, XrdSfsFileExistence &exists_flag, XrdOucErrInfo &out_error, const XrdSecEntity *client, const char *opaque=0)
Definition XrdOfs.cc:2111
void Unpersist(XrdOfsHandle *hP, int xcev=1)
Definition XrdOfs.cc:2947
virtual int Fsync()
Definition XrdOss.hh:172
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