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