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