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