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