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