summaryrefslogtreecommitdiff
path: root/utils/ypr0tools/cramfs-1.1/cramfsck.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-12-24 11:56:46 +0000
committerThomas Martitz <kugel@rockbox.org>2011-12-24 11:56:46 +0000
commit249bba03f1051f4984538f66b9e7d36674c61e5c (patch)
treeb9a0d78e05269ed2043521ab0dfdad83aeaf2aff /utils/ypr0tools/cramfs-1.1/cramfsck.c
parent567e0ad93ef3048f2266932b10dcdb309b1a77c9 (diff)
downloadrockbox-249bba03f1051f4984538f66b9e7d36674c61e5c.tar.gz
rockbox-249bba03f1051f4984538f66b9e7d36674c61e5c.zip
Initial commit of the Samsung YP-R0 port.
This port is a hybrid native/RaaA port. It runs on a embedded linux system, but is the only application. It therefore can implement lots of stuff that native targets also implement, while leveraging the underlying linux kernel. The port is quite advanced. User interface, audio playback, plugins work mostly fine. Missing is e.g. power mangement and USB (see SamsungYPR0 wiki page). Included in utils/ypr0tools are scripts and programs required to generate a patched firmware. The patched firmware has the rootfs modified to load Rockbox. It includes a early/safe USB mode. This port needs a new toolchain, one that includes glibc headers and libraries. rockboxdev.sh can generate it, but e.g. codesourcey and distro packages may also work. Most of the initial effort is done by Lorenzo Miori and others (on ABI), including reverse engineering and patching of the original firmware, initial drivers, and more. Big thanks to you. Flyspray: FS#12348 Author: Lorenzo Miori, myself Merry christmas to ypr0 owners! :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31415 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/ypr0tools/cramfs-1.1/cramfsck.c')
-rw-r--r--utils/ypr0tools/cramfs-1.1/cramfsck.c716
1 files changed, 716 insertions, 0 deletions
diff --git a/utils/ypr0tools/cramfs-1.1/cramfsck.c b/utils/ypr0tools/cramfs-1.1/cramfsck.c
new file mode 100644
index 0000000000..aef017a4b4
--- /dev/null
+++ b/utils/ypr0tools/cramfs-1.1/cramfsck.c
@@ -0,0 +1,716 @@
1/*
2 * cramfsck - check a cramfs file system
3 *
4 * Copyright (C) 2000-2002 Transmeta Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * 1999/12/03: Linus Torvalds (cramfs tester and unarchive program)
21 * 2000/06/03: Daniel Quinlan (CRC and length checking program)
22 * 2000/06/04: Daniel Quinlan (merged programs, added options, support
23 * for special files, preserve permissions and
24 * ownership, cramfs superblock v2, bogus mode
25 * test, pathname length test, etc.)
26 * 2000/06/06: Daniel Quinlan (support for holes, pretty-printing,
27 * symlink size test)
28 * 2000/07/11: Daniel Quinlan (file length tests, start at offset 0 or 512,
29 * fsck-compatible exit codes)
30 * 2000/07/15: Daniel Quinlan (initial support for block devices)
31 * 2002/01/10: Daniel Quinlan (additional checks, test more return codes,
32 * use read if mmap fails, standardize messages)
33 */
34
35/* compile-time options */
36#define INCLUDE_FS_TESTS /* include cramfs checking and extraction */
37
38#define _GNU_SOURCE
39#include <sys/types.h>
40#include <stdio.h>
41#include <stdarg.h>
42#include <sys/stat.h>
43#include <unistd.h>
44#include <sys/mman.h>
45#include <fcntl.h>
46#include <dirent.h>
47#include <stdlib.h>
48#include <errno.h>
49#include <string.h>
50#include <sys/sysmacros.h>
51#include <utime.h>
52#include <sys/ioctl.h>
53#define _LINUX_STRING_H_
54#include <linux/fs.h>
55#include <linux/cramfs_fs.h>
56#include <zlib.h>
57
58/* Exit codes used by fsck-type programs */
59#define FSCK_OK 0 /* No errors */
60#define FSCK_NONDESTRUCT 1 /* File system errors corrected */
61#define FSCK_REBOOT 2 /* System should be rebooted */
62#define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */
63#define FSCK_ERROR 8 /* Operational error */
64#define FSCK_USAGE 16 /* Usage or syntax error */
65#define FSCK_LIBRARY 128 /* Shared library error */
66
67#define PAD_SIZE 512
68
69#define PAGE_CACHE_SIZE page_size
70
71static const char *progname = "cramfsck";
72
73static int fd; /* ROM image file descriptor */
74static char *filename; /* ROM image filename */
75struct cramfs_super super; /* just find the cramfs superblock once */
76static int opt_verbose = 0; /* 1 = verbose (-v), 2+ = very verbose (-vv) */
77#ifdef INCLUDE_FS_TESTS
78static int opt_extract = 0; /* extract cramfs (-x) */
79static char *extract_dir = "root"; /* extraction directory (-x) */
80static uid_t euid; /* effective UID */
81
82/* (cramfs_super + start) <= start_dir < end_dir <= start_data <= end_data */
83static unsigned long start_dir = ~0UL; /* start of first non-root inode */
84static unsigned long end_dir = 0; /* end of the directory structure */
85static unsigned long start_data = ~0UL; /* start of the data (256 MB = max) */
86static unsigned long end_data = 0; /* end of the data */
87
88/* Guarantee access to at least 8kB at a time */
89#define ROMBUFFER_BITS 13
90#define ROMBUFFERSIZE (1 << ROMBUFFER_BITS)
91#define ROMBUFFERMASK (ROMBUFFERSIZE-1)
92static char read_buffer[ROMBUFFERSIZE * 2];
93static unsigned long read_buffer_block = ~0UL;
94
95/* Uncompressing data structures... */
96static char *outbuffer;
97static z_stream stream;
98
99static size_t page_size;
100
101/* Prototypes */
102static void expand_fs(char *, struct cramfs_inode *);
103#endif /* INCLUDE_FS_TESTS */
104
105/* Input status of 0 to print help and exit without an error. */
106static void usage(int status)
107{
108 FILE *stream = status ? stderr : stdout;
109
110 fprintf(stream, "usage: %s [-hv] [-x dir] file\n"
111 " -h print this help\n"
112 " -x dir extract into dir\n"
113 " -v be more verbose\n"
114 " file file to test\n", progname);
115
116 exit(status);
117}
118
119static void die(int status, int syserr, const char *fmt, ...)
120{
121 va_list arg_ptr;
122 int save = errno;
123
124 fflush(0);
125 va_start(arg_ptr, fmt);
126 fprintf(stderr, "%s: ", progname);
127 vfprintf(stderr, fmt, arg_ptr);
128 if (syserr) {
129 fprintf(stderr, ": %s", strerror(save));
130 }
131 fprintf(stderr, "\n");
132 va_end(arg_ptr);
133 exit(status);
134}
135
136static void test_super(int *start, size_t *length) {
137 struct stat st;
138
139 /* find the physical size of the file or block device */
140 if (stat(filename, &st) < 0) {
141 die(FSCK_ERROR, 1, "stat failed: %s", filename);
142 }
143 fd = open(filename, O_RDONLY);
144 if (fd < 0) {
145 die(FSCK_ERROR, 1, "open failed: %s", filename);
146 }
147 if (S_ISBLK(st.st_mode)) {
148 if (ioctl(fd, BLKGETSIZE, length) < 0) {
149 die(FSCK_ERROR, 1, "ioctl failed: unable to determine device size: %s", filename);
150 }
151 *length = *length * 512;
152 }
153 else if (S_ISREG(st.st_mode)) {
154 *length = st.st_size;
155 }
156 else {
157 die(FSCK_ERROR, 0, "not a block device or file: %s", filename);
158 }
159
160 if (*length < sizeof(struct cramfs_super)) {
161 die(FSCK_UNCORRECTED, 0, "file length too short");
162 }
163
164 /* find superblock */
165 if (read(fd, &super, sizeof(super)) != sizeof(super)) {
166 die(FSCK_ERROR, 1, "read failed: %s", filename);
167 }
168 if (super.magic == CRAMFS_MAGIC) {
169 *start = 0;
170 }
171 else if (*length >= (PAD_SIZE + sizeof(super))) {
172 lseek(fd, PAD_SIZE, SEEK_SET);
173 if (read(fd, &super, sizeof(super)) != sizeof(super)) {
174 die(FSCK_ERROR, 1, "read failed: %s", filename);
175 }
176 if (super.magic == CRAMFS_MAGIC) {
177 *start = PAD_SIZE;
178 }
179 }
180
181 /* superblock tests */
182 if (super.magic != CRAMFS_MAGIC) {
183 die(FSCK_UNCORRECTED, 0, "superblock magic not found");
184 }
185 if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
186 die(FSCK_ERROR, 0, "unsupported filesystem features");
187 }
188 if (super.size < PAGE_CACHE_SIZE) {
189 die(FSCK_UNCORRECTED, 0, "superblock size (%d) too small", super.size);
190 }
191 if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
192 if (super.fsid.files == 0) {
193 die(FSCK_UNCORRECTED, 0, "zero file count");
194 }
195 if (*length < super.size) {
196 die(FSCK_UNCORRECTED, 0, "file length too short");
197 }
198 else if (*length > super.size) {
199 fprintf(stderr, "warning: file extends past end of filesystem\n");
200 }
201 }
202 else {
203 fprintf(stderr, "warning: old cramfs format\n");
204 }
205}
206
207static void test_crc(int start)
208{
209 void *buf;
210 u32 crc;
211
212 if (!(super.flags & CRAMFS_FLAG_FSID_VERSION_2)) {
213#ifdef INCLUDE_FS_TESTS
214 return;
215#else /* not INCLUDE_FS_TESTS */
216 die(FSCK_USAGE, 0, "unable to test CRC: old cramfs format");
217#endif /* not INCLUDE_FS_TESTS */
218 }
219
220 crc = crc32(0L, Z_NULL, 0);
221
222 buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
223 if (buf == MAP_FAILED) {
224 buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
225 if (buf != MAP_FAILED) {
226 lseek(fd, 0, SEEK_SET);
227 read(fd, buf, super.size);
228 }
229 }
230 if (buf != MAP_FAILED) {
231 ((struct cramfs_super *) (buf+start))->fsid.crc = crc32(0L, Z_NULL, 0);
232 crc = crc32(crc, buf+start, super.size-start);
233 munmap(buf, super.size);
234 }
235 else {
236 int retval;
237 size_t length = 0;
238
239 buf = malloc(4096);
240 if (!buf) {
241 die(FSCK_ERROR, 1, "malloc failed");
242 }
243 lseek(fd, start, SEEK_SET);
244 for (;;) {
245 retval = read(fd, buf, 4096);
246 if (retval < 0) {
247 die(FSCK_ERROR, 1, "read failed: %s", filename);
248 }
249 else if (retval == 0) {
250 break;
251 }
252 if (length == 0) {
253 ((struct cramfs_super *) buf)->fsid.crc = crc32(0L, Z_NULL, 0);
254 }
255 length += retval;
256 if (length > (super.size-start)) {
257 crc = crc32(crc, buf, retval - (length - (super.size-start)));
258 break;
259 }
260 crc = crc32(crc, buf, retval);
261 }
262 free(buf);
263 }
264
265 if (crc != super.fsid.crc) {
266 die(FSCK_UNCORRECTED, 0, "crc error");
267 }
268}
269
270#ifdef INCLUDE_FS_TESTS
271static void print_node(char type, struct cramfs_inode *i, char *name)
272{
273 char info[10];
274
275 if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) {
276 /* major/minor numbers can be as high as 2^12 or 4096 */
277 snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size));
278 }
279 else {
280 /* size be as high as 2^24 or 16777216 */
281 snprintf(info, 10, "%9d", i->size);
282 }
283
284 printf("%c %04o %s %5d:%-3d %s\n",
285 type, i->mode & ~S_IFMT, info, i->uid, i->gid, name);
286}
287
288/*
289 * Create a fake "blocked" access
290 */
291static void *romfs_read(unsigned long offset)
292{
293 unsigned int block = offset >> ROMBUFFER_BITS;
294 if (block != read_buffer_block) {
295 read_buffer_block = block;
296 lseek(fd, block << ROMBUFFER_BITS, SEEK_SET);
297 read(fd, read_buffer, ROMBUFFERSIZE * 2);
298 }
299 return read_buffer + (offset & ROMBUFFERMASK);
300}
301
302static struct cramfs_inode *cramfs_iget(struct cramfs_inode * i)
303{
304 struct cramfs_inode *inode = malloc(sizeof(struct cramfs_inode));
305
306 if (!inode) {
307 die(FSCK_ERROR, 1, "malloc failed");
308 }
309 *inode = *i;
310 return inode;
311}
312
313static struct cramfs_inode *iget(unsigned int ino)
314{
315 return cramfs_iget(romfs_read(ino));
316}
317
318static void iput(struct cramfs_inode *inode)
319{
320 free(inode);
321}
322
323/*
324 * Return the offset of the root directory
325 */
326static struct cramfs_inode *read_super(void)
327{
328 unsigned long offset = super.root.offset << 2;
329
330 if (!S_ISDIR(super.root.mode))
331 die(FSCK_UNCORRECTED, 0, "root inode is not directory");
332 if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
333 ((offset != sizeof(struct cramfs_super)) &&
334 (offset != PAD_SIZE + sizeof(struct cramfs_super))))
335 {
336 die(FSCK_UNCORRECTED, 0, "bad root offset (%lu)", offset);
337 }
338 return cramfs_iget(&super.root);
339}
340
341static int uncompress_block(void *src, int len)
342{
343 int err;
344
345 stream.next_in = src;
346 stream.avail_in = len;
347
348 stream.next_out = (unsigned char *) outbuffer;
349 stream.avail_out = PAGE_CACHE_SIZE*2;
350
351 inflateReset(&stream);
352
353 if (len > PAGE_CACHE_SIZE*2) {
354 die(FSCK_UNCORRECTED, 0, "data block too large");
355 }
356 err = inflate(&stream, Z_FINISH);
357 if (err != Z_STREAM_END) {
358 die(FSCK_UNCORRECTED, 0, "decompression error %p(%d): %s",
359 zError(err), src, len);
360 }
361 return stream.total_out;
362}
363
364static void do_uncompress(char *path, int fd, unsigned long offset, unsigned long size)
365{
366 unsigned long curr = offset + 4 * ((size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE);
367
368 do {
369 unsigned long out = PAGE_CACHE_SIZE;
370 unsigned long next = *(u32 *) romfs_read(offset);
371
372 if (next > end_data) {
373 end_data = next;
374 }
375
376 offset += 4;
377 if (curr == next) {
378 if (opt_verbose > 1) {
379 printf(" hole at %ld (%d)\n", curr, PAGE_CACHE_SIZE);
380 }
381 if (size < PAGE_CACHE_SIZE)
382 out = size;
383 memset(outbuffer, 0x00, out);
384 }
385 else {
386 if (opt_verbose > 1) {
387 printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr);
388 }
389 out = uncompress_block(romfs_read(curr), next - curr);
390 }
391 if (size >= PAGE_CACHE_SIZE) {
392 if (out != PAGE_CACHE_SIZE) {
393 die(FSCK_UNCORRECTED, 0, "non-block (%ld) bytes", out);
394 }
395 } else {
396 if (out != size) {
397 die(FSCK_UNCORRECTED, 0, "non-size (%ld vs %ld) bytes", out, size);
398 }
399 }
400 size -= out;
401 if (opt_extract) {
402 if (write(fd, outbuffer, out) < 0) {
403 die(FSCK_ERROR, 1, "write failed: %s", path);
404 }
405 }
406 curr = next;
407 } while (size);
408}
409
410static void change_file_status(char *path, struct cramfs_inode *i)
411{
412 struct utimbuf epoch = { 0, 0 };
413
414 if (euid == 0) {
415 if (lchown(path, i->uid, i->gid) < 0) {
416 die(FSCK_ERROR, 1, "lchown failed: %s", path);
417 }
418 if (S_ISLNK(i->mode))
419 return;
420 if ((S_ISUID | S_ISGID) & i->mode) {
421 if (chmod(path, i->mode) < 0) {
422 die(FSCK_ERROR, 1, "chown failed: %s", path);
423 }
424 }
425 }
426 if (S_ISLNK(i->mode))
427 return;
428 if (utime(path, &epoch) < 0) {
429 die(FSCK_ERROR, 1, "utime failed: %s", path);
430 }
431}
432
433static void do_directory(char *path, struct cramfs_inode *i)
434{
435 int pathlen = strlen(path);
436 int count = i->size;
437 unsigned long offset = i->offset << 2;
438 char *newpath = malloc(pathlen + 256);
439
440 if (!newpath) {
441 die(FSCK_ERROR, 1, "malloc failed");
442 }
443 if (offset == 0 && count != 0) {
444 die(FSCK_UNCORRECTED, 0, "directory inode has zero offset and non-zero size: %s", path);
445 }
446 if (offset != 0 && offset < start_dir) {
447 start_dir = offset;
448 }
449 /* TODO: Do we need to check end_dir for empty case? */
450 memcpy(newpath, path, pathlen);
451 newpath[pathlen] = '/';
452 pathlen++;
453 if (opt_verbose) {
454 print_node('d', i, path);
455 }
456 if (opt_extract) {
457 if (mkdir(path, i->mode) < 0) {
458 die(FSCK_ERROR, 1, "mkdir failed: %s", path);
459 }
460 change_file_status(path, i);
461 }
462 while (count > 0) {
463 struct cramfs_inode *child = iget(offset);
464 int size;
465 int newlen = child->namelen << 2;
466
467 size = sizeof(struct cramfs_inode) + newlen;
468 count -= size;
469
470 offset += sizeof(struct cramfs_inode);
471
472 memcpy(newpath + pathlen, romfs_read(offset), newlen);
473 newpath[pathlen + newlen] = 0;
474 if (newlen == 0) {
475 die(FSCK_UNCORRECTED, 0, "filename length is zero");
476 }
477 if ((pathlen + newlen) - strlen(newpath) > 3) {
478 die(FSCK_UNCORRECTED, 0, "bad filename length");
479 }
480 expand_fs(newpath, child);
481
482 offset += newlen;
483
484 if (offset <= start_dir) {
485 die(FSCK_UNCORRECTED, 0, "bad inode offset");
486 }
487 if (offset > end_dir) {
488 end_dir = offset;
489 }
490 iput(child); /* free(child) */
491 }
492 free(newpath);
493}
494
495static void do_file(char *path, struct cramfs_inode *i)
496{
497 unsigned long offset = i->offset << 2;
498 int fd = 0;
499
500 if (offset == 0 && i->size != 0) {
501 die(FSCK_UNCORRECTED, 0, "file inode has zero offset and non-zero size");
502 }
503 if (i->size == 0 && offset != 0) {
504 die(FSCK_UNCORRECTED, 0, "file inode has zero size and non-zero offset");
505 }
506 if (offset != 0 && offset < start_data) {
507 start_data = offset;
508 }
509 if (opt_verbose) {
510 print_node('f', i, path);
511 }
512 if (opt_extract) {
513 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, i->mode);
514 if (fd < 0) {
515 die(FSCK_ERROR, 1, "open failed: %s", path);
516 }
517 }
518 if (i->size) {
519 do_uncompress(path, fd, offset, i->size);
520 }
521 if (opt_extract) {
522 close(fd);
523 change_file_status(path, i);
524 }
525}
526
527static void do_symlink(char *path, struct cramfs_inode *i)
528{
529 unsigned long offset = i->offset << 2;
530 unsigned long curr = offset + 4;
531 unsigned long next = *(u32 *) romfs_read(offset);
532 unsigned long size;
533
534 if (offset == 0) {
535 die(FSCK_UNCORRECTED, 0, "symbolic link has zero offset");
536 }
537 if (i->size == 0) {
538 die(FSCK_UNCORRECTED, 0, "symbolic link has zero size");
539 }
540
541 if (offset < start_data) {
542 start_data = offset;
543 }
544 if (next > end_data) {
545 end_data = next;
546 }
547
548 size = uncompress_block(romfs_read(curr), next - curr);
549 if (size != i->size) {
550 die(FSCK_UNCORRECTED, 0, "size error in symlink: %s", path);
551 }
552 outbuffer[size] = 0;
553 if (opt_verbose) {
554 char *str;
555
556 asprintf(&str, "%s -> %s", path, outbuffer);
557 print_node('l', i, str);
558 if (opt_verbose > 1) {
559 printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr);
560 }
561 free(str);
562 }
563 if (opt_extract) {
564 if (symlink(outbuffer, path) < 0) {
565 die(FSCK_ERROR, 1, "symlink failed: %s", path);
566 }
567 change_file_status(path, i);
568 }
569}
570
571static void do_special_inode(char *path, struct cramfs_inode *i)
572{
573 dev_t devtype = 0;
574 char type;
575
576 if (i->offset) { /* no need to shift offset */
577 die(FSCK_UNCORRECTED, 0, "special file has non-zero offset: %s", path);
578 }
579 if (S_ISCHR(i->mode)) {
580 devtype = i->size;
581 type = 'c';
582 }
583 else if (S_ISBLK(i->mode)) {
584 devtype = i->size;
585 type = 'b';
586 }
587 else if (S_ISFIFO(i->mode)) {
588 if (i->size != 0) {
589 die(FSCK_UNCORRECTED, 0, "fifo has non-zero size: %s", path);
590 }
591 type = 'p';
592 }
593 else if (S_ISSOCK(i->mode)) {
594 if (i->size != 0) {
595 die(FSCK_UNCORRECTED, 0, "socket has non-zero size: %s", path);
596 }
597 type = 's';
598 }
599 else {
600 die(FSCK_UNCORRECTED, 0, "bogus mode: %s (%o)", path, i->mode);
601 return; /* not reached */
602 }
603
604 if (opt_verbose) {
605 print_node(type, i, path);
606 }
607
608 if (opt_extract) {
609 if (mknod(path, i->mode, devtype) < 0) {
610 die(FSCK_ERROR, 1, "mknod failed: %s", path);
611 }
612 change_file_status(path, i);
613 }
614}
615
616static void expand_fs(char *path, struct cramfs_inode *inode)
617{
618 if (S_ISDIR(inode->mode)) {
619 do_directory(path, inode);
620 }
621 else if (S_ISREG(inode->mode)) {
622 do_file(path, inode);
623 }
624 else if (S_ISLNK(inode->mode)) {
625 do_symlink(path, inode);
626 }
627 else {
628 do_special_inode(path, inode);
629 }
630}
631
632static void test_fs(int start)
633{
634 struct cramfs_inode *root;
635
636 root = read_super();
637 umask(0);
638 euid = geteuid();
639 stream.next_in = NULL;
640 stream.avail_in = 0;
641 inflateInit(&stream);
642 expand_fs(extract_dir, root);
643 inflateEnd(&stream);
644 if (start_data != ~0UL) {
645 if (start_data < (sizeof(struct cramfs_super) + start)) {
646 die(FSCK_UNCORRECTED, 0, "directory data start (%ld) < sizeof(struct cramfs_super) + start (%ld)", start_data, sizeof(struct cramfs_super) + start);
647 }
648 if (end_dir != start_data) {
649 die(FSCK_UNCORRECTED, 0, "directory data end (%ld) != file data start (%ld)", end_dir, start_data);
650 }
651 }
652 if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {
653 if (end_data > super.size) {
654 die(FSCK_UNCORRECTED, 0, "invalid file data offset");
655 }
656 }
657 iput(root); /* free(root) */
658}
659#endif /* INCLUDE_FS_TESTS */
660
661int main(int argc, char **argv)
662{
663 int c; /* for getopt */
664 int start = 0;
665 size_t length;
666
667 page_size = sysconf(_SC_PAGESIZE);
668
669 if (argc)
670 progname = argv[0];
671
672 outbuffer = malloc(page_size * 2);
673 if (!outbuffer)
674 die(FSCK_ERROR, 1, "failed to allocate outbuffer");
675
676 /* command line options */
677 while ((c = getopt(argc, argv, "hx:v")) != EOF) {
678 switch (c) {
679 case 'h':
680 usage(FSCK_OK);
681 case 'x':
682#ifdef INCLUDE_FS_TESTS
683 opt_extract = 1;
684 extract_dir = optarg;
685 break;
686#else /* not INCLUDE_FS_TESTS */
687 die(FSCK_USAGE, 0, "compiled without -x support");
688#endif /* not INCLUDE_FS_TESTS */
689 case 'v':
690 opt_verbose++;
691 break;
692 }
693 }
694
695 if ((argc - optind) != 1)
696 usage(FSCK_USAGE);
697 filename = argv[optind];
698
699 test_super(&start, &length);
700 test_crc(start);
701#ifdef INCLUDE_FS_TESTS
702 test_fs(start);
703#endif /* INCLUDE_FS_TESTS */
704
705 if (opt_verbose) {
706 printf("%s: OK\n", filename);
707 }
708
709 exit(FSCK_OK);
710}
711
712/*
713 * Local variables:
714 * c-file-style: "linux"
715 * End:
716 */