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