1 /*
2 * Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3 *
4 * This file is part of MooseFS.
5 *
6 * MooseFS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 2 (only).
9 *
10 * MooseFS is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MooseFS; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18 * or visit http://www.gnu.org/licenses/gpl-2.0.html
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <math.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/statvfs.h>
34 #include <sys/time.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <inttypes.h>
38 #include <poll.h>
39 #include <errno.h>
40
41 #include "datapack.h"
42 #include "strerr.h"
43 #include "mfsstrerr.h"
44 #include "sockets.h"
45 #include "md5.h"
46 #include "MFSCommunication.h"
47
48 #define tcpread(s,b,l) tcptoread(s,b,l,10000)
49 #define tcpwrite(s,b,l) tcptowrite(s,b,l,10000)
50
51 #define STR_AUX(x) #x
52 #define STR(x) STR_AUX(x)
53 const char id[]="@(#) version: " VERSSTR ", written by Jakub Kruszona-Zawadzki";
54
55 #define FILEINFO_QUICK 0x01
56 #define FILEINFO_CRC 0x02
57 #define FILEINFO_SIGNATURE 0x04
58
59 #define DIRINFO_INODES 0x01
60 #define DIRINFO_DIRS 0x02
61 #define DIRINFO_FILES 0x04
62 #define DIRINFO_CHUNKS 0x08
63 #define DIRINFO_LENGTH 0x10
64 #define DIRINFO_SIZE 0x20
65 #define DIRINFO_REALSIZE 0x40
66
67 #define INODE_VALUE_MASK 0x1FFFFFFF
68 #define INODE_TYPE_MASK 0x60000000
69 #define INODE_TYPE_TRASH 0x20000000
70 #define INODE_TYPE_SUSTAINED 0x40000000
71 #define INODE_TYPE_SPECIAL 0x00000000
72
73 static const char* eattrtab[EATTR_BITS]={EATTR_STRINGS};
74 static const char* eattrdesc[EATTR_BITS]={EATTR_DESCRIPTIONS};
75
76 static uint8_t humode=0;
77 static uint8_t numbermode=0;
78
79 #define PHN_USESI 0x01
80 #define PHN_USEIEC 0x00
print_humanized_number(const char * format,uint64_t number,uint8_t flags)81 void print_humanized_number(const char *format,uint64_t number,uint8_t flags) {
82 char numbuf[6]; // [ "xxx" , "xx" , "x" , "x.x" ] + ["" , "X" , "Xi"]
83 uint64_t divisor;
84 uint16_t b;
85 uint8_t i;
86 uint8_t scale;
87
88 if (flags & PHN_USESI) {
89 divisor = 1000;
90 } else {
91 divisor = 1024;
92 }
93 if (number>(UINT64_MAX/100)) {
94 number /= divisor;
95 number *= 100;
96 scale = 1;
97 } else {
98 number *= 100;
99 scale = 0;
100 }
101 while (number>=99950) {
102 number /= divisor;
103 scale+=1;
104 }
105 i=0;
106 if (number<995 && scale>0) {
107 b = ((uint32_t)number + 5) / 10;
108 numbuf[i++]=(b/10)+'0';
109 numbuf[i++]='.';
110 numbuf[i++]=(b%10)+'0';
111 } else {
112 b = ((uint32_t)number + 50) / 100;
113 if (b>=100) {
114 numbuf[i++]=(b/100)+'0';
115 b%=100;
116 }
117 if (b>=10 || i>0) {
118 numbuf[i++]=(b/10)+'0';
119 b%=10;
120 }
121 numbuf[i++]=b+'0';
122 }
123 if (scale>0) {
124 if (flags&PHN_USESI) {
125 numbuf[i++]="-kMGTPE"[scale];
126 } else {
127 numbuf[i++]="-KMGTPE"[scale];
128 numbuf[i++]='i';
129 }
130 }
131 numbuf[i++]='\0';
132 printf(format,numbuf);
133 }
134
print_number_only(uint64_t number,uint8_t bytesflag)135 void print_number_only(uint64_t number,uint8_t bytesflag) {
136 if (humode>0) {
137 if (bytesflag) {
138 if (humode==1 || humode==3) {
139 print_humanized_number("%5sB",number,PHN_USEIEC);
140 } else {
141 print_humanized_number("%4sB",number,PHN_USESI);
142 }
143 } else {
144 if (humode==1 || humode==3) {
145 print_humanized_number("%5s",number,PHN_USEIEC);
146 } else {
147 print_humanized_number("%4s",number,PHN_USESI);
148 }
149 }
150 if (humode>2) {
151 printf(" (%"PRIu64")",number);
152 }
153 } else {
154 if (numbermode==0) {
155 printf("%"PRIu64,number);
156 } else if (numbermode==1) {
157 printf("%"PRIu64,number/1024);
158 } else if (numbermode==2) {
159 printf("%"PRIu64,number/(1024*1024));
160 } else if (numbermode==3) {
161 printf("%"PRIu64,number/(1024*1024*1024));
162 }
163 }
164 }
165
print_number(const char * prefix,const char * suffix,uint64_t number,uint8_t mode32,uint8_t bytesflag,uint8_t dflag)166 void print_number(const char *prefix,const char *suffix,uint64_t number,uint8_t mode32,uint8_t bytesflag,uint8_t dflag) {
167 if (prefix) {
168 printf("%s",prefix);
169 }
170 if (dflag) {
171 if (humode>0) {
172 if (bytesflag) {
173 if (humode==1 || humode==3) {
174 print_humanized_number("%5sB",number,PHN_USEIEC);
175 } else {
176 print_humanized_number("%4sB",number,PHN_USESI);
177 }
178 } else {
179 if (humode==1 || humode==3) {
180 print_humanized_number(" %5s",number,PHN_USEIEC);
181 } else {
182 print_humanized_number(" %4s",number,PHN_USESI);
183 }
184 }
185 if (humode>2) {
186 if (mode32) {
187 printf(" (%10"PRIu32")",(uint32_t)number);
188 } else {
189 printf(" (%20"PRIu64")",number);
190 }
191 }
192 } else {
193 if (numbermode==0) {
194 if (mode32) {
195 printf("%10"PRIu32,(uint32_t)number);
196 } else {
197 printf("%20"PRIu64,number);
198 }
199 } else if (numbermode==1) {
200 if (mode32) {
201 printf("%7"PRIu32,((uint32_t)number)/1024);
202 } else {
203 printf("%17"PRIu64,number/1024);
204 }
205 } else if (numbermode==2) {
206 if (mode32) {
207 printf("%4"PRIu32,((uint32_t)number)/(1024*1024));
208 } else {
209 printf("%14"PRIu64,number/(1024*1024));
210 }
211 } else if (numbermode==3) {
212 if (mode32) {
213 printf("%1"PRIu32,((uint32_t)number)/(1024*1024*1024));
214 } else {
215 printf("%11"PRIu64,number/(1024*1024*1024));
216 }
217 }
218 }
219 } else {
220 switch(humode) {
221 case 0:
222 if (numbermode==0) {
223 if (mode32) {
224 printf(" -");
225 } else {
226 printf(" -");
227 }
228 } else if (numbermode==1) {
229 if (mode32) {
230 printf(" -");
231 } else {
232 printf(" -");
233 }
234 } else if (numbermode==2) {
235 if (mode32) {
236 printf(" -");
237 } else {
238 printf(" -");
239 }
240 } else if (numbermode==3) {
241 if (mode32) {
242 printf("-");
243 } else {
244 printf(" -");
245 }
246 }
247 break;
248 case 1:
249 printf(" -");
250 break;
251 case 2:
252 printf(" -");
253 break;
254 case 3:
255 if (mode32) {
256 printf(" -");
257 } else {
258 printf(" -");
259 }
260 break;
261 case 4:
262 if (mode32) {
263 printf(" -");
264 } else {
265 printf(" -");
266 }
267 break;
268 }
269 }
270 if (suffix) {
271 printf("%s",suffix);
272 }
273 }
274
my_get_number(const char * str,uint64_t * ret,double max,uint8_t bytesflag)275 int my_get_number(const char *str,uint64_t *ret,double max,uint8_t bytesflag) {
276 uint64_t val,frac,fracdiv;
277 double drval,mult;
278 int f;
279 val=0;
280 frac=0;
281 fracdiv=1;
282 f=0;
283 while (*str>='0' && *str<='9') {
284 f=1;
285 val*=10;
286 val+=(*str-'0');
287 str++;
288 }
289 if (*str=='.') { // accept ".5" (without 0)
290 str++;
291 while (*str>='0' && *str<='9') {
292 fracdiv*=10;
293 frac*=10;
294 frac+=(*str-'0');
295 str++;
296 }
297 if (fracdiv==1) { // if there was '.' expect number afterwards
298 return -1;
299 }
300 } else if (f==0) { // but not empty string
301 return -1;
302 }
303 if (str[0]=='\0' || (bytesflag && str[0]=='B' && str[1]=='\0')) {
304 mult=1.0;
305 } else if (str[0]!='\0' && (str[1]=='\0' || (bytesflag && str[1]=='B' && str[2]=='\0'))) {
306 switch(str[0]) {
307 case 'k':
308 mult=1e3;
309 break;
310 case 'M':
311 mult=1e6;
312 break;
313 case 'G':
314 mult=1e9;
315 break;
316 case 'T':
317 mult=1e12;
318 break;
319 case 'P':
320 mult=1e15;
321 break;
322 case 'E':
323 mult=1e18;
324 break;
325 default:
326 return -1;
327 }
328 } else if (str[0]!='\0' && str[1]=='i' && (str[2]=='\0' || (bytesflag && str[2]=='B' && str[3]=='\0'))) {
329 switch(str[0]) {
330 case 'K':
331 mult=1024.0;
332 break;
333 case 'M':
334 mult=1048576.0;
335 break;
336 case 'G':
337 mult=1073741824.0;
338 break;
339 case 'T':
340 mult=1099511627776.0;
341 break;
342 case 'P':
343 mult=1125899906842624.0;
344 break;
345 case 'E':
346 mult=1152921504606846976.0;
347 break;
348 default:
349 return -1;
350 }
351 } else {
352 return -1;
353 }
354 drval = round(((double)frac/(double)fracdiv+(double)val)*mult);
355 if (drval>max) {
356 return -2;
357 } else {
358 *ret = drval;
359 }
360 return 1;
361 }
362
bsd_basename(const char * path,char * bname)363 int bsd_basename(const char *path,char *bname) {
364 const char *endp, *startp;
365
366 /* Empty or NULL string gets treated as "." */
367 if (path == NULL || *path == '\0') {
368 (void)strcpy(bname, ".");
369 return 0;
370 }
371
372 /* Strip trailing slashes */
373 endp = path + strlen(path) - 1;
374 while (endp > path && *endp == '/') {
375 endp--;
376 }
377
378 /* All slashes becomes "/" */
379 if (endp == path && *endp == '/') {
380 (void)strcpy(bname, "/");
381 return 0;
382 }
383
384 /* Find the start of the base */
385 startp = endp;
386 while (startp > path && *(startp - 1) != '/') {
387 startp--;
388 }
389 if (endp - startp + 2 > PATH_MAX) {
390 return -1;
391 }
392 (void)strncpy(bname, startp, endp - startp + 1);
393 bname[endp - startp + 1] = '\0';
394 return 0;
395 }
396
bsd_dirname(const char * path,char * bname)397 int bsd_dirname(const char *path,char *bname) {
398 const char *endp;
399
400 /* Empty or NULL string gets treated as "." */
401 if (path == NULL || *path == '\0') {
402 (void)strcpy(bname, ".");
403 return 0;
404 }
405
406 /* Strip trailing slashes */
407 endp = path + strlen(path) - 1;
408 while (endp > path && *endp == '/') {
409 endp--;
410 }
411
412 /* Find the start of the dir */
413 while (endp > path && *endp != '/') {
414 endp--;
415 }
416
417 /* Either the dir is "/" or there are no slashes */
418 if (endp == path) {
419 (void)strcpy(bname, *endp == '/' ? "/" : ".");
420 return 0;
421 } else {
422 do {
423 endp--;
424 } while (endp > path && *endp == '/');
425 }
426
427 if (endp - path + 2 > PATH_MAX) {
428 return -1;
429 }
430 (void)strncpy(bname, path, endp - path + 1);
431 bname[endp - path + 1] = '\0';
432 return 0;
433 }
434
dirname_inplace(char * path)435 void dirname_inplace(char *path) {
436 char *endp;
437
438 if (path==NULL) {
439 return;
440 }
441 if (path[0]=='\0') {
442 path[0]='.';
443 path[1]='\0';
444 return;
445 }
446
447 /* Strip trailing slashes */
448 endp = path + strlen(path) - 1;
449 while (endp > path && *endp == '/') {
450 endp--;
451 }
452
453 /* Find the start of the dir */
454 while (endp > path && *endp != '/') {
455 endp--;
456 }
457
458 if (endp == path) {
459 if (path[0]=='/') {
460 path[1]='\0';
461 } else {
462 path[0]='.';
463 path[1]='\0';
464 }
465 return;
466 } else {
467 *endp = '\0';
468 }
469 }
470
471 /*
472 int32_t socket_read(int sock,void *buff,uint32_t leng) {
473 uint32_t rcvd=0;
474 int i;
475 while (rcvd<leng) {
476 i = read(sock,((uint8_t*)buff)+rcvd,leng-rcvd);
477 if (i<=0) return i;
478 rcvd+=i;
479 }
480 return rcvd;
481 }
482
483 int32_t socket_write(int sock,void *buff,uint32_t leng) {
484 uint32_t sent=0;
485 int i;
486 while (sent<leng) {
487 i = write(sock,((uint8_t*)buff)+sent,leng-sent);
488 if (i<=0) return i;
489 sent+=i;
490 }
491 return sent;
492 }
493 */
494
master_register_old(int rfd)495 int master_register_old(int rfd) {
496 uint32_t i;
497 const uint8_t *rptr;
498 uint8_t *wptr,regbuff[8+72];
499
500 wptr = regbuff;
501 put32bit(&wptr,CLTOMA_FUSE_REGISTER);
502 put32bit(&wptr,68);
503 memcpy(wptr,FUSE_REGISTER_BLOB_TOOLS_NOACL,64);
504 wptr+=64;
505 put16bit(&wptr,VERSMAJ);
506 put8bit(&wptr,VERSMID);
507 put8bit(&wptr,VERSMIN);
508 if (tcpwrite(rfd,regbuff,8+68)!=8+68) {
509 printf("register to master: send error\n");
510 return -1;
511 }
512 if (tcpread(rfd,regbuff,9)!=9) {
513 printf("register to master: receive error\n");
514 return -1;
515 }
516 rptr = regbuff;
517 i = get32bit(&rptr);
518 if (i!=MATOCL_FUSE_REGISTER) {
519 printf("register to master: wrong answer (type)\n");
520 return -1;
521 }
522 i = get32bit(&rptr);
523 if (i!=1) {
524 printf("register to master: wrong answer (length)\n");
525 return -1;
526 }
527 if (*rptr) {
528 printf("register to master: %s\n",mfsstrerr(*rptr));
529 return -1;
530 }
531 return 0;
532 }
533
master_register(int rfd,uint32_t cuid)534 int master_register(int rfd,uint32_t cuid) {
535 uint32_t i;
536 const uint8_t *rptr;
537 uint8_t *wptr,regbuff[8+73];
538
539 wptr = regbuff;
540 put32bit(&wptr,CLTOMA_FUSE_REGISTER);
541 put32bit(&wptr,73);
542 memcpy(wptr,FUSE_REGISTER_BLOB_ACL,64);
543 wptr+=64;
544 put8bit(&wptr,REGISTER_TOOLS);
545 put32bit(&wptr,cuid);
546 put16bit(&wptr,VERSMAJ);
547 put8bit(&wptr,VERSMID);
548 put8bit(&wptr,VERSMIN);
549 if (tcpwrite(rfd,regbuff,8+73)!=8+73) {
550 printf("register to master: send error\n");
551 return -1;
552 }
553 if (tcpread(rfd,regbuff,9)!=9) {
554 printf("register to master: receive error\n");
555 return -1;
556 }
557 rptr = regbuff;
558 i = get32bit(&rptr);
559 if (i!=MATOCL_FUSE_REGISTER) {
560 printf("register to master: wrong answer (type)\n");
561 return -1;
562 }
563 i = get32bit(&rptr);
564 if (i!=1) {
565 printf("register to master: wrong answer (length)\n");
566 return -1;
567 }
568 if (*rptr) {
569 printf("register to master: %s\n",mfsstrerr(*rptr));
570 return -1;
571 }
572 return 0;
573 }
574
575 static dev_t current_device = 0;
576 static int current_master = -1;
577 static uint32_t masterversion = 0;
578
open_master_conn(const char * name,uint32_t * inode,mode_t * mode,uint8_t needsamedev,uint8_t needrwfs)579 int open_master_conn(const char *name,uint32_t *inode,mode_t *mode,uint8_t needsamedev,uint8_t needrwfs) {
580 char rpath[PATH_MAX+1];
581 struct stat stb;
582 struct statvfs stvfsb;
583 int sd;
584 uint8_t masterinfo[14];
585 const uint8_t *miptr;
586 uint8_t cnt;
587 uint32_t masterip;
588 uint16_t masterport;
589 uint32_t mastercuid;
590 uint32_t pinode;
591 int rpathlen;
592
593 rpath[0]=0;
594 if (realpath(name,rpath)==NULL) {
595 printf("%s: realpath error on (%s): %s\n",name,rpath,strerr(errno));
596 return -1;
597 }
598 // p = rpath;
599 if (needrwfs) {
600 if (statvfs(rpath,&stvfsb)!=0) {
601 printf("%s: (%s) statvfs error: %s\n",name,rpath,strerr(errno));
602 return -1;
603 }
604 if (stvfsb.f_flag&ST_RDONLY) {
605 printf("%s: (%s) Read-only file system\n",name,rpath);
606 return -1;
607 }
608 }
609 if (lstat(rpath,&stb)!=0) {
610 printf("%s: (%s) lstat error: %s\n",name,rpath,strerr(errno));
611 return -1;
612 }
613 pinode = stb.st_ino;
614 *inode = pinode;
615 if (mode) {
616 *mode = stb.st_mode;
617 }
618 if (current_master>=0) {
619 if (current_device==stb.st_dev) {
620 return current_master;
621 }
622 if (needsamedev) {
623 printf("%s: different device\n",name);
624 return -1;
625 }
626 }
627 if (current_master>=0) {
628 close(current_master);
629 current_master=-1;
630 }
631 current_device = stb.st_dev;
632 for(;;) {
633 rpathlen = strlen(rpath);
634 if (rpathlen+strlen("/.masterinfo")<PATH_MAX) {
635 strcpy(rpath+rpathlen,"/.masterinfo");
636 if (lstat(rpath,&stb)==0) {
637 if ((stb.st_ino==0x7FFFFFFF || stb.st_ino==0x7FFFFFFE) && stb.st_nlink==1 && stb.st_uid==0 && stb.st_gid==0 && (stb.st_size==10 || stb.st_size==14)) {
638 if (stb.st_ino==0x7FFFFFFE) { // meta master
639 if (((*inode)&INODE_TYPE_MASK)!=INODE_TYPE_TRASH && ((*inode)&INODE_TYPE_MASK)!=INODE_TYPE_SUSTAINED) {
640 printf("%s: only files in 'trash' and 'sustained' are usable in mfsmeta\n",name);
641 return -1;
642 }
643 (*inode)&=INODE_VALUE_MASK;
644 }
645 sd = open(rpath,O_RDONLY);
646 if (stb.st_size==10) {
647 if (read(sd,masterinfo,10)!=10) {
648 printf("%s: can't read '.masterinfo'\n",name);
649 close(sd);
650 return -1;
651 }
652 } else if (stb.st_size==14) {
653 if (read(sd,masterinfo,14)!=14) {
654 printf("%s: can't read '.masterinfo'\n",name);
655 close(sd);
656 return -1;
657 }
658 }
659 close(sd);
660 miptr = masterinfo;
661 masterip = get32bit(&miptr);
662 masterport = get16bit(&miptr);
663 mastercuid = get32bit(&miptr);
664 if (stb.st_size==14) {
665 masterversion = get32bit(&miptr);
666 } else {
667 masterversion = 0;
668 }
669 if (masterip==0 || masterport==0 || mastercuid==0) {
670 printf("%s: incorrect '.masterinfo'\n",name);
671 return -1;
672 }
673 cnt=0;
674 while (cnt<10) {
675 sd = tcpsocket();
676 if (sd<0) {
677 printf("%s: can't create connection socket: %s\n",name,strerr(errno));
678 return -1;
679 }
680 if (tcpnumtoconnect(sd,masterip,masterport,(cnt%2)?(300*(1<<(cnt>>1))):(200*(1<<(cnt>>1))))<0) {
681 cnt++;
682 if (cnt==10) {
683 printf("%s: can't connect to master (.masterinfo): %s\n",name,strerr(errno));
684 return -1;
685 }
686 tcpclose(sd);
687 } else {
688 cnt=10;
689 }
690 }
691 if (master_register(sd,mastercuid)<0) {
692 printf("%s: can't register to master (.masterinfo)\n",name);
693 return -1;
694 }
695 current_master = sd;
696 return sd;
697 }
698 } else if (pinode==1) { // this is root inode - if there is no .masterinfo here then it is not MFS.
699 printf("%s: not MFS object\n",name);
700 return -1;
701 }
702 } else if (pinode==1) { // found root inode, but path is still to long - give up
703 printf("%s: path too long\n",name);
704 return -1;
705 }
706 rpath[rpathlen]='\0';
707 if (rpath[0]!='/' || rpath[1]=='\0') { // went to '/' without success - this is not MFS
708 printf("%s: not MFS object\n",name);
709 return -1;
710 }
711 dirname_inplace(rpath);
712 if (lstat(rpath,&stb)!=0) {
713 printf("%s: (%s) lstat error: %s\n",name,rpath,strerr(errno));
714 return -1;
715 }
716 pinode = stb.st_ino;
717 }
718 return -1;
719 }
720
close_master_conn(int err)721 void close_master_conn(int err) {
722 if (current_master<0) {
723 return;
724 }
725 if (err) {
726 close(current_master);
727 current_master = -1;
728 current_device = 0;
729 }
730 }
731
732 /*
733 int open_master_conn(const char *name,uint32_t *inode) {
734 char rpath[PATH_MAX],*p;
735 struct stat stb;
736 int sd;
737 if (realpath(name,rpath)==NULL) {
738 printf("%s: realpath error\n",name);
739 return -1;
740 }
741 p = rpath;
742 if (lstat(p,&stb)!=0) {
743 printf("%s: (%s) lstat error\n",name,p);
744 return -1;
745 }
746 *inode = stb.st_ino;
747 for(;;) {
748 if (stb.st_ino==1) { // found fuse root
749 p = strcat(p,"/.master");
750 if (lstat(p,&stb)==0) {
751 if ((stb.st_ino==0x7FFFFFFF || stb.st_ino==0x7FFFFFFE) && stb.st_nlink==1 && stb.st_uid==0 && stb.st_gid==0) {
752 if (stb.st_ino==0x7FFFFFFE) { // meta master
753 if (((*inode)&INODE_TYPE_MASK)!=INODE_TYPE_TRASH && ((*inode)&INODE_TYPE_MASK)!=INODE_TYPE_SUSTAINED) {
754 printf("%s: only files in 'trash' and 'sustained' are usable in mfsmeta\n",name);
755 return -1;
756 }
757 (*inode)&=INODE_VALUE_MASK;
758 }
759 sd = open(p,O_RDWR);
760 if (master_register(sd)<0) {
761 printf("%s: can't register to master\n",name);
762 return -1;
763 }
764 return sd;
765 }
766 }
767 printf("%s: not MFS object\n",name);
768 return -1;
769 }
770 if (p[0]!='/' || p[1]=='\0') {
771 printf("%s: not MFS object\n",name);
772 return -1;
773 }
774 p = dirname(p);
775 if (lstat(p,&stb)!=0) {
776 printf("%s: (%s) lstat error\n",name,p);
777 return -1;
778 }
779 }
780 return -1;
781 }
782
783 int open_two_files_master_conn(const char *fname,const char *sname,uint32_t *finode,uint32_t *sinode) {
784 char frpath[PATH_MAX];
785 char srpath[PATH_MAX];
786 int i;
787 char *p;
788 struct stat stb;
789 int sd;
790 if (realpath(fname,frpath)==NULL) {
791 printf("%s: realpath error\n",fname);
792 return -1;
793 }
794 if (realpath(sname,srpath)==NULL) {
795 printf("%s: realpath error\n",sname);
796 return -1;
797 }
798 if (lstat(frpath,&stb)!=0) {
799 printf("%s: (%s) lstat error\n",fname,frpath);
800 return -1;
801 }
802 *finode = stb.st_ino;
803 if (lstat(srpath,&stb)!=0) {
804 printf("%s: (%s) lstat error\n",sname,srpath);
805 return -1;
806 }
807 *sinode = stb.st_ino;
808
809 for (i=0 ; i<PATH_MAX && frpath[i]==srpath[i] ; i++) {}
810 frpath[i]='\0';
811 p = dirname(frpath);
812 if (lstat(p,&stb)!=0) {
813 printf("%s: lstat error\n",p);
814 return -1;
815 }
816 for(;;) {
817 if (stb.st_ino==1) { // found fuse root
818 p = strcat(p,"/.master");
819 if (lstat(p,&stb)==0) {
820 if ((stb.st_ino==0x7FFFFFFF || stb.st_ino==0x7FFFFFFE) && stb.st_nlink==1 && stb.st_uid==0 && stb.st_gid==0) {
821 if (stb.st_ino==0x7FFFFFFE) { // meta master
822 if ((((*finode)&INODE_TYPE_MASK)!=INODE_TYPE_TRASH && ((*finode)&INODE_TYPE_MASK)!=INODE_TYPE_SUSTAINED) \
823 || (((*sinode)&INODE_TYPE_MASK)!=INODE_TYPE_TRASH && ((*sinode)&INODE_TYPE_MASK)!=INODE_TYPE_SUSTAINED)) {
824 printf("%s,%s: only files in 'trash' and 'sustained' are usable in mfsmeta\n",fname,sname);
825 return -1;
826 }
827 (*finode)&=INODE_VALUE_MASK;
828 (*sinode)&=INODE_VALUE_MASK;
829 }
830 sd = open(p,O_RDWR);
831 if (master_register(sd)<0) {
832 printf("%s,%s: can't register to master\n",fname,sname);
833 return -1;
834 }
835 return sd;
836 }
837 }
838 printf("%s,%s: not same MFS objects\n",fname,sname);
839 return -1;
840 }
841 if (p[0]!='/' || p[1]=='\0') {
842 printf("%s,%s: not same MFS objects\n",fname,sname);
843 return -1;
844 }
845 p = dirname(p);
846 if (lstat(p,&stb)!=0) {
847 printf("%s: lstat error\n",p);
848 return -1;
849 }
850 }
851 return -1;
852 }
853 */
854
file_paths(const char * fname)855 int file_paths(const char* fname) {
856 uint8_t reqbuff[16],*wptr,*buff;
857 const uint8_t *rptr;
858 const char *p;
859 struct stat st;
860 char cwdbuff[MAXPATHLEN];
861 uint32_t arginode;
862 uint32_t cmd,leng,inode;
863 uint32_t pleng;
864 int fd;
865
866 p = fname;
867 while (*p>='0' && *p<='9') {
868 p++;
869 }
870
871 if (*p=='\0' && stat(fname,&st)<0 && errno==ENOENT) {
872 arginode = strtoul(fname,NULL,10);
873 p = getcwd(cwdbuff,MAXPATHLEN);
874 fd = open_master_conn(p,&inode,NULL,0,0);
875 inode = arginode;
876 } else {
877 fd = open_master_conn(fname,&inode,NULL,0,0);
878 }
879 if (fd<0) {
880 return -1;
881 }
882 wptr = reqbuff;
883 put32bit(&wptr,CLTOMA_FUSE_PATHS);
884 put32bit(&wptr,8);
885 put32bit(&wptr,0);
886 put32bit(&wptr,inode);
887 if (tcpwrite(fd,reqbuff,16)!=16) {
888 printf("%s: master query: send error\n",fname);
889 close_master_conn(1);
890 return -1;
891 }
892 if (tcpread(fd,reqbuff,8)!=8) {
893 printf("%s: master query: receive error\n",fname);
894 close_master_conn(1);
895 return -1;
896 }
897 rptr = reqbuff;
898 cmd = get32bit(&rptr);
899 leng = get32bit(&rptr);
900 if (cmd!=MATOCL_FUSE_PATHS) {
901 printf("%s: master query: wrong answer (type)\n",fname);
902 close_master_conn(1);
903 return -1;
904 }
905 buff = malloc(leng);
906 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
907 printf("%s: master query: receive error\n",fname);
908 free(buff);
909 close_master_conn(1);
910 return -1;
911 }
912 close_master_conn(0);
913 rptr = buff;
914 cmd = get32bit(&rptr); // queryid
915 if (cmd!=0) {
916 printf("%s: master query: wrong answer (queryid)\n",fname);
917 free(buff);
918 return -1;
919 }
920 leng-=4;
921 if (leng==1) {
922 printf("%s: %s\n",fname,mfsstrerr(*rptr));
923 free(buff);
924 return -1;
925 }
926 printf("%s:\n",fname);
927 while (leng>=4) {
928 pleng = get32bit(&rptr);
929 leng-=4;
930 if (leng>=pleng) {
931 while (pleng) {
932 putchar(get8bit(&rptr));
933 pleng--;
934 leng--;
935 }
936 putchar('\n');
937 } else {
938 leng=0;
939 }
940 }
941 free(buff);
942 return 0;
943 }
944
945 /* - code moved to file_info
946 int check_file(const char* fname) {
947 uint8_t reqbuff[16],*wptr,*buff;
948 const uint8_t *rptr;
949 uint32_t cmd,leng,inode;
950 uint8_t copies;
951 uint32_t chunks;
952 int fd;
953 fd = open_master_conn(fname,&inode,NULL,0,0);
954 if (fd<0) {
955 return -1;
956 }
957 wptr = reqbuff;
958 put32bit(&wptr,CLTOMA_FUSE_CHECK);
959 put32bit(&wptr,8);
960 put32bit(&wptr,0);
961 put32bit(&wptr,inode);
962 if (tcpwrite(fd,reqbuff,16)!=16) {
963 printf("%s: master query: send error\n",fname);
964 close_master_conn(1);
965 return -1;
966 }
967 if (tcpread(fd,reqbuff,8)!=8) {
968 printf("%s: master query: receive error\n",fname);
969 close_master_conn(1);
970 return -1;
971 }
972 rptr = reqbuff;
973 cmd = get32bit(&rptr);
974 leng = get32bit(&rptr);
975 if (cmd!=MATOCL_FUSE_CHECK) {
976 printf("%s: master query: wrong answer (type)\n",fname);
977 close_master_conn(1);
978 return -1;
979 }
980 buff = malloc(leng);
981 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
982 printf("%s: master query: receive error\n",fname);
983 free(buff);
984 close_master_conn(1);
985 return -1;
986 }
987 close_master_conn(0);
988 rptr = buff;
989 cmd = get32bit(&rptr); // queryid
990 if (cmd!=0) {
991 printf("%s: master query: wrong answer (queryid)\n",fname);
992 free(buff);
993 return -1;
994 }
995 leng-=4;
996 if (leng==1) {
997 printf("%s: %s\n",fname,mfsstrerr(*rptr));
998 free(buff);
999 return -1;
1000 } else if (leng%3!=0 && leng!=44) {
1001 printf("%s: master query: wrong answer (leng)\n",fname);
1002 free(buff);
1003 return -1;
1004 }
1005 printf("%s:\n",fname);
1006 if (leng%3==0) {
1007 for (cmd=0 ; cmd<leng ; cmd+=3) {
1008 copies = get8bit(&rptr);
1009 chunks = get16bit(&rptr);
1010 if (copies==1) {
1011 printf("1 copy:");
1012 } else {
1013 printf("%"PRIu8" copies:",copies);
1014 }
1015 print_number(" ","\n",chunks,1,0,1);
1016 }
1017 } else {
1018 for (cmd=0 ; cmd<11 ; cmd++) {
1019 chunks = get32bit(&rptr);
1020 if (chunks>0) {
1021 if (cmd==1) {
1022 printf(" chunks with 1 copy: ");
1023 } else if (cmd>=10) {
1024 printf(" chunks with 10+ copies:");
1025 } else {
1026 printf(" chunks with %u copies: ",cmd);
1027 }
1028 print_number(" ","\n",chunks,1,0,1);
1029 }
1030 }
1031 }
1032 free(buff);
1033 return 0;
1034 }
1035 */
1036
get_goal(const char * fname,uint8_t mode)1037 int get_goal(const char *fname,uint8_t mode) {
1038 uint8_t reqbuff[17],*wptr,*buff;
1039 const uint8_t *rptr;
1040 uint32_t cmd,leng,inode;
1041 uint8_t fn,dn,i;
1042 uint8_t goal;
1043 uint32_t cnt;
1044 int fd;
1045 fd = open_master_conn(fname,&inode,NULL,0,0);
1046 if (fd<0) {
1047 return -1;
1048 }
1049 wptr = reqbuff;
1050 put32bit(&wptr,CLTOMA_FUSE_GETGOAL);
1051 put32bit(&wptr,9);
1052 put32bit(&wptr,0);
1053 put32bit(&wptr,inode);
1054 put8bit(&wptr,mode);
1055 if (tcpwrite(fd,reqbuff,17)!=17) {
1056 printf("%s: master query: send error\n",fname);
1057 close_master_conn(1);
1058 return -1;
1059 }
1060 if (tcpread(fd,reqbuff,8)!=8) {
1061 printf("%s: master query: receive error\n",fname);
1062 close_master_conn(1);
1063 return -1;
1064 }
1065 rptr = reqbuff;
1066 cmd = get32bit(&rptr);
1067 leng = get32bit(&rptr);
1068 if (cmd!=MATOCL_FUSE_GETGOAL) {
1069 printf("%s: master query: wrong answer (type)\n",fname);
1070 close_master_conn(1);
1071 return -1;
1072 }
1073 buff = malloc(leng);
1074 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1075 printf("%s: master query: receive error\n",fname);
1076 free(buff);
1077 close_master_conn(1);
1078 return -1;
1079 }
1080 close_master_conn(0);
1081 rptr = buff;
1082 cmd = get32bit(&rptr); // queryid
1083 if (cmd!=0) {
1084 printf("%s: master query: wrong answer (queryid)\n",fname);
1085 free(buff);
1086 return -1;
1087 }
1088 leng-=4;
1089 if (leng==1) {
1090 printf("%s: %s\n",fname,mfsstrerr(*rptr));
1091 free(buff);
1092 return -1;
1093 } else if (leng%5!=2) {
1094 printf("%s: master query: wrong answer (leng)\n",fname);
1095 free(buff);
1096 return -1;
1097 } else if (mode==GMODE_NORMAL && leng!=7) {
1098 printf("%s: master query: wrong answer (leng)\n",fname);
1099 free(buff);
1100 return -1;
1101 }
1102 if (mode==GMODE_NORMAL) {
1103 fn = get8bit(&rptr);
1104 dn = get8bit(&rptr);
1105 goal = get8bit(&rptr);
1106 cnt = get32bit(&rptr);
1107 if ((fn!=0 || dn!=1) && (fn!=1 || dn!=0)) {
1108 printf("%s: master query: wrong answer (fn,dn)\n",fname);
1109 free(buff);
1110 return -1;
1111 }
1112 if (cnt!=1) {
1113 printf("%s: master query: wrong answer (cnt)\n",fname);
1114 free(buff);
1115 return -1;
1116 }
1117 printf("%s: %"PRIu8"\n",fname,goal);
1118 } else {
1119 fn = get8bit(&rptr);
1120 dn = get8bit(&rptr);
1121 printf("%s:\n",fname);
1122 for (i=0 ; i<fn ; i++) {
1123 goal = get8bit(&rptr);
1124 cnt = get32bit(&rptr);
1125 printf(" files with goal %"PRIu8" :",goal);
1126 print_number(" ","\n",cnt,1,0,1);
1127 }
1128 for (i=0 ; i<dn ; i++) {
1129 goal = get8bit(&rptr);
1130 cnt = get32bit(&rptr);
1131 printf(" directories with goal %"PRIu8" :",goal);
1132 print_number(" ","\n",cnt,1,0,1);
1133 }
1134 }
1135 free(buff);
1136 return 0;
1137 }
1138
get_trashtime(const char * fname,uint8_t mode)1139 int get_trashtime(const char *fname,uint8_t mode) {
1140 uint8_t reqbuff[17],*wptr,*buff;
1141 const uint8_t *rptr;
1142 uint32_t cmd,leng,inode;
1143 uint32_t fn,dn,i;
1144 uint32_t trashtime;
1145 uint32_t cnt;
1146 int fd;
1147 fd = open_master_conn(fname,&inode,NULL,0,0);
1148 if (fd<0) {
1149 return -1;
1150 }
1151 wptr = reqbuff;
1152 put32bit(&wptr,CLTOMA_FUSE_GETTRASHTIME);
1153 put32bit(&wptr,9);
1154 put32bit(&wptr,0);
1155 put32bit(&wptr,inode);
1156 put8bit(&wptr,mode);
1157 if (tcpwrite(fd,reqbuff,17)!=17) {
1158 printf("%s: master query: send error\n",fname);
1159 close_master_conn(1);
1160 return -1;
1161 }
1162 if (tcpread(fd,reqbuff,8)!=8) {
1163 printf("%s: master query: receive error\n",fname);
1164 close_master_conn(1);
1165 return -1;
1166 }
1167 rptr = reqbuff;
1168 cmd = get32bit(&rptr);
1169 leng = get32bit(&rptr);
1170 if (cmd!=MATOCL_FUSE_GETTRASHTIME) {
1171 printf("%s: master query: wrong answer (type)\n",fname);
1172 close_master_conn(1);
1173 return -1;
1174 }
1175 buff = malloc(leng);
1176 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1177 printf("%s: master query: receive error\n",fname);
1178 free(buff);
1179 close_master_conn(1);
1180 return -1;
1181 }
1182 close_master_conn(0);
1183 rptr = buff;
1184 cmd = get32bit(&rptr); // queryid
1185 if (cmd!=0) {
1186 printf("%s: master query: wrong answer (queryid)\n",fname);
1187 free(buff);
1188 return -1;
1189 }
1190 leng-=4;
1191 if (leng==1) {
1192 printf("%s: %s\n",fname,mfsstrerr(*rptr));
1193 free(buff);
1194 return -1;
1195 } else if (leng<8 || leng%8!=0) {
1196 printf("%s: master query: wrong answer (leng)\n",fname);
1197 free(buff);
1198 return -1;
1199 } else if (mode==GMODE_NORMAL && leng!=16) {
1200 printf("%s: master query: wrong answer (leng)\n",fname);
1201 free(buff);
1202 return -1;
1203 }
1204 if (mode==GMODE_NORMAL) {
1205 fn = get32bit(&rptr);
1206 dn = get32bit(&rptr);
1207 trashtime = get32bit(&rptr);
1208 cnt = get32bit(&rptr);
1209 if ((fn!=0 || dn!=1) && (fn!=1 || dn!=0)) {
1210 printf("%s: master query: wrong answer (fn,dn)\n",fname);
1211 free(buff);
1212 return -1;
1213 }
1214 if (cnt!=1) {
1215 printf("%s: master query: wrong answer (cnt)\n",fname);
1216 free(buff);
1217 return -1;
1218 }
1219 printf("%s: %"PRIu32"\n",fname,trashtime);
1220 } else {
1221 fn = get32bit(&rptr);
1222 dn = get32bit(&rptr);
1223 printf("%s:\n",fname);
1224 for (i=0 ; i<fn ; i++) {
1225 trashtime = get32bit(&rptr);
1226 cnt = get32bit(&rptr);
1227 printf(" files with trashtime %10"PRIu32" :",trashtime);
1228 print_number(" ","\n",cnt,1,0,1);
1229 }
1230 for (i=0 ; i<dn ; i++) {
1231 trashtime = get32bit(&rptr);
1232 cnt = get32bit(&rptr);
1233 printf(" directories with trashtime %10"PRIu32" :",trashtime);
1234 print_number(" ","\n",cnt,1,0,1);
1235 }
1236 }
1237 free(buff);
1238 return 0;
1239 }
1240
get_eattr(const char * fname,uint8_t mode)1241 int get_eattr(const char *fname,uint8_t mode) {
1242 uint8_t reqbuff[17],*wptr,*buff;
1243 const uint8_t *rptr;
1244 uint32_t cmd,leng,inode;
1245 uint8_t fn,dn,i,j;
1246 uint32_t fcnt[EATTR_BITS];
1247 uint32_t dcnt[EATTR_BITS];
1248 uint8_t eattr;
1249 uint32_t cnt;
1250 int fd;
1251 fd = open_master_conn(fname,&inode,NULL,0,0);
1252 if (fd<0) {
1253 return -1;
1254 }
1255 wptr = reqbuff;
1256 put32bit(&wptr,CLTOMA_FUSE_GETEATTR);
1257 put32bit(&wptr,9);
1258 put32bit(&wptr,0);
1259 put32bit(&wptr,inode);
1260 put8bit(&wptr,mode);
1261 if (tcpwrite(fd,reqbuff,17)!=17) {
1262 printf("%s: master query: send error\n",fname);
1263 close_master_conn(1);
1264 return -1;
1265 }
1266 if (tcpread(fd,reqbuff,8)!=8) {
1267 printf("%s: master query: receive error\n",fname);
1268 close_master_conn(1);
1269 return -1;
1270 }
1271 rptr = reqbuff;
1272 cmd = get32bit(&rptr);
1273 leng = get32bit(&rptr);
1274 if (cmd!=MATOCL_FUSE_GETEATTR) {
1275 printf("%s: master query: wrong answer (type)\n",fname);
1276 close_master_conn(1);
1277 return -1;
1278 }
1279 buff = malloc(leng);
1280 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1281 printf("%s: master query: receive error\n",fname);
1282 free(buff);
1283 close_master_conn(1);
1284 return -1;
1285 }
1286 close_master_conn(0);
1287 rptr = buff;
1288 cmd = get32bit(&rptr); // queryid
1289 if (cmd!=0) {
1290 printf("%s: master query: wrong answer (queryid)\n",fname);
1291 free(buff);
1292 return -1;
1293 }
1294 leng-=4;
1295 if (leng==1) {
1296 printf("%s: %s\n",fname,mfsstrerr(*rptr));
1297 free(buff);
1298 return -1;
1299 } else if (leng%5!=2) {
1300 printf("%s: master query: wrong answer (leng)\n",fname);
1301 free(buff);
1302 return -1;
1303 } else if (mode==GMODE_NORMAL && leng!=7) {
1304 printf("%s: master query: wrong answer (leng)\n",fname);
1305 free(buff);
1306 return -1;
1307 }
1308 if (mode==GMODE_NORMAL) {
1309 fn = get8bit(&rptr);
1310 dn = get8bit(&rptr);
1311 eattr = get8bit(&rptr);
1312 cnt = get32bit(&rptr);
1313 if ((fn!=0 || dn!=1) && (fn!=1 || dn!=0)) {
1314 printf("%s: master query: wrong answer (fn,dn)\n",fname);
1315 free(buff);
1316 return -1;
1317 }
1318 if (cnt!=1) {
1319 printf("%s: master query: wrong answer (cnt)\n",fname);
1320 free(buff);
1321 return -1;
1322 }
1323 printf("%s: ",fname);
1324 if (eattr>0) {
1325 cnt=0;
1326 for (j=0 ; j<EATTR_BITS ; j++) {
1327 if (eattr & (1<<j)) {
1328 printf("%s%s",(cnt)?",":"",eattrtab[j]);
1329 cnt=1;
1330 }
1331 }
1332 printf("\n");
1333 } else {
1334 printf("-\n");
1335 }
1336 // printf("%s: %"PRIX8"\n",fname,eattr);
1337 } else {
1338 for (j=0 ; j<EATTR_BITS ; j++) {
1339 fcnt[j]=0;
1340 dcnt[j]=0;
1341 }
1342 fn = get8bit(&rptr);
1343 dn = get8bit(&rptr);
1344 for (i=0 ; i<fn ; i++) {
1345 eattr = get8bit(&rptr);
1346 cnt = get32bit(&rptr);
1347 for (j=0 ; j<EATTR_BITS ; j++) {
1348 if (eattr & (1<<j)) {
1349 fcnt[j]+=cnt;
1350 }
1351 }
1352 }
1353 for (i=0 ; i<dn ; i++) {
1354 eattr = get8bit(&rptr);
1355 cnt = get32bit(&rptr);
1356 for (j=0 ; j<EATTR_BITS ; j++) {
1357 if (eattr & (1<<j)) {
1358 dcnt[j]+=cnt;
1359 }
1360 }
1361 }
1362 printf("%s:\n",fname);
1363 for (j=0 ; j<EATTR_BITS ; j++) {
1364 if (eattrtab[j][0]) {
1365 printf(" not directory nodes with attribute %16s :",eattrtab[j]);
1366 print_number(" ","\n",fcnt[j],1,0,1);
1367 printf(" directories with attribute %16s :",eattrtab[j]);
1368 print_number(" ","\n",dcnt[j],1,0,1);
1369 } else {
1370 if (fcnt[j]>0) {
1371 printf(" not directory nodes with attribute 'unknown-%u' :",j);
1372 print_number(" ","\n",fcnt[j],1,0,1);
1373 }
1374 if (dcnt[j]>0) {
1375 printf(" directories with attribute 'unknown-%u' :",j);
1376 print_number(" ","\n",dcnt[j],1,0,1);
1377 }
1378 }
1379 }
1380 /*
1381 for (i=0 ; i<fn ; i++) {
1382 eattr = get8bit(&rptr);
1383 cnt = get32bit(&rptr);
1384 printf(" files with eattr %"PRIX8" :",eattr);
1385 print_number(" ","\n",cnt,0,1);
1386 }
1387 for (i=0 ; i<dn ; i++) {
1388 eattr = get8bit(&rptr);
1389 cnt = get32bit(&rptr);
1390 printf(" directories with eattr %"PRIX8" :",eattr);
1391 print_number(" ","\n",cnt,0,1);
1392 }
1393 */
1394 }
1395 free(buff);
1396 return 0;
1397 }
1398
set_goal(const char * fname,uint8_t goal,uint8_t mode)1399 int set_goal(const char *fname,uint8_t goal,uint8_t mode) {
1400 uint8_t reqbuff[22],*wptr,*buff;
1401 const uint8_t *rptr;
1402 uint32_t cmd,leng,inode,uid;
1403 uint32_t changed,notchanged,notpermitted,quotaexceeded;
1404 int fd;
1405 fd = open_master_conn(fname,&inode,NULL,0,1);
1406 if (fd<0) {
1407 return -1;
1408 }
1409 uid = getuid();
1410 wptr = reqbuff;
1411 put32bit(&wptr,CLTOMA_FUSE_SETGOAL);
1412 put32bit(&wptr,14);
1413 put32bit(&wptr,0);
1414 put32bit(&wptr,inode);
1415 put32bit(&wptr,uid);
1416 put8bit(&wptr,goal);
1417 put8bit(&wptr,mode);
1418 if (tcpwrite(fd,reqbuff,22)!=22) {
1419 printf("%s: master query: send error\n",fname);
1420 close_master_conn(1);
1421 return -1;
1422 }
1423 if (tcpread(fd,reqbuff,8)!=8) {
1424 printf("%s: master query: receive error\n",fname);
1425 close_master_conn(1);
1426 return -1;
1427 }
1428 rptr = reqbuff;
1429 cmd = get32bit(&rptr);
1430 leng = get32bit(&rptr);
1431 if (cmd!=MATOCL_FUSE_SETGOAL) {
1432 printf("%s: master query: wrong answer (type)\n",fname);
1433 close_master_conn(1);
1434 return -1;
1435 }
1436 buff = malloc(leng);
1437 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1438 printf("%s: master query: receive error\n",fname);
1439 free(buff);
1440 close_master_conn(1);
1441 return -1;
1442 }
1443 close_master_conn(0);
1444 rptr = buff;
1445 cmd = get32bit(&rptr); // queryid
1446 if (cmd!=0) {
1447 printf("%s: master query: wrong answer (queryid)\n",fname);
1448 free(buff);
1449 return -1;
1450 }
1451 leng-=4;
1452 if (leng==1) {
1453 printf("%s: %s\n",fname,mfsstrerr(*rptr));
1454 free(buff);
1455 return -1;
1456 } else if (leng!=12 && leng!=16) {
1457 printf("%s: master query: wrong answer (leng)\n",fname);
1458 free(buff);
1459 return -1;
1460 }
1461 changed = get32bit(&rptr);
1462 notchanged = get32bit(&rptr);
1463 notpermitted = get32bit(&rptr);
1464 if (leng==16) {
1465 quotaexceeded = get32bit(&rptr);
1466 } else {
1467 quotaexceeded = 0;
1468 }
1469 if ((mode&SMODE_RMASK)==0) {
1470 if (changed || mode==SMODE_SET) {
1471 printf("%s: %"PRIu8"\n",fname,goal);
1472 } else {
1473 printf("%s: goal not changed\n",fname);
1474 }
1475 } else {
1476 printf("%s:\n",fname);
1477 print_number(" inodes with goal changed: ","\n",changed,1,0,1);
1478 print_number(" inodes with goal not changed: ","\n",notchanged,1,0,1);
1479 print_number(" inodes with permission denied: ","\n",notpermitted,1,0,1);
1480 if (leng==16) {
1481 print_number(" inodes with quota exceeded: ","\n",quotaexceeded,1,0,1);
1482 }
1483 }
1484 free(buff);
1485 return 0;
1486 }
1487
set_trashtime(const char * fname,uint32_t trashtime,uint8_t mode)1488 int set_trashtime(const char *fname,uint32_t trashtime,uint8_t mode) {
1489 uint8_t reqbuff[25],*wptr,*buff;
1490 const uint8_t *rptr;
1491 uint32_t cmd,leng,inode,uid;
1492 uint32_t changed,notchanged,notpermitted;
1493 int fd;
1494 fd = open_master_conn(fname,&inode,NULL,0,1);
1495 if (fd<0) {
1496 return -1;
1497 }
1498 uid = getuid();
1499 wptr = reqbuff;
1500 put32bit(&wptr,CLTOMA_FUSE_SETTRASHTIME);
1501 put32bit(&wptr,17);
1502 put32bit(&wptr,0);
1503 put32bit(&wptr,inode);
1504 put32bit(&wptr,uid);
1505 put32bit(&wptr,trashtime);
1506 put8bit(&wptr,mode);
1507 if (tcpwrite(fd,reqbuff,25)!=25) {
1508 printf("%s: master query: send error\n",fname);
1509 close_master_conn(1);
1510 return -1;
1511 }
1512 if (tcpread(fd,reqbuff,8)!=8) {
1513 printf("%s: master query: receive error\n",fname);
1514 close_master_conn(1);
1515 return -1;
1516 }
1517 rptr = reqbuff;
1518 cmd = get32bit(&rptr);
1519 leng = get32bit(&rptr);
1520 if (cmd!=MATOCL_FUSE_SETTRASHTIME) {
1521 printf("%s: master query: wrong answer (type)\n",fname);
1522 close_master_conn(1);
1523 return -1;
1524 }
1525 buff = malloc(leng);
1526 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1527 printf("%s: master query: receive error\n",fname);
1528 free(buff);
1529 close_master_conn(1);
1530 return -1;
1531 }
1532 close_master_conn(0);
1533 rptr = buff;
1534 cmd = get32bit(&rptr); // queryid
1535 if (cmd!=0) {
1536 printf("%s: master query: wrong answer (queryid)\n",fname);
1537 free(buff);
1538 return -1;
1539 }
1540 leng-=4;
1541 if (leng==1) {
1542 printf("%s: %s\n",fname,mfsstrerr(*rptr));
1543 free(buff);
1544 return -1;
1545 } else if (leng!=12) {
1546 printf("%s: master query: wrong answer (leng)\n",fname);
1547 free(buff);
1548 return -1;
1549 }
1550 changed = get32bit(&rptr);
1551 notchanged = get32bit(&rptr);
1552 notpermitted = get32bit(&rptr);
1553 if ((mode&SMODE_RMASK)==0) {
1554 if (changed || mode==SMODE_SET) {
1555 printf("%s: %"PRIu32"\n",fname,trashtime);
1556 } else {
1557 printf("%s: trashtime not changed\n",fname);
1558 }
1559 } else {
1560 printf("%s:\n",fname);
1561 print_number(" inodes with trashtime changed: ","\n",changed,1,0,1);
1562 print_number(" inodes with trashtime not changed: ","\n",notchanged,1,0,1);
1563 print_number(" inodes with permission denied: ","\n",notpermitted,1,0,1);
1564 }
1565 free(buff);
1566 return 0;
1567 }
1568
set_eattr(const char * fname,uint8_t eattr,uint8_t mode)1569 int set_eattr(const char *fname,uint8_t eattr,uint8_t mode) {
1570 uint8_t reqbuff[22],*wptr,*buff;
1571 const uint8_t *rptr;
1572 uint32_t cmd,leng,inode,uid;
1573 uint32_t changed,notchanged,notpermitted;
1574 int fd;
1575 fd = open_master_conn(fname,&inode,NULL,0,1);
1576 if (fd<0) {
1577 return -1;
1578 }
1579 uid = getuid();
1580 wptr = reqbuff;
1581 put32bit(&wptr,CLTOMA_FUSE_SETEATTR);
1582 put32bit(&wptr,14);
1583 put32bit(&wptr,0);
1584 put32bit(&wptr,inode);
1585 put32bit(&wptr,uid);
1586 put8bit(&wptr,eattr);
1587 put8bit(&wptr,mode);
1588 if (tcpwrite(fd,reqbuff,22)!=22) {
1589 printf("%s: master query: send error\n",fname);
1590 close_master_conn(1);
1591 return -1;
1592 }
1593 if (tcpread(fd,reqbuff,8)!=8) {
1594 printf("%s: master query: receive error\n",fname);
1595 close_master_conn(1);
1596 return -1;
1597 }
1598 rptr = reqbuff;
1599 cmd = get32bit(&rptr);
1600 leng = get32bit(&rptr);
1601 if (cmd!=MATOCL_FUSE_SETEATTR) {
1602 printf("%s: master query: wrong answer (type)\n",fname);
1603 close_master_conn(1);
1604 return -1;
1605 }
1606 buff = malloc(leng);
1607 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1608 printf("%s: master query: receive error\n",fname);
1609 free(buff);
1610 close_master_conn(1);
1611 return -1;
1612 }
1613 close_master_conn(0);
1614 rptr = buff;
1615 cmd = get32bit(&rptr); // queryid
1616 if (cmd!=0) {
1617 printf("%s: master query: wrong answer (queryid)\n",fname);
1618 free(buff);
1619 return -1;
1620 }
1621 leng-=4;
1622 if (leng==1) {
1623 printf("%s: %s\n",fname,mfsstrerr(*rptr));
1624 free(buff);
1625 return -1;
1626 } else if (leng!=12) {
1627 printf("%s: master query: wrong answer (leng)\n",fname);
1628 free(buff);
1629 return -1;
1630 }
1631 changed = get32bit(&rptr);
1632 notchanged = get32bit(&rptr);
1633 notpermitted = get32bit(&rptr);
1634 if ((mode&SMODE_RMASK)==0) {
1635 if (changed) {
1636 printf("%s: attribute(s) changed\n",fname);
1637 } else {
1638 printf("%s: attribute(s) not changed\n",fname);
1639 }
1640 } else {
1641 printf("%s:\n",fname);
1642 print_number(" inodes with attributes changed: ","\n",changed,1,0,1);
1643 print_number(" inodes with attributes not changed: ","\n",notchanged,1,0,1);
1644 print_number(" inodes with permission denied: ","\n",notpermitted,1,0,1);
1645 }
1646 free(buff);
1647 return 0;
1648 }
1649
ip_port_cmp(const void * a,const void * b)1650 int ip_port_cmp(const void*a,const void*b) {
1651 return memcmp(a,b,6);
1652 }
1653
get_checksum_block(const char * csstrip,uint32_t csip,uint16_t csport,uint64_t chunkid,uint32_t version,uint8_t crcblock[4096])1654 int get_checksum_block(const char *csstrip,uint32_t csip,uint16_t csport,uint64_t chunkid,uint32_t version,uint8_t crcblock[4096]) {
1655 uint8_t reqbuff[20],*wptr,*buff;
1656 const uint8_t *rptr;
1657 int fd;
1658 uint32_t cmd,leng;
1659 uint16_t cnt;
1660
1661 cnt=0;
1662 while (cnt<10) {
1663 fd = tcpsocket();
1664 if (fd<0) {
1665 printf("can't create connection socket: %s\n",strerr(errno));
1666 return -1;
1667 }
1668 if (tcpnumtoconnect(fd,csip,csport,(cnt%2)?(300*(1<<(cnt>>1))):(200*(1<<(cnt>>1))))<0) {
1669 cnt++;
1670 if (cnt==10) {
1671 printf("can't connect to chunkserver %s:%"PRIu16": %s\n",csstrip,csport,strerr(errno));
1672 return -1;
1673 }
1674 tcpclose(fd);
1675 } else {
1676 cnt=10;
1677 }
1678 }
1679 wptr = reqbuff;
1680 put32bit(&wptr,ANTOCS_GET_CHUNK_CHECKSUM_TAB);
1681 put32bit(&wptr,12);
1682 put64bit(&wptr,chunkid);
1683 put32bit(&wptr,version);
1684 if (tcpwrite(fd,reqbuff,20)!=20) {
1685 printf("%s:%"PRIu16": cs query: send error\n",csstrip,csport);
1686 tcpclose(fd);
1687 return -1;
1688 }
1689 if (tcpread(fd,reqbuff,8)!=8) {
1690 printf("%s:%"PRIu16" cs query: receive error\n",csstrip,csport);
1691 tcpclose(fd);
1692 return -1;
1693 }
1694 rptr = reqbuff;
1695 cmd = get32bit(&rptr);
1696 leng = get32bit(&rptr);
1697 if (cmd!=CSTOAN_CHUNK_CHECKSUM_TAB) {
1698 printf("%s:%"PRIu16" cs query: wrong answer (type)\n",csstrip,csport);
1699 tcpclose(fd);
1700 return -1;
1701 }
1702 if (leng!=13 && leng!=(4096+12)) {
1703 printf("%s:%"PRIu16" cs query: wrong answer (size)\n",csstrip,csport);
1704 tcpclose(fd);
1705 return -1;
1706 }
1707 buff = malloc(leng);
1708 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1709 printf("%s:%"PRIu16" cs query: receive error\n",csstrip,csport);
1710 free(buff);
1711 tcpclose(fd);
1712 return -1;
1713 }
1714 tcpclose(fd);
1715 rptr = buff;
1716 if (chunkid!=get64bit(&rptr)) {
1717 printf("%s:%"PRIu16" cs query: wrong answer (chunkid)\n",csstrip,csport);
1718 free(buff);
1719 return -1;
1720 }
1721 if (version!=get32bit(&rptr)) {
1722 printf("%s:%"PRIu16" cs query: wrong answer (version)\n",csstrip,csport);
1723 free(buff);
1724 return -1;
1725 }
1726 leng-=12;
1727 if (leng==1) {
1728 printf("%s:%"PRIu16" cs query error: %s\n",csstrip,csport,mfsstrerr(*rptr));
1729 free(buff);
1730 return -1;
1731 }
1732 memcpy(crcblock,rptr,4096);
1733 free(buff);
1734 return 0;
1735 }
1736
digest_to_str(char strdigest[33],uint8_t digest[16])1737 void digest_to_str(char strdigest[33],uint8_t digest[16]) {
1738 uint32_t i;
1739 for (i=0 ; i<16 ; i++) {
1740 snprintf(strdigest+2*i,3,"%02X",digest[i]);
1741 }
1742 strdigest[32]='\0';
1743 }
1744
file_info(uint8_t fileinfomode,const char * fname)1745 int file_info(uint8_t fileinfomode,const char *fname) {
1746 uint8_t reqbuff[20],*wptr,*buff;
1747 const uint8_t *rptr;
1748 uint32_t fchunks;
1749 uint32_t indx,cmd,leng,inode,version;
1750 uint32_t chunks,copies,copy;
1751 char csstrip[16];
1752 uint32_t csip;
1753 uint16_t csport;
1754 uint8_t protover;
1755 uint64_t fleng,chunkid;
1756 uint8_t crcblock[4096];
1757 md5ctx filectx,chunkctx;
1758 uint8_t chunkdigest[16],currentdigest[16];
1759 uint8_t firstdigest;
1760 uint8_t checksumerror;
1761 char strdigest[33];
1762 int fd;
1763 fd = open_master_conn(fname,&inode,NULL,0,0);
1764 if (fd<0) {
1765 return -1;
1766 }
1767 wptr = reqbuff;
1768 put32bit(&wptr,CLTOMA_FUSE_CHECK);
1769 put32bit(&wptr,8);
1770 put32bit(&wptr,0);
1771 put32bit(&wptr,inode);
1772 if (tcpwrite(fd,reqbuff,16)!=16) {
1773 printf("%s: master query: send error\n",fname);
1774 close_master_conn(1);
1775 return -1;
1776 }
1777 if (tcpread(fd,reqbuff,8)!=8) {
1778 printf("%s: master query: receive error\n",fname);
1779 close_master_conn(1);
1780 return -1;
1781 }
1782 rptr = reqbuff;
1783 cmd = get32bit(&rptr);
1784 leng = get32bit(&rptr);
1785 if (cmd!=MATOCL_FUSE_CHECK) {
1786 printf("%s: master query: wrong answer (type)\n",fname);
1787 close_master_conn(1);
1788 return -1;
1789 }
1790 buff = malloc(leng);
1791 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1792 printf("%s: master query: receive error\n",fname);
1793 free(buff);
1794 close_master_conn(1);
1795 return -1;
1796 }
1797 close_master_conn(0);
1798 rptr = buff;
1799 cmd = get32bit(&rptr); // queryid
1800 if (cmd!=0) {
1801 printf("%s: master query: wrong answer (queryid)\n",fname);
1802 free(buff);
1803 return -1;
1804 }
1805 leng-=4;
1806 if (leng==1) {
1807 printf("%s: %s\n",fname,mfsstrerr(*rptr));
1808 free(buff);
1809 return -1;
1810 } else if (leng%3!=0 && leng!=44) {
1811 printf("%s: master query: wrong answer (leng)\n",fname);
1812 free(buff);
1813 return -1;
1814 }
1815 if (fileinfomode&FILEINFO_QUICK) {
1816 printf("%s:\n",fname);
1817 }
1818 fchunks = 0;
1819 if (leng%3==0) {
1820 for (cmd=0 ; cmd<leng ; cmd+=3) {
1821 copies = get8bit(&rptr);
1822 chunks = get16bit(&rptr);
1823 if (fileinfomode&FILEINFO_QUICK) {
1824 if (copies==1) {
1825 printf("1 copy:");
1826 } else {
1827 printf("%"PRIu32" copies:",copies);
1828 }
1829 print_number(" ","\n",chunks,1,0,1);
1830 }
1831 fchunks += chunks;
1832 }
1833 } else {
1834 for (cmd=0 ; cmd<11 ; cmd++) {
1835 chunks = get32bit(&rptr);
1836 if (chunks>0 && (fileinfomode&FILEINFO_QUICK)) {
1837 if (cmd==1) {
1838 printf(" chunks with 1 copy: ");
1839 } else if (cmd>=10) {
1840 printf(" chunks with 10+ copies:");
1841 } else {
1842 printf(" chunks with %u copies: ",cmd);
1843 }
1844 print_number(" ","\n",chunks,1,0,1);
1845 }
1846 fchunks += chunks;
1847 }
1848 }
1849 free(buff);
1850 if ((fileinfomode&FILEINFO_QUICK)==0) {
1851 // printf("masterversion: %08X\n",masterversion);
1852 if (fileinfomode&FILEINFO_SIGNATURE) {
1853 md5_init(&filectx);
1854 }
1855 printf("%s:\n",fname);
1856 if (fchunks==0) {
1857 printf("\tno chunks - empty file\n");
1858 }
1859 for (indx=0 ; indx<fchunks ; indx++) {
1860 wptr = reqbuff;
1861 put32bit(&wptr,CLTOMA_FUSE_READ_CHUNK);
1862 put32bit(&wptr,12);
1863 put32bit(&wptr,0);
1864 put32bit(&wptr,inode);
1865 put32bit(&wptr,indx);
1866 if (tcpwrite(fd,reqbuff,20)!=20) {
1867 printf("%s [%"PRIu32"]: master query: send error\n",fname,indx);
1868 close_master_conn(1);
1869 return -1;
1870 }
1871 if (tcpread(fd,reqbuff,8)!=8) {
1872 printf("%s [%"PRIu32"]: master query: receive error\n",fname,indx);
1873 close_master_conn(1);
1874 return -1;
1875 }
1876 rptr = reqbuff;
1877 cmd = get32bit(&rptr);
1878 leng = get32bit(&rptr);
1879 if (cmd!=MATOCL_FUSE_READ_CHUNK) {
1880 printf("%s [%"PRIu32"]: master query: wrong answer (type)\n",fname,indx);
1881 close_master_conn(1);
1882 return -1;
1883 }
1884 buff = malloc(leng);
1885 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
1886 printf("%s [%"PRIu32"]: master query: receive error\n",fname,indx);
1887 free(buff);
1888 close_master_conn(1);
1889 return -1;
1890 }
1891 rptr = buff;
1892 cmd = get32bit(&rptr); // queryid
1893 if (cmd!=0) {
1894 printf("%s [%"PRIu32"]: master query: wrong answer (queryid)\n",fname,indx);
1895 free(buff);
1896 close_master_conn(1);
1897 return -1;
1898 }
1899 leng-=4;
1900 if (leng==1) {
1901 printf("%s [%"PRIu32"]: %s\n",fname,indx,mfsstrerr(*rptr));
1902 free(buff);
1903 close_master_conn(1);
1904 return -1;
1905 } else if (leng&1) {
1906 if (leng<21 || ((leng-21)%10)!=0) {
1907 printf("%s [%"PRIu32"]: master query: wrong answer (leng)\n",fname,indx);
1908 free(buff);
1909 close_master_conn(1);
1910 return -1;
1911 }
1912 protover = get8bit(&rptr);
1913 } else {
1914 if (leng<20 || ((leng-20)%6)!=0) {
1915 printf("%s [%"PRIu32"]: master query: wrong answer (leng)\n",fname,indx);
1916 free(buff);
1917 close_master_conn(1);
1918 return -1;
1919 }
1920 protover = 0;
1921 }
1922 fleng = get64bit(&rptr);
1923 chunkid = get64bit(&rptr);
1924 version = get32bit(&rptr);
1925 if (fleng>0) {
1926 if (chunkid==0 && version==0) {
1927 printf("\tchunk %"PRIu32": empty\n",indx);
1928 } else {
1929 printf("\tchunk %"PRIu32": %016"PRIX64"_%08"PRIX32" / (id:%"PRIu64" ver:%"PRIu32")\n",indx,chunkid,version,chunkid,version);
1930 if (protover) {
1931 copies = (leng-21)/10;
1932 } else {
1933 copies = (leng-20)/6;
1934 }
1935 if (leng>0) {
1936 wptr = (uint8_t*)rptr;
1937 qsort(wptr,copies,(protover)?10:6,ip_port_cmp);
1938 firstdigest = 1;
1939 checksumerror = 0;
1940 for (copy=0 ; copy<copies ; copy++) {
1941 snprintf(csstrip,16,"%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8,rptr[0],rptr[1],rptr[2],rptr[3]);
1942 csstrip[15]=0;
1943 csip = get32bit(&rptr);
1944 csport = get16bit(&rptr);
1945 if (protover) {
1946 rptr+=4;
1947 }
1948 if (fileinfomode&(FILEINFO_CRC|FILEINFO_SIGNATURE)) {
1949 if (get_checksum_block(csstrip,csip,csport,chunkid,version,crcblock)==0) {
1950 md5_init(&chunkctx);
1951 md5_update(&chunkctx,crcblock,4096);
1952 if ((fileinfomode&FILEINFO_SIGNATURE) && firstdigest) {
1953 md5_update(&filectx,crcblock,4096);
1954 }
1955 md5_final(currentdigest,&chunkctx);
1956 if (firstdigest) {
1957 memcpy(chunkdigest,currentdigest,16);
1958 } else {
1959 if (memcmp(chunkdigest,currentdigest,16)!=0) {
1960 checksumerror = 1;
1961 }
1962 }
1963 firstdigest = 0;
1964 if (fileinfomode&FILEINFO_CRC) {
1965 digest_to_str(strdigest,currentdigest);
1966 printf("\t\tcopy %"PRIu32": %s:%"PRIu16" (checksum digest: %s)\n",copy+1,csstrip,csport,strdigest);
1967 } else {
1968 printf("\t\tcopy %"PRIu32": %s:%"PRIu16"\n",copy+1,csstrip,csport);
1969 }
1970 } else {
1971 if (fileinfomode&FILEINFO_CRC) {
1972 printf("\t\tcopy %"PRIu32": %s:%"PRIu16" - can't get checksum\n",copy+1,csstrip,csport);
1973 } else {
1974 printf("\t\tcopy %"PRIu32": %s:%"PRIu16"\n",copy+1,csstrip,csport);
1975 }
1976 }
1977 } else {
1978 printf("\t\tcopy %"PRIu32": %s:%"PRIu16"\n",copy+1,csstrip,csport);
1979 }
1980 }
1981 if (checksumerror) {
1982 printf("\t\tcopies have different checksums !!!\n");
1983 }
1984 if ((fileinfomode&FILEINFO_SIGNATURE) && firstdigest) {
1985 printf("\t\tcouldn't add this chunk to signature !!!\n");
1986 }
1987 } else {
1988 printf("\t\tno valid copies !!!\n");
1989 }
1990 }
1991 }
1992 free(buff);
1993 }
1994 // while (indx<((fleng+MFSCHUNKMASK)>>MFSCHUNKBITS));
1995 close_master_conn(0);
1996 if (fileinfomode&FILEINFO_SIGNATURE) {
1997 md5_final(currentdigest,&filectx);
1998 digest_to_str(strdigest,currentdigest);
1999 printf("%s signature: %s\n",fname,strdigest);
2000 }
2001 }
2002 return 0;
2003 }
2004
append_file(const char * fname,const char * afname)2005 int append_file(const char *fname,const char *afname) {
2006 uint8_t reqbuff[28+NGROUPS_MAX*4+4],*wptr,*buff;
2007 const uint8_t *rptr;
2008 uint32_t cmd,leng,inode,ainode,uid,gid;
2009 gid_t grouplist[NGROUPS_MAX];
2010 uint32_t i,gids;
2011 uint8_t addmaingroup;
2012 mode_t dmode,smode;
2013 int fd;
2014 fd = open_master_conn(fname,&inode,&dmode,0,1);
2015 if (fd<0) {
2016 return -1;
2017 }
2018 if (open_master_conn(afname,&ainode,&smode,1,1)<0) {
2019 return -1;
2020 }
2021
2022 if ((smode&S_IFMT)!=S_IFREG) {
2023 printf("%s: not a file\n",afname);
2024 return -1;
2025 }
2026 if ((dmode&S_IFMT)!=S_IFREG) {
2027 printf("%s: not a file\n",fname);
2028 return -1;
2029 }
2030 uid = getuid();
2031 gid = getgid();
2032 if (masterversion>=VERSION2INT(2,0,0)) {
2033 gids = getgroups(NGROUPS_MAX,grouplist);
2034 addmaingroup = 1;
2035 for (i=0 ; i<gids ; i++) {
2036 if (grouplist[i]==gid) {
2037 addmaingroup = 0;
2038 }
2039 }
2040 } else {
2041 gids = 0;
2042 addmaingroup = 0;
2043 }
2044 wptr = reqbuff;
2045 put32bit(&wptr,CLTOMA_FUSE_APPEND);
2046 put32bit(&wptr,20+(addmaingroup+gids)*4);
2047 put32bit(&wptr,0);
2048 put32bit(&wptr,inode);
2049 put32bit(&wptr,ainode);
2050 put32bit(&wptr,uid);
2051 if (masterversion<VERSION2INT(2,0,0)) {
2052 put32bit(&wptr,gid);
2053 } else {
2054 put32bit(&wptr,addmaingroup+gids);
2055 if (addmaingroup) {
2056 put32bit(&wptr,gid);
2057 }
2058 for (i=0 ; i<gids ; i++) {
2059 put32bit(&wptr,grouplist[i]);
2060 }
2061 }
2062 if (tcpwrite(fd,reqbuff,28+(addmaingroup+gids)*4)!=(int32_t)(28+(addmaingroup+gids)*4)) {
2063 printf("%s: master query: send error\n",fname);
2064 close_master_conn(1);
2065 return -1;
2066 }
2067 if (tcpread(fd,reqbuff,8)!=8) {
2068 printf("%s: master query: receive error\n",fname);
2069 close_master_conn(1);
2070 return -1;
2071 }
2072 rptr = reqbuff;
2073 cmd = get32bit(&rptr);
2074 leng = get32bit(&rptr);
2075 if (cmd!=MATOCL_FUSE_APPEND) {
2076 printf("%s: master query: wrong answer (type)\n",fname);
2077 close_master_conn(1);
2078 return -1;
2079 }
2080 buff = malloc(leng);
2081 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
2082 printf("%s: master query: receive error\n",fname);
2083 free(buff);
2084 close_master_conn(1);
2085 return -1;
2086 }
2087 close_master_conn(0);
2088 rptr = buff;
2089 cmd = get32bit(&rptr); // queryid
2090 if (cmd!=0) {
2091 printf("%s: master query: wrong answer (queryid)\n",fname);
2092 free(buff);
2093 return -1;
2094 }
2095 leng-=4;
2096 if (leng!=1) {
2097 printf("%s: master query: wrong answer (leng)\n",fname);
2098 free(buff);
2099 return -1;
2100 } else if (*rptr!=STATUS_OK) {
2101 printf("%s: %s\n",fname,mfsstrerr(*rptr));
2102 free(buff);
2103 return -1;
2104 }
2105 free(buff);
2106 return 0;
2107 }
2108
dir_info(uint8_t dirinfomode,const char * fname)2109 int dir_info(uint8_t dirinfomode,const char *fname) {
2110 uint8_t reqbuff[16],*wptr,*buff;
2111 const uint8_t *rptr;
2112 uint32_t cmd,leng,inode;
2113 uint32_t inodes,dirs,files,chunks;
2114 uint64_t length,size,realsize;
2115 int fd;
2116 fd = open_master_conn(fname,&inode,NULL,0,0);
2117 if (fd<0) {
2118 return -1;
2119 }
2120 wptr = reqbuff;
2121 put32bit(&wptr,CLTOMA_FUSE_GETDIRSTATS);
2122 put32bit(&wptr,8);
2123 put32bit(&wptr,0);
2124 put32bit(&wptr,inode);
2125 if (tcpwrite(fd,reqbuff,16)!=16) {
2126 printf("%s: master query: send error\n",fname);
2127 close_master_conn(1);
2128 return -1;
2129 }
2130 if (tcpread(fd,reqbuff,8)!=8) {
2131 printf("%s: master query: receive error\n",fname);
2132 close_master_conn(1);
2133 return -1;
2134 }
2135 rptr = reqbuff;
2136 cmd = get32bit(&rptr);
2137 leng = get32bit(&rptr);
2138 if (cmd!=MATOCL_FUSE_GETDIRSTATS) {
2139 printf("%s: master query: wrong answer (type)\n",fname);
2140 close_master_conn(1);
2141 return -1;
2142 }
2143 buff = malloc(leng);
2144 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
2145 printf("%s: master query: receive error\n",fname);
2146 free(buff);
2147 close_master_conn(1);
2148 return -1;
2149 }
2150 rptr = buff;
2151 cmd = get32bit(&rptr); // queryid
2152 if (cmd!=0) {
2153 printf("%s: master query: wrong answer (queryid)\n",fname);
2154 free(buff);
2155 close_master_conn(1);
2156 return -1;
2157 }
2158 leng-=4;
2159 if (leng==1) {
2160 printf("%s: %s\n",fname,mfsstrerr(*rptr));
2161 free(buff);
2162 close_master_conn(1);
2163 return -1;
2164 } else if (leng!=56 && leng!=40) {
2165 printf("%s: master query: wrong answer (leng)\n",fname);
2166 free(buff);
2167 close_master_conn(1);
2168 return -1;
2169 }
2170 close_master_conn(0);
2171 inodes = get32bit(&rptr);
2172 dirs = get32bit(&rptr);
2173 files = get32bit(&rptr);
2174 if (leng==56) {
2175 rptr+=8;
2176 }
2177 chunks = get32bit(&rptr);
2178 if (leng==56) {
2179 rptr+=8;
2180 }
2181 length = get64bit(&rptr);
2182 size = get64bit(&rptr);
2183 realsize = get64bit(&rptr);
2184 free(buff);
2185 if (dirinfomode==0) {
2186 printf("%s:\n",fname);
2187 print_number(" inodes: ","\n",inodes,0,0,1);
2188 print_number(" directories: ","\n",dirs,0,0,1);
2189 print_number(" files: ","\n",files,0,0,1);
2190 print_number(" chunks: ","\n",chunks,0,0,1);
2191 print_number(" length: ","\n",length,0,1,1);
2192 print_number(" size: ","\n",size,0,1,1);
2193 print_number(" realsize: ","\n",realsize,0,1,1);
2194 } else {
2195 if (dirinfomode&DIRINFO_INODES) {
2196 print_number_only(inodes,0);
2197 printf("\t");
2198 }
2199 if (dirinfomode&DIRINFO_DIRS) {
2200 print_number_only(dirs,0);
2201 printf("\t");
2202 }
2203 if (dirinfomode&DIRINFO_FILES) {
2204 print_number_only(files,0);
2205 printf("\t");
2206 }
2207 if (dirinfomode&DIRINFO_CHUNKS) {
2208 print_number_only(chunks,0);
2209 printf("\t");
2210 }
2211 if (dirinfomode&DIRINFO_LENGTH) {
2212 print_number_only(length,1);
2213 printf("\t");
2214 }
2215 if (dirinfomode&DIRINFO_SIZE) {
2216 print_number_only(size,1);
2217 printf("\t");
2218 }
2219 if (dirinfomode&DIRINFO_REALSIZE) {
2220 print_number_only(realsize,1);
2221 printf("\t");
2222 }
2223 printf("%s\n",fname);
2224 }
2225 return 0;
2226 }
2227
file_repair(const char * fname)2228 int file_repair(const char *fname) {
2229 uint8_t reqbuff[24+NGROUPS_MAX*4+4],*wptr,*buff;
2230 const uint8_t *rptr;
2231 uint32_t cmd,leng,inode,uid,gid;
2232 gid_t grouplist[NGROUPS_MAX];
2233 uint32_t i,gids;
2234 uint8_t addmaingroup;
2235 uint32_t notchanged,erased,repaired;
2236 int fd;
2237 fd = open_master_conn(fname,&inode,NULL,0,1);
2238 if (fd<0) {
2239 return -1;
2240 }
2241 uid = getuid();
2242 gid = getgid();
2243 if (masterversion>=VERSION2INT(2,0,0)) {
2244 gids = getgroups(NGROUPS_MAX,grouplist);
2245 addmaingroup = 1;
2246 for (i=0 ; i<gids ; i++) {
2247 if (grouplist[i]==gid) {
2248 addmaingroup = 0;
2249 }
2250 }
2251 } else {
2252 gids = 0;
2253 addmaingroup = 0;
2254 }
2255 wptr = reqbuff;
2256 put32bit(&wptr,CLTOMA_FUSE_REPAIR);
2257 put32bit(&wptr,16+(addmaingroup+gids)*4);
2258 put32bit(&wptr,0);
2259 put32bit(&wptr,inode);
2260 put32bit(&wptr,uid);
2261 if (masterversion<VERSION2INT(2,0,0)) {
2262 put32bit(&wptr,gid);
2263 } else {
2264 put32bit(&wptr,addmaingroup+gids);
2265 if (addmaingroup) {
2266 put32bit(&wptr,gid);
2267 }
2268 for (i=0 ; i<gids ; i++) {
2269 put32bit(&wptr,grouplist[i]);
2270 }
2271 }
2272 if (tcpwrite(fd,reqbuff,24+(addmaingroup+gids)*4)!=(int32_t)(24+(addmaingroup+gids)*4)) {
2273 printf("%s: master query: send error\n",fname);
2274 close_master_conn(1);
2275 return -1;
2276 }
2277 if (tcpread(fd,reqbuff,8)!=8) {
2278 printf("%s: master query: receive error\n",fname);
2279 close_master_conn(1);
2280 return -1;
2281 }
2282 rptr = reqbuff;
2283 cmd = get32bit(&rptr);
2284 leng = get32bit(&rptr);
2285 if (cmd!=MATOCL_FUSE_REPAIR) {
2286 printf("%s: master query: wrong answer (type)\n",fname);
2287 close_master_conn(1);
2288 return -1;
2289 }
2290 buff = malloc(leng);
2291 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
2292 printf("%s: master query: receive error\n",fname);
2293 free(buff);
2294 close_master_conn(1);
2295 return -1;
2296 }
2297 rptr = buff;
2298 cmd = get32bit(&rptr); // queryid
2299 if (cmd!=0) {
2300 printf("%s: master query: wrong answer (queryid)\n",fname);
2301 free(buff);
2302 close_master_conn(1);
2303 return -1;
2304 }
2305 leng-=4;
2306 if (leng==1) {
2307 printf("%s: %s\n",fname,mfsstrerr(*rptr));
2308 free(buff);
2309 close_master_conn(1);
2310 return -1;
2311 } else if (leng!=12) {
2312 printf("%s: master query: wrong answer (leng)\n",fname);
2313 free(buff);
2314 close_master_conn(1);
2315 return -1;
2316 }
2317 close_master_conn(0);
2318 notchanged = get32bit(&rptr);
2319 erased = get32bit(&rptr);
2320 repaired = get32bit(&rptr);
2321 free(buff);
2322 printf("%s:\n",fname);
2323 print_number(" chunks not changed: ","\n",notchanged,1,0,1);
2324 print_number(" chunks erased: ","\n",erased,1,0,1);
2325 print_number(" chunks repaired: ","\n",repaired,1,0,1);
2326 return 0;
2327 }
2328
2329 /*
2330 int eattr_control(const char *fname,uint8_t mode,uint8_t eattr) {
2331 uint8_t reqbuff[22],*wptr,*buff;
2332 const uint8_t *rptr;
2333 uint32_t cmd,leng,inode;
2334 uint8_t nodeeattr,functioneattr;
2335 // uint32_t curinodes;
2336 // uint64_t curlength,cursize,currealsize;
2337 int fd;
2338 fd = open_master_conn(fname,&inode,NULL,0,(mode<2)?1:0);
2339 if (fd<0) {
2340 return -1;
2341 }
2342 wptr = reqbuff;
2343 put32bit(&wptr,CLTOMA_FUSE_EATTR);
2344 put32bit(&wptr,14);
2345 put32bit(&wptr,0);
2346 put32bit(&wptr,inode);
2347 put32bit(&wptr,getuid());
2348 put8bit(&wptr,mode&1);
2349 put8bit(&wptr,(mode>1)?0:eattr);
2350 if (tcpwrite(fd,reqbuff,22)!=22) {
2351 printf("%s: master query: send error\n",fname);
2352 close_master_conn(1);
2353 return -1;
2354 }
2355 if (tcpread(fd,reqbuff,8)!=8) {
2356 printf("%s: master query: receive error\n",fname);
2357 close_master_conn(1);
2358 return -1;
2359 }
2360 rptr = reqbuff;
2361 cmd = get32bit(&rptr);
2362 leng = get32bit(&rptr);
2363 if (cmd!=MATOCL_FUSE_EATTR) {
2364 printf("%s: master query: wrong answer (type)\n",fname);
2365 close_master_conn(1);
2366 return -1;
2367 }
2368 buff = malloc(leng);
2369 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
2370 printf("%s: master query: receive error\n",fname);
2371 free(buff);
2372 close_master_conn(1);
2373 return -1;
2374 }
2375 rptr = buff;
2376 cmd = get32bit(&rptr); // queryid
2377 if (cmd!=0) {
2378 printf("%s: master query: wrong answer (queryid)\n",fname);
2379 free(buff);
2380 close_master_conn(1);
2381 return -1;
2382 }
2383 leng-=4;
2384 if (leng==1) {
2385 printf("%s: %s\n",fname,mfsstrerr(*rptr));
2386 free(buff);
2387 close_master_conn(1);
2388 return -1;
2389 } else if (leng!=2) {
2390 printf("%s: master query: wrong answer (leng)\n",fname);
2391 free(buff);
2392 close_master_conn(1);
2393 return -1;
2394 }
2395 close_master_conn(0);
2396 nodeeattr = get8bit(&rptr) & eattr;
2397 functioneattr = get8bit(&rptr) & eattr;
2398 free(buff);
2399 printf("%s:",fname);
2400 printf(" nodeeattr:");
2401 if (nodeeattr==0) {
2402 printf("-");
2403 } else {
2404 // as for now there is only one eattr: noowner
2405 if (nodeeattr&EATTR_NOOWNER) {
2406 printf("noowner");
2407 } else {
2408 printf("?");
2409 }
2410 }
2411 printf("; workingeattr:");
2412 if (functioneattr==0) {
2413 printf("-");
2414 } else {
2415 // as for now there is only one eattr: noowner
2416 if (functioneattr&EATTR_NOOWNER) {
2417 printf("noowner");
2418 } else {
2419 printf("?");
2420 }
2421 }
2422 printf("\n");
2423 return 0;
2424 }
2425 */
2426
quota_control(const char * fname,uint8_t del,uint8_t qflags,uint32_t sinodes,uint64_t slength,uint64_t ssize,uint64_t srealsize,uint32_t hinodes,uint64_t hlength,uint64_t hsize,uint64_t hrealsize)2427 int quota_control(const char *fname,uint8_t del,uint8_t qflags,uint32_t sinodes,uint64_t slength,uint64_t ssize,uint64_t srealsize,uint32_t hinodes,uint64_t hlength,uint64_t hsize,uint64_t hrealsize) {
2428 uint8_t reqbuff[73],*wptr,*buff;
2429 const uint8_t *rptr;
2430 uint32_t cmd,leng,inode;
2431 uint32_t curinodes;
2432 uint64_t curlength,cursize,currealsize;
2433 int fd;
2434 // printf("set quota: %s (soft:%1X,i:%"PRIu32",l:%"PRIu64",w:%"PRIu64",r:%"PRIu64"),(hard:%1X,i:%"PRIu32",l:%"PRIu64",w:%"PRIu64",r:%"PRIu64")\n",fname,sflags,sinodes,slength,ssize,srealsize,hflags,hinodes,hlength,hsize,hrealsize);
2435 fd = open_master_conn(fname,&inode,NULL,0,qflags?1:0);
2436 if (fd<0) {
2437 return -1;
2438 }
2439 wptr = reqbuff;
2440 put32bit(&wptr,CLTOMA_FUSE_QUOTACONTROL);
2441 put32bit(&wptr,(del)?9:65);
2442 put32bit(&wptr,0);
2443 put32bit(&wptr,inode);
2444 put8bit(&wptr,qflags);
2445 if (del==0) {
2446 put32bit(&wptr,sinodes);
2447 put64bit(&wptr,slength);
2448 put64bit(&wptr,ssize);
2449 put64bit(&wptr,srealsize);
2450 put32bit(&wptr,hinodes);
2451 put64bit(&wptr,hlength);
2452 put64bit(&wptr,hsize);
2453 put64bit(&wptr,hrealsize);
2454 }
2455 if (tcpwrite(fd,reqbuff,(del)?17:73)!=((del)?17:73)) {
2456 printf("%s: master query: send error\n",fname);
2457 close_master_conn(1);
2458 return -1;
2459 }
2460 if (tcpread(fd,reqbuff,8)!=8) {
2461 printf("%s: master query: receive error\n",fname);
2462 close_master_conn(1);
2463 return -1;
2464 }
2465 rptr = reqbuff;
2466 cmd = get32bit(&rptr);
2467 leng = get32bit(&rptr);
2468 if (cmd!=MATOCL_FUSE_QUOTACONTROL) {
2469 printf("%s: master query: wrong answer (type)\n",fname);
2470 close_master_conn(1);
2471 return -1;
2472 }
2473 buff = malloc(leng);
2474 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
2475 printf("%s: master query: receive error\n",fname);
2476 free(buff);
2477 close_master_conn(1);
2478 return -1;
2479 }
2480 rptr = buff;
2481 cmd = get32bit(&rptr); // queryid
2482 if (cmd!=0) {
2483 printf("%s: master query: wrong answer (queryid)\n",fname);
2484 free(buff);
2485 close_master_conn(1);
2486 return -1;
2487 }
2488 leng-=4;
2489 if (leng==1) {
2490 printf("%s: %s\n",fname,mfsstrerr(*rptr));
2491 free(buff);
2492 close_master_conn(1);
2493 return -1;
2494 } else if (leng!=85) {
2495 printf("%s: master query: wrong answer (leng)\n",fname);
2496 free(buff);
2497 close_master_conn(1);
2498 return -1;
2499 }
2500 close_master_conn(0);
2501 qflags = get8bit(&rptr);
2502 sinodes = get32bit(&rptr);
2503 slength = get64bit(&rptr);
2504 ssize = get64bit(&rptr);
2505 srealsize = get64bit(&rptr);
2506 hinodes = get32bit(&rptr);
2507 hlength = get64bit(&rptr);
2508 hsize = get64bit(&rptr);
2509 hrealsize = get64bit(&rptr);
2510 curinodes = get32bit(&rptr);
2511 curlength = get64bit(&rptr);
2512 cursize = get64bit(&rptr);
2513 currealsize = get64bit(&rptr);
2514 free(buff);
2515 printf("%s: (current values | soft quota | hard quota)\n",fname);
2516 print_number(" inodes | ",NULL,curinodes,0,0,1);
2517 print_number(" | ",NULL,sinodes,0,0,qflags"A_FLAG_SINODES);
2518 print_number(" | "," |\n",hinodes,0,0,qflags"A_FLAG_HINODES);
2519 print_number(" length | ",NULL,curlength,0,1,1);
2520 print_number(" | ",NULL,slength,0,1,qflags"A_FLAG_SLENGTH);
2521 print_number(" | "," |\n",hlength,0,1,qflags"A_FLAG_HLENGTH);
2522 print_number(" size | ",NULL,cursize,0,1,1);
2523 print_number(" | ",NULL,ssize,0,1,qflags"A_FLAG_SSIZE);
2524 print_number(" | "," |\n",hsize,0,1,qflags"A_FLAG_HSIZE);
2525 print_number(" realsize | ",NULL,currealsize,0,1,1);
2526 print_number(" | ",NULL,srealsize,0,1,qflags"A_FLAG_SREALSIZE);
2527 print_number(" | "," |\n",hrealsize,0,1,qflags"A_FLAG_HREALSIZE);
2528 return 0;
2529 }
2530
2531 /*
2532 int get_quota(const char *fname) {
2533 printf("get quota: %s\n",fname);
2534 return 0;
2535 }
2536
2537 int delete_quota(const char *fname,uint8_t sflags,uint8_t hflags) {
2538 printf("delete quota: %s (soft:%1X,hard:%1X)\n",fname,sflags,hflags);
2539 return 0;
2540 }
2541 */
2542
make_snapshot(const char * dstdir,const char * dstbase,const char * srcname,uint32_t srcinode,uint8_t smode)2543 int make_snapshot(const char *dstdir,const char *dstbase,const char *srcname,uint32_t srcinode,uint8_t smode) {
2544 uint8_t reqbuff[8+24+255+NGROUPS_MAX*4+4],*wptr,*buff;
2545 const uint8_t *rptr;
2546 uint32_t cmd,leng,dstinode,uid,gid;
2547 gid_t grouplist[NGROUPS_MAX];
2548 uint32_t i,gids;
2549 uint8_t addmaingroup;
2550 uint32_t nleng;
2551 uint16_t umsk;
2552 int fd;
2553 umsk = umask(0);
2554 umask(umsk);
2555 nleng = strlen(dstbase);
2556 if (nleng>255) {
2557 printf("%s: name too long\n",dstbase);
2558 return -1;
2559 }
2560 fd = open_master_conn(dstdir,&dstinode,NULL,0,1);
2561 if (fd<0) {
2562 return -1;
2563 }
2564 uid = getuid();
2565 gid = getgid();
2566 if (masterversion>=VERSION2INT(2,0,0)) {
2567 gids = getgroups(NGROUPS_MAX,grouplist);
2568 addmaingroup = 1;
2569 for (i=0 ; i<gids ; i++) {
2570 if (grouplist[i]==gid) {
2571 addmaingroup = 0;
2572 }
2573 }
2574 } else {
2575 gids = 0;
2576 addmaingroup = 0;
2577 }
2578 wptr = reqbuff;
2579 put32bit(&wptr,CLTOMA_FUSE_SNAPSHOT);
2580 if (masterversion<VERSION2INT(1,7,0)) {
2581 put32bit(&wptr,22+nleng);
2582 } else {
2583 put32bit(&wptr,24+nleng+(addmaingroup+gids)*4);
2584 }
2585 put32bit(&wptr,0);
2586 put32bit(&wptr,srcinode);
2587 put32bit(&wptr,dstinode);
2588 put8bit(&wptr,nleng);
2589 memcpy(wptr,dstbase,nleng);
2590 wptr+=nleng;
2591 put32bit(&wptr,uid);
2592 if (masterversion<VERSION2INT(2,0,0)) {
2593 put32bit(&wptr,gid);
2594 } else {
2595 put32bit(&wptr,addmaingroup+gids);
2596 if (addmaingroup) {
2597 put32bit(&wptr,gid);
2598 }
2599 for (i=0 ; i<gids ; i++) {
2600 put32bit(&wptr,grouplist[i]);
2601 }
2602 }
2603 put8bit(&wptr,smode);
2604 if (masterversion>=VERSION2INT(1,7,0)) {
2605 put16bit(&wptr,umsk);
2606 }
2607 if (tcpwrite(fd,reqbuff,((masterversion>=VERSION2INT(1,7,0))?32:30)+nleng+(addmaingroup+gids)*4)!=(int32_t)(((masterversion>=VERSION2INT(1,7,0))?32:30)+nleng+(addmaingroup+gids)*4)) {
2608 printf("%s->%s/%s: master query: send error\n",srcname,dstdir,dstbase);
2609 close_master_conn(1);
2610 return -1;
2611 }
2612 if (tcpread(fd,reqbuff,8)!=8) {
2613 printf("%s->%s/%s: master query: receive error\n",srcname,dstdir,dstbase);
2614 close_master_conn(1);
2615 return -1;
2616 }
2617 rptr = reqbuff;
2618 cmd = get32bit(&rptr);
2619 leng = get32bit(&rptr);
2620 if (cmd!=MATOCL_FUSE_SNAPSHOT) {
2621 printf("%s->%s/%s: master query: wrong answer (type)\n",srcname,dstdir,dstbase);
2622 close_master_conn(1);
2623 return -1;
2624 }
2625 buff = malloc(leng);
2626 if (tcpread(fd,buff,leng)!=(int32_t)leng) {
2627 printf("%s->%s/%s: master query: receive error\n",srcname,dstdir,dstbase);
2628 free(buff);
2629 close_master_conn(1);
2630 return -1;
2631 }
2632 rptr = buff;
2633 cmd = get32bit(&rptr); // queryid
2634 if (cmd!=0) {
2635 printf("%s->%s/%s: master query: wrong answer (queryid)\n",srcname,dstdir,dstbase);
2636 free(buff);
2637 close_master_conn(1);
2638 return -1;
2639 }
2640 leng-=4;
2641 if (leng!=1) {
2642 printf("%s->%s/%s: master query: wrong answer (leng)\n",srcname,dstdir,dstbase);
2643 free(buff);
2644 close_master_conn(1);
2645 return -1;
2646 }
2647 close_master_conn(0);
2648 if (*rptr!=0) {
2649 printf("%s->%s/%s: %s\n",srcname,dstdir,dstbase,mfsstrerr(*rptr));
2650 free(buff);
2651 return -1;
2652 }
2653 return 0;
2654 }
2655
snapshot(const char * dstname,char * const * srcnames,uint32_t srcelements,uint8_t smode)2656 int snapshot(const char *dstname,char * const *srcnames,uint32_t srcelements,uint8_t smode) {
2657 char to[PATH_MAX+1],base[PATH_MAX+1],dir[PATH_MAX+1];
2658 char src[PATH_MAX+1];
2659 struct stat sst,dst;
2660 int status;
2661 uint32_t i,l;
2662
2663 if (stat(dstname,&dst)<0) { // dst does not exist
2664 if (errno!=ENOENT) {
2665 printf("%s: stat error: %s\n",dstname,strerr(errno));
2666 return -1;
2667 }
2668 if (srcelements>1) {
2669 printf("can snapshot multiple elements only into existing directory\n");
2670 return -1;
2671 }
2672 if (lstat(srcnames[0],&sst)<0) {
2673 printf("%s: lstat error: %s\n",srcnames[0],strerr(errno));
2674 return -1;
2675 }
2676 if (bsd_dirname(dstname,dir)<0) {
2677 printf("%s: dirname error\n",dstname);
2678 return -1;
2679 }
2680 if (stat(dir,&dst)<0) {
2681 printf("%s: stat error: %s\n",dir,strerr(errno));
2682 return -1;
2683 }
2684 if (sst.st_dev != dst.st_dev) {
2685 printf("(%s,%s): both elements must be on the same device\n",dstname,srcnames[0]);
2686 return -1;
2687 }
2688 if (realpath(dir,to)==NULL) {
2689 printf("%s: realpath error on %s: %s\n",dir,to,strerr(errno));
2690 return -1;
2691 }
2692 if (bsd_basename(dstname,base)<0) {
2693 printf("%s: basename error\n",dstname);
2694 return -1;
2695 }
2696 if (strlen(dstname)>0 && dstname[strlen(dstname)-1]=='/' && !S_ISDIR(sst.st_mode)) {
2697 printf("directory %s does not exist\n",dstname);
2698 return -1;
2699 }
2700 return make_snapshot(to,base,srcnames[0],sst.st_ino,smode);
2701 } else { // dst exists
2702 if (realpath(dstname,to)==NULL) {
2703 printf("%s: realpath error on %s: %s\n",dstname,to,strerr(errno));
2704 return -1;
2705 }
2706 if (!S_ISDIR(dst.st_mode)) { // dst id not a directory
2707 if (srcelements>1) {
2708 printf("can snapshot multiple elements only into existing directory\n");
2709 return -1;
2710 }
2711 if (lstat(srcnames[0],&sst)<0) {
2712 printf("%s: lstat error: %s\n",srcnames[0],strerr(errno));
2713 return -1;
2714 }
2715 if (sst.st_dev != dst.st_dev) {
2716 printf("(%s,%s): both elements must be on the same device\n",dstname,srcnames[0]);
2717 return -1;
2718 }
2719 memcpy(dir,to,PATH_MAX+1);
2720 dirname_inplace(dir);
2721 // if (bsd_dirname(to,dir)<0) {
2722 // printf("%s: dirname error\n",to);
2723 // return -1;
2724 // }
2725 if (bsd_basename(to,base)<0) {
2726 printf("%s: basename error\n",to);
2727 return -1;
2728 }
2729 return make_snapshot(dir,base,srcnames[0],sst.st_ino,smode);
2730 } else { // dst is a directory
2731 status = 0;
2732 for (i=0 ; i<srcelements ; i++) {
2733 if (lstat(srcnames[i],&sst)<0) {
2734 printf("%s: lstat error: %s\n",srcnames[i],strerr(errno));
2735 status=-1;
2736 continue;
2737 }
2738 if (sst.st_dev != dst.st_dev) {
2739 printf("(%s,%s): both elements must be on the same device\n",dstname,srcnames[i]);
2740 status=-1;
2741 continue;
2742 }
2743 if (!S_ISDIR(sst.st_mode)) { // src is not a directory
2744 if (!S_ISLNK(sst.st_mode)) { // src is not a symbolic link
2745 if (realpath(srcnames[i],src)==NULL) {
2746 printf("%s: realpath error on %s: %s\n",srcnames[i],src,strerr(errno));
2747 status=-1;
2748 continue;
2749 }
2750 if (bsd_basename(src,base)<0) {
2751 printf("%s: basename error\n",src);
2752 status=-1;
2753 continue;
2754 }
2755 } else { // src is a symbolic link
2756 if (bsd_basename(srcnames[i],base)<0) {
2757 printf("%s: basename error\n",srcnames[i]);
2758 status=-1;
2759 continue;
2760 }
2761 }
2762 if (make_snapshot(to,base,srcnames[i],sst.st_ino,smode)<0) {
2763 status=-1;
2764 }
2765 } else { // src is a directory
2766 l = strlen(srcnames[i]);
2767 if (l>0 && srcnames[i][l-1]!='/') { // src is a directory and name has trailing slash
2768 if (realpath(srcnames[i],src)==NULL) {
2769 printf("%s: realpath error on %s: %s\n",srcnames[i],src,strerr(errno));
2770 status=-1;
2771 continue;
2772 }
2773 if (bsd_basename(src,base)<0) {
2774 printf("%s: basename error\n",src);
2775 status=-1;
2776 continue;
2777 }
2778 if (make_snapshot(to,base,srcnames[i],sst.st_ino,smode)<0) {
2779 status=-1;
2780 }
2781 } else { // src is a directory and name has not trailing slash
2782 memcpy(dir,to,PATH_MAX+1);
2783 dirname_inplace(dir);
2784 //if (bsd_dirname(to,dir)<0) {
2785 // printf("%s: dirname error\n",to);
2786 // status=-1;
2787 // continue;
2788 //}
2789 if (bsd_basename(to,base)<0) {
2790 printf("%s: basename error\n",to);
2791 status=-1;
2792 continue;
2793 }
2794 if (make_snapshot(dir,base,srcnames[i],sst.st_ino,smode)<0) {
2795 status=-1;
2796 }
2797 }
2798 }
2799 }
2800 return status;
2801 }
2802 }
2803 }
2804
2805 enum {
2806 MFSGETGOAL=1,
2807 MFSSETGOAL,
2808 MFSGETTRASHTIME,
2809 MFSSETTRASHTIME,
2810 MFSCHECKFILE,
2811 MFSFILEINFO,
2812 MFSAPPENDCHUNKS,
2813 MFSDIRINFO,
2814 MFSFILEREPAIR,
2815 MFSMAKESNAPSHOT,
2816 MFSGETEATTR,
2817 MFSSETEATTR,
2818 MFSDELEATTR,
2819 MFSGETQUOTA,
2820 MFSSETQUOTA,
2821 MFSDELQUOTA,
2822 MFSFILEPATHS
2823 };
2824
print_numberformat_options()2825 static inline void print_numberformat_options() {
2826 fprintf(stderr," -n - show numbers in plain format\n");
2827 fprintf(stderr," -h - \"human-readable\" numbers using base 2 prefixes (IEC 60027)\n");
2828 fprintf(stderr," -H - \"human-readable\" numbers using base 10 prefixes (SI)\n");
2829 fprintf(stderr," -k - show plain numbers in kibis (binary kilo - 1024)\n");
2830 fprintf(stderr," -m - show plain numbers in mebis (binary mega - 1024^2)\n");
2831 fprintf(stderr," -g - show plain numbers in gibis (binary giga - 1024^3)\n");
2832 }
2833
print_recursive_option()2834 static inline void print_recursive_option() {
2835 fprintf(stderr," -r - do it recursively\n");
2836 }
2837
print_extra_attributes()2838 static inline void print_extra_attributes() {
2839 int j;
2840 fprintf(stderr,"\nattributes:\n");
2841 for (j=0 ; j<EATTR_BITS ; j++) {
2842 if (eattrtab[j][0]) {
2843 fprintf(stderr," %s - %s\n",eattrtab[j],eattrdesc[j]);
2844 }
2845 }
2846 }
2847
usage(int f)2848 void usage(int f) {
2849 switch (f) {
2850 case MFSGETGOAL:
2851 fprintf(stderr,"get objects goal (desired number of copies)\n\nusage: mfsgetgoal [-nhHkmgr] name [name ...]\n");
2852 print_numberformat_options();
2853 print_recursive_option();
2854 break;
2855 case MFSSETGOAL:
2856 fprintf(stderr,"set objects goal (desired number of copies)\n\nusage: mfssetgoal [-nhHkmgr] GOAL[-|+] name [name ...]\n");
2857 print_numberformat_options();
2858 print_recursive_option();
2859 fprintf(stderr," GOAL+ - increase goal to given value\n");
2860 fprintf(stderr," GOAL- - decrease goal to given value\n");
2861 fprintf(stderr," GOAL - just set goal to given value\n");
2862 break;
2863 case MFSGETTRASHTIME:
2864 fprintf(stderr,"get objects trashtime (how many seconds file should be left in trash)\n\nusage: mfsgettrashtime [-nhHkmgr] name [name ...]\n");
2865 print_numberformat_options();
2866 print_recursive_option();
2867 break;
2868 case MFSSETTRASHTIME:
2869 fprintf(stderr,"set objects trashtime (how many seconds file should be left in trash)\n\nusage: mfssettrashtime [-nhHkmgr] SECONDS[-|+] name [name ...]\n");
2870 print_numberformat_options();
2871 print_recursive_option();
2872 fprintf(stderr," SECONDS+ - increase trashtime to given value\n");
2873 fprintf(stderr," SECONDS- - decrease trashtime to given value\n");
2874 fprintf(stderr," SECONDS - just set trashtime to given value\n");
2875 break;
2876 case MFSCHECKFILE:
2877 fprintf(stderr,"check files\n\nusage: mfscheckfile [-nhHkmg] name [name ...]\n");
2878 break;
2879 case MFSFILEINFO:
2880 fprintf(stderr,"show files info (shows detailed info of each file chunk)\n\nusage: mfsfileinfo [-qcs] name [name ...]\n");
2881 fprintf(stderr,"switches:\n");
2882 fprintf(stderr,"-q - quick info (show only number of valid copies)\n");
2883 fprintf(stderr,"-c - receive chunk checksums from chunkservers\n");
2884 fprintf(stderr,"-s - calculate file signature (using checksums)\n");
2885 break;
2886 case MFSAPPENDCHUNKS:
2887 fprintf(stderr,"append file chunks to another file. If destination file doesn't exist then it's created as empty file and then chunks are appended\n\nusage: mfsappendchunks dstfile name [name ...]\n");
2888 break;
2889 case MFSDIRINFO:
2890 fprintf(stderr,"show directories stats\n\nusage: mfsdirinfo [-nhHkmg] [-idfclsr] name [name ...]\n");
2891 print_numberformat_options();
2892 fprintf(stderr,"'show' switches:\n");
2893 fprintf(stderr," -i - show number of inodes\n");
2894 fprintf(stderr," -d - show number of directories\n");
2895 fprintf(stderr," -f - show number of files\n");
2896 fprintf(stderr," -c - show number of chunks\n");
2897 fprintf(stderr," -l - show length\n");
2898 fprintf(stderr," -s - show size\n");
2899 fprintf(stderr," -r - show realsize\n");
2900 fprintf(stderr,"\nIf no 'show' switches are present then show everything\n");
2901 fprintf(stderr,"\nMeaning of some not obvious output data:\n 'length' is just sum of files lengths\n 'size' is sum of chunks lengths\n 'realsize' is estimated hdd usage (usually size multiplied by current goal)\n");
2902 break;
2903 case MFSFILEREPAIR:
2904 fprintf(stderr,"repair given file. Use it with caution. It forces file to be readable, so it could erase (fill with zeros) file when chunkservers are not currently connected.\n\nusage: mfsfilerepair [-nhHkmg] name [name ...]\n");
2905 print_numberformat_options();
2906 break;
2907 case MFSMAKESNAPSHOT:
2908 fprintf(stderr,"make snapshot (lazy copy)\n\nusage: mfsmakesnapshot [-op] src [src ...] dst\n");
2909 fprintf(stderr,"-o - allow to overwrite existing objects\n");
2910 fprintf(stderr,"-c - 'cp' mode for attributes (create objects using current uid,gid,umask etc.)\n");
2911 break;
2912 case MFSGETEATTR:
2913 fprintf(stderr,"get objects extra attributes\n\nusage: mfsgeteattr [-nhHkmgr] name [name ...]\n");
2914 print_numberformat_options();
2915 print_recursive_option();
2916 break;
2917 case MFSSETEATTR:
2918 fprintf(stderr,"set objects extra attributes\n\nusage: mfsseteattr [-nhHkmgr] -f attrname [-f attrname ...] name [name ...]\n");
2919 print_numberformat_options();
2920 print_recursive_option();
2921 fprintf(stderr," -f attrname - specify attribute to set\n");
2922 print_extra_attributes();
2923 break;
2924 case MFSDELEATTR:
2925 fprintf(stderr,"delete objects extra attributes\n\nusage: mfsdeleattr [-nhHkmgr] -f attrname [-f attrname ...] name [name ...]\n");
2926 print_numberformat_options();
2927 print_recursive_option();
2928 fprintf(stderr," -f attrname - specify attribute to delete\n");
2929 print_extra_attributes();
2930 break;
2931 case MFSGETQUOTA:
2932 fprintf(stderr,"get quota for given directory (directories)\n\nusage: mfsgetquota [-nhHkmg] dirname [dirname ...]\n");
2933 print_numberformat_options();
2934 break;
2935 case MFSSETQUOTA:
2936 fprintf(stderr,"set quota for given directory (directories)\n\nusage: mfssetquota [-nhHkmg] [-iI inodes] [-lL length] [-sS size] [-rR realsize] dirname [dirname ...]\n");
2937 print_numberformat_options();
2938 fprintf(stderr," -i/-I - set soft/hard limit for number of filesystem objects\n");
2939 fprintf(stderr," -l/-L - set soft/hard limit for sum of files lengths\n");
2940 fprintf(stderr," -s/-S - set soft/hard limit for sum of file sizes (chunk sizes)\n");
2941 fprintf(stderr," -r/-R - set soft/hard limit for estimated hdd usage (usually size multiplied by goal)\n");
2942 fprintf(stderr,"\nAll numbers can have decimal point and SI/IEC symbol prefix at the end\ndecimal (SI): (k - 10^3 , M - 10^6 , G - 10^9 , T - 10^12 , P - 10^15 , E - 10^18)\nbinary (IEC 60027): (Ki - 2^10 , Mi - 2^20 , Gi - 2^30 , Ti - 2^40 , Pi - 2^50 , Ei - 2^60 )\n");
2943 break;
2944 case MFSDELQUOTA:
2945 fprintf(stderr,"delete quota for given directory (directories)\n\nusage: mfsdelquota [-nhHkmgailsrAILSR] dirname [dirname ...]\n");
2946 print_numberformat_options();
2947 fprintf(stderr," -i/-I - delete inodes soft/hard quota\n");
2948 fprintf(stderr," -l/-L - delete length soft/hard quota\n");
2949 fprintf(stderr," -s/-S - delete size soft/hard quota\n");
2950 fprintf(stderr," -r/-R - delete real size soft/hard quota\n");
2951 fprintf(stderr," -a/-A - delete all soft/hard quotas\n");
2952 break;
2953 case MFSFILEPATHS:
2954 fprintf(stderr,"show all paths of given files or node numbers\n\nusage: mfsfilepaths name/inode [name/inode ...]\n");
2955 fprintf(stderr,"\nIn case of converting node to path, tool has to be run in mfs-mounted directory\n");
2956 break;
2957 }
2958 exit(1);
2959 }
2960
main(int argc,char ** argv)2961 int main(int argc,char **argv) {
2962 int l,f,status;
2963 int i,found;
2964 int ch;
2965 int snapmode = 0;
2966 int rflag = 0;
2967 uint8_t dirinfomode = 0;
2968 uint8_t fileinfomode = 0;
2969 uint64_t v;
2970 uint8_t eattr = 0,goal = 1,smode = SMODE_SET;
2971 uint32_t trashtime = 86400;
2972 uint32_t sinodes = 0,hinodes = 0;
2973 uint64_t slength = 0,hlength = 0,ssize = 0,hsize = 0,srealsize = 0,hrealsize = 0;
2974 uint8_t qflags = 0;
2975 char *appendfname = NULL;
2976 char *hrformat;
2977
2978 strerr_init();
2979
2980 l = strlen(argv[0]);
2981 #define CHECKNAME(name) ((l==(int)(sizeof(name)-1) && strcmp(argv[0],name)==0) || (l>(int)(sizeof(name)-1) && strcmp((argv[0])+(l-sizeof(name)),"/" name)==0))
2982 if (CHECKNAME("mfstools")) {
2983 if (argc==2 && strcmp(argv[1],"create")==0) {
2984 fprintf(stderr,"create symlinks\n");
2985 #define SYMLINK(name) if (symlink(argv[0],name)<0) { \
2986 perror("error creating symlink '"name"'"); \
2987 }
2988 SYMLINK("mfsgetgoal")
2989 SYMLINK("mfssetgoal")
2990 SYMLINK("mfsgettrashtime")
2991 SYMLINK("mfssettrashtime")
2992 SYMLINK("mfscheckfile")
2993 SYMLINK("mfsfileinfo")
2994 SYMLINK("mfsappendchunks")
2995 SYMLINK("mfsdirinfo")
2996 SYMLINK("mfsfilerepair")
2997 SYMLINK("mfsmakesnapshot")
2998 SYMLINK("mfsgeteattr")
2999 SYMLINK("mfsseteattr")
3000 SYMLINK("mfsdeleattr")
3001 SYMLINK("mfsgetquota")
3002 SYMLINK("mfssetquota")
3003 SYMLINK("mfsdelquota")
3004 SYMLINK("mfsfilepaths")
3005 // deprecated tools:
3006 SYMLINK("mfsrgetgoal")
3007 SYMLINK("mfsrsetgoal")
3008 SYMLINK("mfsrgettrashtime")
3009 SYMLINK("mfsrsettrashtime")
3010 return 0;
3011 } else {
3012 fprintf(stderr,"mfs multi tool\n\nusage:\n\tmfstools create - create symlinks (mfs<toolname> -> %s)\n",argv[0]);
3013 fprintf(stderr,"\ntools:\n");
3014 fprintf(stderr,"\tmfsgetgoal\n\tmfssetgoal\n\tmfsgettrashtime\n\tmfssettrashtime\n");
3015 fprintf(stderr,"\tmfscheckfile\n\tmfsfileinfo\n\tmfsappendchunks\n\tmfsdirinfo\n\tmfsfilerepair\n");
3016 fprintf(stderr,"\tmfsmakesnapshot\n");
3017 fprintf(stderr,"\tmfsgeteattr\n\tmfsseteattr\n\tmfsdeleattr\n");
3018 fprintf(stderr,"\tmfsgetquota\n\tmfssetquota\n\tmfsdelquota\n");
3019 fprintf(stderr,"\ndeprecated tools:\n");
3020 fprintf(stderr,"\tmfsrgetgoal = mfsgetgoal -r\n");
3021 fprintf(stderr,"\tmfsrsetgoal = mfssetgoal -r\n");
3022 fprintf(stderr,"\tmfsrgettrashtime = mfsgettreshtime -r\n");
3023 fprintf(stderr,"\tmfsrsettrashtime = mfssettreshtime -r\n");
3024 return 1;
3025 }
3026 } else if (CHECKNAME("mfsgetgoal")) {
3027 f=MFSGETGOAL;
3028 } else if (CHECKNAME("mfsrgetgoal")) {
3029 f=MFSGETGOAL;
3030 rflag=1;
3031 fprintf(stderr,"deprecated tool - use \"mfsgetgoal -r\"\n");
3032 } else if (CHECKNAME("mfssetgoal")) {
3033 f=MFSSETGOAL;
3034 } else if (CHECKNAME("mfsrsetgoal")) {
3035 f=MFSSETGOAL;
3036 rflag=1;
3037 fprintf(stderr,"deprecated tool - use \"mfssetgoal -r\"\n");
3038 } else if (CHECKNAME("mfsgettrashtime")) {
3039 f=MFSGETTRASHTIME;
3040 } else if (CHECKNAME("mfsrgettrashtime")) {
3041 f=MFSGETTRASHTIME;
3042 rflag=1;
3043 fprintf(stderr,"deprecated tool - use \"mfsgettrashtime -r\"\n");
3044 } else if (CHECKNAME("mfssettrashtime")) {
3045 f=MFSSETTRASHTIME;
3046 } else if (CHECKNAME("mfsrsettrashtime")) {
3047 f=MFSSETTRASHTIME;
3048 rflag=1;
3049 fprintf(stderr,"deprecated tool - use \"mfssettrashtime -r\"\n");
3050 } else if (CHECKNAME("mfscheckfile")) {
3051 f=MFSCHECKFILE;
3052 } else if (CHECKNAME("mfsfileinfo")) {
3053 f=MFSFILEINFO;
3054 } else if (CHECKNAME("mfsappendchunks")) {
3055 f=MFSAPPENDCHUNKS;
3056 } else if (CHECKNAME("mfsdirinfo")) {
3057 f=MFSDIRINFO;
3058 } else if (CHECKNAME("mfsgeteattr")) {
3059 f=MFSGETEATTR;
3060 } else if (CHECKNAME("mfsseteattr")) {
3061 f=MFSSETEATTR;
3062 } else if (CHECKNAME("mfsdeleattr")) {
3063 f=MFSDELEATTR;
3064 } else if (CHECKNAME("mfsgetquota")) {
3065 f=MFSGETQUOTA;
3066 } else if (CHECKNAME("mfssetquota")) {
3067 f=MFSSETQUOTA;
3068 } else if (CHECKNAME("mfsdelquota")) {
3069 f=MFSDELQUOTA;
3070 } else if (CHECKNAME("mfsfilerepair")) {
3071 f=MFSFILEREPAIR;
3072 } else if (CHECKNAME("mfsmakesnapshot")) {
3073 f=MFSMAKESNAPSHOT;
3074 } else if (CHECKNAME("mfsfilepaths")) {
3075 f=MFSFILEPATHS;
3076 } else {
3077 fprintf(stderr,"unknown binary name\n");
3078 return 1;
3079 }
3080 // argc--;
3081 // argv++;
3082
3083 hrformat = getenv("MFSHRFORMAT");
3084 if (hrformat) {
3085 if (hrformat[0]>='0' && hrformat[0]<='4') {
3086 humode=hrformat[0]-'0';
3087 }
3088 if (hrformat[0]=='h') {
3089 if (hrformat[1]=='+') {
3090 humode=3;
3091 } else {
3092 humode=1;
3093 }
3094 }
3095 if (hrformat[0]=='H') {
3096 if (hrformat[1]=='+') {
3097 humode=4;
3098 } else {
3099 humode=2;
3100 }
3101 }
3102 }
3103
3104 // parse options
3105 switch (f) {
3106 case MFSMAKESNAPSHOT:
3107 while ((ch=getopt(argc,argv,"oc"))!=-1) {
3108 switch(ch) {
3109 case 'o':
3110 snapmode |= SNAPSHOT_MODE_CAN_OVERWRITE;
3111 break;
3112 case 'c':
3113 snapmode |= SNAPSHOT_MODE_CPLIKE_ATTR;
3114 break;
3115 }
3116 }
3117 argc -= optind;
3118 argv += optind;
3119 if (argc<2) {
3120 usage(f);
3121 }
3122 return snapshot(argv[argc-1],argv,argc-1,snapmode);
3123 case MFSGETGOAL:
3124 case MFSSETGOAL:
3125 case MFSGETTRASHTIME:
3126 case MFSSETTRASHTIME:
3127 while ((ch=getopt(argc,argv,"rnhHkmg"))!=-1) {
3128 switch(ch) {
3129 case 'n':
3130 humode=0;
3131 break;
3132 case 'h':
3133 humode=1;
3134 break;
3135 case 'H':
3136 humode=2;
3137 break;
3138 case 'k':
3139 numbermode=1;
3140 break;
3141 case 'm':
3142 numbermode=2;
3143 break;
3144 case 'g':
3145 numbermode=3;
3146 break;
3147 case 'r':
3148 rflag=1;
3149 break;
3150 }
3151 }
3152 argc -= optind;
3153 argv += optind;
3154 if ((f==MFSSETGOAL || f==MFSSETTRASHTIME) && argc==0) {
3155 usage(f);
3156 }
3157 if (f==MFSSETGOAL) {
3158 char *p = argv[0];
3159 if (p[0]>'0' && p[0]<='9' && (p[1]=='\0' || ((p[1]=='-' || p[1]=='+') && p[2]=='\0'))) {
3160 goal = p[0]-'0';
3161 if (p[1]=='-') {
3162 smode=SMODE_DECREASE;
3163 } else if (p[1]=='+') {
3164 smode=SMODE_INCREASE;
3165 }
3166 } else {
3167 fprintf(stderr,"goal should be given as a digit between 1 and 9 optionally folowed by '-' or '+'\n");
3168 usage(f);
3169 }
3170 argc--;
3171 argv++;
3172 }
3173 if (f==MFSSETTRASHTIME) {
3174 char *p = argv[0];
3175 trashtime = 0;
3176 while (p[0]>='0' && p[0]<='9') {
3177 trashtime*=10;
3178 trashtime+=(p[0]-'0');
3179 p++;
3180 }
3181 if (p[0]=='\0' || ((p[0]=='-' || p[0]=='+') && p[1]=='\0')) {
3182 if (p[0]=='-') {
3183 smode=SMODE_DECREASE;
3184 } else if (p[0]=='+') {
3185 smode=SMODE_INCREASE;
3186 }
3187 } else {
3188 fprintf(stderr,"trashtime should be given as number of seconds optionally folowed by '-' or '+'\n");
3189 usage(f);
3190 }
3191 argc--;
3192 argv++;
3193 }
3194 break;
3195 case MFSGETEATTR:
3196 while ((ch=getopt(argc,argv,"rnhHkmg"))!=-1) {
3197 switch(ch) {
3198 case 'n':
3199 humode=0;
3200 break;
3201 case 'h':
3202 humode=1;
3203 break;
3204 case 'H':
3205 humode=2;
3206 break;
3207 case 'k':
3208 numbermode=1;
3209 break;
3210 case 'm':
3211 numbermode=2;
3212 break;
3213 case 'g':
3214 numbermode=3;
3215 break;
3216 case 'r':
3217 rflag=1;
3218 break;
3219 }
3220 }
3221 argc -= optind;
3222 argv += optind;
3223 break;
3224 case MFSSETEATTR:
3225 case MFSDELEATTR:
3226 while ((ch=getopt(argc,argv,"rnhHkmgf:"))!=-1) {
3227 switch(ch) {
3228 case 'n':
3229 humode=0;
3230 break;
3231 case 'h':
3232 humode=1;
3233 break;
3234 case 'H':
3235 humode=2;
3236 break;
3237 case 'k':
3238 numbermode=1;
3239 break;
3240 case 'm':
3241 numbermode=2;
3242 break;
3243 case 'g':
3244 numbermode=3;
3245 break;
3246 case 'r':
3247 rflag=1;
3248 break;
3249 case 'f':
3250 found=0;
3251 for (i=0 ; found==0 && i<EATTR_BITS ; i++) {
3252 if (strcmp(optarg,eattrtab[i])==0) {
3253 found=1;
3254 eattr|=1<<i;
3255 }
3256 }
3257 if (!found) {
3258 fprintf(stderr,"unknown flag\n");
3259 usage(f);
3260 }
3261 break;
3262 }
3263 }
3264 argc -= optind;
3265 argv += optind;
3266 if (eattr==0 && argc>=1) {
3267 if (f==MFSSETEATTR) {
3268 fprintf(stderr,"no attribute(s) to set\n");
3269 } else {
3270 fprintf(stderr,"no attribute(s) to delete\n");
3271 }
3272 usage(f);
3273 }
3274 break;
3275 case MFSFILEREPAIR:
3276 case MFSGETQUOTA:
3277 case MFSCHECKFILE:
3278 while ((ch=getopt(argc,argv,"nhHkmg"))!=-1) {
3279 switch(ch) {
3280 case 'n':
3281 humode=0;
3282 break;
3283 case 'h':
3284 humode=1;
3285 break;
3286 case 'H':
3287 humode=2;
3288 break;
3289 case 'k':
3290 numbermode=1;
3291 break;
3292 case 'm':
3293 numbermode=2;
3294 break;
3295 case 'g':
3296 numbermode=3;
3297 break;
3298 }
3299 }
3300 argc -= optind;
3301 argv += optind;
3302 break;
3303 case MFSFILEINFO:
3304 humode = 0;
3305 numbermode = 0;
3306 while ((ch=getopt(argc,argv,"qcs"))!=-1) {
3307 switch(ch) {
3308 case 'q':
3309 fileinfomode |= FILEINFO_QUICK;
3310 break;
3311 case 'c':
3312 fileinfomode |= FILEINFO_CRC;
3313 break;
3314 case 's':
3315 fileinfomode |= FILEINFO_SIGNATURE;
3316 break;
3317 }
3318 }
3319 argc -= optind;
3320 argv += optind;
3321 break;
3322 case MFSDIRINFO:
3323 while ((ch=getopt(argc,argv,"nhHkmgidfclsr"))!=-1) {
3324 switch(ch) {
3325 case 'n':
3326 humode=0;
3327 break;
3328 case 'h':
3329 humode=1;
3330 break;
3331 case 'H':
3332 humode=2;
3333 break;
3334 case 'k':
3335 numbermode=1;
3336 break;
3337 case 'm':
3338 numbermode=2;
3339 break;
3340 case 'g':
3341 numbermode=3;
3342 break;
3343 case 'i':
3344 dirinfomode |= DIRINFO_INODES;
3345 break;
3346 case 'd':
3347 dirinfomode |= DIRINFO_DIRS;
3348 break;
3349 case 'f':
3350 dirinfomode |= DIRINFO_FILES;
3351 break;
3352 case 'c':
3353 dirinfomode |= DIRINFO_CHUNKS;
3354 break;
3355 case 'l':
3356 dirinfomode |= DIRINFO_LENGTH;
3357 break;
3358 case 's':
3359 dirinfomode |= DIRINFO_SIZE;
3360 break;
3361 case 'r':
3362 dirinfomode |= DIRINFO_REALSIZE;
3363 break;
3364 }
3365 }
3366 argc -= optind;
3367 argv += optind;
3368 break;
3369 case MFSSETQUOTA:
3370 if (getuid()) {
3371 fprintf(stderr,"only root can change quota\n");
3372 usage(f);
3373 }
3374 while ((ch=getopt(argc,argv,"nhHkmgi:I:l:L:s:S:r:R:"))!=-1) {
3375 switch(ch) {
3376 case 'n':
3377 humode=0;
3378 break;
3379 case 'h':
3380 humode=1;
3381 break;
3382 case 'H':
3383 humode=2;
3384 break;
3385 case 'k':
3386 numbermode=1;
3387 break;
3388 case 'm':
3389 numbermode=2;
3390 break;
3391 case 'g':
3392 numbermode=3;
3393 break;
3394 case 'i':
3395 if (my_get_number(optarg,&v,UINT32_MAX,0)<0) {
3396 fprintf(stderr,"bad inodes limit\n");
3397 usage(f);
3398 }
3399 if (qflags & QUOTA_FLAG_SINODES) {
3400 fprintf(stderr,"'soft inodes' quota defined twice\n");
3401 usage(f);
3402 }
3403 sinodes = v;
3404 qflags |= QUOTA_FLAG_SINODES;
3405 break;
3406 case 'I':
3407 if (my_get_number(optarg,&v,UINT32_MAX,0)<0) {
3408 fprintf(stderr,"bad inodes limit\n");
3409 usage(f);
3410 }
3411 if (qflags & QUOTA_FLAG_HINODES) {
3412 fprintf(stderr,"'hard inodes' quota defined twice\n");
3413 usage(f);
3414 }
3415 hinodes = v;
3416 qflags |= QUOTA_FLAG_HINODES;
3417 break;
3418 case 'l':
3419 if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3420 fprintf(stderr,"bad length limit\n");
3421 usage(f);
3422 }
3423 if (qflags & QUOTA_FLAG_SLENGTH) {
3424 fprintf(stderr,"'soft length' quota defined twice\n");
3425 usage(f);
3426 }
3427 slength = v;
3428 qflags |= QUOTA_FLAG_SLENGTH;
3429 break;
3430 case 'L':
3431 if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3432 fprintf(stderr,"bad length limit\n");
3433 usage(f);
3434 }
3435 if (qflags & QUOTA_FLAG_HLENGTH) {
3436 fprintf(stderr,"'hard length' quota defined twice\n");
3437 usage(f);
3438 }
3439 hlength = v;
3440 qflags |= QUOTA_FLAG_HLENGTH;
3441 break;
3442 case 's':
3443 if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3444 fprintf(stderr,"bad size limit\n");
3445 usage(f);
3446 }
3447 if (qflags & QUOTA_FLAG_SSIZE) {
3448 fprintf(stderr,"'soft size' quota defined twice\n");
3449 usage(f);
3450 }
3451 ssize = v;
3452 qflags |= QUOTA_FLAG_SSIZE;
3453 break;
3454 case 'S':
3455 if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3456 fprintf(stderr,"bad size limit\n");
3457 usage(f);
3458 }
3459 if (qflags & QUOTA_FLAG_HSIZE) {
3460 fprintf(stderr,"'hard size' quota defined twice\n");
3461 usage(f);
3462 }
3463 hsize = v;
3464 qflags |= QUOTA_FLAG_HSIZE;
3465 break;
3466 case 'r':
3467 if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3468 fprintf(stderr,"bad real size limit\n");
3469 usage(f);
3470 }
3471 if (qflags & QUOTA_FLAG_SREALSIZE) {
3472 fprintf(stderr,"'soft realsize' quota defined twice\n");
3473 usage(f);
3474 }
3475 srealsize = v;
3476 qflags |= QUOTA_FLAG_SREALSIZE;
3477 break;
3478 case 'R':
3479 if (my_get_number(optarg,&v,UINT64_MAX,1)<0) {
3480 fprintf(stderr,"bad real size limit\n");
3481 usage(f);
3482 }
3483 if (qflags & QUOTA_FLAG_HREALSIZE) {
3484 fprintf(stderr,"'hard realsize' quota defined twice\n");
3485 usage(f);
3486 }
3487 hrealsize = v;
3488 qflags |= QUOTA_FLAG_HREALSIZE;
3489 break;
3490 }
3491 }
3492 if (qflags==0) {
3493 fprintf(stderr,"quota options not defined\n");
3494 usage(f);
3495 }
3496 argc -= optind;
3497 argv += optind;
3498 break;
3499 case MFSDELQUOTA:
3500 if (getuid()) {
3501 fprintf(stderr,"only root can change quota\n");
3502 usage(f);
3503 }
3504 while ((ch=getopt(argc,argv,"nhHkmgiIlLsSrRaA"))!=-1) {
3505 switch(ch) {
3506 case 'n':
3507 humode=0;
3508 break;
3509 case 'h':
3510 humode=1;
3511 break;
3512 case 'H':
3513 humode=2;
3514 break;
3515 case 'k':
3516 numbermode=1;
3517 break;
3518 case 'm':
3519 numbermode=2;
3520 break;
3521 case 'g':
3522 numbermode=3;
3523 break;
3524 case 'i':
3525 if (qflags & QUOTA_FLAG_SINODES) {
3526 fprintf(stderr,"'soft inodes' option given twice\n");
3527 usage(f);
3528 }
3529 qflags |= QUOTA_FLAG_SINODES;
3530 break;
3531 case 'I':
3532 if (qflags & QUOTA_FLAG_HINODES) {
3533 fprintf(stderr,"'hard inodes' option given twice\n");
3534 usage(f);
3535 }
3536 qflags |= QUOTA_FLAG_HINODES;
3537 break;
3538 case 'l':
3539 if (qflags & QUOTA_FLAG_SLENGTH) {
3540 fprintf(stderr,"'soft length' option given twice\n");
3541 usage(f);
3542 }
3543 qflags |= QUOTA_FLAG_SLENGTH;
3544 break;
3545 case 'L':
3546 if (qflags & QUOTA_FLAG_HLENGTH) {
3547 fprintf(stderr,"'hard length' option given twice\n");
3548 usage(f);
3549 }
3550 qflags |= QUOTA_FLAG_HLENGTH;
3551 break;
3552 case 's':
3553 if (qflags & QUOTA_FLAG_SSIZE) {
3554 fprintf(stderr,"'soft size' option given twice\n");
3555 usage(f);
3556 }
3557 qflags |= QUOTA_FLAG_SSIZE;
3558 break;
3559 case 'S':
3560 if (qflags & QUOTA_FLAG_HSIZE) {
3561 fprintf(stderr,"'hard size' option given twice\n");
3562 usage(f);
3563 }
3564 qflags |= QUOTA_FLAG_HSIZE;
3565 break;
3566 case 'r':
3567 if (qflags & QUOTA_FLAG_SREALSIZE) {
3568 fprintf(stderr,"'soft realsize' option given twice\n");
3569 usage(f);
3570 }
3571 qflags |= QUOTA_FLAG_SREALSIZE;
3572 break;
3573 case 'R':
3574 if (qflags & QUOTA_FLAG_HREALSIZE) {
3575 fprintf(stderr,"'hard realsize' option given twice\n");
3576 usage(f);
3577 }
3578 qflags |= QUOTA_FLAG_HREALSIZE;
3579 break;
3580 case 'a':
3581 if (qflags & QUOTA_FLAG_SALL) {
3582 fprintf(stderr,"'all soft quotas' defined together with other soft quota options\n");
3583 usage(f);
3584 }
3585 qflags |= QUOTA_FLAG_SALL;
3586 break;
3587 case 'A':
3588 if (qflags & QUOTA_FLAG_HALL) {
3589 fprintf(stderr,"'all hard quotas' defined together with other hard quota options\n");
3590 usage(f);
3591 }
3592 qflags |= QUOTA_FLAG_HALL;
3593 break;
3594 }
3595 }
3596 if (qflags==0) {
3597 fprintf(stderr,"quota options not defined\n");
3598 usage(f);
3599 }
3600 argc -= optind;
3601 argv += optind;
3602 break;
3603 default:
3604 while (getopt(argc,argv,"")!=-1);
3605 argc -= optind;
3606 argv += optind;
3607 // argc--; // skip appname
3608 // argv++;
3609 }
3610
3611 if (f==MFSAPPENDCHUNKS) {
3612 if (argc<=1) {
3613 usage(f);
3614 }
3615 appendfname = argv[0];
3616 i = open(appendfname,O_RDWR | O_CREAT,0666);
3617 if (i<0) {
3618 fprintf(stderr,"can't create/open file: %s\n",appendfname);
3619 return 1;
3620 }
3621 close(i);
3622 argc--;
3623 argv++;
3624 }
3625
3626 if (argc<1) {
3627 usage(f);
3628 }
3629 status=0;
3630 while (argc>0) {
3631 switch (f) {
3632 case MFSGETGOAL:
3633 if (get_goal(*argv,(rflag)?GMODE_RECURSIVE:GMODE_NORMAL)<0) {
3634 status=1;
3635 }
3636 break;
3637 case MFSSETGOAL:
3638 if (set_goal(*argv,goal,(rflag)?(smode | SMODE_RMASK):smode)<0) {
3639 status=1;
3640 }
3641 break;
3642 case MFSGETTRASHTIME:
3643 if (get_trashtime(*argv,(rflag)?GMODE_RECURSIVE:GMODE_NORMAL)<0) {
3644 status=1;
3645 }
3646 break;
3647 case MFSSETTRASHTIME:
3648 if (set_trashtime(*argv,trashtime,(rflag)?(smode | SMODE_RMASK):smode)<0) {
3649 status=1;
3650 }
3651 break;
3652 case MFSCHECKFILE:
3653 if (file_info(FILEINFO_QUICK,*argv)<0) {
3654 status=1;
3655 }
3656 break;
3657 case MFSFILEINFO:
3658 if (file_info(fileinfomode,*argv)<0) {
3659 status=1;
3660 }
3661 break;
3662 case MFSAPPENDCHUNKS:
3663 if (append_file(appendfname,*argv)<0) {
3664 status=1;
3665 }
3666 break;
3667 case MFSDIRINFO:
3668 if (dir_info(dirinfomode,*argv)<0) {
3669 status=1;
3670 }
3671 break;
3672 case MFSFILEREPAIR:
3673 if (file_repair(*argv)<0) {
3674 status=1;
3675 }
3676 break;
3677 case MFSGETEATTR:
3678 if (get_eattr(*argv,(rflag)?GMODE_RECURSIVE:GMODE_NORMAL)<0) {
3679 status=1;
3680 }
3681 break;
3682 case MFSSETEATTR:
3683 if (set_eattr(*argv,eattr,(rflag)?(SMODE_RMASK | SMODE_INCREASE):SMODE_INCREASE)<0) {
3684 status=1;
3685 }
3686 break;
3687 case MFSDELEATTR:
3688 if (set_eattr(*argv,eattr,(rflag)?(SMODE_RMASK | SMODE_DECREASE):SMODE_DECREASE)<0) {
3689 status=1;
3690 }
3691 break;
3692 case MFSGETQUOTA:
3693 if (quota_control(*argv,1,0,0,0,0,0,0,0,0,0)<0) {
3694 status=1;
3695 }
3696 break;
3697 case MFSSETQUOTA:
3698 if (quota_control(*argv,0,qflags,sinodes,slength,ssize,srealsize,hinodes,hlength,hsize,hrealsize)<0) {
3699 status=1;
3700 }
3701 break;
3702 case MFSDELQUOTA:
3703 if (quota_control(*argv,1,qflags,0,0,0,0,0,0,0,0)<0) {
3704 status=1;
3705 }
3706 break;
3707 case MFSFILEPATHS:
3708 if (file_paths(*argv)<0) {
3709 status=1;
3710 }
3711 break;
3712 }
3713 argc--;
3714 argv++;
3715 }
3716 return status;
3717 }
3718