?? ldm.c
字號:
} return tmp;}/** * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one * @block: string to convert * @buffer: output buffer * @buflen: size of output buffer * * This converts @block, a counted, non-null-terminated ASCII string, into a * C-style, null-terminated, ASCII string and returns this in @buffer. The * maximum number of characters converted is given by @buflen. * * The first bytes of a counted string stores the length of the string in bytes. * * Return the number of characters written to @buffer, not including the * terminating null character, on success, and -1 on error, in which case * @buffer is not defined. */static int get_vstr(const u8 *block, u8 *buffer, const int buflen){ int length = block[0]; if (length < 1) return -1; if (length >= buflen) { printk(LDM_ERR "String too long for buffer in get_vstr(): " "(%d/%d). Truncating.\n", length, buflen); length = buflen - 1; } memcpy(buffer, block + 1, length); buffer[length] = (u8)'\0'; return length;}/** * get_disk_objid - obtain the object id for the device we are working on * @dev: partition device holding the LDM database * @vm: in memory vmdb structure of the LDM database * @ph: in memory privhead structure of the device we are working on * @dk: in memory ldmdisk structure to return information into * * This obtains the object id for the device we are working on as defined by * the private header @ph. The obtained object id, together with the disk's * GUID from @ph are returned in the ldmdisk structure pointed to by @dk. * * A Disk has two Ids. The main one is a GUID in string format. The second, * used internally for cross-referencing, is a small, sequentially allocated, * number. The PRIVHEAD, just after the partition table, tells us the disk's * GUID. To find the disk's object id, we have to look through the database. * * Return 1 on success and -1 on error, in which case @dk is undefined. */static int get_disk_objid(struct block_device *bdev, const struct vmdb *vm, const struct privhead *ph, struct ldmdisk *dk, unsigned long base){ Sector sect; unsigned char *data; u8 *disk_id; int vblk; int vsize; /* VBLK size. */ int perbuf; /* VBLKs per buffer. */ int buffer, lastbuf, lastofs, err; disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL); if (!disk_id) goto no_mem; vsize = vm->vblk_size; if (vsize < 1 || vsize > 512) goto err_out; perbuf = 512 / vsize; if (perbuf < 1 || 512 % vsize) goto err_out; /* 512 == VMDB size */ lastbuf = vm->last_vblk_seq / perbuf - 1; lastofs = vm->last_vblk_seq % perbuf; if (lastofs) lastbuf++; if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > ph->config_size * 512) goto err_out; for (buffer = 0; buffer < lastbuf; buffer++) { data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); if (!data) goto read_err; for (vblk = 0; vblk < perbuf; vblk++) { int rel_objid, rel_name, delta; u8 *block; if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs) break; block = data + vblk * vsize; delta = vblk * vsize + 0x18; if (delta >= 512) goto brelse_out; if (block[0x0D] != 0) /* Extended VBLK, ignore */ continue; if ((block[0x13] != VBLK_DSK1) && (block[0x13] != VBLK_DSK2)) continue; /* Calculate relative offsets. */ rel_objid = 1 + block[0x18]; if (delta + rel_objid >= 512) goto brelse_out; rel_name = 1 + block[0x18 + rel_objid] + rel_objid; if (delta + rel_name >= 512 || delta + rel_name + block[0x18 + rel_name] >= 512) goto brelse_out; err = get_vstr(block + 0x18 + rel_name, disk_id, DISK_ID_SIZE); if (err == -1) goto brelse_out; if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) { dk->obj_id = get_vnum(block + 0x18, &err); put_dev_sector(sect); if (err) goto out; strncpy(dk->disk_id, ph->disk_id, sizeof(dk->disk_id)); dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0'; err = 1; goto out; } } put_dev_sector(sect); } err = -1;out: kfree(disk_id); return err;brelse_out: put_dev_sector(sect); goto err_out;no_mem: printk(LDM_CRIT "Not enough memory to allocate required buffers.\n"); goto err_out;read_err: printk(LDM_CRIT "Disk read failed in get_disk_objid.\n");err_out: err = -1; goto out;}/** * parse_vmdb - parse the LDM database vmdb structure * @buffer: LDM database vmdb structure loaded from the device * @vm: in memory vmdb structure to return parsed information in * * This parses the LDM database vmdb structure supplied in @buffer and sets up * the in memory vmdb structure @vm with the obtained information. * * Return 1 on success and -1 on error, in which case @vm is undefined. * * NOTE: The *_start, *_size and *_seq values returned in @vm have not been * checked for validity, so make sure to check them when using them. */static int parse_vmdb(const u8 *buffer, struct vmdb *vm){ if (MAGIC_VMDB != BE32(buffer)) { printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n"); return -1; } vm->ver_major = BE16(buffer + 0x12); vm->ver_minor = BE16(buffer + 0x14); if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. " "Aborting.\n", 4, 10, vm->ver_major, vm->ver_minor); return -1; } vm->vblk_size = BE32(buffer + 0x08); vm->vblk_offset = BE32(buffer + 0x0C); vm->last_vblk_seq = BE32(buffer + 0x04); ldm_debug("Parsed VMDB successfully.\n"); return 1;}/** * validate_vmdb - validate the vmdb * @dev: partition device holding the LDM database * @vm: in memory vmdb in which to return information * * Find the vmdb of the LDM database stored on @dev and return the parsed * information into @vm. * * Return 1 on success and -1 on error, in which case @vm is undefined. */static int validate_vmdb(struct block_device *bdev, struct vmdb *vm, unsigned long base){ Sector sect; unsigned char *data; int ret; data = read_dev_sector(bdev, base + OFF_VMDB * 2 + 1, §); if (!data) { printk(LDM_CRIT "Disk read failed in validate_vmdb.\n"); return -1; } ret = parse_vmdb(data, vm); put_dev_sector(sect); return ret;}/** * compare_tocblocks - compare two tables of contents * @toc1: first toc * @toc2: second toc * * This compares the two tables of contents @toc1 and @toc2. * * Return 1 if @toc1 and @toc2 are equal and -1 otherwise. */static int compare_tocblocks(const struct tocblock *toc1, const struct tocblock *toc2){ if ((toc1->bitmap1_start == toc2->bitmap1_start) && (toc1->bitmap1_size == toc2->bitmap1_size) && (toc1->bitmap2_start == toc2->bitmap2_start) && (toc1->bitmap2_size == toc2->bitmap2_size) && !strncmp(toc1->bitmap1_name, toc2->bitmap1_name, sizeof(toc1->bitmap1_name)) && !strncmp(toc1->bitmap2_name, toc2->bitmap2_name, sizeof(toc1->bitmap2_name))) return 1; return -1;}/** * parse_tocblock - parse the LDM database table of contents structure * @buffer: LDM database toc structure loaded from the device * @toc: in memory toc structure to return parsed information in * * This parses the LDM database table of contents structure supplied in @buffer * and sets up the in memory table of contents structure @toc with the obtained * information. * * Return 1 on success and -1 on error, in which case @toc is undefined. * * FIXME: The *_start and *_size values returned in @toc are not been checked * for validity but as we don't use the actual values for anything other than * comparing between the toc and its backups, the values are not important. */static int parse_tocblock(const u8 *buffer, struct tocblock *toc){ if (MAGIC_TOCBLOCK != BE64(buffer)) { printk(LDM_CRIT "Cannot find TOCBLOCK, database may be " "corrupt.\n"); return -1; } strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name)); toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0'; toc->bitmap1_start = BE64(buffer + 0x2E); toc->bitmap1_size = BE64(buffer + 0x36); /*toc->bitmap1_flags = BE64(buffer + 0x3E);*/ if (strncmp(toc->bitmap1_name, TOC_BITMAP1, sizeof(toc->bitmap1_name)) != 0) { printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is " "%s.\n", TOC_BITMAP1, toc->bitmap1_name); return -1; } strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name)); toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0'; toc->bitmap2_start = BE64(buffer + 0x50); toc->bitmap2_size = BE64(buffer + 0x58); /*toc->bitmap2_flags = BE64(buffer + 0x60);*/ if (strncmp(toc->bitmap2_name, TOC_BITMAP2, sizeof(toc->bitmap2_name)) != 0) { printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is " "%s.\n", TOC_BITMAP2, toc->bitmap2_name); return -1; } ldm_debug("Parsed TOCBLOCK successfully.\n"); return 1;}/** * validate_tocblocks - validate the table of contents and its backups * @dev: partition device holding the LDM database * @toc1: in memory table of contents in which to return information * Find and compare the four tables of contents of the LDM database stored on * @dev and return the parsed information into @toc1. * * Return 1 on success and -1 on error, in which case @toc1 is undefined. */static int validate_tocblocks(struct block_device *bdev, struct tocblock *toc1, unsigned long base){ Sector sect; unsigned char *data; struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL; int err; toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL); if (!toc2) goto no_mem; toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL); if (!toc3) goto no_mem; toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL); if (!toc4) goto no_mem; /* Read and parse first toc. */ data = read_dev_sector(bdev, base + OFF_TOCBLOCK1 * 2 + 1, §); if (!data) { printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n"); goto err_out; } err = parse_tocblock(data, toc1); put_dev_sector(sect); if (err != 1) goto out; /* Read and parse second toc. */ data = read_dev_sector(bdev, base + OFF_TOCBLOCK2 * 2, §); if (!data) { printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n"); goto err_out; } err = parse_tocblock(data, toc2); put_dev_sector(sect); if (err != 1) goto out; /* Read and parse third toc. */ data = read_dev_sector(bdev, base + OFF_TOCBLOCK3 * 2 + 1, §); if (!data) { printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n"); goto err_out; } err = parse_tocblock(data, toc3); put_dev_sector(sect); if (err != 1) goto out; /* Read and parse fourth toc. */ data = read_dev_sector(bdev, base + OFF_TOCBLOCK4 * 2, §); if (!data) { printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n"); goto err_out; } err = parse_tocblock(data, toc4); put_dev_sector(sect); if (err != 1) goto out; /* Compare all tocs. */ err = compare_tocblocks(toc1, toc2); if (err != 1) { printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n"); goto out; } err = compare_tocblocks(toc3, toc4); if (err != 1) { printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n"); goto out; } err = compare_tocblocks(toc1, toc3);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -