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