XrdFfsXrootdfs.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /* xrootdfs.cc  FUSE based file system interface to Xrootd Storage Cluster    */
00003 /*                                                                            */
00004 /* (c) 2010 by the Board of Trustees of the Leland Stanford, Jr., University  */
00005 /*                            All Rights Reserved                             */
00006 /* Author: Wei Yang (SLAC National Accelerator Laboratory, 2009)              */
00007 /*         Contract DE-AC02-76-SFO0515 with the Department of Energy          */
00008 /******************************************************************************/
00009 
00010 #define FUSE_USE_VERSION 26
00011 
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <unistd.h>
00015 
00016 #if defined(__linux__)
00017 /* For pread()/pwrite() */
00018 #ifndef _XOPEN_SOURCE
00019 #define _XOPEN_SOURCE 500
00020 #endif
00021 #endif
00022 
00023 #ifdef HAVE_FUSE
00024 #include <fuse.h>
00025 #include <string.h>
00026 #include <fcntl.h>
00027 #include <dirent.h>
00028 #include <errno.h>
00029 #include <sys/time.h>
00030 #include <pthread.h>
00031 #include <pwd.h>
00032 #include <libgen.h>
00033 #include <syslog.h>
00034 #if !defined(__solaris__)
00035 #include <sys/xattr.h>
00036 #endif
00037 
00038 #include "XrdFfs/XrdFfsPosix.hh"
00039 #include "XrdFfs/XrdFfsMisc.hh"
00040 #include "XrdFfs/XrdFfsWcache.hh"
00041 #include "XrdFfs/XrdFfsQueue.hh"
00042 //#include "XrdFfs/XrdFfsDent.hh"
00043 #include "XrdFfs/XrdFfsFsinfo.hh"
00044 #include "XrdPosix/XrdPosixXrootd.hh"
00045 
00046 char *rdr, *cns, *fastls="", *daemon_user;
00047 //enum Boolean {false, true} ofsfwd;
00048 bool ofsfwd;
00049 
00050 static void* xrootdfs_init(struct fuse_conn_info *conn)
00051 {
00052     struct passwd *pw;
00053 
00054     if (daemon_user != NULL)
00055     {
00056         pw = getpwnam(daemon_user);
00057         setgid((gid_t)pw->pw_gid);
00058         setuid((uid_t)pw->pw_uid);
00059     }
00060 
00061 /*
00062    From FAQ:
00063       Miscellaneous threads should be started from the init() method.
00064    Threads started before fuse_main() will exit when the process goes
00065    into the background.
00066 */
00067 
00068 #ifndef NOUSE_QUEUE
00069     if (getenv("XROOTDFS_NWORKERS") != NULL)
00070         XrdFfsQueue_create_workers(atoi(getenv("XROOTDFS_NWORKERS")));
00071     else
00072         XrdFfsQueue_create_workers(4);
00073 
00074     syslog(LOG_INFO, "INFO: Starting %d workers", XrdFfsQueue_count_workers());
00075 #else
00076     syslog(LOG_INFO, "INFO: Not compiled to use task queue");
00077 #endif
00078     return NULL;
00079 }
00080 
00081 static int xrootdfs_getattr(const char *path, struct stat *stbuf)
00082 {
00083 //  int res, fd;
00084     int res;
00085     char rootpath[1024];
00086     uid_t user_uid, uid;
00087     gid_t user_gid, gid;
00088 
00089     user_uid = fuse_get_context()->uid;
00090     uid = getuid();
00091 
00092     user_gid = fuse_get_context()->gid;
00093     gid = getgid();
00094 
00095     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00096 
00097     rootpath[0]='\0';
00098 /*
00099     if (cns != NULL && fastls != NULL)
00100         strcat(rootpath,cns);
00101     else
00102         strcat(rootpath,rdr);
00103     strcat(rootpath,path);
00104 
00105 //    setegid(fuse_get_context()->gid);
00106 //    seteuid(fuse_get_context()->uid);
00107 
00108     res = XrdFfsPosix_stat(rootpath, stbuf);
00109 */
00110 
00111     if (cns != NULL && fastls != NULL)
00112     {
00113         strcat(rootpath,cns);
00114         strcat(rootpath,path);
00115         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00116         res = XrdFfsPosix_stat(rootpath, stbuf);
00117     }
00118     else
00119         res = XrdFfsPosix_statall(rdr, path, stbuf, fuse_get_context()->uid);
00120 
00121 //    seteuid(getuid());
00122 //    setegid(getgid());
00123 
00124 //    stbuf->st_uid = user_uid;
00125 //    stbuf->st_gid = user_gid;
00126 
00127     if (res == 0)
00128     {
00129         if (S_ISREG(stbuf->st_mode))
00130         {
00131 /*
00132    By adding the following 'if' block, 'fastls = RDR' will force XrootdFS to check
00133    with redirector for file status info (not directory). 
00134 
00135    Some applicatios such as SRM may do extensive file or directory existence checking.
00136    These applications can't tolerant slow responding on file or directory info (if
00137    don't exist). They also expect correct file size. For this type of application, we
00138    can set 'fastls = RDR'.
00139 
00140    Allowing multi-thread may solve this problem. However, XrootdFS crashs under some 
00141    situation, and we have to add -s (single thread) option when runing XrootdFS.
00142  */
00143             if (cns != NULL && fastls != NULL && strcmp(fastls,"RDR") == 0)
00144             {
00145                 rootpath[0]='\0';
00146                 strcat(rootpath,rdr);
00147                 strcat(rootpath,path);
00148                 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00149                 XrdFfsPosix_stat(rootpath, stbuf);
00150 //                stbuf->st_uid = user_uid;
00151 //                stbuf->st_gid = user_gid;
00152             }
00153             stbuf->st_mode |= 0666;
00154             stbuf->st_mode &= 0772777;  /* remove sticky bit and suid bit */
00155             stbuf->st_blksize = 32768;  /* unfortunately, it is ignored, see include/fuse.h */
00156             return 0;
00157         }
00158         else if (S_ISDIR(stbuf->st_mode))
00159         {
00160             stbuf->st_mode |= 0777;
00161             stbuf->st_mode &= 0772777;  /* remove sticky bit and suid bit */
00162             return 0;
00163         }
00164         else
00165             return -EIO;
00166     }
00167     else if (res == -1 && cns != NULL && fastls != NULL)
00168         return -errno;
00169     else if (cns == NULL)
00170         return -errno;
00171     else
00172     {
00173         rootpath[0]='\0';
00174         strcat(rootpath,cns);
00175         strcat(rootpath,path);
00176         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00177         res = XrdFfsPosix_stat(rootpath, stbuf);
00178 //        stbuf->st_uid = user_uid;
00179 //        stbuf->st_gid = user_gid;
00180         if (res == -1)
00181             return -errno;
00182         else 
00183         {
00184             if (S_ISREG(stbuf->st_mode))
00185                 return -ENOENT;
00186             else if (S_ISDIR(stbuf->st_mode))
00187             {
00188                 stbuf->st_mode |= 0777;
00189                 stbuf->st_mode &= 0772777;
00190                 return 0;
00191             }
00192             else
00193                 return -EIO;
00194         }
00195     }
00196 }
00197 
00198 static int xrootdfs_access(const char *path, int mask)
00199 {
00200 /*
00201     int res;
00202     res = access(path, mask);
00203     if (res == -1)
00204         return -errno;
00205 */
00206     return 0;
00207 }
00208 
00209 static int xrootdfs_readlink(const char *path, char *buf, size_t size)
00210 {
00211 /*
00212     int res;
00213 
00214     res = readlink(path, buf, size - 1);
00215     if (res == -1)
00216         return -errno;
00217 
00218     buf[res] = '\0';
00219 */
00220     return 0;
00221 }
00222 
00223 static int xrootdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
00224                        off_t offset, struct fuse_file_info *fi)
00225 {
00226     DIR *dp;
00227     struct dirent *de;
00228 
00229     (void) offset;
00230     (void) fi;
00231 
00232     char rootpath[1024];
00233 
00234     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00235 /* 
00236    if CNS server is not defined, there is no way to list files in a directory
00237    because we don't know the data nodes
00238 */
00239     if (cns != NULL)
00240     {
00241         rootpath[0]='\0';
00242         strcat(rootpath,cns);
00243         strcat(rootpath,path);
00244 
00245         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00246         dp = XrdFfsPosix_opendir(rootpath);
00247         if (dp == NULL)
00248             return -errno;
00249                                                                                                                                                
00250         while ((de = XrdFfsPosix_readdir(dp)) != NULL)
00251         {
00252 /*
00253             struct stat st;
00254             memset(&st, 0, sizeof(st));
00255             st.st_ino = de->d_ino;
00256             st.st_mode = de->d_type << 12;
00257  */
00258             if (filler(buf, de->d_name, NULL, 0))
00259                 break;
00260         }
00261         XrdFfsPosix_closedir(dp);
00262         return 0;
00263     }
00264     else  /* if there is no CNS, try collect dirents from all known data servers. */
00265     {
00266          int i, n;
00267          char **dnarray;
00268 
00269          n = XrdFfsPosix_readdirall(rdr, path, &dnarray, fuse_get_context()->uid);
00270 
00271          for (i = 0; i < n; i++)
00272              if (filler(buf, dnarray[i], NULL, 0)) break;
00273 
00274 /* 
00275   this loop should not be merged with the above loop because all members of 
00276   dnarray[] should be freed, or there will be memory leak.
00277  */
00278          for (i = 0; i < n; i++) 
00279              free(dnarray[i]);
00280          free(dnarray); 
00281 
00282          return -errno;
00283     }
00284 }
00285 
00286 static int xrootdfs_mknod(const char *path, mode_t mode, dev_t rdev)
00287 {
00288     int res;
00289 
00290     /* On Linux this could just be 'mknod(path, mode, rdev)' but this
00291        is more portable */
00292     char rootpath[1024];
00293 
00294     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00295     if (S_ISREG(mode))
00296     {
00297         rootpath[0]='\0';
00298         strcat(rootpath,rdr);
00299         strcat(rootpath,path);
00300 
00301         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00302         res = XrdFfsPosix_open(rootpath, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 
00303 //        res = XrdFfsPosix_open(rootpath, O_CREAT | O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 
00304         if (res == -1)
00305             return -errno;
00306         XrdFfsPosix_close(res);
00307 /* We have to make sure CNS file is created as well, otherwise, xrootdfs_getattr()
00308    may or may not find this file (due to multi-threads) */
00309         if (cns == NULL)
00310             return 0;
00311 
00312         rootpath[0]='\0';
00313         strcat(rootpath,cns);
00314         strcat(rootpath,path);
00315 
00316         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00317         res = XrdFfsPosix_open(rootpath, O_CREAT | O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 
00318         XrdFfsPosix_close(res);
00319 /* We actually don't need to care about error by this XrdFfsPosix_open() */
00320     }
00321     return 0;
00322 }
00323 
00324 static int xrootdfs_mkdir(const char *path, mode_t mode)
00325 {
00326     int res;
00327     char rootpath[1024];
00328 /*  
00329     Posix Mkdir() fails on the current version of Xrootd, 20071101-0808p1 
00330     So we avoid doing that. This is fixed in CVS head version.
00331 */
00332 /*
00333     if CNS is defined, only mkdir() on CNS. Otherwise, mkdir() on redirector
00334  */
00335     rootpath[0]='\0';
00336 
00337     if (cns != NULL)
00338         strcat(rootpath,cns);
00339     else
00340         strcat(rootpath,rdr);
00341 
00342     strcat(rootpath,path);
00343 
00344     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00345     XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00346     res = XrdFfsPosix_mkdir(rootpath, mode);
00347     return ((res == -1)? -errno : 0);
00348 }
00349 
00350 static int xrootdfs_unlink(const char *path)
00351 {
00352     int res;
00353     char rootpath[1024];
00354 
00355     rootpath[0]='\0';
00356     strcat(rootpath,rdr);
00357     strcat(rootpath,path);
00358 
00359     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00360     if (ofsfwd == true)
00361     {
00362         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00363         res = XrdFfsPosix_unlink(rootpath);
00364     }
00365     else
00366         res = XrdFfsPosix_unlinkall(rdr, path, fuse_get_context()->uid);
00367 
00368     if (res == -1)
00369         return -errno;
00370 
00371     if (cns != NULL && ofsfwd == false)
00372     {
00373         rootpath[0]='\0';
00374         strcat(rootpath,cns);
00375         strcat(rootpath,path);
00376 
00377         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00378         res = XrdFfsPosix_unlink(rootpath);
00379         if (res == -1)
00380             return -errno;
00381     }
00382     return 0;
00383 }
00384 
00385 static int xrootdfs_rmdir(const char *path)
00386 {
00387     int res;
00388 //  struct stat stbuf;
00389     char rootpath[1024];
00390 
00391     rootpath[0]='\0';
00392     strcat(rootpath,rdr);
00393     strcat(rootpath,path);
00394 
00395     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00396     if (ofsfwd == true)
00397     { 
00398         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00399         res = XrdFfsPosix_rmdir(rootpath);
00400     }
00401     else
00402         res = XrdFfsPosix_rmdirall(rdr, path, fuse_get_context()->uid);
00403 
00404     if (res == -1)
00405         return -errno;
00406 
00407     if (cns != NULL && ofsfwd == false)
00408     {
00409         rootpath[0]='\0';
00410         strcat(rootpath,cns);
00411         strcat(rootpath,path);
00412 
00413         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00414         res = XrdFfsPosix_rmdir(rootpath);
00415         if (res == -1)
00416             return -errno;
00417     }
00418     /* 
00419       clear cache in redirector. otherwise, an immediate mkdir(path) will fail
00420      */
00421     if (ofsfwd == false)
00422     {
00423         rootpath[0]='\0';
00424         strcat(rootpath,rdr);
00425         strcat(rootpath,path);
00426 
00427         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00428         XrdFfsPosix_rmdir(rootpath);
00429     }
00430     return 0;
00431 }
00432 
00433 static int xrootdfs_symlink(const char *from, const char *to)
00434 {
00435 /*
00436     int res;
00437 
00438     res = symlink(from, to);
00439     if (res == -1)
00440         return -errno;
00441 */
00442     return -EIO;
00443 }
00444 
00445 static int xrootdfs_rename(const char *from, const char *to)
00446 {
00447     int res;
00448     char from_path[1024], to_path[1024];
00449     struct stat stbuf;
00450 
00451     from_path[0]='\0';
00452     strcat(from_path, rdr);
00453     strcat(from_path, from);
00454 
00455     to_path[0]='\0';
00456     strcat(to_path, rdr);
00457     strcat(to_path, to);
00458 /*
00459   As of 2009-11-19(20), the CVS head has a bug in XrdFfsPosix_rename() fixed so that 
00460   the removal of old file and creation of new file is notified to redirector
00461   (to update its cache). Until this is bundled in main stream xrootd releases,
00462   we will just retuen a -EXDEV for now.
00463 
00464   After the main stream xrootd includes this fix, the ideal way is:
00465   1. do actual renaming on data servers if if is a file in order to speed up
00466      renaming
00467   2. return -EXDEV for renaming of directory so that files in the directory
00468      are renamed individually (in order for the .pfn pointing back correctly).
00469  */
00470     return -EXDEV;
00471 
00472     XrdFfsPosix_stat(from_path, &stbuf);
00473     if (S_ISDIR(stbuf.st_mode)) /* && cns == NULL && ofsfwd == false) */
00474         return -EXDEV;
00475 
00476     if (ofsfwd == true)
00477         res = XrdFfsPosix_rename(from_path, to_path);
00478     else
00479         res = XrdFfsPosix_renameall(rdr, from, to, fuse_get_context()->uid);
00480 
00481     if (res == -1)
00482         return -errno;
00483 
00484     if (cns != NULL && ofsfwd == false)
00485     {
00486         from_path[0]='\0';
00487         strcat(from_path, cns);
00488         strcat(from_path, from);
00489 
00490         to_path[0]='\0';
00491         strcat(to_path, cns);
00492         strcat(to_path, to);
00493 
00494         res = XrdFfsPosix_rename(from_path, to_path);
00495         if (res == -1)
00496             return -errno;
00497     }
00498     return 0;
00499 
00500 /*  return -EXDEV */
00501 }
00502 
00503 static int xrootdfs_link(const char *from, const char *to)
00504 {
00505 /*
00506     int res;
00507 
00508     res = link(from, to);
00509     if (res == -1)
00510         return -errno;
00511 */
00512     return -EMLINK;
00513 }
00514 
00515 static int xrootdfs_chmod(const char *path, mode_t mode)
00516 {
00517 /*
00518     int res;
00519 
00520     res = chmod(path, mode);
00521     if (res == -1)
00522         return -errno;
00523 */
00524     return 0;
00525 }
00526 
00527 static int xrootdfs_chown(const char *path, uid_t uid, gid_t gid)
00528 {
00529 /*
00530     int res;
00531 
00532     res = lchown(path, uid, gid);
00533     if (res == -1)
00534         return -errno;
00535 */
00536     return 0;
00537 }
00538 
00539 /* _ftruncate() will only work with kernel >= 2.6.15. See FUSE ChangeLog */
00540 static int xrootdfs_ftruncate(const char *path, off_t size,
00541                               struct fuse_file_info *fi)
00542 {
00543     int fd, res;
00544 //  char rootpath[1024];
00545                                                                                                                                            
00546     fd = (int) fi->fh;
00547     XrdFfsWcache_flush(fd);
00548     res = XrdFfsPosix_ftruncate(fd, size);
00549     if (res == -1)
00550         return -errno;
00551                                                                                                                               
00552 /* 
00553    There is no need to update the size of the CNS shadow file now. That
00554    should be updated when the file is closed 
00555 
00556     if (cns != NULL) 
00557     {
00558         rootpath[0]='\0';
00559         strcat(rootpath,cns);
00560         strcat(rootpath,path);
00561 
00562         res = XrdFfsPosix_truncate(rootpath, size);
00563         if (res == -1)
00564             return -errno;
00565     }
00566 */
00567     return 0;
00568 }
00569 
00570 static int xrootdfs_truncate(const char *path, off_t size)
00571 {
00572     int res;
00573     char rootpath[1024];
00574 
00575     rootpath[0]='\0';
00576     strcat(rootpath,rdr);
00577     strcat(rootpath,path);
00578 
00579     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00580     if (ofsfwd == true)
00581     {
00582         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00583         res = XrdFfsPosix_truncate(rootpath, size);
00584     }
00585     else
00586         res = XrdFfsPosix_truncateall(rdr, path, size, fuse_get_context()->uid);
00587 
00588     if (res == -1)
00589         return -errno;
00590 
00591     if (cns != NULL && ofsfwd == false)
00592     {
00593         rootpath[0]='\0';
00594         strcat(rootpath,cns);
00595         strcat(rootpath,path);
00596 
00597         XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00598         res = XrdFfsPosix_truncate(rootpath, size);
00599         if (res == -1)
00600             return -errno;
00601     }
00602     return 0;
00603 }
00604 
00605 static int xrootdfs_utimens(const char *path, const struct timespec ts[2])
00606 {
00607 /*
00608     int res;
00609     struct timeval tv[2];
00610 
00611     tv[0].tv_sec = ts[0].tv_sec;
00612     tv[0].tv_usec = ts[0].tv_nsec / 1000;
00613     tv[1].tv_sec = ts[1].tv_sec;
00614     tv[1].tv_usec = ts[1].tv_nsec / 1000;
00615 
00616     res = utimes(path, tv);
00617     if (res == -1)
00618         return -errno;
00619 */
00620     return 0;
00621 }
00622 
00623 static int xrootdfs_open(const char *path, struct fuse_file_info *fi)
00624 {
00625     int res;
00626     char rootpath[1024]="";
00627     strcat(rootpath,rdr);
00628     strcat(rootpath,path);
00629 
00630     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00631     XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00632     res = XrdFfsPosix_open(rootpath, fi->flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
00633     if (res == -1)
00634         return -errno;
00635 
00636     fi->fh = res;
00637     XrdFfsWcache_create(fi->fh);
00638     return 0;
00639 }
00640 
00641 static int xrootdfs_read(const char *path, char *buf, size_t size, off_t offset,
00642                     struct fuse_file_info *fi)
00643 {
00644     int fd;
00645     int res;
00646 
00647     fd = (int) fi->fh;
00648     XrdFfsWcache_flush(fd);  /* in case is the file is reading/writing */
00649     res = XrdFfsPosix_pread(fd, buf, size, offset);
00650     if (res == -1)
00651         res = -errno;
00652 
00653     return res;
00654 }
00655 
00656 static int xrootdfs_write(const char *path, const char *buf, size_t size,
00657                      off_t offset, struct fuse_file_info *fi)
00658 {
00659     int fd;
00660     int res;
00661 
00662 /* 
00663    File already existed. FUSE uses xrootdfs_open() and xrootdfs_truncate() to open and
00664    truncate a file before calling xrootdfs_write() 
00665 */
00666     fd = (int) fi->fh;
00667 //    res = XrdFfsPosix_pwrite(fd, buf, size, offset);
00668     res = XrdFfsWcache_pwrite(fd, (char *)buf, size, offset);
00669     if (res == -1)
00670         res = -errno;
00671 
00672     return res;
00673 }
00674 
00675 static int xrootdfs_statfs(const char *path, struct statvfs *stbuf)
00676 {
00677     int res;
00678 //  char rootpath[1024], xattr[256];
00679 //  char *token, *key, *value;
00680 //  char *lasts_xattr[256], *lasts_tokens[128];
00681 //  long long size;
00682 
00683 //    XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00684 #ifndef __macos__
00685     stbuf->f_bsize = 1024;
00686 #else
00687     stbuf->f_bsize = 1024 * 128; // work around 32 bit fsblkcnt_t in struct statvfs on Mac OSX
00688     stbuf->f_frsize = stbuf->f_bsize; // seems there are other limitations, 1024*128 is a max we set
00689 #endif
00690 
00691 //    res = XrdFfsPosix_statvfsall(rdr, path, stbuf, fuse_get_context()->uid);
00692     res = XrdFfsFsinfo_cache_search(&XrdFfsPosix_statvfsall, rdr, path, stbuf, fuse_get_context()->uid);
00693 
00694 /*
00695     stbuf->f_blocks /= stbuf->f_bsize;
00696     stbuf->f_bavail /= stbuf->f_bsize;
00697     stbuf->f_bfree /= stbuf->f_bsize;
00698 */
00699     return res;
00700 /*
00701     stbuf->f_bsize = 16384;
00702     stbuf->f_blocks = 1048576;
00703     stbuf->f_bfree = stbuf->f_blocks;
00704     stbuf->f_bavail = stbuf->f_blocks;
00705 
00706     if (cns == NULL) return 0; 
00707 
00708     rootpath[0]='\0';
00709     strcat(rootpath,cns);
00710     strcat(rootpath,path);
00711 
00712     res = XrdFfsPosix_getxattr(rootpath, "xroot.space", xattr, 256);
00713     if (res == -1)
00714         return 0;
00715     else 
00716     {
00717         token = strtok_r(xattr, "&", lasts_xattr);
00718         while (token != NULL)
00719         {
00720              token = strtok_r(NULL, "&", lasts_xattr); 
00721              if (token == NULL) break;
00722              key = strtok_r(token, "=", lasts_tokens);
00723              value = strtok_r(NULL, "=", lasts_tokens);
00724              if (!strcmp(key,"oss.used"))
00725              {
00726                   sscanf((const char*)value, "%lld", &size);
00727                   stbuf->f_bavail = size / stbuf->f_bsize;
00728              }
00729              else if (!strcmp(key,"oss.quota"))
00730              {
00731                   sscanf((const char*)value, "%lld", &size);
00732                   stbuf->f_blocks = size / stbuf->f_bsize;
00733              }
00734         }
00735         stbuf->f_bavail = stbuf->f_blocks - stbuf->f_bavail;
00736         stbuf->f_bfree = stbuf->f_bavail;
00737     }
00738     return 0;
00739  */
00740 }
00741 
00742 static int xrootdfs_release(const char *path, struct fuse_file_info *fi)
00743 {
00744     /* Just a stub.  This method is optional and can safely be left
00745        unimplemented */
00746 
00747     int fd, oflag;
00748     struct stat xrdfile, cnsfile;
00749     char rootpath[1024];
00750 
00751     fd = (int) fi->fh;
00752     XrdFfsWcache_flush(fd);
00753     XrdFfsWcache_destroy(fd);
00754     XrdFfsPosix_close(fd);
00755     fi->fh = 0;
00756 /* 
00757    Return at here because the current version of Cluster Name Space daemon 
00758    doesn't implement the 'truncate' functon we originally planned.
00759 
00760     return 0;
00761 */
00762     if (cns == NULL || (fi->flags & 0100001) == (0100000 | O_RDONLY))
00763         return 0;
00764 
00765     int res;
00766     char xattr[256], xrdtoken[256];
00767     char *token, *key, *value;
00768     char *lasts_xattr[256], *lasts_tokens[128];
00769 
00770     rootpath[0]='\0';
00771     strcat(rootpath,rdr);
00772     strcat(rootpath,path);
00773 /*
00774  * Get xrootd token info from data nodes. And set the token info on CNS
00775  */
00776     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00777     XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00778     xrdtoken[0]='\0';
00779     res = XrdFfsPosix_getxattr(rootpath, "xroot.xattr", xattr, 256);
00780     if (res != -1)
00781     {
00782         token = strtok_r(xattr, "&", lasts_xattr);
00783         while (token != NULL)
00784         {
00785              key = strtok_r(token, "=", lasts_tokens);
00786              value = strtok_r(NULL, "=", lasts_tokens);
00787              if (!strcmp(key,"oss.cgroup")) 
00788                  strcpy(xrdtoken, value);
00789 
00790              if (!strcmp(key,"oss.used"))
00791                 {long long llVal;
00792                  sscanf((const char*)value, "%lld", &llVal);
00793                  xrdfile.st_size = llVal;
00794                 }
00795              token = strtok_r(NULL, "&", lasts_xattr);
00796         }
00797     }
00798     else
00799     {
00800         XrdFfsPosix_stat(rootpath,&xrdfile);
00801     }
00802 
00803     rootpath[0]='\0';
00804     strcat(rootpath,cns);
00805     strcat(rootpath,path);
00806 
00807     XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00808     if (xrdtoken[0] != '\0' && strstr(path,"?oss.cgroup=") == NULL)
00809     {
00810         strcat(rootpath,"?oss.cgroup=");
00811         strcat(rootpath,xrdtoken);
00812     }
00813 
00814     if (XrdFfsPosix_stat(rootpath,&cnsfile) == -1)
00815         oflag = O_CREAT|O_WRONLY;
00816     else
00817         oflag = O_TRUNC|O_WRONLY;
00818 
00819 /* 
00820    This creates a file on CNS with the right size. But it is actually an empty file.
00821    It doesn't use disk space, only inodes.
00822 */
00823     if (cnsfile.st_size != xrdfile.st_size)
00824     {
00825         fd = XrdFfsPosix_open(rootpath,oflag,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
00826         if (fd >= 0) 
00827         {
00828             XrdFfsPosix_lseek(fd,(off_t)xrdfile.st_size-1,SEEK_SET);
00829             XrdFfsPosix_write(fd,"",1);
00830             XrdFfsPosix_close(fd);
00831         }
00832     }
00833 
00834     return 0;
00835 }
00836 
00837 static int xrootdfs_fsync(const char *path, int isdatasync,
00838                      struct fuse_file_info *fi)
00839 {
00840     /* Just a stub.  This method is optional and can safely be left
00841        unimplemented */
00842 
00843     (void) path;
00844     (void) isdatasync;
00845     (void) fi;
00846     return 0;
00847 }
00848 
00849 /* xattr operations are optional and can safely be left unimplemented */
00850 static int xrootdfs_setxattr(const char *path, const char *name, const char *value,
00851                         size_t size, int flags)
00852 {
00853     if (fuse_get_context()->uid != 0 && fuse_get_context()->uid != getuid())
00854         return -EPERM;
00855 
00856     if (!strcmp(name,"xrootdfs.fs.dataserverlist"))
00857     {
00858         int i;
00859         char *hostlist, *p1, *p2;
00860 
00861         XrdFfsMisc_refresh_url_cache(rdr);
00862 
00863         hostlist = (char*) malloc(sizeof(char) * XrdFfs_MAX_NUM_NODES * 1024);
00864         i = XrdFfsMisc_get_list_of_data_servers(hostlist);
00865 
00866         syslog(LOG_INFO, "INFO: Will use the following %d data servers", i);
00867         p1 = hostlist;
00868         p2 = strchr(p1, '\n');
00869         while (p2 != NULL)
00870         {
00871             p2[0] = '\0';
00872             syslog(LOG_INFO, "   %s", p1);
00873             p1 = p2 +1;
00874             p2 = strchr(p1, '\n');
00875         }
00876         free(hostlist);
00877     }
00878     else if (!strcmp(name,"xrootdfs.fs.nworkers"))
00879     {
00880         int i, j;
00881         char *tmp_value;
00882         tmp_value=strdup(value);
00883         if (size > 0) tmp_value[size] = '\0';
00884 
00885         i = XrdFfsQueue_count_workers();
00886         j = atoi(tmp_value);
00887         free(tmp_value);
00888         if (j > i) 
00889             XrdFfsQueue_create_workers( j-i );
00890         if (j < i)
00891             XrdFfsQueue_remove_workers( i-j ); // XrdFfsQueue_remove_workers() will wait until workers are removed.
00892         j = XrdFfsQueue_count_workers();
00893 #ifndef NOUSE_QUEUE
00894         syslog(LOG_INFO, "INFO: Adjust the number of workers from %d to %d", i, j);
00895 #endif
00896     }
00897     return 0;
00898 }
00899 
00900 static int xrootdfs_getxattr(const char *path, const char *name, char *value,
00901                     size_t size)
00902 {
00903     int xattrlen;
00904     char rootpath[1024]="";
00905     char rooturl[1024]="";
00906 
00907     if (!strcmp(name,"xroot.url"))
00908     {
00909         errno = 0;
00910         strcat(rootpath,rdr);
00911         strcat(rootpath,path);
00912 
00913 //        XrdFfsMisc_get_current_url(rootpath, rooturl);
00914         strcat(rooturl, rootpath);
00915 
00916         if (size == 0)
00917             return strlen(rooturl);
00918         else if (size >= strlen(rooturl)) 
00919         {
00920             size = strlen(rooturl);
00921             if (size != 0) 
00922             {
00923                 value[0] = '\0';
00924                 strcat(value, rooturl);
00925             }
00926             return size;
00927         }
00928         else
00929         {
00930             errno = ERANGE;
00931             return -1;
00932         }
00933     }
00934     else if (!strcmp(name, "xrootdfs.fs.dataserverlist"))
00935     {
00936         char hostlist[4096 * 1024];
00937         XrdFfsMisc_get_list_of_data_servers(hostlist);
00938 
00939         if (size == 0)
00940             return strlen(hostlist);
00941         else if (size >= strlen(hostlist))
00942         {
00943              size = strlen(hostlist);
00944              if (size != 0)
00945              {
00946                   value[0] = '\0';
00947                   strcat(value, hostlist);
00948              }
00949              return size;
00950         }
00951         else
00952         {
00953             errno = ERANGE;
00954             return -1;
00955         }
00956     }
00957     else if (!strcmp(name, "xrootdfs.fs.nworkers"))
00958     {
00959         char nworkers[7];
00960         int n;
00961         n = XrdFfsQueue_count_workers();
00962         sprintf(nworkers, "%d", n);
00963 
00964         if (size == 0)
00965             return strlen(nworkers);
00966         else if (size >= strlen(nworkers))
00967         {
00968              size = strlen(nworkers);
00969              if (size != 0)
00970              {
00971                   value[0] = '\0';
00972                   strcat(value, nworkers);
00973              }
00974              return size;
00975         }
00976         else
00977         {
00978             errno = ERANGE;
00979             return -1;
00980         }
00981     }
00982 
00983     if (cns != NULL)
00984         strcat(rootpath,cns);
00985     else
00986         strcat(rootpath,rdr);
00987     strcat(rootpath,path);
00988 
00989     XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
00990     XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
00991     xattrlen = XrdFfsPosix_getxattr(rootpath, name, value, size);
00992     if (xattrlen == -1)
00993         return -errno;
00994     else
00995         return xattrlen;
00996 }
00997 
00998 static int xrootdfs_listxattr(const char *path, char *list, size_t size)
00999 {
01000 /*
01001     int res = llistxattr(path, list, size);
01002     if (res == -1)
01003         return -errno;
01004     return res;
01005 */
01006     return 0;
01007 }
01008 
01009 static int xrootdfs_removexattr(const char *path, const char *name)
01010 {
01011 /*
01012     int res = lremovexattr(path, name);
01013     if (res == -1)
01014         return -errno;
01015 */
01016     return 0;
01017 }
01018 
01019 static struct fuse_operations xrootdfs_oper; 
01020 
01021 int main(int argc, char *argv[])
01022 {
01023     static XrdPosixXrootd abc; // Do one time init for posix interface
01024     xrootdfs_oper.init          = xrootdfs_init;
01025     xrootdfs_oper.getattr       = xrootdfs_getattr;
01026     xrootdfs_oper.access        = xrootdfs_access;
01027     xrootdfs_oper.readlink      = xrootdfs_readlink;
01028     xrootdfs_oper.readdir       = xrootdfs_readdir;
01029     xrootdfs_oper.mknod         = xrootdfs_mknod;
01030     xrootdfs_oper.mkdir         = xrootdfs_mkdir;
01031     xrootdfs_oper.symlink       = xrootdfs_symlink;
01032     xrootdfs_oper.unlink        = xrootdfs_unlink;
01033     xrootdfs_oper.rmdir         = xrootdfs_rmdir;
01034     xrootdfs_oper.rename        = xrootdfs_rename;
01035     xrootdfs_oper.link          = xrootdfs_link;
01036     xrootdfs_oper.chmod         = xrootdfs_chmod;
01037     xrootdfs_oper.chown         = xrootdfs_chown;
01038     xrootdfs_oper.ftruncate     = xrootdfs_ftruncate;
01039     xrootdfs_oper.truncate      = xrootdfs_truncate;
01040     xrootdfs_oper.utimens       = xrootdfs_utimens;
01041     xrootdfs_oper.open          = xrootdfs_open;
01042     xrootdfs_oper.read          = xrootdfs_read;
01043     xrootdfs_oper.write         = xrootdfs_write;
01044     xrootdfs_oper.statfs        = xrootdfs_statfs;
01045     xrootdfs_oper.release       = xrootdfs_release;
01046     xrootdfs_oper.fsync         = xrootdfs_fsync;
01047     xrootdfs_oper.setxattr      = xrootdfs_setxattr;
01048     xrootdfs_oper.getxattr      = xrootdfs_getxattr;
01049     xrootdfs_oper.listxattr     = xrootdfs_listxattr;
01050     xrootdfs_oper.removexattr   = xrootdfs_removexattr;
01051 
01052     rdr = getenv("XROOTDFS_RDRURL");
01053     cns = getenv("XROOTDFS_CNSURL");
01054 /* convert xroot://... to root://... */
01055     if (rdr[0] == 'x') rdr = rdr+1;
01056     if (cns != NULL && cns[0] == 'x') cns = cns+1;
01057 
01058     fastls = getenv("XROOTDFS_FASTLS");
01059 /*
01060     If this is defined, XrootdFS will setuid/setgid to this user at xrootdfs_init().
01061  */
01062     daemon_user = getenv("XROOTDFS_USER");
01063 /*
01064     XROOTDFS_OFSFWD (ofs.fwd (and ofs.fwd 3way) on rm, rmdir, mv, truncate.
01065     if this is not defined, XrootdFS will go to CNS and each data server
01066     and do the work.
01067 
01068     If CNS is not defined, we have to set ofsfwd to false, or we will not be able to 
01069     get a return status of rm, rmdir, mv and truncate.
01070  */
01071     if (cns != NULL && getenv("XROOTDFS_OFSFWD") != NULL && ! strcmp(getenv("XROOTDFS_OFSFWD"),"1"))
01072         ofsfwd = true;
01073     else
01074         ofsfwd = false;
01075 
01076     XrdFfsMisc_xrd_init(rdr,0);
01077     XrdFfsWcache_init();
01078 
01079     umask(0);
01080     return fuse_main(argc, argv, &xrootdfs_oper, NULL);
01081 }
01082 #else
01083 
01084 int main(int argc, char *argv[])
01085 {
01086     printf("This platform does not have FUSE; xrootdfs cannot be started!");
01087     exit(13);
01088 }
01089 #endif

Generated on Tue Jul 5 14:46:35 2011 for ROOT_528-00b_version by  doxygen 1.5.1