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