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&QUOTA_FLAG_SINODES);
2518 	print_number(" | "," |\n",hinodes,0,0,qflags&QUOTA_FLAG_HINODES);
2519 	print_number(" length   | ",NULL,curlength,0,1,1);
2520 	print_number(" | ",NULL,slength,0,1,qflags&QUOTA_FLAG_SLENGTH);
2521 	print_number(" | "," |\n",hlength,0,1,qflags&QUOTA_FLAG_HLENGTH);
2522 	print_number(" size     | ",NULL,cursize,0,1,1);
2523 	print_number(" | ",NULL,ssize,0,1,qflags&QUOTA_FLAG_SSIZE);
2524 	print_number(" | "," |\n",hsize,0,1,qflags&QUOTA_FLAG_HSIZE);
2525 	print_number(" realsize | ",NULL,currealsize,0,1,1);
2526 	print_number(" | ",NULL,srealsize,0,1,qflags&QUOTA_FLAG_SREALSIZE);
2527 	print_number(" | "," |\n",hrealsize,0,1,qflags&QUOTA_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