XRootD
Loading...
Searching...
No Matches
XrdFfsPosix.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* XrdFfsPosix.cc C wrapper to some of the Xrootd Posix library functions */
3/* */
4/* (c) 2010 by the Board of Trustees of the Leland Stanford, Jr., University */
5/* All Rights Reserved */
6/* Author: Wei Yang (SLAC National Accelerator Laboratory, 2009) */
7/* Contract DE-AC02-76-SFO0515 with the Department 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#define _FILE_OFFSET_BITS 64
31#include <cerrno>
32#include <cstdio>
33#include <cstring>
34#include <sys/types.h>
35
36#if !defined(__solaris__) && !defined(__FreeBSD__)
37#include <sys/xattr.h>
38#endif
39
40#ifndef ENOATTR
41 #define ENOATTR ENODATA
42#endif
43
44#include <iostream>
45#include <libgen.h>
46#include <unistd.h>
47#include <cstdlib>
48#include <syslog.h>
49#include "XrdFfs/XrdFfsPosix.hh"
51#include "XrdFfs/XrdFfsMisc.hh"
52#include "XrdFfs/XrdFfsDent.hh"
53#include "XrdFfs/XrdFfsQueue.hh"
54
56#include "XrdCl/XrdClFile.hh"
57#include "XrdCl/XrdClURL.hh"
59
60#ifdef __cplusplus
61 extern "C" {
62#endif
63
64#define MAXROOTURLLEN 1024 // this is also defined in other files
65
66int XrdFfsPosix_stat(const char *path, struct stat *buf)
67{
68 int rc;
69 errno = 0;
70 rc = XrdPosixXrootd::Stat(path, buf);
71 if (rc == 0 && S_ISBLK(buf->st_mode)) /* If 'buf' come from HPSS, xrootd will return it as a block device! */
72 { /* So we re-mark it to a regular file */
73 buf->st_mode &= 0007777;
74 if ( buf->st_mode & S_IXUSR )
75 buf->st_mode |= 0040000; /* a directory */
76 else
77 buf->st_mode |= 0100000; /* a file */
78 }
79 return rc;
80}
81
82DIR *XrdFfsPosix_opendir(const char *path)
83{
84 return XrdPosixXrootd::Opendir(path);
85}
86
87struct dirent *XrdFfsPosix_readdir(DIR *dirp)
88{
89 return XrdPosixXrootd::Readdir(dirp);
90}
91
93{
94 return XrdPosixXrootd::Closedir(dirp);
95}
96
97int XrdFfsPosix_mkdir(const char *path, mode_t mode)
98{
99 XrdCl::URL url(path);
100 std::string dir = url.GetPath();
101 XrdCl::LocationInfo *info = nullptr;
102 XrdCl::FileSystem fs(path);
103
105 std::unique_ptr<XrdCl::LocationInfo> ptr( info );
106
107 if( !st.IsOK() )
108 {
109 errno = ENOENT;
110 return -1;
111 }
112 std::string nodeUrl = "root://" + info->At(0).GetAddress() + "/" + dir;
113
114 return XrdPosixXrootd::Mkdir(nodeUrl.c_str(), mode);
115}
116
117int XrdFfsPosix_rmdir(const char *path)
118{
119 return XrdPosixXrootd::Rmdir(path);
120}
121
122int XrdFfsPosix_open(const char *path, int oflags, mode_t mode)
123{
124 return XrdPosixXrootd::Open(path, oflags, mode);
125}
126
127int XrdFfsPosix_close(int fildes)
128{
129 return XrdPosixXrootd::Close(fildes);
130}
131
132off_t XrdFfsPosix_lseek(int fildes, off_t offset, int whence)
133{
134 return XrdPosixXrootd::Lseek(fildes, (long long)offset, whence);
135}
136
137ssize_t XrdFfsPosix_read(int fildes, void *buf, size_t nbyte)
138{
139 return XrdPosixXrootd::Read(fildes, buf, nbyte);
140}
141
142ssize_t XrdFfsPosix_pread(int fildes, void *buf, size_t nbyte, off_t offset)
143{
144 return XrdPosixXrootd::Pread(fildes, buf, nbyte, (long long)offset);
145}
146
147ssize_t XrdFfsPosix_write(int fildes, const void *buf, size_t nbyte)
148{
149 return XrdPosixXrootd::Write(fildes, buf, nbyte);
150}
151
152ssize_t XrdFfsPosix_pwrite(int fildes, const void *buf, size_t nbyte, off_t offset)
153{
154 return XrdPosixXrootd::Pwrite(fildes, buf, nbyte, (long long) offset);
155}
156
157int XrdFfsPosix_fsync(int fildes)
158{
159 return XrdPosixXrootd::Fsync(fildes);
160}
161
162int XrdFfsPosix_unlink(const char *path)
163{
164 return XrdPosixXrootd::Unlink(path);
165}
166
167int XrdFfsPosix_rename(const char *oldpath, const char *newpath)
168{
169 return XrdPosixXrootd::Rename(oldpath, newpath);
170}
171
172int XrdFfsPosix_ftruncate(int fildes, off_t offset)
173{
174 return XrdPosixXrootd::Ftruncate(fildes, offset);
175}
176int XrdFfsPosix_truncate(const char *path, off_t Size)
177{
178 return XrdPosixXrootd::Truncate(path, Size);
179}
180
181long long XrdFfsPosix_getxattr(const char *path, const char *name, void *value, unsigned long long size)
182{
183 int bufsize;
184 char xattrbuf[1024], nameclass[128], *namesubclass;
185 char *token, *key, *val;
186 char *lasts_xattr[256], *lasts_tokens[128];
187
188/*
189 Xrootd only support two names: xroot.space and xroot.xattr. We add support of xroot.space.*
190 such as xroot.space.oss.cgroup etc.
191 */
192 strncpy(nameclass, name, 11);
193 nameclass[11] = '\0';
194
195 if (strcmp(nameclass, "xroot.space") != 0 &&
196 strcmp(nameclass, "xroot.xattr") != 0 &&
197 strcmp(nameclass, "xroot.cksum") != 0)
198 {
199 errno = ENOATTR;
200 return -1;
201 }
202
203 bufsize = XrdPosixXrootd::Getxattr(path, nameclass, xattrbuf, size);
204 if (bufsize == -1) return -1;
205
206 if (strlen(name) > 11)
207 {
208 strcpy(nameclass, name);
209 namesubclass = &nameclass[12];
210 }
211 else /* xroot.space or xroot.xattr or xroot.cksum is provided. */
212 {
213 strcpy((char*)value, xattrbuf);
214 return bufsize;
215 }
216
217 token = strtok_r(xattrbuf, "&", lasts_xattr);
218 while ( token != NULL )
219 {
220 key = strtok_r(token, "=", lasts_tokens);
221 val = strtok_r(NULL, "=", lasts_tokens);
222 if (! strcmp(key, namesubclass))
223 {
224 strcpy((char*)value, val);
225 return strlen(val);
226 }
227 token = strtok_r(NULL, "&", lasts_xattr);
228 }
229 errno = ENOATTR;
230 return -1;
231}
232
233/* clean redirector cache */
234
235void XrdFfsPosix_clear_from_rdr_cache(const char *rdrurl)
236{
237 int fd;
238 fd = XrdFfsPosix_open(rdrurl, O_CREAT | O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
239 if ( fd != -1 )
240 {
242 XrdFfsPosix_unlink(rdrurl);
243 }
244}
245
246/* Posix IO functions to operation on all data servers */
247
249 char *url;
250 int *res;
251 int *err;
252 mode_t st_mode;
253};
254
256{
258
259 if (S_ISREG(args->st_mode))
260 *(args->res) = XrdFfsPosix_unlink(args->url);
261 else if (S_ISDIR(args->st_mode))
262 *(args->res) = XrdFfsPosix_rmdir(args->url);
263
264 *(args->err) = errno;
265 return NULL;
266}
267
268int XrdFfsPosix_deleteall(const char *rdrurl, const char *path, uid_t user_uid, mode_t st_mode)
269{
270 int i, nurls, res;
271 char *newurls[XrdFfs_MAX_NUM_NODES];
272 int res_i[XrdFfs_MAX_NUM_NODES];
273 int errno_i[XrdFfs_MAX_NUM_NODES];
276
277 nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
278
279 for (i = 0; i < nurls; i++)
280 {
281 errno_i[i] = 0;
282 strncat(newurls[i],path, MAXROOTURLLEN - strlen(newurls[i]) -1);
283 XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid, 0);
284 args[i].url = newurls[i];
285 args[i].err = &errno_i[i];
286 args[i].res = &res_i[i];
287 args[i].st_mode = st_mode;
288#ifdef NOUSE_QUEUE
289 XrdFfsPosix_x_deleteall((void*) &args[i]);
290 }
291#else
292 jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_deleteall, (void**)(&args[i]), 0);
293 }
294 for (i = 0; i < nurls; i++)
295 {
296 XrdFfsQueue_wait_task(jobs[i]);
297 XrdFfsQueue_free_task(jobs[i]);
298 }
299#endif
300 res = -1;
301 errno = ENOENT;
302 for (i = 0; i < nurls; i++)
303 if (res_i[i] == 0)
304 {
305 res = 0;
306 errno = 0;
307 }
308 else if (res_i[i] != 0 && errno_i[i] == 125) // host is down
309 {
310 res = -1;
311 errno = ETIMEDOUT;
312 syslog(LOG_WARNING, "WARNING: unlink/rmdir(%s) failed (connection timeout)", newurls[i]);
313 break;
314 }
315 else if (res_i[i] != 0 && errno_i[i] != ENOENT)
316 {
317 res = -1;
318 errno = errno_i[i];
319 syslog(LOG_WARNING, "WARNING: unlink/rmdir(%s) failed (errno = %d)", newurls[i], errno);
320 break;
321 }
322
323 for (i = 0; i < nurls; i++)
324 free(newurls[i]);
325
326 return res;
327}
328
329int XrdFfsPosix_unlinkall(const char *rdrurl, const char *path, uid_t user_uid)
330{
331 return XrdFfsPosix_deleteall(rdrurl, path, user_uid, S_IFREG);
332}
333
334int XrdFfsPosix_rmdirall(const char *rdrurl, const char *path, uid_t user_uid)
335{
336 return XrdFfsPosix_deleteall(rdrurl, path, user_uid, S_IFDIR);
337}
338
339int XrdFfsPosix_renameall(const char *rdrurl, const char *from, const char *to, uid_t user_uid)
340{
341 int i, nurls, res, rval = 0;
342 struct stat stbuf;
343 char fromurl[1024], tourl[1024], *newurls[XrdFfs_MAX_NUM_NODES];
344
345 nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
346 if (nurls < 0) rval = -1;
347
348 for (i = 0; i < nurls; i++)
349 {
350 errno = 0;
351
352 fromurl[0]='\0';
353 strcat(fromurl, newurls[i]);
354 strncat(fromurl, from, MAXROOTURLLEN - strlen(fromurl) -1);
355 tourl[0]='\0';
356 strcat(tourl, newurls[i]);
357 strncat(tourl, to, MAXROOTURLLEN - strlen(tourl) -1);
358
359 XrdFfsMisc_xrd_secsss_editurl(fromurl, user_uid, 0);
360 XrdFfsMisc_xrd_secsss_editurl(tourl, user_uid, 0);
361 res = (XrdFfsPosix_stat(fromurl, &stbuf));
362 if (res == 0)
363 {
364/* XrdFfsPosix_rename doesn't need this protection
365 newdir = strdup(tourl);
366 newdir = dirname(newdir);
367 if (XrdFfsPosix_stat(newdir, &stbuf) == -1)
368 XrdFfsPosix_mkdir(newdir, 0777);
369
370 free(newdir);
371*/
372 rval = XrdFfsPosix_rename(fromurl, tourl);
373 if (rval == -1)
374 {
375 syslog(LOG_WARNING, "WARNING: rename(%s, %s) failed (errno = %d)", fromurl, tourl, errno);
376 break;
377 }
378/* if a successful rename is followed by a failed one, will return failure (and leave both old and new files) for
379 user to investigate. */
380 }
381 }
382
383 for (i = 0; i < nurls; i++)
384 free(newurls[i]);
385
386 if (rval != 0 && errno == 0) errno = EIO;
387 return rval;
388}
389
390int XrdFfsPosix_truncateall(const char *rdrurl, const char *path, off_t size, uid_t user_uid)
391{
392 int i, nurls, res, rval = 0;
393 struct stat stbuf;
394 char *newurls[XrdFfs_MAX_NUM_NODES];
395
396 nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
397 if (nurls < 0) rval = -1;
398
399 for (i = 0; i < nurls; i++)
400 {
401 errno = 0;
402 strncat(newurls[i],path, MAXROOTURLLEN - strlen(newurls[i]) -1);
403 XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid, 0);
404 res = (XrdFfsPosix_stat(newurls[i], &stbuf));
405 if (res == 0)
406 {
407 if (S_ISREG(stbuf.st_mode))
408 rval = XrdFfsPosix_truncate(newurls[i], size);
409 else
410 rval = -1;
411 if (rval == -1)
412 {
413 syslog(LOG_WARNING, "WARNING: (f)truncate(%s) failed (errno = %d)", newurls[i], errno);
414 break;
415 }
416/* again, it will be messy if a successful truncate is followed by a failed one */
417 }
418 else if (errno != ENOENT)
419 rval = -1;
420 }
421
422 for (i = 0; i < nurls; i++)
423 free(newurls[i]);
424
425 if (rval != 0 && errno == 0) errno = EIO;
426 return rval;
427}
428
435
436/*
437 It seems xrootd posix return dp[i] != NULL even if the dir
438 doesn't exist on a data server. XrdFfsPosix_readdir() returns
439 NULL in this case.
440
441 Do we need some protection here? We are not in trouble so far
442 because FUSE's _getattr will test the existence of the dir
443 so we know that at least one data server has the directory.
444 */
446{
448 DIR *dp;
449 struct dirent *de;
450
451/*
452 Xrootd's Opendir will not return NULL even under some error. For instance,
453 when it is supposed to return ENOENT or ENOTDIR, it actually returns
454 EINPROGRESS (115), and DIR *dp will not be NULL.
455 */
456 dp = XrdFfsPosix_opendir(args->url);
457 if ( dp == NULL && errno != 0)
458 {
459 *(args->err) = errno;
460 *(args->res) = -1;
461 if (dp != NULL)
463 }
464 else
465 {
466 *(args->res) = 0;
467 while ((de = XrdFfsPosix_readdir(dp)) != NULL)
468 XrdFfsDent_names_add(args->dents, de->d_name);
470 }
471 return NULL;
472}
473
474int XrdFfsPosix_readdirall(const char *rdrurl, const char *path, char*** direntarray, uid_t user_uid)
475{
476 int i, j, n, nents, nurls;
477 bool hasDirLock = false;
478
479 char *newurls[XrdFfs_MAX_NUM_NODES];
480 int res_i[XrdFfs_MAX_NUM_NODES];
481 int errno_i[XrdFfs_MAX_NUM_NODES];
482 struct XrdFfsDentnames *dir_i[XrdFfs_MAX_NUM_NODES] = {0};
485
486// for (i = 0; i < XrdFfs_MAX_NUM_NODES; i++)
487// dir_i[i] = NULL;
488
489 nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
490/*
491 If a directory doesn't exist on any data server, it is better to return -1 with errno = ENOENT
492 than to return 0 with errno = 0. But this is difficult because it depends on correct returning
493 from XrdPosixXrootd::Opendir(). This has never been a problem for xrootdfs itself because FUSE
494 does stat() before readdir().
495
496 In the use case of XrdPssDir::Opendir(), it does expect this function to return -1/ENOENT. In
497 this use case the "rdrurl" contains the complete URL and "path" contains "" so "nurls" will be
498 zero if no data server has the directory. The following is a quick and dirty fix for this use
499 case. The orignal code was: if (nurls < 0) { errno = EACCES; return -1; }
500 */
501 if (nurls <= 0)
502 {
503 errno = (nurls == 0? ENOENT : EACCES);
504 return -1;
505 }
506
507 for (i = 0; i < nurls; i++)
508 {
509 errno_i[i] = 0;
510 strncat(newurls[i], path, MAXROOTURLLEN - strlen(newurls[i]) -1);
511 XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid, 0);
512 args[i].url = newurls[i];
513 args[i].err = &errno_i[i];
514 args[i].res = &res_i[i];
515 args[i].dents = &dir_i[i];
516#ifdef NOUSE_QUEUE
517 XrdFfsPosix_x_readdirall((void*) &args[i]);
518 }
519#else
520 jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_readdirall, (void**)(&args[i]), 0);
521 }
522 for (i = 0; i < nurls; i++)
523 {
524 XrdFfsQueue_wait_task(jobs[i]);
525 XrdFfsQueue_free_task(jobs[i]);
526 }
527#endif
528
529 errno = 0;
530 for (i = 0; i < nurls; i++)
531 if (res_i[i] != 0 && errno_i[i] == 125) // when host i is down
532 {
533 errno = ETIMEDOUT;
534 syslog(LOG_WARNING, "WARNING: opendir(%s) failed (connection timeout)", newurls[i]);
535 break;
536 }
537
538 for (i = 0; i < nurls; i++)
539 free(newurls[i]);
540 for (i = 1; i < nurls; i++)
541 XrdFfsDent_names_join(&dir_i[i], &dir_i[i-1]);
542
543 char *last = NULL, **dnarraytmp;
544
545 n = XrdFfsDent_names_extract(&dir_i[nurls-1], &dnarraytmp);
546 *direntarray = (char **) malloc(sizeof(char*) * n);
547
548// note that dnarraytmp[] may contain redundant entries
549
550 nents = 0;
551 for (i = 0; i < n; i++)
552 {
553 // put DIR_LOCK to the last one to allow rm -rf to work...
554 //
555 if (! strcmp(dnarraytmp[i], "DIR_LOCK"))
556 {
557 hasDirLock = true;
558 continue;
559 }
560
561 if (i != 0) // can be used to filter out .lock .fail, etc.
562 {
563 char *tmp, *tmp_dot;
564 tmp = strdup(dnarraytmp[i]);
565 tmp_dot = tmp + strlen(tmp) - 5;
566
567 if (! strcmp(tmp_dot, ".lock") || ! strcmp(tmp_dot, ".fail")) // filter out .lock/.fail files
568 {
569 for (j = nents - 1; j >= 0; j--)
570 {
571 tmp_dot[0] = '\0';
572 if (! strcmp(tmp, (*direntarray)[j]))
573 {
574 tmp_dot[0] = '.';
575 free(tmp);
576 break;
577 }
578 }
579 if (j >= 0) continue; // found the file cooresponding to the .lock/.fail
580 }
581 free(tmp);
582 }
583
584 if (last == NULL || strcmp(last, dnarraytmp[i]) != 0)
585 {
586 last = dnarraytmp[i];
587 (*direntarray)[nents++] = strdup(dnarraytmp[i]);
588 }
589 }
590
591 for (i = 0; i < n; i++) free(dnarraytmp[i]); // do not mergo with the above because the above loop has 'break'.
592 free(dnarraytmp);
593
594/* inject this list into dent cache */
595
596 char *p;
597 p = strdup(path);
598 XrdFfsDent_cache_fill(p, direntarray, nents);
599 free(p);
600
601 if (hasDirLock) (*direntarray)[nents++] = strdup("DIR_LOCK");
602
603 return nents;
604}
605
606/*
607 struct XrdFfsPosixX_statvfsall_args, void XrdFfsPosix_x_statvfsall(), int XrdFfsPosiXrdFfsPosix_x_statvfsall() are
608 organized in such a way to allow using pthread if needed
609 */
610
612 char *url;
613 int *res;
614 int *err;
615 struct statvfs *stbuf;
617};
618
620{
622 char xattr[256];
623 off_t oss_size;
624 long long llVal;
625
626 *(args->res) = XrdFfsPosix_getxattr(args->url, "xroot.space.oss.space", xattr, 256);
627 *(args->err) = errno;
628 sscanf((const char*)xattr, "%lld", &llVal);
629 oss_size = static_cast<off_t>(llVal);
630 args->stbuf->f_blocks = (fsblkcnt_t) (oss_size / args->stbuf->f_bsize);
631// sscanf((const char*)xattr, "%lld", &(args->stbuf->f_blocks));
632 if (*(args->res) == -1)
633 {
634 args->stbuf->f_blocks = 0;
635 args->stbuf->f_bavail = 0;
636 args->stbuf->f_bfree = 0;
637 return NULL;
638 }
639 *(args->res) = XrdFfsPosix_getxattr(args->url, "xroot.space.oss.free", xattr, 256);
640 *(args->err) = errno;
641 sscanf((const char*)xattr, "%lld", &llVal);
642 oss_size = static_cast<off_t>(llVal);
643 args->stbuf->f_bavail = (fsblkcnt_t) (oss_size / args->stbuf->f_bsize);
644// sscanf((const char*)xattr, "%lld", &(args->stbuf->f_bavail));
645 if (*(args->res) == -1)
646 {
647 args->stbuf->f_blocks = 0;
648 args->stbuf->f_bavail = 0;
649 args->stbuf->f_bfree = 0;
650 return NULL;
651 }
652
653/*
654 The relation of the output of df and stbuf->f_blocks, f_bfree and f_bavail is
655 Filesystem Size Used Avail Use% Mounted on
656 f_blocks f_blocks - f_bfree f_bavail
657
658 In the case of querying without oss.cgroup, f_bfree = f_bavail (e.g. Used is used space by all oss.space)
659 In the case of querying with oss.cgroup, Used is used space by the specified oss.space (oss_size/f_bsize) and
660 therefore f_bfree = f_blocks - oss_size / f_bsize (e.g. Used is oss_size / f_bsize)
661 */
662
663 if (args->osscgroup != 1)
664 args->stbuf->f_bfree = args->stbuf->f_bavail;
665 else
666 {
667 *(args->res) = XrdFfsPosix_getxattr(args->url, "xroot.space.oss.used", xattr, 256);
668 *(args->err) = errno;
669 sscanf((const char*)xattr, "%lld", &llVal);
670 oss_size = static_cast<off_t>(llVal);
671 args->stbuf->f_bfree = args->stbuf->f_blocks - (fsblkcnt_t) (oss_size / args->stbuf->f_bsize);
672// args->stbuf->f_bfree = args->stbuf->f_blocks - oss_size;
673 }
674 return NULL;
675}
676
677int XrdFfsPosix_statvfsall(const char *rdrurl, const char *path, struct statvfs *stbuf, uid_t user_uid)
678{
679 int i, nurls;
680 short osscgroup;
681
682 char *newurls[XrdFfs_MAX_NUM_NODES];
683 int res_i[XrdFfs_MAX_NUM_NODES];
684 int errno_i[XrdFfs_MAX_NUM_NODES];
685 struct statvfs stbuf_i[XrdFfs_MAX_NUM_NODES];
688
689 nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
690 if (nurls < 0)
691 {
692 errno = EACCES;
693 return -1;
694 }
695
696 if (strstr(path, "oss.cgroup") != NULL)
697 osscgroup = 1;
698 else
699 osscgroup = 0;
700 for (i = 0; i < nurls; i++)
701 {
702 strncat(newurls[i], path, MAXROOTURLLEN - strlen(newurls[i]) -1);
703// XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid);
704 args[i].url = newurls[i];
705 args[i].res = &res_i[i];
706 args[i].err = &errno_i[i];
707 stbuf_i[i].f_bsize = stbuf->f_bsize;
708 args[i].stbuf = &(stbuf_i[i]);
709 args[i].osscgroup = osscgroup;
710#ifdef NOUSE_QUEUE
711 XrdFfsPosix_x_statvfsall((void*) &args[i]);
712 }
713#else
714 jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_statvfsall, (void**)(&args[i]), 0);
715 }
716 for (i = 0; i < nurls; i++)
717 {
718 XrdFfsQueue_wait_task(jobs[i]);
719 XrdFfsQueue_free_task(jobs[i]);
720 }
721#endif
722 /*
723 for statfs call, we don't care about return code and errno
724 */
725 stbuf->f_blocks = 0;
726 stbuf->f_bfree = 0;
727 stbuf->f_bavail = 0;
728 for (i = 0; i < nurls; i++)
729 {
730 stbuf->f_blocks += args[i].stbuf->f_blocks;
731 stbuf->f_bavail += args[i].stbuf->f_bavail;
732 stbuf->f_bfree += args[i].stbuf->f_bfree;
733 }
734
735 for (i = 0; i < nurls; i++)
736 free(newurls[i]);
737
738 return 0;
739}
740
741/* XrdFfsPosiXrdFfsPosix_x_statall() */
742
744 char *url;
745 int *res;
746 int *err;
747 struct stat *stbuf;
748};
749
751{
752 struct XrdFfsPosixX_statall_args *args = (struct XrdFfsPosixX_statall_args *)x;
753
754 *(args->res) = XrdFfsPosix_stat(args->url, args->stbuf);
755 *(args->err) = errno;
756 return (void *)0;
757}
758
759int XrdFfsPosix_statall(const char *rdrurl, const char *path, struct stat *stbuf, uid_t user_uid)
760{
761 int i, res, nurls;
762
763 char *newurls[XrdFfs_MAX_NUM_NODES];
764 int res_i[XrdFfs_MAX_NUM_NODES];
765 int errno_i[XrdFfs_MAX_NUM_NODES];
766 struct stat stbuf_i[XrdFfs_MAX_NUM_NODES];
769
770 char *p1, *p2, *dir, *file, rootpath[MAXROOTURLLEN];
771
772 rootpath[0] = '\0';
773 strncat(rootpath,rdrurl, MAXROOTURLLEN - strlen(rootpath) -1);
774 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
775 p1 = strdup(path);
776 p2 = strdup(path);
777 dir = dirname(p1);
778 file = basename(p2);
779
780// if task queue is too long, or if the stat() is from an ls -l command, the stat() against redirector
782 {
783 XrdFfsMisc_xrd_secsss_editurl(rootpath, user_uid, 0);
784 res = XrdFfsPosix_stat(rootpath, stbuf);
785// maybe a data server is down since the last _readdir()? in that case, continue
786// we also saw a case where redirectors report the file exist but meta redirector report
787// that the file doesn't exist, and we need to continue at here
788 if (res == 0)
789 {
790 free(p1);
791 free(p2);
792 return 0;
793 }
794 }
795 free(p1);
796 free(p2);
797
798 nurls = XrdFfsMisc_get_all_urls(rdrurl, newurls, XrdFfs_MAX_NUM_NODES);
799
800 for (i = 0; i < nurls; i++)
801 {
802 strncat(newurls[i], path, MAXROOTURLLEN - strlen(path) -1);
803 XrdFfsMisc_xrd_secsss_editurl(newurls[i], user_uid, 0);
804 args[i].url = newurls[i];
805 args[i].res = &res_i[i];
806 args[i].err = &errno_i[i];
807 args[i].stbuf = &(stbuf_i[i]);
808#ifdef NOUSE_QUEUE
809 XrdFfsPosix_x_statall((void*) &args[i]);
810 }
811#else
812 jobs[i] = XrdFfsQueue_create_task(XrdFfsPosix_x_statall, (void**)(&args[i]), 0);
813 }
814 for (i = 0; i < nurls; i++)
815 {
816 XrdFfsQueue_wait_task(jobs[i]);
817 XrdFfsQueue_free_task(jobs[i]);
818 }
819#endif
820 res = -1;
821 errno = ENOENT;
822 for (i = 0; i < nurls; i++)
823 {
824 time_t max_mtime = 0;
825 if (res_i[i] == 0)
826 {
827 if (stbuf_i[i].st_mtime <= max_mtime) continue;
828 res = 0;
829 errno = 0;
830 memcpy((void*)stbuf, (void*)(&stbuf_i[i]), sizeof(struct stat));
831 break;
832 }
833 else if (res_i[i] != 0 && errno_i[i] == 125) // when host i is down
834 {
835 res = -1;
836 errno = ETIMEDOUT;
837 syslog(LOG_WARNING, "WARNING: stat(%s) failed (connection timeout)", newurls[i]);
838 }
839 }
840
841 for (i = 0; i < nurls; i++)
842 free(newurls[i]);
843
844 return res;
845}
846
847#ifdef __cplusplus
848 }
849#endif
int XrdFfsDent_cache_search(char *dname, char *dentname)
void XrdFfsDent_names_join(struct XrdFfsDentnames **p, struct XrdFfsDentnames **n)
Definition XrdFfsDent.cc:78
void XrdFfsDent_names_add(struct XrdFfsDentnames **p, char *name)
Definition XrdFfsDent.cc:56
int XrdFfsDent_cache_fill(char *dname, char ***dnarray, int nents)
int XrdFfsDent_names_extract(struct XrdFfsDentnames **p, char ***dnarray)
int XrdFfsMisc_get_number_of_data_servers()
void XrdFfsMisc_xrd_secsss_editurl(char *url, uid_t user_uid, int *id)
int XrdFfsMisc_get_all_urls(const char *oldurl, char **newurls, const int nnodes)
#define XrdFfs_MAX_NUM_NODES
Definition XrdFfsMisc.hh:34
int XrdFfsPosix_ftruncate(int fildes, off_t offset)
int XrdFfsPosix_rmdirall(const char *rdrurl, const char *path, uid_t user_uid)
int XrdFfsPosix_rename(const char *oldpath, const char *newpath)
DIR * XrdFfsPosix_opendir(const char *path)
int XrdFfsPosix_open(const char *path, int oflags, mode_t mode)
int XrdFfsPosix_fsync(int fildes)
int XrdFfsPosix_unlink(const char *path)
struct dirent * XrdFfsPosix_readdir(DIR *dirp)
int XrdFfsPosix_renameall(const char *rdrurl, const char *from, const char *to, uid_t user_uid)
void XrdFfsPosix_clear_from_rdr_cache(const char *rdrurl)
int XrdFfsPosix_truncate(const char *path, off_t Size)
ssize_t XrdFfsPosix_pwrite(int fildes, const void *buf, size_t nbyte, off_t offset)
#define ENOATTR
int XrdFfsPosix_truncateall(const char *rdrurl, const char *path, off_t size, uid_t user_uid)
ssize_t XrdFfsPosix_read(int fildes, void *buf, size_t nbyte)
void * XrdFfsPosix_x_statvfsall(void *x)
void * XrdFfsPosix_x_statall(void *x)
int XrdFfsPosix_closedir(DIR *dirp)
void * XrdFfsPosix_x_deleteall(void *x)
int XrdFfsPosix_rmdir(const char *path)
off_t XrdFfsPosix_lseek(int fildes, off_t offset, int whence)
int XrdFfsPosix_close(int fildes)
ssize_t XrdFfsPosix_pread(int fildes, void *buf, size_t nbyte, off_t offset)
int XrdFfsPosix_statvfsall(const char *rdrurl, const char *path, struct statvfs *stbuf, uid_t user_uid)
void * XrdFfsPosix_x_readdirall(void *x)
int XrdFfsPosix_deleteall(const char *rdrurl, const char *path, uid_t user_uid, mode_t st_mode)
struct XrdFfsDentnames ** dents
int XrdFfsPosix_readdirall(const char *rdrurl, const char *path, char ***direntarray, uid_t user_uid)
int XrdFfsPosix_statall(const char *rdrurl, const char *path, struct stat *stbuf, uid_t user_uid)
int XrdFfsPosix_unlinkall(const char *rdrurl, const char *path, uid_t user_uid)
int XrdFfsPosix_stat(const char *path, struct stat *buf)
int XrdFfsPosix_mkdir(const char *path, mode_t mode)
#define MAXROOTURLLEN
long long XrdFfsPosix_getxattr(const char *path, const char *name, void *value, unsigned long long size)
ssize_t XrdFfsPosix_write(int fildes, const void *buf, size_t nbyte)
void XrdFfsQueue_free_task(struct XrdFfsQueueTasks *task)
struct XrdFfsQueueTasks * XrdFfsQueue_create_task(void *(*func)(void *), void **args, short initstat)
unsigned int XrdFfsQueue_count_tasks()
void XrdFfsQueue_wait_task(struct XrdFfsQueueTasks *task)
#define statvfs(a, b)
Definition XrdPosix.hh:105
#define stat(a, b)
Definition XrdPosix.hh:101
Send file/filesystem queries to an XRootD cluster.
XRootDStatus DeepLocate(const std::string &path, OpenFlags::Flags flags, ResponseHandler *handler, uint16_t timeout=0) XRD_WARN_UNUSED_RESULT
const std::string & GetAddress() const
Get address.
Path location info.
Location & At(uint32_t index)
Get the location at index.
URL representation.
Definition XrdClURL.hh:31
const std::string & GetPath() const
Get the path.
Definition XrdClURL.hh:217
static ssize_t Pread(int fildes, void *buf, size_t nbyte, off_t offset)
Pread() conforms to POSIX.1-2001 pread()
static int Closedir(DIR *dirp)
Closedir() conforms to POSIX.1-2001 closedir()
static int Stat(const char *path, struct stat *buf)
Stat() conforms to POSIX.1-2001 stat()
static int Mkdir(const char *path, mode_t mode)
Mkdir() conforms to POSIX.1-2001 mkdir()
static int Unlink(const char *path)
Unlink() conforms to POSIX.1-2001 unlink()
static int Rmdir(const char *path)
Rmdir() conforms to POSIX.1-2001 rmdir()
static int Rename(const char *oldpath, const char *newpath)
Rename() conforms to POSIX.1-2001 rename()
static int Close(int fildes)
Close() conforms to POSIX.1-2001 close()
static ssize_t Write(int fildes, const void *buf, size_t nbyte)
Write() conforms to POSIX.1-2001 write()
static struct dirent * Readdir(DIR *dirp)
static int Ftruncate(int fildes, off_t offset)
Ftruncate() conforms to POSIX.1-2001 ftruncate()
static DIR * Opendir(const char *path)
Opendir() conforms to POSIX.1-2001 opendir()
static int Fsync(int fildes)
Fsync() conforms to POSIX.1-2001 fsync()
static long long Getxattr(const char *path, const char *name, void *value, unsigned long long size)
static ssize_t Read(int fildes, void *buf, size_t nbyte)
Read() conforms to POSIX.1-2001 read()
static off_t Lseek(int fildes, off_t offset, int whence)
Lseek() conforms to POSIX.1-2001 lseek()
static int Open(const char *path, int oflag, mode_t mode=0, XrdPosixCallBack *cbP=0)
static ssize_t Pwrite(int fildes, const void *buf, size_t nbyte, off_t offset)
Pwrite() conforms to POSIX.1-2001 pwrite()
static int Truncate(const char *path, off_t offset)
Telldir() conforms to POSIX.1-2001 telldir()
bool IsOK() const
We're fine.