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