/** * ntfs_mst_pread - multi sector transfer (mst) positioned read * @dev: device to read from * @pos: position in file descriptor to read from * @count: number of blocks to read * @bksize: size of each block that needs mst deprotecting * @b: output data buffer * * Multi sector transfer (mst) positioned read. This function will read @count * blocks of size @bksize bytes each from device @dev at position @pos into the * the data buffer @b. * * On success, return the number of successfully read blocks. If this number is * lower than @count this means that we have reached end of file, that the read * was interrupted, or that an error was encountered during the read so that * the read is partial. 0 means end of file or nothing was read (also return 0 * when @count or @bksize are 0). * * On error and nothing was read, return -1 with errno set appropriately to the * return code of either seek, read, or set to EINVAL in case of invalid * arguments. * * NOTE: If an incomplete multi sector transfer has been detected the magic * will have been changed to magic_BAAD but no error will be returned. Thus it * is possible that we return count blocks as being read but that any number * (between zero and count!) of these blocks is actually subject to a multi * sector transfer error. This should be detected by the caller by checking for * the magic being "BAAD". */ s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, const u32 bksize, void *b) { s64 br, i; if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) { errno = EINVAL; return -1; } /* Do the read. */ br = ntfs_pread(dev, pos, count * bksize, b); if (br < 0) return br; /* * Apply fixups to successfully read data, disregarding any errors * returned from the MST fixup function. This is because we want to * fixup everything possible and we rely on the fact that the "BAAD" * magic will be detected later on. */ count = br / bksize; for (i = 0; i < count; ++i) ntfs_mst_post_read_fixup((NTFS_RECORD*) ((u8*)b + i * bksize), bksize); /* Finally, return the number of complete blocks read. */ return count; }
static int print_serial(ntfs_volume *vol) { NTFS_BOOT_SECTOR *bs; /* full boot sectors */ int res; res = -1; bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size); if (bs && (ntfs_pread(vol->dev, 0, vol->sector_size, bs) == vol->sector_size)) { ntfs_log_info("Serial number : %016llx\n", (long long)le64_to_cpu(bs->volume_serial_number)); res = 0; free(bs); } if (res) ntfs_log_info("Error getting the serial number\n"); return (res); }
/** * ntfs_cluster_read - read ntfs clusters * @vol: volume to read from * @lcn: starting logical cluster number * @count: number of clusters to read * @b: output data buffer * * Read @count ntfs clusters starting at logical cluster number @lcn from * volume @vol into buffer @b. Return number of clusters read or -1 on error, * with errno set to the error code. */ s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count, void *b) { s64 br; if (!vol || lcn < 0 || count < 0) { errno = EINVAL; return -1; } if (vol->nr_clusters < lcn + count) { errno = ESPIPE; return -1; } br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits, count << vol->cluster_size_bits, b); if (br < 0) { ntfs_log_perror("Error reading cluster(s)"); return br; } return br >> vol->cluster_size_bits; }
static int change_serial(ntfs_volume *vol, u64 sector, le64 serial_number, NTFS_BOOT_SECTOR *bs, NTFS_BOOT_SECTOR *oldbs) { int res; le64 mask; BOOL same; res = -1; if ((ntfs_pread(vol->dev, sector << vol->sector_size_bits, vol->sector_size, bs) == vol->sector_size)) { same = TRUE; if (!sector) /* save the real bootsector */ memcpy(oldbs, bs, vol->sector_size); else /* backup bootsector must be similar */ same = !memcmp(oldbs, bs, vol->sector_size); if (same) { if (opts.new_serial & 2) bs->volume_serial_number = serial_number; else { mask = const_cpu_to_le64(~0x0ffffffffULL); bs->volume_serial_number = (serial_number & mask) | (bs->volume_serial_number & ~mask); } if (opts.noaction || (ntfs_pwrite(vol->dev, sector << vol->sector_size_bits, vol->sector_size, bs) == vol->sector_size)) { res = 0; } } else { ntfs_log_info("* Warning : the backup boot sector" " does not match (leaving unchanged)\n"); res = 0; } } return (res); }
/** * Return: 0 ok, 1 error. * * todo: may we use ntfs_boot_sector_is_ntfs() instead? * It already does the checks but will not be able to fix anything. */ static BOOL verify_boot_sector(struct ntfs_device *dev, ntfs_volume *rawvol) { u8 buf[512]; NTFS_BOOT_SECTOR *ntfs_boot = (NTFS_BOOT_SECTOR *)&buf; //u32 bytes_per_cluster; current_mft_record = 9; if (ntfs_pread(dev, 0, sizeof(buf), buf) != sizeof(buf)) { check_failed("Failed to read boot sector.\n"); return 1; } if ((buf[0]!=0xeb) || ((buf[1]!=0x52) && (buf[1]!=0x5b)) || (buf[2]!=0x90)) { check_failed("Boot sector: Bad jump.\n"); } if (ntfs_boot->oem_id != magicNTFS) { check_failed("Boot sector: Bad NTFS magic.\n"); } bytes_per_sector = le16_to_cpu(ntfs_boot->bpb.bytes_per_sector); if (!bytes_per_sector) { check_failed("Boot sector: Bytes per sector is 0.\n"); } if (bytes_per_sector%512) { check_failed("Boot sector: Bytes per sector is not a multiple" " of 512.\n"); } sectors_per_cluster = ntfs_boot->bpb.sectors_per_cluster; // todo: if partition, query bios and match heads/tracks? */ // Initialize some values into rawvol. We will need those later. rawvol->dev = dev; ntfs_boot_sector_parse(rawvol, (NTFS_BOOT_SECTOR *)buf); return 0; }
/** * Load the runlist of the <attr_type> attribute. * * Return NULL if an error. * The caller is responsible on freeing the allocated memory if the result is not NULL. * * Set size_of_file_record to some reasonable size when in doubt (the Windows default is 1024.) * * attr_type must be little endian. * * This function has code duplication with check_file_record() and * check_attr_record() but its goal is to be less strict. Thus the * duplicated checks are the minimal required for not crashing. * * Assumes dev is open. */ static runlist *load_runlist(ntfs_volume *rawvol, s64 offset_to_file_record, u32 attr_type, u32 size_of_file_record) { u8 *buf; u16 attrs_offset; u32 length; ATTR_RECORD *attr_rec; if (size_of_file_record<22) // offset to attrs_offset return NULL; buf = (u8*)ntfs_malloc(size_of_file_record); if (!buf) return NULL; if (ntfs_pread(rawvol->dev, offset_to_file_record, size_of_file_record, buf) != size_of_file_record) { check_failed("Failed to read file record at offset %lld (0x%llx).\n", (long long)offset_to_file_record, (long long)offset_to_file_record); return NULL; } attrs_offset = le16_to_cpu(((MFT_RECORD*)buf)->attrs_offset); // first attribute must be after the header. if (attrs_offset<42) { check_failed("First attribute must be after the header (%u).\n", (int)attrs_offset); } attr_rec = (ATTR_RECORD *)(buf + attrs_offset); //printf("uv1.\n"); while ((u8*)attr_rec<=buf+size_of_file_record-4) { //printf("Attr type: 0x%x.\n", attr_rec->type); // Check attribute record. (Only what is in the buffer) if (attr_rec->type==AT_END) { check_failed("Attribute 0x%x not found in file record at offset %lld (0x%llx).\n", (int)le32_to_cpu(attr_rec->type), (long long)offset_to_file_record, (long long)offset_to_file_record); return NULL; } if ((u8*)attr_rec>buf+size_of_file_record-8) { // not AT_END yet no room for the length field. check_failed("Attribute 0x%x is not AT_END, yet no " "room for the length field.\n", (int)le32_to_cpu(attr_rec->type)); return NULL; } length = le32_to_cpu(attr_rec->length); // Check that this attribute does not overflow the mft_record if ((u8*)attr_rec+length >= buf+size_of_file_record) { check_failed("Attribute (0x%x) is larger than FILE record at offset %lld (0x%llx).\n", (int)le32_to_cpu(attr_rec->type), (long long)offset_to_file_record, (long long)offset_to_file_record); return NULL; } // todo: what ATTRIBUTE_LIST (0x20)? if (attr_rec->type==attr_type) { // Eurika! // ntfs_mapping_pairs_decompress only use two values from vol. Just fake it. // todo: it will also use vol->major_ver if defined(DEBUG). But only for printing purposes. // Assume ntfs_boot_sector_parse() was called. return ntfs_mapping_pairs_decompress(rawvol, attr_rec, NULL); } attr_rec = (ATTR_RECORD*)((u8*)attr_rec+length); } // If we got here, there was an overflow. check_failed("file record corrupted at offset %lld (0x%llx).\n", (long long)offset_to_file_record, (long long)offset_to_file_record); return NULL; }