📄 volume.c
字号:
"%s\n", strerror(errno)); /* * We now initialize the cluster allocator. * * FIXME: Move this to its own function? (AIA) */ // TODO: Make this tunable at mount time. (AIA) vol->mft_zone_multiplier = 1; /* Determine the size of the MFT zone. */ mft_zone_size = vol->nr_clusters; switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */ case 4: mft_zone_size >>= 1; /* 50% */ break; case 3: mft_zone_size = mft_zone_size * 3 >> 3; /* 37.5% */ break; case 2: mft_zone_size >>= 2; /* 25% */ break; /* case 1: */ default: mft_zone_size >>= 3; /* 12.5% */ break; } /* Setup the mft zone. */ vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn; ntfs_log_debug("mft_zone_pos = 0x%llx\n", (long long)vol->mft_zone_pos); /* * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs * source) and if the actual mft_lcn is in the expected place or even * further to the front of the volume, extend the mft_zone to cover the * beginning of the volume as well. This is in order to protect the * area reserved for the mft bitmap as well within the mft_zone itself. * On non-standard volumes we don't protect it as the overhead would be * higher than the speed increase we would get by doing it. */ mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size; if (mft_lcn * vol->cluster_size < 16 * 1024) mft_lcn = (16 * 1024 + vol->cluster_size - 1) / vol->cluster_size; if (vol->mft_zone_start <= mft_lcn) vol->mft_zone_start = 0; ntfs_log_debug("mft_zone_start = 0x%llx\n", (long long)vol->mft_zone_start); /* * Need to cap the mft zone on non-standard volumes so that it does * not point outside the boundaries of the volume. We do this by * halving the zone size until we are inside the volume. */ vol->mft_zone_end = vol->mft_lcn + mft_zone_size; while (vol->mft_zone_end >= vol->nr_clusters) { mft_zone_size >>= 1; vol->mft_zone_end = vol->mft_lcn + mft_zone_size; } ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end); /* * 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_debug("Failed to open inode FILE_LogFile.\n"); errno = EIO; return -1; } if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) { ntfs_log_debug("Failed to open $FILE_LogFile/$DATA\n"); err = EIO; goto exit; } if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp)) err = EOPNOTSUPP; if (rp) 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 = malloc(NTFS_HIBERFILE_HEADER_SIZE); if (!buf) { ntfs_log_perror("Error allocating memory for hiberfile.sys header"); 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_debug("Hibernated non-system partition, refused to " "mount!\n"); errno = EPERM; goto out; } if (memcmp(buf, "hibr", 4) == 0) { ntfs_log_debug("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_debug("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;#ifndef NTFS_DISABLE_DEBUG_LOGGING 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 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits); if (!m || !m2) { ntfs_log_perror("Failed to allocate memory"); 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_debug("Failed to read $MFT, unexpected length " "(%d != %lld).\n", vol->mftmirr_size, l); 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 == -1) ntfs_log_perror("Failed to read $MFTMirr"); else { ntfs_log_debug("Failed to read $MFTMirr, unexpected " "length (%d != %lld).\n", vol->mftmirr_size, 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_debug("$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_debug("$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_debug("$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_debug("$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_debug("$MFTMirr does not match $MFT. Run " "chkdsk.\n"); 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_debug("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 = (ntfschar*)malloc(na->data_size); if (!vol->upcase) { ntfs_log_debug(FAILED); ntfs_log_debug("Not enough memory to load $UpCase.\n"); 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_debug("Amount of data read does not correspond to expected " "length!\n"); 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. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -