"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "chironfs-1.1.1/src/chironfs.c" of archive chironfs-1.1.1.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /* Copyright 2005-2008 Luis Furquim
    2  *
    3  *
    4  * This program is free software; you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation; version 3 of the License.
    7  *
    8  * This program is distributed in the hope that it will be useful,
    9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11  * GNU General Public License for more details.
   12  *
   13  * You should have received a copy of the GNU General Public License
   14  * along with this program; if not, write to the Free Software
   15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   16  *
   17  */
   18 
   19 
   20 #include "config.h"
   21 
   22 #ifdef linux
   23 /* For pread()/pwrite() */
   24 #define _XOPEN_SOURCE 500
   25 #endif
   26 
   27 #define FUSE_USE_VERSION 25
   28 
   29 //
   30 // The lines below are from a patch contributed by Yen-Ming Lee,
   31 // porting ChironFS to FreeBSD
   32 //
   33 #include <fuse.h>
   34 #if defined(linux) || defined(__FreeBSD__)
   35 
   36 //#include <fuse/fuse.h>
   37 #include <fuse/fuse_opt.h>
   38 
   39 #else
   40 
   41 typedef  uint64_t cpuset_t;
   42 
   43 //
   44 // The line below are from a patch contributed by Antti Kantee
   45 // to make ChironFS run on NetBSD
   46 //
   47 
   48 #include <fuse_opt.h>
   49 
   50 #endif
   51 //
   52 // End of BSD patches
   53 //
   54 
   55 #include <stdlib.h>
   56 #include <stdio.h>
   57 #include <string.h>
   58 #include <stdarg.h>
   59 #include <unistd.h>
   60 #include <fcntl.h>
   61 #include <dirent.h>
   62 #include <errno.h>
   63 #include <time.h>
   64 #include <sys/time.h>
   65 #include <libgen.h>
   66 
   67 #ifdef HAVE_SETXATTR
   68 #include <sys/xattr.h>
   69 #endif
   70 
   71 #ifdef __linux__
   72 
   73 #include <linux/limits.h>
   74 #include <mntent.h>
   75 #include <bits/wordsize.h>
   76 
   77 #else
   78 
   79 #include <limits.h>
   80 #include <sys/types.h>
   81 #include <sys/statvfs.h>
   82 
   83 #endif
   84 
   85 
   86 //
   87 // The lines below are from a patch contributed by Yen-Ming Lee,
   88 // porting ChironFS to FreeBSD
   89 //
   90 #ifndef HAVE_GETMNTENT
   91 #include <sys/param.h>
   92 #include <sys/ucred.h>
   93 #include <sys/mount.h>
   94 #endif
   95 //
   96 // End of BSD patch
   97 //
   98 
   99 
  100 #include <stdint.h>
  101 #include <pwd.h>
  102 #include <grp.h>
  103 #include <sys/stat.h>
  104 
  105 
  106 #ifdef __linux__
  107 
  108 #define _REENTRANT
  109 
  110 #ifndef _POSIX_SOURCE
  111 #define _POSIX_SOURCE
  112 #endif
  113 
  114 /* for LinuxThreads */
  115 #define _P __P
  116 
  117 #endif
  118 
  119 #include <pthread.h>
  120 
  121 #include "config.h"
  122 
  123 #include "chiron-types.h"
  124 #include "chirondbg.h"
  125 #include "chironfn.h"
  126 #define _CHIRON_H_
  127 #include "chironfs.h"
  128 
  129 
  130 ////////////////////////////////////////////////////////////////////////////
  131 ////////////////////////////////////////////////////////////////////////////
  132 //
  133 //
  134 //  H A S H    F U N C T I O N S
  135 //
  136 //
  137 ////////////////////////////////////////////////////////////////////////////
  138 ////////////////////////////////////////////////////////////////////////////
  139 
  140 
  141 //
  142 //
  143 // This hash function was taken from http://www.concentric.net/~Ttwang/tech/inthash.htm
  144 // under the title "Robert Jenkins' 32 bit integer hash function"
  145 // There were no license statement there
  146 //
  147 //
  148 uint32_t hash( uint32_t a)
  149 {
  150    a = (a+0x7ed55d16) + (a<<12);
  151    a = (a^0xc761c23c) ^ (a>>19);
  152    a = (a+0x165667b1) + (a<<5);
  153    a = (a+0xd3a2646c) ^ (a<<9);
  154    a = (a+0xfd7046c5) + (a<<3);
  155    a = (a^0xb55a4f09) ^ (a>>16);
  156    return a;
  157 }
  158 
  159 
  160 // and this under the title "64 bit Mix Functions"
  161 uint64_t hash64shift(uint64_t key)
  162 {
  163   key = (~key) + (key << 21); // key = (key << 21) - key - 1;
  164   key = key ^ ((key >> 24));
  165   key = (key + (key << 3)) + (key << 8); // key * 265
  166   key = key ^ (key >> 14);
  167   key = (key + (key << 2)) + (key << 4); // key * 21
  168   key = key ^ (key >> 28);
  169   key = key + (key << 31);
  170   return key;
  171 }
  172 
  173 
  174 
  175 //
  176 //
  177 // End of Robert Jenkins' 32 bit hash function code
  178 //
  179 //
  180 
  181 
  182 unsigned hash_fd(unsigned fd_main)
  183 {
  184 
  185    return(
  186       (qt_hash_bits > 32)
  187          ? (hash64shift(fd_main) & hash_mask)
  188          : (hash(fd_main) & hash_mask)
  189    );
  190 }
  191 
  192 int fd_hashseekfree(unsigned fd_ndx)
  193 {
  194    unsigned i = fd_ndx;
  195    decl_tmvar(t1, t2, t3);
  196 
  197    gettmday(&t1,NULL);
  198 
  199                                                    dbg(("\nbufsz=%lx \thash=%lx",FD_BUF_SIZE,i));
  200 
  201    // If the hash address is used, search for an unused
  202    // starting at the next address, otherwise use it
  203    while ((tab_fd.fd[i]!=NULL) && (i<FD_BUF_SIZE)) {
  204       dbg(("X"));
  205       i++;
  206    }
  207    if (i<FD_BUF_SIZE) {
  208                                                    dbg(("\tused=%lx",i));
  209 
  210       return(i);
  211    }
  212 
  213    // If there is no free address until the end of the table
  214    // then restart the search from the beginning of the table
  215    i = 0;
  216    while ((tab_fd.fd[i]!=NULL) && (i<fd_ndx)) {
  217       i++;
  218    }
  219 
  220    gettmday(&t2,NULL);
  221    timeval_subtract(&t3,&t2,&t1);
  222    dbg(("\nhash time %ld secs,  %ld usecs",t3.tv_sec,t3.tv_usec));
  223 
  224    if (i<fd_ndx) {
  225                                                    dbg(("\tused=%lx",i));
  226       return(i);
  227    }
  228 
  229    // If there is no free address, return the error
  230    // We expect that it never happens because we set
  231    // the buffer to hold the file-max (the max opened
  232    // file system-wide)
  233    call_log("hash allocation","too many opened files",0);
  234    return(CHIRONFS_ERR_TOO_MANY_FOPENS);
  235 }
  236 
  237 int fd_hashset(int *fd)
  238 {
  239    int i, fd_ndx = -1;
  240 
  241    for(i=0;i<max_replica;++i) {
  242       if ((!paths[i].disabled) && (fd[i]>=0)) {
  243          fd_ndx = fd_hashseekfree(hash_fd(fd[i]));
  244          break;
  245       }
  246    }
  247 
  248    if (i==max_replica) {
  249       return(-1);
  250    }
  251 
  252    // If the hash address is not used then use it
  253    if (fd_ndx>=0) {
  254       tab_fd.fd[fd_ndx] = fd;
  255    }
  256    return(fd_ndx);
  257 }
  258 
  259 int choose_replica(int try)
  260 {
  261    decl_tmvar(t1, t2, t3);
  262    gettmday(&t1,NULL);
  263 
  264    if (!try) {
  265       curr_replica_high++;
  266       if (curr_replica_high==max_replica_high) {
  267          curr_replica_high = 0;
  268       }
  269    }
  270 
  271    if (try==max_replica_high) {
  272       curr_replica_low++;
  273       if (curr_replica_low==max_replica_low) {
  274          curr_replica_low = 0;
  275       }
  276    }
  277 
  278    gettmday(&t2,NULL);
  279    timeval_subtract(&t3,&t2,&t1);
  280    dbg(("\nchoose_replica time %ld secs,  %ld usecs",t3.tv_sec,t3.tv_usec));
  281 
  282    if (try<max_replica_high) {
  283                                        dbg(("\nhigh: try:  %u",try));
  284                                        dbg((",\trepl: %u",curr_replica_high));
  285                                        dbg((",\trr:   %u",round_robin_high[curr_replica_high][try]));
  286       return(round_robin_high[curr_replica_high][try]);
  287    }
  288                         dbg(("\nlow try:  %u",try));
  289                         dbg((",\trepl: %u",curr_replica_low));
  290                         dbg((",\trr:   %u",round_robin_low[curr_replica_low][try-max_replica_high]));
  291    return(round_robin_low[curr_replica_low][try-max_replica_high]);
  292 }
  293 
  294 void disable_replica(int n)
  295 {
  296    if (n<0) {
  297       call_log("disabling replica",paths[-n].path,CHIRONFS_ADM_FORCED);
  298       paths[-n].disabled = time(NULL);
  299    } else {
  300       call_log("disabling replica",paths[n].path,0);
  301       paths[n].disabled = time(NULL);
  302    }
  303 }
  304 
  305 void enable_replica(int n)
  306 {
  307    if (n<0) {
  308       call_log("enabling replica",paths[-n].path,CHIRONFS_ADM_FORCED);
  309       paths[-n].disabled = (time_t)1;
  310    } else {
  311       call_log("enabling replica",paths[n].path,0);
  312       paths[n].disabled = (time_t)1;
  313    }
  314 }
  315 
  316 void trust_replica(int n)
  317 {
  318    if (n<0) {
  319       call_log("trusting replica",paths[-n].path,CHIRONFS_ADM_FORCED);
  320       paths[-n].disabled = (time_t)0;
  321    } else {
  322       call_log("trusting replica",paths[n].path,0);
  323       paths[n].disabled = (time_t)0;
  324    }
  325 }
  326 
  327 
  328 ////////////////////////////////////////////////////////////////////////////
  329 ////////////////////////////////////////////////////////////////////////////
  330 //
  331 //
  332 //  P E R M I S S I O N   C H E C K   F U N C T I O N S
  333 //
  334 //
  335 ////////////////////////////////////////////////////////////////////////////
  336 ////////////////////////////////////////////////////////////////////////////
  337 
  338 #define get_ownership()                                    \
  339    context = fuse_get_context();                           \
  340    gid     = context->gid;                                 \
  341    slash   = strrchr(fname,'/');                           \
  342    if (slash!=NULL) {                                      \
  343       if (slash==fname) {                                  \
  344          dir_stat = stat("/", &stbuf);                     \
  345       } else {                                             \
  346          (*slash) = 0;                                     \
  347          dir_stat = stat(fname, &stbuf);                   \
  348       }                                                    \
  349       if (!dir_stat) {                                     \
  350          if (stbuf.st_mode&02000) {                        \
  351                                                     dbg(("\nmode: %o",stbuf.st_mode));       \
  352                                                     dbg(("\ngid: %u",stbuf.st_gid));         \
  353             gid = stbuf.st_gid;                            \
  354          }                                                 \
  355       }                                                    \
  356       if (slash!=fname) {                                  \
  357          (*slash) = '/';                                   \
  358       }                                                    \
  359    }
  360 
  361 
  362 #define decl_get_rights_vars()               \
  363    static struct fuse_context *context;      \
  364    struct stat    stbuf;                     \
  365    int            i, res=0;                  \
  366    struct group  result_buf, *result=NULL;   \
  367    char          *buffer;                    \
  368    struct passwd *pw;                        \
  369    uid_t          pw_uid;                    \
  370    int            perm;                      \
  371    char         **member;                    \
  372    context  = fuse_get_context()
  373 
  374 
  375 #define get_rights(fn,file)                                       \
  376    if ((res=fn(file, &stbuf))<0) {                                \
  377                                                           dbg(("\nfn1 ret=%d file=%s",res,file));    \
  378       return(res);                                                \
  379    }
  380 
  381 #define process_rights()                                          \
  382                                                           dbg(("\ncuid:%d\tstuid:%d",context->uid,stbuf.st_uid));  \
  383    if (context->uid==stbuf.st_uid) {                              \
  384       perm = (stbuf.st_mode&0700) >> 6;                           \
  385    } else if (context->gid==stbuf.st_gid) {                       \
  386       perm = (stbuf.st_mode&070) >> 3;                            \
  387    } else {                                                       \
  388       i = 1024;                                                   \
  389       do {                                                        \
  390          buffer     = calloc(i,sizeof(char));                     \
  391          if (buffer!=NULL) {                                      \
  392             res = getgrgid_r(stbuf.st_gid,                        \
  393                             &result_buf,                          \
  394                              buffer, i,                           \
  395                              &result);                            \
  396             if (res==ERANGE) {                                    \
  397                free(buffer);                                      \
  398                i <<= 1;                                           \
  399             }                                                     \
  400          }                                                        \
  401       } while ((res==ERANGE) && (buffer!=NULL));                  \
  402       if (buffer==NULL) {                                         \
  403          errno = ENOMEM;                                          \
  404          return(-1);                                              \
  405       }                                                           \
  406       if (result!=NULL) {                                         \
  407          member = result->gr_mem;                                 \
  408          while (*member) {                                        \
  409            pw = getpwnam(*member);                                \
  410            pw_uid = pw->pw_uid;                                   \
  411            if (pw_uid==context->uid) {                            \
  412               perm = (stbuf.st_mode&070) >> 3;                    \
  413               break;                                              \
  414            }                                                      \
  415            member++;                                              \
  416          }                                                        \
  417          if (*member==NULL) {                                     \
  418             perm = stbuf.st_mode&7;                               \
  419          }                                                        \
  420       } else {                                                    \
  421          perm = stbuf.st_mode&7;                                  \
  422       }                                                           \
  423       free(buffer);                                               \
  424    }
  425 
  426 
  427 // verify if all directories in the path are allowed to enter (rwx, r-x or --x)
  428 #define may_enter(filename)                          \
  429    dname = strdup(filename);                         \
  430    if (dname==NULL) {                                \
  431       errno = ENOMEM;                                \
  432       return(-1);                                    \
  433    }                                                 \
  434    bkdname = dname;                                  \
  435    do {                                              \
  436       dname = dirname(dname);                        \
  437       get_rights(stat,dname);                        \
  438       process_rights();                              \
  439       if (!(perm&1)) {                               \
  440          free(dname);                                \
  441          errno = EACCES;                             \
  442                                                      dbg(("\ndirperm: %d",perm));  \
  443          return(-1);                                 \
  444       }                                              \
  445    } while ((dname!=NULL) && (strcmp(dname,"/")));   \
  446    free(bkdname)
  447 
  448 
  449 
  450 int get_rights_by_name(const char *fname)
  451 {
  452    decl_get_rights_vars();
  453    char          *dname, *bkdname;
  454    if (!context->uid) {
  455       return(7);
  456    }
  457    may_enter(fname);
  458    get_rights(stat,fname);
  459    process_rights();
  460                                                    dbg(("\nperm: %d",perm));
  461    return(perm);
  462 }
  463 
  464 
  465 int get_rights_by_name_l(const char *fname)
  466 {
  467    decl_get_rights_vars();
  468    char          *dname, *bkdname;
  469    if (!context->uid) {
  470       return(7);
  471    }
  472    may_enter(fname);
  473    get_rights(lstat,fname);
  474    process_rights();
  475    return(perm);
  476 }
  477 
  478 
  479 int get_rights_by_fd(int fd)
  480 {
  481    decl_get_rights_vars();
  482    if (!context->uid) {
  483       return(7);
  484    }
  485    get_rights(fstat,fd);
  486    process_rights();
  487    return(perm);
  488 }
  489 
  490 int get_rights_by_mode(struct stat stb)
  491 {
  492    decl_get_rights_vars();
  493    stbuf = stb;
  494    if (!context->uid) {
  495       return(7);
  496    }
  497 
  498    process_rights();
  499                                                    dbg(("\nperm: %d",perm));
  500    return(perm);
  501 }
  502 
  503 
  504 int check_may_enter(char *fname)
  505 {
  506    decl_get_rights_vars();
  507    char          *dname, *bkdname;
  508    if (!context->uid) {
  509       return(0);
  510    }
  511    may_enter(fname);
  512    return(0);
  513 }
  514 
  515 
  516 
  517 ////////////////////////////////////////////////////////////////////////////
  518 ////////////////////////////////////////////////////////////////////////////
  519 //
  520 //
  521 //  W R A P P E R   F U N C T I O N S
  522 //
  523 //
  524 ////////////////////////////////////////////////////////////////////////////
  525 ////////////////////////////////////////////////////////////////////////////
  526 
  527 
  528 static int chiron_open(const char *path_orig, struct fuse_file_info *fi)
  529 {
  530    char   *fname, *path, *slash, *dname;
  531    int     i, fd_ndx = -1, *fd, *err_list, perm, perm_mask=0;
  532    int     succ_cnt=0, fail_cnt=0, file_exists, dir_stat;
  533    unsigned int gid;
  534    static struct fuse_context *context;
  535    struct stat stbuf;
  536    decl_tmvar(t1, t2, t3);
  537    decl_tmvar(t4, t5, t6);
  538                                                 dbg(("\nopen %s",path_orig));
  539 
  540    gettmday(&t1,NULL);
  541 
  542 
  543    fd = calloc(max_replica,sizeof(int));
  544    if (fd==NULL) {
  545       return -ENOMEM;
  546    }
  547 
  548    err_list = calloc(max_replica,sizeof(int));
  549    if (err_list==NULL) {
  550       free(fd);
  551       return -ENOMEM;
  552    }
  553 
  554    path = strdup(path_orig);
  555 
  556    if (path!=NULL) {
  557       for(i=(max_replica-1);i>=0;--i) {
  558          gettmday(&t5,NULL);
  559          if (!paths[i].disabled) {
  560             fname = xlate(path,paths[i].path);
  561             if (fname!=NULL) {
  562                file_exists = lstat(fname, &stbuf);
  563                if (file_exists<0) {
  564                   file_exists = (errno!=ENOENT);
  565                } else {
  566                   file_exists = 1;
  567                }
  568                if ((!file_exists) && (fi->flags&O_CREAT)) {
  569                   dname = strdup(fname);
  570                   if (dname==NULL) {
  571                      errno = ENOMEM;
  572                      perm  = -1;
  573                   } else {
  574                      perm = get_rights_by_name(dirname(dname));
  575                      free(dname);
  576                   }
  577                } else {
  578                   perm = get_rights_by_name(fname);
  579                }
  580                if (perm<0) {
  581                   fail_cnt++;
  582                   err_list[i] = -errno;
  583                   fd[i] = -1;
  584                } else {
  585                   if (fi->flags&(O_WRONLY|O_TRUNC|O_APPEND|O_CREAT)) {
  586                      perm_mask = 2;
  587                   } else if (fi->flags&O_RDWR) {
  588                      perm_mask = 6;
  589                   } else if ((fi->flags&(O_RDONLY|O_EXCL)) == (O_RDONLY)) {
  590                      perm_mask = 4;
  591                   }
  592                   if (((perm&perm_mask)!=perm_mask) || (!perm_mask) || (!perm)) {
  593                      fail_cnt++;
  594                      err_list[i] = EACCES;
  595                                           dbg(("\nfailopen, perm=%d, perm_mask=%d, fi->flags=0%o\n",perm,perm_mask,fi->flags));
  596                   } else {
  597                      fd[i] = open(fname,fi->flags);
  598                      if (fd[i]<=0) {
  599                         fail_cnt++;
  600                         err_list[i] = errno;
  601                      } else {
  602                         if (!file_exists) {
  603                            get_ownership();
  604                            if (lchown(fname, context->uid, gid)==(-1)) {
  605                               fail_cnt++;
  606                               err_list[i] = -errno;
  607                               close(fd[i]);
  608                               fd[i] = -1;
  609                            } else {
  610                               succ_cnt++;
  611                            }
  612                         } else {
  613                            succ_cnt++;
  614                                                       dbg(("\nopened fd=%x, perm=%d, perm_mask=%d, fi->flags=0%o\n",fd[i],perm,perm_mask,fi->flags));
  615                         }
  616                      }
  617                   }
  618                }
  619                free(fname);
  620             } else {
  621                fail_cnt++;
  622                err_list[i] = -ENOMEM;
  623                fd[i] = -1;
  624             }
  625          }
  626 
  627          gettmday(&t4,NULL);
  628          timeval_subtract(&t6,&t5,&t4);
  629          dbg(("\nopen replica time %ld secs,  %ld usecs",t3.tv_sec,t3.tv_usec));
  630 
  631       }
  632       free(path);
  633       if (fail_cnt && succ_cnt) {
  634          for(i=0;i<max_replica;++i) {
  635             if (!paths[i].disabled) {
  636                if (fd[i]<0) {
  637                   if (err_list[i]<0) {
  638                      call_log("open+chown",paths[i].path,-err_list[i]);
  639                   } else {
  640                      call_log("open",paths[i].path,err_list[i]);
  641                   }
  642                   disable_replica(i);
  643                }
  644             }
  645          }
  646       }
  647 
  648       if (succ_cnt) {
  649          free(err_list);
  650          if ((fd_ndx=fd_hashset(fd))<0) {
  651             for(i=(max_replica-1);i>=0;--i) {
  652                if ((!paths[i].disabled) && (fd[i]>0)) {
  653                   close(fd[i]);
  654                }
  655             }
  656             // fd_ndx = -ENOMEM;
  657          }
  658          if (fd_ndx < 0) {
  659             free( fd );        /* Thanks to Patrick Prasse for send this patch line fixing a memory leak */
  660             return -EMFILE;
  661          }
  662 //    we dont free fd anymore because it is being put in tab_fd. Now this will be freed only on close.
  663          fi->fh = fd_ndx;
  664          return(0);
  665       }
  666       gettmday(&t2,NULL);
  667       timeval_subtract(&t3,&t2,&t1);
  668       dbg(("\nopen total time %ld secs,  %ld usecs",t3.tv_sec,t3.tv_usec));
  669 
  670       for(i=(max_replica-1);i>=0;--i) {
  671          if (!paths[i].disabled) {
  672             if (err_list[i]) {
  673                dbg(("\nretval: %d,%d,%d\n",-err_list[i],err_list[i],i));
  674                errno = err_list[i];
  675             }
  676          }
  677       }
  678 
  679    } else {
  680       errno = ENOMEM;
  681    }
  682 
  683    free(err_list);
  684    free( fd );           /* Thanks to Patrick Prasse for send this patch line fixing a memory leak */
  685    return(-errno);
  686 }
  687 
  688 static int chiron_release(const char *path, struct fuse_file_info *fi)
  689 {
  690     /* Just a stub.  This method is optional and can safely be left
  691        unimplemented */
  692 
  693    int i, r;
  694    decl_tmvar(t1, t2, t3);
  695 
  696    (void) path;
  697 
  698    gettmday(&t1,NULL);
  699                                              dbg(("release(%d)",fi->fh));
  700    if (tab_fd.fd[fi->fh]==NULL) {
  701       return(-EINVAL);
  702    }
  703 
  704    for(i=0,r=-1;i<max_replica;++i) {
  705       if ((tab_fd.fd[fi->fh][i]>0) && (!paths[i].disabled)) {
  706          r &= close(tab_fd.fd[fi->fh][i]);
  707          tab_fd.fd[fi->fh][i] = 0;
  708       }
  709    }
  710    free(tab_fd.fd[fi->fh]); // this is the fd chunk allocated in the chiron_open function
  711    tab_fd.fd[fi->fh] = NULL;
  712 
  713    gettmday(&t2,NULL);
  714    timeval_subtract(&t3,&t2,&t1);
  715    dbg(("\nrelease time %ld secs,  %ld usecs",t3.tv_sec,t3.tv_usec));
  716 
  717    return(r);
  718 }
  719 
  720 static int chiron_read(const char *path, char *buf, size_t size,
  721                    off_t offset, struct fuse_file_info *fi)
  722 {
  723    int     i, replica, *err_list, perm;
  724    ssize_t r;
  725    int     fail_cnt=0;
  726    decl_tmvar(t1, t2, t3);
  727 
  728 
  729    (void) path;
  730 
  731    gettmday(&t1,NULL);
  732 
  733                                                             dbg(("read(%d)",fi->fh));
  734 
  735    if (tab_fd.fd[fi->fh]==NULL) {
  736       return(-EINVAL);
  737    }
  738 
  739    err_list = calloc(max_replica,sizeof(int));
  740    if (err_list==NULL) {
  741       return -ENOMEM;
  742    }
  743 
  744    for(i=0;i<max_replica;++i) {
  745       replica = choose_replica(i);
  746       if ((tab_fd.fd[fi->fh][replica]>0) && (!paths[replica].disabled)) {
  747          perm = get_rights_by_fd(tab_fd.fd[fi->fh][replica]);
  748          if (perm<0) {
  749             err_list[replica] = errno;
  750             fail_cnt++;
  751          } else {
  752             if (!(perm&4)) {
  753                free(err_list);
  754                return(-EACCES);
  755             }
  756             r = pread(tab_fd.fd[fi->fh][replica],buf,size,offset);
  757             if (r>=0) {
  758                if (fail_cnt) {
  759                   for(i=0;i<max_replica;++i) {
  760                      if (err_list[i]) {
  761                         call_log("read",paths[i].path,err_list[i]);
  762                      }
  763                   }
  764                }
  765                free(err_list);
  766                return(r);
  767             } else {
  768                err_list[replica] = errno;
  769                fail_cnt++;
  770             }
  771          }
  772       }
  773    }
  774 
  775    gettmday(&t2,NULL);
  776    timeval_subtract(&t3,&t2,&t1);
  777    dbg(("\nread time %ld secs,  %ld usecs",t3.tv_sec,t3.tv_usec));
  778 
  779    for(i=(max_replica-1);i>=0;--i) {
  780       if (!paths[i].disabled) {
  781          if (err_list[i]) {
  782             dbg(("\nretval: %d,%d,%d\n",-err_list[i],err_list[i],i));
  783             errno = err_list[i];
  784          }
  785       }
  786    }
  787 
  788    free(err_list);
  789    return(-errno);
  790 }
  791 
  792 static int chiron_write(const char *path, const char *buf, size_t size,
  793                      off_t offset, struct fuse_file_info *fi)
  794 {
  795    int     i, fail_cnt=0, succ_cnt=0, ret, *err_list, perm;
  796    ssize_t *w;
  797    decl_tmvar(t1, t2, t3);
  798 
  799    gettmday(&t1,NULL);
  800    (void) path;
  801 
  802                                                                   dbg(("write(%d)",fi->fh));
  803    if (tab_fd.fd[fi->fh]==NULL) {
  804       return(-EINVAL);
  805    }
  806 
  807    w = calloc(max_replica,sizeof(ssize_t));
  808    if (w==NULL) {
  809       print_err(CHIRONFS_ERR_LOW_MEMORY,"replica return code table allocation");
  810       return(-ENOMEM);
  811    }
  812    err_list = calloc(max_replica,sizeof(int));
  813    if (err_list==NULL) {
  814       free(w);
  815       print_err(CHIRONFS_ERR_LOW_MEMORY,"replica error code table allocation");
  816       return(-ENOMEM);
  817    }
  818    for(i=0;i<max_replica;++i) {
  819       if (!paths[i].disabled) {
  820          if (tab_fd.fd[fi->fh][i]>0) {
  821             perm = get_rights_by_fd(tab_fd.fd[fi->fh][i]);
  822             if (perm<0) {
  823                err_list[i] = errno;
  824                fail_cnt++;
  825             } else {
  826                if (!(perm&2)) {
  827                   err_list[i] = EACCES;
  828                   fail_cnt++;
  829                } else {
  830                   w[i] = pwrite(tab_fd.fd[fi->fh][i],buf,size,offset);
  831                   if (w[i]<0) {
  832                      err_list[i] = errno;
  833                      fail_cnt++;
  834                   } else {
  835                      succ_cnt++;
  836                   }
  837                }
  838             }
  839          }
  840       }
  841    }
  842 
  843    if (fail_cnt && succ_cnt) {
  844       for(i=0;i<max_replica;++i) {
  845          if (!paths[i].disabled) {
  846             if (w[i]<0) {
  847                call_log("write",paths[i].path,err_list[i]);
  848                disable_replica(i);
  849             }
  850          }
  851       }
  852    }
  853 
  854    if (succ_cnt) {
  855       for(i=0;i<max_replica;++i) {
  856          if (!paths[i].disabled) {
  857             if (w[i]>=0) {
  858                ret = w[i];
  859                free( w );
  860                free(err_list);
  861                return(ret);
  862             }
  863          }
  864       }
  865    }
  866 
  867    gettmday(&t2,NULL);
  868    timeval_subtract(&t3,&t2,&t1);
  869    dbg(("\nwrite total time %ld secs,  %ld usecs",t3.tv_sec,t3.tv_usec));
  870 
  871    free( w );
  872    free(err_list);
  873    return(-errno);
  874 }
  875 
  876 #define dodir_byname_ro(fn,logmsgstr)                          \
  877    char *fname;                                                \
  878    int i=0, st=-1, einval=0, qterr=0, staterr=0, replica;      \
  879    int *err_list, perm;                                        \
  880    decl_tmvar(t1, t2, t3);                                     \
  881    gettmday(&t1,NULL);                                         \
  882    err_list = calloc(max_replica,sizeof(int));                 \
  883    if (err_list==NULL) {                                       \
  884       return -ENOMEM;                                          \
  885    }                                                           \
  886    do {                                                        \
  887       replica = choose_replica(i);                             \
  888       if (!paths[replica].disabled) {                          \
  889          fname = xlate(path,paths[replica].path);              \
  890          if (fname!=NULL) {                                    \
  891             perm = check_may_enter(fname);                     \
  892             if (perm<0) {                                      \
  893                qterr++;                                        \
  894                staterr = -errno;                               \
  895                err_list[replica] = errno;                      \
  896                free(fname);                                    \
  897             } else {                                           \
  898                st = fn;                                        \
  899                if (st == -1) {                                 \
  900                   qterr++;                                     \
  901                   staterr = -errno;                            \
  902                   err_list[replica] = errno;                   \
  903                   free(fname);                                 \
  904                } else {                                        \
  905                   if (qterr) {                                 \
  906                      for(i=0;i<max_replica;++i) {              \
  907                         if (err_list[i]) {                     \
  908                            call_log(logmsgstr,paths[i].path,err_list[i]);   \
  909                         }                                      \
  910                      }                                         \
  911                   }                                            \
  912                                           gettmday(&t2,NULL);                          \
  913                                           timeval_subtract(&t3,&t2,&t1);               \
  914                                           dbg(("\n%s succ time %ld secs,  %ld usecs",logmsgstr,t3.tv_sec,t3.tv_usec));  \
  915                   free(err_list);                              \
  916                   free(fname);                                 \
  917                   return(st);                                  \
  918                }                                               \
  919             }                                                  \
  920          } else {                                              \
  921             einval++;                                          \
  922          }                                                     \
  923       }                                                        \
  924       ++i;                                                     \
  925    } while ((st<0) && (i<max_replica));                        \
  926                                           gettmday(&t2,NULL);                                         \
  927                                           timeval_subtract(&t3,&t2,&t1);                              \
  928                                           dbg(("\n%s fail time %ld secs,  %ld usecs",logmsgstr,t3.tv_sec,t3.tv_usec));  \
  929    free(err_list);                                             \
  930    if (qterr) {                                                \
  931       return(staterr);                                         \
  932    }                                                           \