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