9bc57986924d979189bb685689df75812fb4f703
[lwext4.git] / fs_test / lwext4_server.c
1 \r
2 #include <errno.h>\r
3 #include <stdio.h>\r
4 #include <stdlib.h>\r
5 #include <unistd.h>\r
6 #include <string.h>\r
7 #include <stdint.h>\r
8 #include <stdbool.h>\r
9 #include <getopt.h>\r
10 #include <time.h>\r
11 \r
12 #ifdef WIN32\r
13 #include <winsock2.h>\r
14 #include <ws2tcpip.h>\r
15 #include <windows.h>\r
16 #else\r
17 #include <sys/socket.h>\r
18 #include <netinet/in.h>\r
19 #include <arpa/inet.h>\r
20 #include <sys/types.h>\r
21 #endif\r
22 \r
23 \r
24 #include <ext4_filedev.h>\r
25 #include <io_raw.h>\r
26 \r
27 #include <ext4.h>\r
28 \r
29 static int winsock_init(void);\r
30 static void winsock_fini(void);\r
31 static char* entry_to_str(uint8_t type);\r
32 \r
33 #define MAX_FILES   64\r
34 #define MAX_DIRS    64\r
35 \r
36 #define MAX_RW_BUFFER   (1024 * 1024)\r
37 #define RW_BUFFER_PATERN    ('x')\r
38 \r
39 \r
40 /**@brief   Default connection port*/\r
41 static int connection_port = 1234;\r
42 \r
43 /**@brief   Default filesystem filename.*/\r
44 static char *ext4_fname = "ext2";\r
45 \r
46 /**@brief   Verbose mode*/\r
47 static int verbose = 0;\r
48 \r
49 /**@brief   Winpart mode*/\r
50 static int winpart = 0;\r
51 \r
52 /**@brief   Blockdev handle*/\r
53 static struct ext4_blockdev *bd;\r
54 \r
55 static int cache_wb = 0;\r
56 \r
57 static char read_buffer[MAX_RW_BUFFER];\r
58 static char write_buffer[MAX_RW_BUFFER];\r
59 \r
60 \r
61 static const char *usage = "                                    \n\\r
62 Welcome in lwext4_server.                                       \n\\r
63 Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)  \n\\r
64 Usage:                                                          \n\\r
65     --image     (-i) - ext2/3/4 image file                      \n\\r
66     --port      (-p) - server port                              \n\\r
67     --verbose   (-v) - verbose mode                             \n\\r
68     --winpart   (-w) - windows_partition mode                   \n\\r
69     --cache_wb  (-c) - cache writeback_mode                     \n\\r
70 \n";\r
71 \r
72 \r
73 \r
74 /**@brief   Open file instance descriptor.*/\r
75 struct lwext4_files {\r
76     char        name[255];\r
77     ext4_file   fd;\r
78 };\r
79 \r
80 /**@brief   Open directory instance descriptor.*/\r
81 struct lwext4_dirs {\r
82     char        name[255];\r
83     ext4_dir    fd;\r
84 };\r
85 \r
86 /**@brief   Library call opcode.*/\r
87 struct lwext4_op_codes {\r
88     char *func;\r
89 };\r
90 \r
91 /**@brief   Library call wraper.*/\r
92 struct lwext4_call {\r
93     int (*lwext4_call)(char *p);\r
94 };\r
95 \r
96 /**@brief  */\r
97 static struct lwext4_files file_tab[MAX_FILES];\r
98 \r
99 /**@brief  */\r
100 static struct lwext4_dirs  dir_tab[MAX_DIRS];\r
101 \r
102 /**@brief  */\r
103 static struct lwext4_op_codes op_codes[] = {\r
104         "device_register",\r
105         "mount",\r
106         "umount",\r
107         "mount_point_stats",\r
108         "cache_write_back",\r
109         "fremove",\r
110         "fopen",\r
111         "fclose",\r
112         "fread",\r
113         "fwrite",\r
114         "fseek",\r
115         "ftell",\r
116         "fsize",\r
117         "dir_rm",\r
118         "dir_mk",\r
119         "dir_open",\r
120         "dir_close",\r
121         "dir_entry_get",\r
122 \r
123         "multi_fcreate",\r
124         "multi_fwrite",\r
125         "multi_fread",\r
126         "multi_fremove",\r
127         "multi_dcreate",\r
128         "multi_dremove",\r
129         "stats_save",\r
130         "stats_check",\r
131 };\r
132 \r
133 int _device_register(char *p);\r
134 int _mount(char *p);\r
135 int _umount(char *p);\r
136 int _mount_point_stats(char *p);\r
137 int _cache_write_back(char *p);\r
138 int _fremove(char *p);\r
139 int _fopen(char *p);\r
140 int _fclose(char *p);\r
141 int _fread(char *p);\r
142 int _fwrite(char *p);\r
143 int _fseek(char *p);\r
144 int _ftell(char *p);\r
145 int _fsize(char *p);\r
146 int _dir_rm(char *p);\r
147 int _dir_mk(char *p);\r
148 int _dir_open(char *p);\r
149 int _dir_close(char *p);\r
150 int _dir_close(char *p);\r
151 int _dir_entry_get(char *p);\r
152 \r
153 int _multi_fcreate(char *p);\r
154 int _multi_fwrite(char *p);\r
155 int _multi_fread(char *p);\r
156 int _multi_fremove(char *p);\r
157 int _multi_dcreate(char *p);\r
158 int _multi_dremove(char *p);\r
159 int _stats_save(char *p);\r
160 int _stats_check(char *p);\r
161 \r
162 /**@brief  */\r
163 static struct lwext4_call op_call[] = {\r
164         _device_register,  /*PARAMS(3):   0 cache_mode dev_name   */\r
165         _mount,            /*PARAMS(2):   dev_name mount_point    */\r
166         _umount,           /*PARAMS(1):   mount_point             */\r
167         _mount_point_stats,/*PARAMS(2):   mount_point, 0          */\r
168         _cache_write_back, /*PARAMS(2):   mount_point, en         */\r
169         _fremove,          /*PARAMS(1):   path                    */\r
170         _fopen,            /*PARAMS(2):   fid path flags          */\r
171         _fclose,           /*PARAMS(1):   fid                     */\r
172         _fread,            /*PARAMS(4):   fid 0 len 0             */\r
173         _fwrite,           /*PARAMS(4):   fid 0 len 0             */\r
174         _fseek,            /*PARAMS(2):   fid off origin          */\r
175         _ftell,            /*PARAMS(2):   fid exp                 */\r
176         _fsize,            /*PARAMS(2):   fid exp                 */\r
177         _dir_rm,           /*PARAMS(1):   path                    */\r
178         _dir_mk,           /*PARAMS(1):   path                    */\r
179         _dir_open,         /*PARAMS(2):   did, path               */\r
180         _dir_close,        /*PARAMS(1):   did                     */\r
181         _dir_entry_get,    /*PARAMS(2):   did, exp                */\r
182 \r
183         _multi_fcreate,    /*PARAMS(3):   path prefix cnt         */\r
184         _multi_fwrite,     /*PARAMS(4):   path prefix cnt size    */\r
185         _multi_fread,      /*PARAMS(4):   path prefix cnt size    */\r
186         _multi_fremove,    /*PARAMS(2):   path prefix cnt         */\r
187         _multi_dcreate,    /*PARAMS(3):   path prefix cnt         */\r
188         _multi_dremove,    /*PARAMS(2):   path prefix             */\r
189         _stats_save,       /*PARAMS(1):   path                    */\r
190         _stats_check,      /*PARAMS(1):   path                    */\r
191 };\r
192 \r
193 static clock_t get_ms(void)\r
194 {\r
195     struct timeval t;\r
196     gettimeofday(&t, NULL);\r
197     return (t.tv_sec * 1000) + (t.tv_usec / 1000);\r
198 }\r
199 \r
200 /**@brief  */\r
201 static int exec_op_code(char *opcode)\r
202 {\r
203     int i;\r
204     int r = -1;\r
205 \r
206     for (i = 0; i < sizeof(op_codes) / sizeof(op_codes[0]); ++i) {\r
207 \r
208         if(strncmp(op_codes[i].func, opcode, strlen(op_codes[i].func)))\r
209             continue;\r
210 \r
211         if(opcode[strlen(op_codes[i].func)] != ' ')\r
212             continue;\r
213 \r
214         printf("%s\n", opcode);\r
215         opcode += strlen(op_codes[i].func);\r
216         /*Call*/\r
217 \r
218         clock_t t = get_ms();\r
219         r = op_call[i].lwext4_call(opcode);\r
220 \r
221         printf("rc: %d, time: %ums\n", r, (unsigned int)(get_ms() - t));\r
222 \r
223         break;\r
224     }\r
225 \r
226     return r;\r
227 }\r
228 \r
229 \r
230 static int server_open(void)\r
231 {\r
232     int fd = 0;\r
233     struct sockaddr_in serv_addr;\r
234 \r
235     memset(&serv_addr, 0, sizeof(serv_addr));\r
236 \r
237     if(winsock_init() < 0) {\r
238         printf("winsock_init() error\n");\r
239         exit(-1);\r
240     }\r
241 \r
242     fd = socket(AF_INET, SOCK_STREAM, 0);\r
243     if(fd < 0) {\r
244         printf("socket() error: %s\n", strerror(errno));\r
245         exit(-1);\r
246     }\r
247 \r
248     int yes = 1;\r
249     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(int))) {\r
250         printf("setsockopt() error: %s\n", strerror(errno));\r
251         exit(-1);\r
252     }\r
253 \r
254     serv_addr.sin_family = AF_INET;\r
255     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);\r
256     serv_addr.sin_port = htons(connection_port);\r
257 \r
258     if(bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))){\r
259         printf("bind() error: %s\n", strerror(errno));\r
260         exit(-1);\r
261     }\r
262 \r
263     if(listen(fd, 1)){\r
264         printf("listen() error: %s\n", strerror(errno));\r
265         exit(-1);\r
266     }\r
267 \r
268     return fd;\r
269 }\r
270 \r
271 static bool parse_opt(int argc, char **argv)\r
272 {\r
273     int option_index = 0;\r
274     int c;\r
275 \r
276     static struct option long_options[] = {\r
277             {"image",   required_argument, 0, 'i'},\r
278             {"port",    required_argument, 0, 'p'},\r
279             {"verbose", required_argument, 0, 'v'},\r
280             {"winpart", required_argument, 0, 'w'},\r
281             {"cache_wb",required_argument, 0, 'c'},\r
282             {0, 0, 0, 0}\r
283     };\r
284 \r
285     while(-1 != (c = getopt_long (argc, argv, "i:p:v:w:c:", long_options, &option_index))) {\r
286 \r
287         switch(c){\r
288         case 'i':\r
289             ext4_fname = optarg;\r
290             break;\r
291         case 'p':\r
292             connection_port = atoi(optarg);\r
293             break;\r
294         case 'v':\r
295             verbose = atoi(optarg);\r
296             break;\r
297         case 'c':\r
298             cache_wb = atoi(optarg);\r
299             break;\r
300         default:\r
301             printf("%s", usage);\r
302             return false;\r
303 \r
304         }\r
305     }\r
306     return true;\r
307 }\r
308 \r
309 int main(int argc, char *argv[])\r
310 {\r
311     int n;\r
312     int listenfd;\r
313     int connfd;\r
314     char op_code[128];\r
315 \r
316     if(!parse_opt(argc, argv))\r
317         return -1;\r
318 \r
319     listenfd = server_open();\r
320 \r
321     printf("lwext4_server: listening on port: %d\n", connection_port);\r
322 \r
323     memset(write_buffer, RW_BUFFER_PATERN, MAX_RW_BUFFER);\r
324     while(1)\r
325     {\r
326         connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);\r
327 \r
328         n = recv(connfd, op_code, sizeof(op_code), 0);\r
329 \r
330         if(n < 0) {\r
331             printf("recv() error: %s fd = %d\n", strerror(errno), connfd);\r
332             break;\r
333         }\r
334 \r
335         op_code[n] = 0;\r
336 \r
337         int r = exec_op_code(op_code);\r
338 \r
339         n = send(connfd, (void *)&r, sizeof(r), 0);\r
340         if(n < 0) {\r
341             printf("send() error: %s fd = %d\n", strerror(errno), connfd);\r
342             break;\r
343         }\r
344 \r
345         close(connfd);\r
346     }\r
347 \r
348     winsock_fini();\r
349     return 0;\r
350 }\r
351 \r
352 \r
353 int _device_register(char *p)\r
354 {\r
355     int dev;\r
356     int cache_mode;\r
357     char dev_name[32];\r
358 \r
359     if(sscanf(p, "%d %d %s", &dev, &cache_mode, dev_name) != 3){\r
360         printf("Param list error\n");\r
361         return -1;\r
362     }\r
363 \r
364 #ifdef WIN32\r
365     if(winpart){\r
366         ext4_io_raw_filename(ext4_fname);\r
367         bd = ext4_io_raw_dev_get();\r
368 \r
369     }\r
370     else\r
371 #endif\r
372     {\r
373         ext4_filedev_filename(ext4_fname);\r
374         bd = ext4_filedev_get();\r
375     }\r
376     return ext4_device_register(bd, 0, dev_name);\r
377 }\r
378 \r
379 int _mount(char *p)\r
380 {\r
381     char dev_name[32];\r
382     char mount_point[32];\r
383     int rc;\r
384 \r
385     if(sscanf(p, "%s %s", dev_name, mount_point) != 2){\r
386         printf("Param list error\n");\r
387         return -1;\r
388     }\r
389 \r
390     rc = ext4_mount(dev_name, mount_point);\r
391     if(cache_wb)\r
392         ext4_cache_write_back(mount_point, 1);\r
393     return rc;\r
394 }\r
395 \r
396 int _umount(char *p)\r
397 {\r
398     char mount_point[32];\r
399 \r
400     if(sscanf(p, "%s", mount_point) != 1){\r
401         printf("Param list error\n");\r
402         return -1;\r
403     }\r
404 \r
405     if(cache_wb)\r
406         ext4_cache_write_back(mount_point, 0);\r
407 \r
408     return ext4_umount(mount_point);\r
409 }\r
410 \r
411 int _mount_point_stats(char *p)\r
412 {\r
413     char mount_point[32];\r
414     int d;\r
415     int rc;\r
416     struct ext4_mount_stats stats;\r
417 \r
418     if(sscanf(p, "%s %d", mount_point, &d) != 2){\r
419         printf("Param list error\n");\r
420         return -1;\r
421     }\r
422 \r
423     rc = ext4_mount_point_stats(mount_point, &stats);\r
424 \r
425     if(rc != EOK)\r
426         return;\r
427 \r
428     if(verbose){\r
429         printf("\tinodes_count = %d\n", stats.inodes_count);\r
430         printf("\tfree_inodes_count = %d\n", stats.free_inodes_count);\r
431         printf("\tblocks_count = %llu\n", stats.blocks_count);\r
432         printf("\tfree_blocks_count = %llu\n", stats.free_blocks_count);\r
433 \r
434         printf("\tblock_size = %d\n", stats.block_size);\r
435         printf("\tblock_group_count = %d\n", stats.block_group_count);\r
436         printf("\tblocks_per_group = %d\n", stats.blocks_per_group);\r
437         printf("\tinodes_per_group = %d\n", stats.inodes_per_group);\r
438 \r
439         printf("\tvolume_name = %s\n", stats.volume_name);\r
440     }\r
441 \r
442     return rc;\r
443 }\r
444 \r
445 int _cache_write_back(char *p)\r
446 {\r
447     char mount_point[32];\r
448     int en;\r
449 \r
450     if(sscanf(p, "%s %d", mount_point, &en) != 2){\r
451         printf("Param list error\n");\r
452         return -1;\r
453     }\r
454 \r
455     return ext4_cache_write_back(mount_point, en);\r
456 }\r
457 \r
458 \r
459 int _fremove(char *p)\r
460 {\r
461     char path[255];\r
462 \r
463     if(sscanf(p, "%s", path) != 1){\r
464         printf("Param list error\n");\r
465         return -1;\r
466     }\r
467 \r
468     return ext4_fremove(path);\r
469 }\r
470 \r
471 int _fopen(char *p)\r
472 {\r
473     int fid = MAX_FILES;\r
474     char path[256];\r
475     char flags[8];\r
476     int rc;\r
477 \r
478     if(sscanf(p, "%d %s %s", &fid, path, flags) != 3){\r
479         printf("Param list error\n");\r
480         return -1;\r
481     }\r
482 \r
483     if(!(fid < MAX_FILES)){\r
484         printf("File id too big\n");\r
485         return -1;\r
486     }\r
487 \r
488     rc = ext4_fopen(&file_tab[fid].fd, path, flags);\r
489 \r
490     if(rc == EOK)\r
491         strcpy(file_tab[fid].name, path);\r
492 \r
493     return rc;\r
494 }\r
495 \r
496 int _fclose(char *p)\r
497 {\r
498     int fid = MAX_FILES;\r
499     int rc;\r
500 \r
501     if(sscanf(p, "%d", &fid) != 1){\r
502         printf("Param list error\n");\r
503         return -1;\r
504     }\r
505 \r
506     if(!(fid < MAX_FILES)){\r
507         printf("File id too big\n");\r
508         return -1;\r
509     }\r
510 \r
511     if(file_tab[fid].name[0] == 0){\r
512         printf("File id empty\n");\r
513         return -1;\r
514     }\r
515 \r
516     rc = ext4_fclose(&file_tab[fid].fd);\r
517 \r
518     if(rc == EOK)\r
519         file_tab[fid].name[0] = 0;\r
520 \r
521     return rc;\r
522 }\r
523 \r
524 int _fread(char *p)\r
525 {\r
526     int fid = MAX_FILES;\r
527     int len;\r
528     int d;\r
529     int rc;\r
530     int rb;\r
531 \r
532     if(sscanf(p, "%d %d %d %d", &fid, &d, &len, &d) != 4){\r
533         printf("Param list error\n");\r
534         return -1;\r
535     }\r
536 \r
537     if(!(fid < MAX_FILES)){\r
538         printf("File id too big\n");\r
539         return -1;\r
540     }\r
541 \r
542     if(file_tab[fid].name[0] == 0){\r
543         printf("File id empty\n");\r
544         return -1;\r
545     }\r
546 \r
547     while(len){\r
548         d = len > MAX_RW_BUFFER ? MAX_RW_BUFFER : len;\r
549 \r
550         memset(read_buffer, 0, MAX_RW_BUFFER);\r
551         rc = ext4_fread(&file_tab[fid].fd, read_buffer, d, &rb);\r
552 \r
553         if(rc != EOK)\r
554             break;\r
555 \r
556         if(rb != d){\r
557             printf("Read count error\n");\r
558             return -1;\r
559         }\r
560 \r
561         if(memcmp(read_buffer, write_buffer, d)){\r
562             printf("Read compare error\n");\r
563             return -1;\r
564         }\r
565 \r
566         len -= d;\r
567     }\r
568 \r
569     return rc;\r
570 }\r
571 \r
572 int _fwrite(char *p)\r
573 {\r
574     int fid = MAX_FILES;\r
575     int len;\r
576     int d;\r
577     int rc;\r
578     int wb;\r
579 \r
580     if(sscanf(p, "%d %d %d %d", &fid, &d, &len, &d) != 4){\r
581         printf("Param list error\n");\r
582         return -1;\r
583     }\r
584 \r
585     if(!(fid < MAX_FILES)){\r
586         printf("File id too big\n");\r
587         return -1;\r
588     }\r
589 \r
590     if(file_tab[fid].name[0] == 0){\r
591         printf("File id empty\n");\r
592         return -1;\r
593     }\r
594 \r
595     while(len){\r
596         d = len > MAX_RW_BUFFER ? MAX_RW_BUFFER : len;\r
597         rc = ext4_fwrite(&file_tab[fid].fd, write_buffer, d, &wb);\r
598 \r
599         if(rc != EOK)\r
600             break;\r
601 \r
602         if(wb != d){\r
603             printf("Write count error\n");\r
604             return -1;\r
605         }\r
606 \r
607         len -= d;\r
608     }\r
609 \r
610     return rc;\r
611 }\r
612 \r
613 int _fseek(char *p)\r
614 {\r
615     int fid = MAX_FILES;\r
616     int off;\r
617     int origin;\r
618 \r
619     if(sscanf(p, "%d %d %d", &fid, &off, &origin) != 3){\r
620         printf("Param list error\n");\r
621         return -1;\r
622     }\r
623 \r
624     if(!(fid < MAX_FILES)){\r
625         printf("File id too big\n");\r
626         return -1;\r
627     }\r
628 \r
629     if(file_tab[fid].name[0] == 0){\r
630         printf("File id empty\n");\r
631         return -1;\r
632     }\r
633 \r
634     return ext4_fseek(&file_tab[fid].fd, off, origin);\r
635 }\r
636 \r
637 int _ftell(char *p)\r
638 {\r
639     int fid = MAX_FILES;\r
640     uint32_t exp_pos;\r
641 \r
642     if(sscanf(p, "%d %u", &fid, &exp_pos) != 2){\r
643         printf("Param list error\n");\r
644         return -1;\r
645     }\r
646 \r
647     if(!(fid < MAX_FILES)){\r
648         printf("File id too big\n");\r
649         return -1;\r
650     }\r
651 \r
652     if(file_tab[fid].name[0] == 0){\r
653         printf("File id empty\n");\r
654         return -1;\r
655     }\r
656 \r
657 \r
658     if(exp_pos != ext4_ftell(&file_tab[fid].fd)){\r
659         printf("Expected filepos error\n");\r
660         return -1;\r
661     }\r
662 \r
663     return EOK;\r
664 }\r
665 \r
666 int _fsize(char *p)\r
667 {\r
668     int fid = MAX_FILES;\r
669     uint32_t exp_size;\r
670 \r
671     if(sscanf(p, "%d %u", &fid, &exp_size) != 2){\r
672         printf("Param list error\n");\r
673         return -1;\r
674     }\r
675 \r
676     if(!(fid < MAX_FILES)){\r
677         printf("File id too big\n");\r
678         return -1;\r
679     }\r
680 \r
681     if(file_tab[fid].name[0] == 0){\r
682         printf("File id empty\n");\r
683         return -1;\r
684     }\r
685 \r
686     if(exp_size != ext4_fsize(&file_tab[fid].fd)){\r
687         printf("Expected filesize error\n");\r
688         return -1;\r
689     }\r
690 \r
691     return EOK;\r
692 }\r
693 \r
694 int _dir_rm(char *p)\r
695 {\r
696     char path[255];\r
697 \r
698     if(sscanf(p, "%s", path) != 1){\r
699         printf("Param list error\n");\r
700         return -1;\r
701     }\r
702 \r
703     return ext4_dir_rm(path);\r
704 }\r
705 \r
706 int _dir_mk(char *p)\r
707 {\r
708     char path[255];\r
709 \r
710     if(sscanf(p, "%s", path) != 1){\r
711         printf("Param list error\n");\r
712         return -1;\r
713     }\r
714 \r
715     return ext4_dir_mk(path);\r
716 }\r
717 \r
718 int _dir_open(char *p)\r
719 {\r
720     int did = MAX_DIRS;\r
721     char path[255];\r
722     int rc;\r
723 \r
724     if(sscanf(p, "%d %s", &did, path) != 2){\r
725         printf("Param list error\n");\r
726         return -1;\r
727     }\r
728 \r
729     if(!(did < MAX_DIRS)){\r
730         printf("Dir id too big\n");\r
731         return -1;\r
732     }\r
733 \r
734     rc = ext4_dir_open(&dir_tab[did].fd, path);\r
735 \r
736     if(rc == EOK)\r
737         strcpy(dir_tab[did].name, path);\r
738 \r
739     return rc;\r
740 }\r
741 \r
742 int _dir_close(char *p)\r
743 {\r
744     int did = MAX_DIRS;\r
745     int rc;\r
746 \r
747     if(sscanf(p, "%d", &did) != 1){\r
748         printf("Param list error\n");\r
749         return -1;\r
750     }\r
751 \r
752     if(!(did < MAX_DIRS)){\r
753         printf("Dir id too big\n");\r
754         return -1;\r
755     }\r
756 \r
757     if(dir_tab[did].name[0] == 0){\r
758         printf("Dir id empty\n");\r
759         return -1;\r
760     }\r
761 \r
762     rc = ext4_dir_close(&dir_tab[did].fd);\r
763 \r
764     if(rc == EOK)\r
765         dir_tab[did].name[0] = 0;\r
766 \r
767     return rc;\r
768 }\r
769 \r
770 int _dir_entry_get(char *p)\r
771 {\r
772     int did = MAX_DIRS;\r
773     int exp;\r
774     char name[256];\r
775 \r
776     if(sscanf(p, "%d %d", &did, &exp) != 2){\r
777         printf("Param list error\n");\r
778         return -1;\r
779     }\r
780 \r
781     if(!(did < MAX_DIRS)){\r
782         printf("Dir id too big\n");\r
783         return -1;\r
784     }\r
785 \r
786     if(dir_tab[did].name[0] == 0){\r
787         printf("Dir id empty\n");\r
788         return -1;\r
789     }\r
790 \r
791 \r
792     int idx = 0;\r
793     ext4_direntry *d;\r
794 \r
795     while(d = ext4_dir_entry_get(&dir_tab[did].fd, idx++)){\r
796 \r
797         memcpy(name, d->name, d->name_length);\r
798         name[d->name_length] = 0;\r
799         if(verbose){\r
800             printf("\t%s %s\n", entry_to_str(d->inode_type), name);\r
801         }\r
802     }\r
803 \r
804     idx--;\r
805 \r
806     if(idx < 2){\r
807         printf("Minumum dir entry error\n");\r
808         return -1;\r
809     }\r
810 \r
811     if((idx - 2) != exp){\r
812         printf("Expected dir entry error\n");\r
813         return -1;\r
814     }\r
815 \r
816     return EOK;\r
817 }\r
818 \r
819 int _multi_fcreate(char *p)\r
820 {\r
821     char path[256];\r
822     char path1[256];\r
823     char prefix[32];\r
824     int cnt;\r
825     int rc;\r
826     int i;\r
827     ext4_file   fd;\r
828 \r
829     if(sscanf(p, "%s %s %d", path, prefix, &cnt) != 3){\r
830         printf("Param list error\n");\r
831         return -1;\r
832     }\r
833 \r
834     for (i = 0; i < cnt; ++i) {\r
835         sprintf(path1, "%s%s%d", path, prefix, i);\r
836         rc = ext4_fopen(&fd, path1, "wb+");\r
837 \r
838         if(rc != EOK)\r
839             break;\r
840     }\r
841 \r
842     return rc;\r
843 }\r
844 \r
845 int _multi_fwrite(char *p)\r
846 {\r
847     char path[256];\r
848     char path1[256];\r
849     char prefix[32];\r
850     int cnt;\r
851     int len, ll;\r
852     int rc;\r
853     int i, d, wb;\r
854     ext4_file   fd;\r
855 \r
856     if(sscanf(p, "%s %s %d %d", path, prefix, &cnt, &ll) != 4){\r
857         printf("Param list error\n");\r
858         return -1;\r
859     }\r
860 \r
861     for (i = 0; i < cnt; ++i) {\r
862         sprintf(path1, "%s%s%d", path, prefix, i);\r
863         rc = ext4_fopen(&fd, path1, "rb+");\r
864 \r
865         if(rc != EOK)\r
866             break;\r
867 \r
868         len = ll;\r
869         while(len){\r
870             d = len > MAX_RW_BUFFER ? MAX_RW_BUFFER : len;\r
871             rc = ext4_fwrite(&fd, write_buffer, d, &wb);\r
872 \r
873             if(rc != EOK)\r
874                 break;\r
875 \r
876             if(wb != d){\r
877                 printf("Write count error\n");\r
878                 return -1;\r
879             }\r
880 \r
881             len -= d;\r
882         }\r
883     }\r
884 \r
885     return rc;\r
886 }\r
887 \r
888 int _multi_fread(char *p)\r
889 {\r
890     char path[256];\r
891     char path1[256];\r
892     char prefix[32];\r
893     int cnt;\r
894     int len, ll;\r
895     int rc;\r
896     int i, d, rb;\r
897     ext4_file   fd;\r
898 \r
899     if(sscanf(p, "%s %s %d %d", path, prefix, &cnt, &ll) != 4){\r
900         printf("Param list error\n");\r
901         return -1;\r
902     }\r
903 \r
904     for (i = 0; i < cnt; ++i) {\r
905         sprintf(path1, "%s%s%d", path, prefix, i);\r
906         rc = ext4_fopen(&fd, path1, "rb+");\r
907 \r
908         if(rc != EOK)\r
909             break;\r
910 \r
911         len = ll;\r
912         while(len){\r
913             d = len > MAX_RW_BUFFER ? MAX_RW_BUFFER : len;\r
914 \r
915             memset(read_buffer, 0, MAX_RW_BUFFER);\r
916             rc = ext4_fread(&fd, read_buffer, d, &rb);\r
917 \r
918             if(rc != EOK)\r
919                 break;\r
920 \r
921             if(rb != d){\r
922                 printf("Read count error\n");\r
923                 return -1;\r
924             }\r
925 \r
926             if(memcmp(read_buffer, write_buffer, d)){\r
927                 printf("Read compare error\n");\r
928                 return -1;\r
929             }\r
930 \r
931             len -= d;\r
932         }\r
933     }\r
934 \r
935     return rc;\r
936 }\r
937 \r
938 int _multi_fremove(char *p)\r
939 {\r
940     char path[256];\r
941     char path1[256];\r
942     char prefix[32];\r
943     int  cnt, i, rc;\r
944 \r
945     if(sscanf(p, "%s %s %d", path, prefix, &cnt) != 3){\r
946         printf("Param list error\n");\r
947         return -1;\r
948     }\r
949 \r
950     for (i = 0; i < cnt; ++i) {\r
951         sprintf(path1, "%s%s%d", path, prefix, i);\r
952         rc = ext4_fremove(path1);\r
953         if(rc != EOK)\r
954             break;\r
955     }\r
956 \r
957     return rc;\r
958 }\r
959 \r
960 int _multi_dcreate(char *p)\r
961 {\r
962     char path[256];\r
963     char path1[256];\r
964     char prefix[32];\r
965     int  cnt, i, rc;\r
966 \r
967     if(sscanf(p, "%s %s %d", path, prefix, &cnt) != 3){\r
968         printf("Param list error\n");\r
969         return -1;\r
970     }\r
971 \r
972     for (i = 0; i < cnt; ++i) {\r
973         sprintf(path1, "%s%s%d", path, prefix, i);\r
974         rc = ext4_dir_mk(path1);\r
975         if(rc != EOK)\r
976             break;\r
977     }\r
978 \r
979     return rc;\r
980 }\r
981 \r
982 int _multi_dremove(char *p)\r
983 {\r
984     char path[256];\r
985     char path1[256];\r
986     char prefix[32];\r
987     int  cnt, i, rc;\r
988 \r
989     if(sscanf(p, "%s %s %d", path, prefix, &cnt) != 3){\r
990         printf("Param list error\n");\r
991         return -1;\r
992     }\r
993 \r
994     for (i = 0; i < cnt; ++i) {\r
995         sprintf(path1, "%s%s%d", path, prefix, i);\r
996         rc = ext4_dir_rm(path1);\r
997         if(rc != EOK)\r
998             break;\r
999     }\r
1000 \r
1001     return rc;\r
1002 }\r
1003 \r
1004 struct ext4_mount_stats  saved_stats;\r
1005 \r
1006 int _stats_save(char *p)\r
1007 {\r
1008     char path[256];\r
1009 \r
1010     if(sscanf(p, "%s", path) != 1){\r
1011         printf("Param list error\n");\r
1012         return -1;\r
1013     }\r
1014 \r
1015     return ext4_mount_point_stats(path, &saved_stats);\r
1016 }\r
1017 \r
1018 int _stats_check(char *p)\r
1019 {\r
1020     char path[256];\r
1021     int rc;\r
1022 \r
1023     struct ext4_mount_stats  actual_stats;\r
1024 \r
1025     if(sscanf(p, "%s", path) != 1){\r
1026         printf("Param list error\n");\r
1027         return -1;\r
1028     }\r
1029 \r
1030     rc = ext4_mount_point_stats(path, &actual_stats);\r
1031 \r
1032     if(rc != EOK)\r
1033         return rc;\r
1034 \r
1035     if(memcmp(&saved_stats, &actual_stats, sizeof(struct ext4_mount_stats))){\r
1036         if(verbose){\r
1037             printf("\tMount point stats error:\n");\r
1038             printf("\tsaved_stats:\n");\r
1039             printf("\tinodes_count = %d\n", saved_stats.inodes_count);\r
1040             printf("\tfree_inodes_count = %d\n", saved_stats.free_inodes_count);\r
1041             printf("\tblocks_count = %llu\n", saved_stats.blocks_count);\r
1042             printf("\tfree_blocks_count = %llu\n", saved_stats.free_blocks_count);\r
1043             printf("\tblock_size = %d\n", saved_stats.block_size);\r
1044             printf("\tblock_group_count = %d\n", saved_stats.block_group_count);\r
1045             printf("\tblocks_per_group = %d\n", saved_stats.blocks_per_group);\r
1046             printf("\tinodes_per_group = %d\n", saved_stats.inodes_per_group);\r
1047             printf("\tvolume_name = %s\n", saved_stats.volume_name);\r
1048             printf("\tactual_stats:\n");\r
1049             printf("\tinodes_count = %d\n", actual_stats.inodes_count);\r
1050             printf("\tfree_inodes_count = %d\n", actual_stats.free_inodes_count);\r
1051             printf("\tblocks_count = %llu\n", actual_stats.blocks_count);\r
1052             printf("\tfree_blocks_count = %llu\n", actual_stats.free_blocks_count);\r
1053             printf("\tblock_size = %d\n", actual_stats.block_size);\r
1054             printf("\tblock_group_count = %d\n", actual_stats.block_group_count);\r
1055             printf("\tblocks_per_group = %d\n", actual_stats.blocks_per_group);\r
1056             printf("\tinodes_per_group = %d\n", actual_stats.inodes_per_group);\r
1057             printf("\tvolume_name = %s\n", actual_stats.volume_name);\r
1058         }\r
1059         return -1;\r
1060     }\r
1061 \r
1062 \r
1063    return rc;\r
1064 }\r
1065 \r
1066 \r
1067 static char* entry_to_str(uint8_t type)\r
1068 {\r
1069     switch(type){\r
1070     case EXT4_DIRENTRY_UNKNOWN:\r
1071         return "[UNK] ";\r
1072     case EXT4_DIRENTRY_REG_FILE:\r
1073         return "[FIL] ";\r
1074     case EXT4_DIRENTRY_DIR:\r
1075         return "[DIR] ";\r
1076     case EXT4_DIRENTRY_CHRDEV:\r
1077         return "[CHA] ";\r
1078     case EXT4_DIRENTRY_BLKDEV:\r
1079         return "[BLK] ";\r
1080     case EXT4_DIRENTRY_FIFO:\r
1081         return "[FIF] ";\r
1082     case EXT4_DIRENTRY_SOCK:\r
1083         return "[SOC] ";\r
1084     case EXT4_DIRENTRY_SYMLINK:\r
1085         return "[SYM] ";\r
1086     default:\r
1087         break;\r
1088     }\r
1089     return "[???]";\r
1090 }\r
1091 \r
1092 static int winsock_init(void)\r
1093 {\r
1094 #if WIN32\r
1095     int rc;\r
1096     static WSADATA wsaData;\r
1097     rc = WSAStartup(MAKEWORD(2,2), &wsaData);\r
1098     if (rc != 0) {\r
1099         return -1;\r
1100     }\r
1101 #endif\r
1102     return 0;\r
1103 }\r
1104 \r
1105 static void winsock_fini(void)\r
1106 {\r
1107 #if WIN32\r
1108     WSACleanup();\r
1109 #endif\r
1110 }\r
1111 \r