📄 volume.c
字号:
* Set the current position within each data zone to the start of the * respective zone. */ vol->data1_zone_pos = vol->mft_zone_end; ntfs_log_debug("data1_zone_pos = 0x%llx\n", vol->data1_zone_pos); vol->data2_zone_pos = 0; ntfs_log_debug("data2_zone_pos = 0x%llx\n", vol->data2_zone_pos); /* Set the mft data allocation position to mft record 24. */ vol->mft_data_pos = 24; /* * The cluster allocator is now fully operational. */ /* Need to setup $MFT so we can use the library read functions. */ ntfs_log_debug("Loading $MFT... "); if (ntfs_mft_load(vol) < 0) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to load $MFT"); goto error_exit; } ntfs_log_debug(OK); /* Need to setup $MFTMirr so we can use the write functions, too. */ ntfs_log_debug("Loading $MFTMirr... "); if (ntfs_mftmirr_load(vol) < 0) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to load $MFTMirr"); goto error_exit; } ntfs_log_debug(OK); return vol;error_exit: eo = errno; free(bs); if (vol) __ntfs_volume_release(vol); errno = eo; return NULL;}/** * ntfs_volume_check_logfile - check logfile on target volume * @vol: volume on which to check logfile * * Return 0 on success and -1 on error with errno set error code. */static int ntfs_volume_check_logfile(ntfs_volume *vol){ ntfs_inode *ni; ntfs_attr *na = NULL; RESTART_PAGE_HEADER *rp = NULL; int err = 0; if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) { ntfs_log_perror("Failed to open inode FILE_LogFile"); errno = EIO; return -1; } if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) { ntfs_log_perror("Failed to open $FILE_LogFile/$DATA"); err = EIO; goto exit; } if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp)) err = EOPNOTSUPP; free(rp);exit: if (na) ntfs_attr_close(na); ntfs_inode_close(ni); if (err) { errno = err; return -1; } return 0;}/** * ntfs_hiberfile_open - Find and open '/hiberfil.sys' * @vol: An ntfs volume obtained from ntfs_mount * * Return: inode Success, hiberfil.sys is valid * NULL hiberfil.sys doesn't exist or some other error occurred */static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol){ u64 inode; ntfs_inode *ni_root; ntfs_inode *ni_hibr = NULL; ntfschar *unicode = NULL; int unicode_len; const char *hiberfile = "hiberfil.sys"; if (!vol) { errno = EINVAL; return NULL; } ni_root = ntfs_inode_open(vol, FILE_root); if (!ni_root) { ntfs_log_debug("Couldn't open the root directory.\n"); return NULL; } unicode_len = ntfs_mbstoucs(hiberfile, &unicode, 0); if (unicode_len < 0) { ntfs_log_perror("Couldn't convert 'hiberfil.sys' to Unicode"); goto out; } inode = ntfs_inode_lookup_by_name(ni_root, unicode, unicode_len); if (inode == (u64)-1) { ntfs_log_debug("Couldn't find file '%s'.\n", hiberfile); goto out; } inode = MREF(inode); ni_hibr = ntfs_inode_open(vol, inode); if (!ni_hibr) { ntfs_log_debug("Couldn't open inode %lld.\n", (long long)inode); goto out; }out: ntfs_inode_close(ni_root); free(unicode); return ni_hibr;}#define NTFS_HIBERFILE_HEADER_SIZE 4096/** * ntfs_volume_check_hiberfile - check hiberfil.sys whether Windows is * hibernated on the target volume * @vol: volume on which to check hiberfil.sys * * Return: 0 if Windows isn't hibernated for sure * -1 otherwise and errno is set to the appropriate value */static int ntfs_volume_check_hiberfile(ntfs_volume *vol){ ntfs_inode *ni; ntfs_attr *na = NULL; int i, bytes_read, ret = -1; char *buf = NULL; ni = ntfs_hiberfile_open(vol); if (!ni) { if (errno == ENOENT) return 0; return -1; } buf = ntfs_malloc(NTFS_HIBERFILE_HEADER_SIZE); if (!buf) goto out; na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { ntfs_log_perror("Failed to open hiberfil.sys data attribute"); goto out; } bytes_read = ntfs_attr_pread(na, 0, NTFS_HIBERFILE_HEADER_SIZE, buf); if (bytes_read == -1) { ntfs_log_perror("Failed to read hiberfil.sys"); goto out; } if (bytes_read < NTFS_HIBERFILE_HEADER_SIZE) { ntfs_log_error("Hibernated non-system partition, refused to " "mount.\n"); errno = EPERM; goto out; } if (memcmp(buf, "hibr", 4) == 0) { ntfs_log_error("Windows is hibernated, refused to mount.\n"); errno = EPERM; goto out; } for (i = 0; i < NTFS_HIBERFILE_HEADER_SIZE; i++) { if (buf[i]) { ntfs_log_error("Windows is hibernated, won't mount.\n"); errno = EPERM; goto out; } } /* All right, all header bytes are zero */ ret = 0;out: if (na) ntfs_attr_close(na); free(buf); ntfs_inode_close(ni); return ret;}/** * ntfs_device_mount - open ntfs volume * @dev: device to open * @flags: optional mount flags * * This function mounts an ntfs volume. @dev should describe the device which * to mount as the ntfs volume. * * @flags is an optional second parameter. The same flags are used as for * the mount system call (man 2 mount). Currently only the following flags * are implemented: * MS_RDONLY - mount volume read-only * MS_NOATIME - do not update access time * * The function opens the device @dev and verifies that it contains a valid * bootsector. Then, it allocates an ntfs_volume structure and initializes * some of the values inside the structure from the information stored in the * bootsector. It proceeds to load the necessary system files and completes * setting up the structure. * * Return the allocated volume structure on success and NULL on error with * errno set to the error code. */ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags){ s64 l;#ifdef DEBUG const char *OK = "OK\n"; const char *FAILED = "FAILED\n";#endif ntfs_volume *vol; u8 *m = NULL, *m2 = NULL; ntfs_attr_search_ctx *ctx = NULL; ntfs_inode *ni; ntfs_attr *na; ATTR_RECORD *a; VOLUME_INFORMATION *vinf; ntfschar *vname; int i, j, eo; u32 u; vol = ntfs_volume_startup(dev, flags); if (!vol) { ntfs_log_perror("Failed to startup volume"); return NULL; } /* Load data from $MFT and $MFTMirr and compare the contents. */ m = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); m2 = ntfs_malloc(vol->mftmirr_size << vol->mft_record_size_bits); if (!m || !m2) goto error_exit; l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size, vol->mft_record_size, m); if (l != vol->mftmirr_size) { if (l == -1) ntfs_log_perror("Failed to read $MFT"); else { ntfs_log_error("Failed to read $MFT, unexpected length " "(%lld != %d).\n", (long long)l, vol->mftmirr_size); errno = EIO; } goto error_exit; } l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size, vol->mft_record_size, m2); if (l != vol->mftmirr_size) { if (l == 4) vol->mftmirr_size = 4; else { if (l == -1) ntfs_log_perror("Failed to read $MFTMirr"); else { ntfs_log_error("Failed to read $MFTMirr " "unexpected length (%d != %lld)." "\n", vol->mftmirr_size, (long long)l); errno = EIO; } goto error_exit; } } ntfs_log_debug("Comparing $MFTMirr to $MFT... "); for (i = 0; i < vol->mftmirr_size; ++i) { MFT_RECORD *mrec, *mrec2; const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", "$Volume", "$AttrDef", "root directory", "$Bitmap", "$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" }; const char *s; if (i < 12) s = ESTR[i]; else if (i < 16) s = "system file"; else s = "mft record"; mrec = (MFT_RECORD*)(m + i * vol->mft_record_size); if (mrec->flags & MFT_RECORD_IN_USE) { if (ntfs_is_baad_recordp(mrec)) { ntfs_log_debug("FAILED\n"); ntfs_log_error("$MFT error: Incomplete multi " "sector transfer detected in " "'%s'.\n", s); goto io_error_exit; } if (!ntfs_is_mft_recordp(mrec)) { ntfs_log_debug("FAILED\n"); ntfs_log_error("$MFT error: Invalid mft " "record for '%s'.\n", s); goto io_error_exit; } } mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size); if (mrec2->flags & MFT_RECORD_IN_USE) { if (ntfs_is_baad_recordp(mrec2)) { ntfs_log_debug("FAILED\n"); ntfs_log_error("$MFTMirr error: Incomplete " "multi sector transfer " "detected in '%s'.\n", s); goto io_error_exit; } if (!ntfs_is_mft_recordp(mrec2)) { ntfs_log_debug("FAILED\n"); ntfs_log_error("$MFTMirr error: Invalid mft " "record for '%s'.\n", s); goto io_error_exit; } } if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) { ntfs_log_debug(FAILED); ntfs_log_error("$MFTMirr does not match $MFT (record " "%d).\n", i); goto io_error_exit; } } ntfs_log_debug(OK); free(m2); free(m); m = m2 = NULL; /* Now load the bitmap from $Bitmap. */ ntfs_log_debug("Loading $Bitmap... "); vol->lcnbmp_ni = ntfs_inode_open(vol, FILE_Bitmap); if (!vol->lcnbmp_ni) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open inode"); goto error_exit; } /* Get an ntfs attribute for $Bitmap/$DATA. */ vol->lcnbmp_na = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0); if (!vol->lcnbmp_na) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open ntfs attribute"); goto error_exit; } /* Done with the $Bitmap mft record. */ ntfs_log_debug(OK); /* Now load the upcase table from $UpCase. */ ntfs_log_debug("Loading $UpCase... "); ni = ntfs_inode_open(vol, FILE_UpCase); if (!ni) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open inode"); goto error_exit; } /* Get an ntfs attribute for $UpCase/$DATA. */ na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0); if (!na) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open ntfs attribute"); goto error_exit; } /* * Note: Normally, the upcase table has a length equal to 65536 * 2-byte Unicode characters but allow for different cases, so no * checks done. Just check we don't overflow 32-bits worth of Unicode * characters. */ if (na->data_size & ~0x1ffffffffULL) { ntfs_log_debug(FAILED); ntfs_log_error("Error: Upcase table is too big (max 32-bit " "allowed).\n"); errno = EINVAL; goto error_exit; } if (vol->upcase_len != na->data_size >> 1) { vol->upcase_len = na->data_size >> 1; /* Throw away default table. */ free(vol->upcase); vol->upcase = ntfs_malloc(na->data_size); if (!vol->upcase) { ntfs_log_debug(FAILED); goto error_exit; } } /* Read in the $DATA attribute value into the buffer. */ l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase); if (l != na->data_size) { ntfs_log_debug(FAILED); ntfs_log_error("Failed to read $UpCase, unexpected length " "(%lld != %lld).\n", (long long)l, (long long)na->data_size); errno = EIO; goto error_exit; } /* Done with the $UpCase mft record. */ ntfs_log_debug(OK); ntfs_attr_close(na); if (ntfs_inode_close(ni)) ntfs_log_perror("Failed to close inode, leaking memory"); /* * Now load $Volume and set the version information and flags in the * vol structure accordingly. */ ntfs_log_debug("Loading $Volume... "); vol->vol_ni = ntfs_inode_open(vol, FILE_Volume); if (!vol->vol_ni) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to open inode"); goto error_exit; } /* Get a search context for the $Volume/$VOLUME_INFORMATION lookup. */ ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL); if (!ctx) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to allocate attribute search context"); goto error_exit; } /* Find the $VOLUME_INFORMATION attribute. */ if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { ntfs_log_debug(FAILED); ntfs_log_perror("$VOLUME_INFORMATION attribute not found in " "$Volume"); goto error_exit; } a = ctx->attr; /* Has to be resident. */ if (a->non_resident) { ntfs_log_debug(FAILED); ntfs_log_error("Attribute $VOLUME_INFORMATION must be " "resident but it isn't.\n"); errno = EIO; goto error_exit; } /* Get a pointer to the value of the attribute. */ vinf = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a); /* Sanity checks. */ if ((char*)vinf + le32_to_cpu(a->value_length) > (char*)ctx->mrec + le32_to_cpu(ctx->mrec->bytes_in_use) || le16_to_cpu(a->value_offset) + le32_to_cpu( a->value_length) > le32_to_cpu(a->length)) { ntfs_log_debug(FAILED); ntfs_log_error("$VOLUME_INFORMATION in $Volume is corrupt.\n"); errno = EIO; goto error_exit; } /* Setup vol from the volume information attribute value. */ vol->major_ver = vinf->major_ver; vol->minor_ver = vinf->minor_ver; /* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are defined using cpu_to_le16() macro and hence are consistent. */ vol->flags = vinf->flags; /* * Reinitialize the search context for the $Volume/$VOLUME_NAME lookup. */ ntfs_attr_reinit_search_ctx(ctx); if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if (errno != ENOENT) { ntfs_log_debug(FAILED); ntfs_log_perror("Failed to lookup of $VOLUME_NAME in " "$Volume failed"); goto error_exit; } /* * Attribute not present. This has been seen in the field. * Treat this the same way as if the attribute was present but * had zero length. */ vol->vol_name = ntfs_malloc(1); if (!vol->vol_name) { ntfs_log_debug(FAILED); goto error_exit; } vol->vol_name[0] = '\0'; } else { a = ctx->attr; /* Has to be resident. */ if (a->non_resident) { ntfs_log_debug(FAILED); ntfs_log_error("$VOLUME_NAME must be resident.\n"); errno = EIO; goto error_exit; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -