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