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