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