"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 } \