4 #include "fsck.cmdline.h"
6 static struct fsck_args_info conf
;
9 INIT_STDERR_LOGGING(conf
.loglevel_arg
);
12 signed char hexval_table
[256] = {
13 -1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
14 -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
15 -1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */
16 -1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */
17 -1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */
18 -1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */
19 0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
20 8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */
21 -1, 10, 11, 12, 13, 14, 15, -1, /* 40-47 */
22 -1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */
23 -1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */
24 -1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */
25 -1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */
26 -1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */
27 -1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */
28 -1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */
29 -1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */
30 -1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */
31 -1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */
32 -1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */
33 -1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */
34 -1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */
35 -1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */
36 -1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */
37 -1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */
38 -1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */
39 -1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */
40 -1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */
41 -1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */
42 -1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */
43 -1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */
44 -1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
47 int asc_to_hash(const char *asc_hash
, int len
, HASH_TYPE
*hash
)
50 const unsigned char *asc
= (const unsigned char *) asc_hash
;
52 while (*asc
&& i
++ < len
) {
53 unsigned int val
= (hexval_table
[asc
[0]] << 4) | hexval_table
[asc
[1]];
64 * check for object boundary violations
66 * test whether the range pointed to by the index entry for a given cell is
67 * contained in mapped data file. This should always be the case. Otherwise
68 * we are in real trouble.
70 static int check_range(struct osl_table
*t
, uint32_t row_num
, uint32_t col_num
)
73 struct osl_object obj
;
74 struct osl_column
*col
;
76 char *map_start
, *obj_start
;
78 ret
= get_cell_index(t
, row_num
, col_num
, &index_entry
);
81 ret
= get_mapped_object(t
, col_num
, row_num
, &obj
);
84 col
= t
->columns
+ col_num
;
86 map_start
= col
->data_map
.data
;
87 // PARA_INFO_LOG("obj: %p..%p\n", obj_start, obj_start + obj.size);
88 // PARA_INFO_LOG("map: %p..%p\n", map_start, map_start + col->data_map.size);
89 if (obj_start
< map_start
|| obj_start
+ obj
.size
> map_start
+ col
->data_map
.size
) {
90 PARA_CRIT_LOG("range violation in row %u, col %u\n", row_num
,
92 return -E_RANGE_VIOLATION
;
94 PARA_DEBUG_LOG("col %u: ok\n", col_num
);
99 * check all cells of the given table for boundary violations
101 static int check_index_ranges(struct osl_table
*t
)
105 PARA_NOTICE_LOG("checking for range violations in index\n");
106 //PARA_DEBUG_LOG("%d rows. %d columns\n", t->num_rows, t->desc->num_columns);
107 t
->num_invalid_rows
= 0;
108 for (i
= 0; i
< t
->num_rows
; i
++) {
109 if (row_is_invalid(t
, i
)) {
110 t
->num_invalid_rows
++;
113 for (j
= 0; j
< t
->desc
->num_columns
; j
++) { /* FXIME */
114 const struct osl_column_description
*cd
=
115 get_column_description(t
->desc
, j
);
116 if (cd
->storage_type
!= OSL_MAPPED_STORAGE
)
118 ret
= check_range(t
, i
, j
);
120 if (ret
!= -E_INVALID_OBJECT
&&
121 ret
!= -E_RANGE_VIOLATION
)
123 if (ret
== -E_INVALID_OBJECT
) {
124 PARA_CRIT_LOG("row %d, col %d maps to an "
125 "invalid object\n", i
, j
);
127 ret
= mark_row_invalid(t
, i
);
130 t
->num_invalid_rows
++;
136 if (t
->num_invalid_rows
)
137 PARA_NOTICE_LOG("ranges OK. %d invalid row(s) detected\n",
138 t
->num_invalid_rows
);
140 PARA_INFO_LOG("no invalid rows, no range violations, good\n");
146 static int move_index_entry(struct osl_table
*t
, uint32_t dest
, uint32_t src
)
148 char *dest_ie
, *src_ie
;
149 int ret
= get_row_index(t
, dest
, &dest_ie
);
153 ret
= get_row_index(t
, src
, &src_ie
);
156 PARA_INFO_LOG("moving entry #%u to position %u\n", src
, dest
);
157 memcpy(dest_ie
, src_ie
, t
->row_index_size
);
161 static int map_index(const struct osl_table_description
*desc
, struct osl_object
*map
)
163 char *filename
= index_filename(desc
);
166 ret
= mmap_full_file(filename
, O_RDWR
, map
);
167 PARA_INFO_LOG("mapping index %s: ret: %d, size: %zu\n", filename
, ret
, map
->size
);
172 static int prune_invalid_rows_from_index(struct osl_table
*t
)
174 uint32_t top
= 0, bottom
;
178 if (!t
->num_invalid_rows
) {
179 PARA_INFO_LOG("all rows are valid, good\n");
182 PARA_NOTICE_LOG("deleting %u invalid row(s) (%d bytes) from index\n",
183 t
->num_invalid_rows
, t
->row_index_size
* t
->num_invalid_rows
);
184 bottom
= t
->num_rows
- 1;
185 while (top
< bottom
) {
186 if (!row_is_invalid(t
, top
)) {
190 while (bottom
> top
) {
191 if (row_is_invalid(t
, bottom
)) {
195 /* move bottom index entry to top */
196 move_index_entry(t
, top
, bottom
);
202 PARA_INFO_LOG("unmapping index\n");
203 para_munmap(t
->index_map
.data
, t
->index_map
.size
);
204 filename
= index_filename(t
->desc
);
205 ret
= para_truncate(filename
, t
->row_index_size
206 * t
->num_invalid_rows
);
210 ret
= map_index(t
->desc
, &t
->index_map
);
213 t
->num_rows
= table_num_rows(t
);
217 static int check_for_invalid_objects(struct osl_table
*t
, uint32_t **lost_bytes
)
220 const struct osl_column_description
*cd
;
221 uint32_t *loss
= para_malloc(sizeof(uint32_t) * t
->desc
->num_columns
);
223 PARA_NOTICE_LOG("looking for mapped objects not contained in index\n");
224 /* first count used bytes */
225 FOR_EACH_MAPPED_COLUMN(i
, t
, cd
) {
226 loss
[i
] = t
->columns
[i
].data_map
.size
;
227 for (j
= 0; j
< t
->num_rows
; j
++) {
228 struct osl_object obj
;
229 ret
= get_mapped_object(t
, i
, j
, &obj
);
231 loss
[i
] -= obj
.size
+ 1; /* add one for header byte */
234 if (ret
!= -E_INVALID_OBJECT
)
236 PARA_CRIT_LOG("row %d, col %d points to an invalid "
237 "mapped object, bad\n", j
, i
);
241 FOR_EACH_MAPPED_COLUMN(i
, t
, cd
) {
243 PARA_NOTICE_LOG("column %u contains %u lost bytes\n",
249 PARA_INFO_LOG("all mapped objects are valid, good\n");
257 /* prune_invalid_rows() must be run on the table before calling this */
258 static int prune_mapped_column(struct osl_table
*t
, uint32_t col_num
, int fd
)
261 uint32_t written
= 0;
262 struct osl_column
*col
= t
->columns
+ col_num
;
264 PARA_INFO_LOG("pruning col %u\n", col_num
);
265 for (i
= 0; i
< t
->num_rows
; i
++) {
266 struct osl_object obj
;
269 PARA_DEBUG_LOG("checking row %u/%u\n", i
, t
->num_rows
);
270 ret
= get_mapped_object(t
, col_num
, i
, &obj
);
273 ret
= para_write_all(fd
, (char *)(obj
.data
) - 1, obj
.size
+ 1);
276 written
+= obj
.size
+ 1;
277 ret
= get_row_index(t
, i
, &index_entry
);
280 update_cell_index(index_entry
, col
, written
, obj
.size
);
285 static int prune_objects(struct osl_table
*t
, uint32_t *lost_bytes
)
288 const struct osl_column_description
*cd
;
289 char **col_filenames
= para_calloc(t
->desc
->num_columns
* sizeof(char *));
290 char **new_col_filenames
= para_calloc(t
->desc
->num_columns
* sizeof(char *));
291 char *idx_filename
= index_filename(t
->desc
);
292 char *old_idx_filename
= make_message("%s.bak", idx_filename
);
295 PARA_NOTICE_LOG("removing unreferenced objects from data files\n");
296 /* first make a copy of the index */
297 ret
= para_open(old_idx_filename
, O_WRONLY
| O_CREAT
| O_EXCL
, 0644);
301 ret
= para_write_all(fd
, t
->index_map
.data
, t
->index_map
.size
);
305 FOR_EACH_MAPPED_COLUMN(i
, t
, cd
) {
308 col_filenames
[i
] = column_filename(t
, i
);
309 new_col_filenames
[i
] = make_message("%s.fsck", col_filenames
[i
]);
310 ret
= para_open(new_col_filenames
[i
], O_WRONLY
| O_CREAT
| O_EXCL
, 0644);
312 goto out_unlink_data
;
314 ret
= prune_mapped_column(t
, i
, fd
);
317 goto out_unlink_data
;
319 ret
= unmap_table(t
, OSL_MARK_CLEAN
);
321 goto out_unlink_data
;
322 FOR_EACH_MAPPED_COLUMN(i
, t
, cd
) {
325 ret
= para_rename(new_col_filenames
[i
], col_filenames
[i
]);
326 if (ret
< 0) { /* we're kinda screwed here */
327 PARA_CRIT_LOG("rename of col %i failed: %s\n", i
,
332 unlink(old_idx_filename
);
333 ret
= map_table(t
, 0);
336 FOR_EACH_MAPPED_COLUMN(i
, t
, cd
)
337 unlink(new_col_filenames
[i
]);
339 free(old_idx_filename
);
341 FOR_EACH_MAPPED_COLUMN(i
, t
, cd
) {
342 free(col_filenames
[i
]);
343 free(new_col_filenames
[i
]);
346 free(new_col_filenames
);
350 static struct osl_column_description hash_tree_table_cols
[] = {
352 .storage_type
= OSL_NO_STORAGE
,
353 .storage_flags
= OSL_RBTREE
| OSL_FIXED_SIZE
| OSL_UNIQUE
,
355 .compare_function
= uint32_compare
,
356 .data_size
= HASH_SIZE
360 static const struct osl_table_description hash_tree_table_desc
= {
361 .dir
= "/", /* irrelevant */
365 .column_descriptions
= hash_tree_table_cols
369 * The hash_tree table contains all hashes of the disk storage name column.
370 * of each row. It is used for checking if a disk storage file has a reference
373 static struct osl_table
*hash_tree_table
;
374 static HASH_TYPE
*hashes
;
376 static int check_disk_storage_column(struct osl_table
*t
, int row_num
,
377 int col_num
, char *ds_name
, unsigned *num_missing_objects
)
381 char *path
= disk_storage_path(t
, col_num
, ds_name
);
382 unsigned dsnc
= t
->disk_storage_name_column
;
383 struct osl_object obj
;
385 PARA_DEBUG_LOG("checking if %s is a regular file\n", path
);
386 ret
= stat(path
, &statbuf
);
387 if (ret
< 0 && errno
== ENOENT
) {
389 (*num_missing_objects
)++;
390 PARA_ERROR_LOG("row %d: object %s is missing\n", row_num
, path
);
391 PARA_NOTICE_LOG("trying to delete row %d\n", row_num
);
392 ret
= osl_get_row(t
, dsnc
, &obj
, &row
);
394 PARA_CRIT_LOG("unable to get row %d\n", row_num
);
395 mark_row_invalid(t
, row_num
);
396 PARA_CRIT_LOG("Please re-run fsck\n");
399 ret
= osl_del_row(t
, row
);
407 ret
= -E_NOT_A_REGULAR_FILE
;
408 if (!(S_IFREG
& statbuf
.st_mode
))
413 static int check_disk_storage_presence(struct osl_table
*t
)
416 struct osl_object obj
, hash_obj
= {.size
= HASH_SIZE
};
418 const struct osl_column_description
*cd
;
419 unsigned dsnc
= t
->disk_storage_name_column
, missing_objects
= 0;
423 hashes
= para_malloc(t
->num_rows
* HASH_SIZE
);
424 PARA_NOTICE_LOG("looking for missing disk storage objects\n");
425 for (i
= 0; i
< t
->num_rows
; i
++) {
426 if (row_is_invalid(t
, i
))
428 ret
= get_mapped_object(t
, dsnc
, i
, &obj
);
431 hash_object(&obj
, hashes
+ i
* HASH_SIZE
);
432 hash_obj
.data
= hashes
+ i
* HASH_SIZE
;
433 osl_add_row(hash_tree_table
, &hash_obj
);
434 ds_name
= disk_storage_name_of_hash(t
, hashes
+ i
* HASH_SIZE
);
435 FOR_EACH_DISK_STORAGE_COLUMN(j
, t
, cd
) {
436 ret
= check_disk_storage_column(t
, i
, j
, ds_name
,
443 if (!missing_objects
)
444 PARA_INFO_LOG("all referenced disk storage objects exist, good\n");
446 PARA_NOTICE_LOG("%d missing object(s)\n", missing_objects
);
447 return missing_objects
;
453 static int dummy_compare(const struct osl_object
*obj1
, const struct osl_object
*obj2
)
462 static unsigned files_pruned
;
464 int prune_disk_storage_file(const char *path
, const void *private_data
)
466 HASH_TYPE hash
[HASH_SIZE
];
467 unsigned flags
= *(unsigned *)private_data
;
468 struct osl_object obj
= {.data
= hash
, .size
= HASH_SIZE
};
471 size_t len
= strlen(path
);
474 PARA_DEBUG_LOG("path: %s\n", path
);
475 if (flags
& OSL_LARGE_TABLE
) {
476 if (len
< HASH_SIZE
* 2 + 2)
478 // PARA_NOTICE_LOG("p: %s\n", path + len - 2 * HASH_SIZE - 1);
479 ret
= asc_to_hash(path
+ len
- 2 * HASH_SIZE
- 1, 1, hash
);
482 ret
= asc_to_hash(path
+ len
- 2 * HASH_SIZE
+ 2, HASH_SIZE
- 1,
486 // PARA_INFO_LOG("high: %x, low: %x, hash: %x\n", high, low, hash);
488 if (len
< 2 * HASH_SIZE
+ 1)
490 ret
= asc_to_hash(path
+ len
- 2 * HASH_SIZE
, 2 * HASH_SIZE
, hash
);
493 // PARA_INFO_LOG("hash: %x\n", hash);
497 char asc
[2 * HASH_SIZE
+ 1];
498 hash_to_asc(hash
, asc
);
499 PARA_NOTICE_LOG("before: %s\nafter: %s\n", path
, asc
);
502 ret
= osl_get_row(hash_tree_table
, 0, &obj
, &row
);
505 PARA_NOTICE_LOG("unreferenced file in hash dir: %s\n", path
);
508 PARA_ERROR_LOG("could not read hash value of %s\n", path
);
510 PARA_NOTICE_LOG("removing %s\n", path
);
516 static int prune_disk_storage_files(struct osl_table
*t
)
519 const struct osl_column_description
*cd
;
521 PARA_NOTICE_LOG("looking for unreferenced disk storage files\n");
522 FOR_EACH_DISK_STORAGE_COLUMN(i
, t
, cd
) {
523 char *dirname
= column_filename(t
, i
);
524 ret
= for_each_file_in_dir(dirname
, prune_disk_storage_file
, &t
->desc
->flags
);
528 PARA_NOTICE_LOG("%u disk storage files deleted\n",
531 PARA_INFO_LOG("all files are are referenced, good\n");
535 static int check_disk_storage_columns(struct osl_table
*t
)
538 const struct osl_column_description
*cd
;
540 if (!t
->num_disk_storage_columns
) {
541 PARA_NOTICE_LOG("no disk storage columns in table '%s', "
542 "skipping checks\n", t
->desc
->name
);
545 FOR_EACH_COLUMN(i
, t
->desc
, cd
)
546 t
->desc
->column_descriptions
[i
].compare_function
= dummy_compare
;
547 ret
= init_rbtrees(t
);
550 PARA_NOTICE_LOG("creating rbtree for disk storage hash values\n");
551 ret
= osl_open_table(&hash_tree_table_desc
, &hash_tree_table
);
554 ret
= check_disk_storage_presence(t
);
556 goto out_close_hash_tree
;
557 ret
= prune_disk_storage_files(t
);
559 osl_close_table(hash_tree_table
, 0);
562 clear_rbtrees(t
); /* TODO why are we doing that here? Seems odd */
566 static void set_dummy_contents(struct osl_table_description
*desc
)
569 struct osl_column_description
*cd
;
571 for (i
= 0; i
< desc
->num_columns
; i
++) {
572 cd
= get_column_description(desc
, i
);
573 cd
->compare_function
= dummy_compare
;
577 static int fsck_init(struct osl_table_description
*desc
, struct osl_table
**t
)
579 struct osl_object map
;
580 int ret
= map_index(desc
, &map
);
584 ret
= read_table_desc(&map
, desc
);
586 para_munmap(map
.data
, map
.size
);
589 set_dummy_contents(desc
);
590 ret
= init_table_structure(desc
, t
);
592 para_munmap(map
.data
, map
.size
);
595 PARA_INFO_LOG("unmapping index\n");
596 para_munmap(map
.data
, map
.size
);
597 if (conf
.force_given
)
598 ret
= map_table(*t
, (MAP_TBL_FL_IGNORE_DIRTY
));
600 ret
= map_table(*t
, 0);
602 (*t
)->num_rows
= table_num_rows(*t
);
607 static void fsck_cleanup(struct osl_table
*t
)
610 if (t
->desc
->column_descriptions
) {
611 struct osl_column_description
*cd
;
612 for (i
= 0; i
< t
->desc
->num_columns
; i
++) {
613 cd
= get_column_description(t
->desc
, i
);
614 free((char*)cd
->name
);
616 free(t
->desc
->column_descriptions
);
625 #define ST_CASE(st) case st: return #st
627 const char *get_asc_storage_type(enum osl_storage_type st
)
630 ST_CASE(OSL_MAPPED_STORAGE
);
631 ST_CASE(OSL_DISK_STORAGE
);
632 ST_CASE(OSL_NO_STORAGE
);
637 #define APPEND_ASC_SF(sf, flag, str) do { if (sf & flag) { \
638 if (str) str = para_strcat(str, " | " # flag); \
639 else str = para_strdup(#flag); }} while (0)
642 char *get_asc_storage_flags(enum osl_storage_type sf
)
646 APPEND_ASC_SF(sf
, OSL_RBTREE
, asc_sf
);
647 APPEND_ASC_SF(sf
, OSL_FIXED_SIZE
, asc_sf
);
648 APPEND_ASC_SF(sf
, OSL_UNIQUE
, asc_sf
);
652 static int dump_table_desc(struct osl_table
*t
, int fd
)
654 const struct osl_table_description
*desc
= t
->desc
;
656 struct osl_column_description
*cd
;
657 char *msg
= make_message("static struct osl_column_description cols[] = {\n");
658 ret
= para_write_all(fd
, msg
, strlen(msg
));
662 FOR_EACH_COLUMN(i
, desc
, cd
) {
664 msg
= make_message("\t[%d] = {\n", i
);
665 ret
= para_write_all(fd
, msg
, strlen(msg
));
669 asc_st
= get_asc_storage_type(cd
->storage_type
);
670 msg
= make_message("\t\t.storage_type = %s,\n", asc_st
);
671 ret
= para_write_all(fd
, msg
, strlen(msg
));
675 if (cd
->storage_flags
) {
676 char *asc_sf
= get_asc_storage_flags(cd
->storage_flags
);
677 msg
= make_message("\t\t,storage_flags = %s,\n", asc_sf
);
679 ret
= para_write_all(fd
, msg
, strlen(msg
));
684 if (cd
->storage_flags
& OSL_FIXED_SIZE
) {
685 msg
= make_message("\t\t.data_size = %u,\n", cd
->data_size
);
686 ret
= para_write_all(fd
, msg
, strlen(msg
));
691 msg
= make_message("\t\t.name = \"%s\",\n", cd
->name
);
692 ret
= para_write_all(fd
, msg
, strlen(msg
));
696 if (cd
->storage_flags
& OSL_RBTREE
) {
697 msg
= make_message("\t\t.compare_function = compare_func,\n");
698 ret
= para_write_all(fd
, msg
, strlen(msg
));
703 msg
= make_message("\t},\n");
704 ret
= para_write_all(fd
, msg
, strlen(msg
));
709 msg
= make_message("};\n");
710 ret
= para_write_all(fd
, msg
, strlen(msg
));
717 static int dump_row(struct osl_table
*t
, unsigned row_num
, const char *row_dir
)
720 const struct osl_column_description
*cd
;
722 struct osl_object obj
;
724 HASH_TYPE hash
[HASH_SIZE
];
727 FOR_EACH_MAPPED_COLUMN(i
, t
, cd
) {
728 ret
= get_mapped_object(t
, i
, row_num
, &obj
);
731 filename
= make_message("%s/col_%03u", row_dir
, i
);
732 ret
= para_write_file(filename
, obj
.data
, obj
.size
);
737 if (!t
->num_disk_storage_columns
)
739 dsnc
= t
->disk_storage_name_column
;
740 ret
= get_mapped_object(t
, dsnc
, i
, &obj
);
743 hash_object(&obj
, hash
);
744 ds_name
= disk_storage_name_of_hash(t
, hash
);
745 FOR_EACH_DISK_STORAGE_COLUMN(i
, t
, cd
) {
746 filename
= disk_storage_path(t
, i
, ds_name
);
747 ret
= mmap_full_file(filename
, O_RDONLY
, &obj
);
751 filename
= make_message("%s/col_%03u", row_dir
, i
);
752 ret
= para_write_file(filename
, obj
.data
, obj
.size
);
763 static int dump_rows(char *dump_dir
, struct osl_table
*t
)
766 char *current_dir
= NULL
;
769 for (i
= 0; i
< t
->num_rows
; i
++) {
771 if (row_is_invalid(t
, i
))
775 current_dir
= make_message("%s/rows_%u-%u", dump_dir
, i
, i
+ 999);
776 PARA_NOTICE_LOG("dumping rows %u - %u\n", i
, i
+ 999);
777 ret
= para_mkdir(current_dir
, 0777);
781 row_dir
= make_message("%s/row_%03u", current_dir
, i
);
782 ret
= para_mkdir(row_dir
, 0777);
787 ret
= dump_row(t
, i
, row_dir
);
797 static int dump_table(char *dump_dir
, struct osl_table_description
*desc
)
799 struct osl_table
*t
= NULL
;
800 int fd
, ret
= fsck_init(desc
, &t
);
805 ret
= para_mkdir(dump_dir
, 0777);
808 desc_file
= make_message("%s/table_description.c", dump_dir
);
809 ret
= para_open(desc_file
, O_WRONLY
| O_CREAT
| O_EXCL
, 0644);
814 ret
= dump_table_desc(t
, fd
);
818 ret
= dump_rows(dump_dir
, t
);
824 static int fsck(struct osl_table_description
*desc
)
827 struct osl_table
*t
= NULL
;
828 uint32_t *lost_bytes
= NULL
;
830 ret
= fsck_init(desc
, &t
);
833 ret
= check_index_ranges(t
);
836 ret
= check_disk_storage_columns(t
);
839 ret
= prune_invalid_rows_from_index(t
);
842 ret
= check_for_invalid_objects(t
, &lost_bytes
);
845 if (ret
> 0) { /* at least one mapped data file needs pruning */
846 ret
= prune_objects(t
, lost_bytes
);
851 PARA_INFO_LOG("success\n");
853 unmap_table(t
, OSL_MARK_CLEAN
);
859 int main(__a_unused
int argc
, char **argv
)
862 struct osl_table_description desc
= {.column_descriptions
= NULL
};
863 char *base_dir
= NULL
;
865 ret
= fsck_cmdline_parser(argc
, argv
, &conf
);
867 ret
= -E_FSCK_SYNTAX
;
870 HANDLE_VERSION_FLAG("fsck", conf
);
871 if (!conf
.inputs_num
) {
872 /* FIXME: Find all subdirs */
873 ret
= -E_FSCK_SYNTAX
;
876 desc
.dir
= conf
.base_dir_arg
;
877 if (!conf
.base_dir_given
) {
878 char *home
= para_homedir();
879 base_dir
= make_message("%s/.paraslash/afs_database", home
);
883 for (i
= 0; i
< conf
.inputs_num
; i
++) {
884 desc
.name
= conf
.inputs
[i
];
885 if (!conf
.no_fsck_given
) {
890 if (conf
.dump_dir_given
&& *conf
.dump_dir_arg
) {
891 ret
= dump_table(conf
.dump_dir_arg
, &desc
);
900 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret
));
901 return ret
< 0? EXIT_FAILURE
: EXIT_SUCCESS
;