📄 super.c
字号:
/* * super.c * * Copyright (C) 1995-1997, 1999 Martin von L鰓is * Copyright (C) 1996-1997 R間is Duchesne * Copyright (C) 1999 Steve Dodd * Copyright (C) 2000-2001 Anton Altparmakov (AIA) */#include <linux/ntfs_fs.h>#include <linux/errno.h>#include <linux/bitops.h>#include <linux/module.h>#include "ntfstypes.h"#include "struct.h"#include "super.h"#include "macros.h"#include "inode.h"#include "support.h"#include "util.h"#include <linux/smp_lock.h>/* All important structures in NTFS use 2 consistency checks: * . a magic structure identifier (FILE, INDX, RSTR, RCRD...) * . a fixup technique : the last word of each sector (called a fixup) of a * structure's record should end with the word at offset <n> of the first * sector, and if it is the case, must be replaced with the words following * <n>. The value of <n> and the number of fixups is taken from the fields * at the offsets 4 and 6. Note that the sector size is defined as * NTFS_SECTOR_SIZE and not as the hardware sector size (this is concordant * with what the Windows NTFS driver does). * * This function performs these 2 checks, and _fails_ if: * . the input size is invalid * . the fixup header is invalid * . the size does not match the number of sectors * . the magic identifier is wrong * . a fixup is invalid */int ntfs_fixup_record(char *record, char *magic, int size){ int start, count, offset; ntfs_u16 fixup; if (!IS_MAGIC(record, magic)) return 0; start = NTFS_GETU16(record + 4); count = NTFS_GETU16(record + 6) - 1; if (size & (NTFS_SECTOR_SIZE - 1) || start & 1 || start + count * 2 > size || size >> 9 != count) { if (size <= 0) printk(KERN_ERR "NTFS: BUG: ntfs_fixup_record() got " "zero size! Please report this to " "linux-ntfs-dev@lists.sf.net\n"); return 0; } fixup = NTFS_GETU16(record + start); start += 2; offset = NTFS_SECTOR_SIZE - 2; while (count--) { if (NTFS_GETU16(record + offset) != fixup) return 0; NTFS_PUTU16(record + offset, NTFS_GETU16(record + start)); start += 2; offset += NTFS_SECTOR_SIZE; } return 1;}/* * Get vital informations about the ntfs partition from the boot sector. * Return 0 on success or -1 on error. */int ntfs_init_volume(ntfs_volume *vol, char *boot){ int sectors_per_cluster_bits; __s64 ll; ntfs_cluster_t mft_zone_size, tc; /* System defined default values, in case we don't load $AttrDef. */ vol->at_standard_information = 0x10; vol->at_attribute_list = 0x20; vol->at_file_name = 0x30; vol->at_volume_version = 0x40; vol->at_security_descriptor = 0x50; vol->at_volume_name = 0x60; vol->at_volume_information = 0x70; vol->at_data = 0x80; vol->at_index_root = 0x90; vol->at_index_allocation = 0xA0; vol->at_bitmap = 0xB0; vol->at_symlink = 0xC0; /* Sector size. */ vol->sector_size = NTFS_GETU16(boot + 0xB); ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->sector_size = 0x%x\n", vol->sector_size); ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster = " "0x%x\n", NTFS_GETU8(boot + 0xD)); sectors_per_cluster_bits = ffs(NTFS_GETU8(boot + 0xD)) - 1; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: sectors_per_cluster_bits " "= 0x%x\n", sectors_per_cluster_bits); vol->mft_clusters_per_record = NTFS_GETS8(boot + 0x40); ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_clusters_per_record" " = 0x%x\n", vol->mft_clusters_per_record); vol->index_clusters_per_record = NTFS_GETS8(boot + 0x44); ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: " "vol->index_clusters_per_record = 0x%x\n", vol->index_clusters_per_record); vol->cluster_size = vol->sector_size << sectors_per_cluster_bits; vol->cluster_size_bits = ffs(vol->cluster_size) - 1; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size = 0x%x\n", vol->cluster_size); ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->cluster_size_bits = " "0x%x\n", vol->cluster_size_bits); if (vol->mft_clusters_per_record > 0) vol->mft_record_size = vol->cluster_size << (ffs(vol->mft_clusters_per_record) - 1); else /* * When mft_record_size < cluster_size, mft_clusters_per_record * = -log2(mft_record_size) bytes. mft_record_size normaly is * 1024 bytes, which is encoded as 0xF6 (-10 in decimal). */ vol->mft_record_size = 1 << -vol->mft_clusters_per_record; vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size = 0x%x" "\n", vol->mft_record_size); ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_record_size_bits = " "0x%x\n", vol->mft_record_size_bits); if (vol->index_clusters_per_record > 0) vol->index_record_size = vol->cluster_size << (ffs(vol->index_clusters_per_record) - 1); else /* * When index_record_size < cluster_size, * index_clusters_per_record = -log2(index_record_size) bytes. * index_record_size normaly equals 4096 bytes, which is * encoded as 0xF4 (-12 in decimal). */ vol->index_record_size = 1 << -vol->index_clusters_per_record; vol->index_record_size_bits = ffs(vol->index_record_size) - 1; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size = " "0x%x\n", vol->index_record_size); ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size_bits " "= 0x%x\n", vol->index_record_size_bits); /* * Get the size of the volume in clusters (ofs 0x28 is nr_sectors) and * check for 64-bit-ness. Windows currently only uses 32 bits to save * the clusters so we do the same as it is much faster on 32-bit CPUs. */ ll = NTFS_GETS64(boot + 0x28) >> sectors_per_cluster_bits; if (ll >= (__s64)1 << 31) { ntfs_error("Cannot handle 64-bit clusters. Please inform " "linux-ntfs-dev@lists.sf.net that you got this " "error.\n"); return -1; } vol->nr_clusters = (ntfs_cluster_t)ll; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->nr_clusters = 0x%x\n", vol->nr_clusters); vol->mft_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x30); vol->mft_mirr_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x38); /* Determine MFT zone size. */ 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 mft zone. */ vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_pos = %x\n", 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 well as the overhead * would be higher than the speed increase we would get by doing it. */ tc = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size; if (tc * vol->cluster_size < 16 * 1024) tc = (16 * 1024 + vol->cluster_size - 1) / vol->cluster_size; if (vol->mft_zone_start <= tc) vol->mft_zone_start = (ntfs_cluster_t)0; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_start = %x\n", 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_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_end = %x\n", 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_debug(DEBUG_FILE3, "ntfs_init_volume: vol->data1_zone_pos = %x\n", vol->data1_zone_pos); vol->data2_zone_pos = (ntfs_cluster_t)0; ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->data2_zone_pos = %x\n", vol->data2_zone_pos); /* Set the mft data allocation position to mft record 24. */ vol->mft_data_pos = 24UL; /* This will be initialized later. */ vol->upcase = 0; vol->upcase_length = 0; vol->mft_ino = 0; return 0;}static void ntfs_init_upcase(ntfs_inode *upcase){ ntfs_io io;#define UPCASE_LENGTH 256 upcase->vol->upcase = ntfs_malloc(UPCASE_LENGTH << 1); if (!upcase->vol->upcase) return; io.fn_put = ntfs_put; io.fn_get = 0; io.param = (char*)upcase->vol->upcase; io.size = UPCASE_LENGTH << 1; ntfs_read_attr(upcase, upcase->vol->at_data, 0, 0, &io); upcase->vol->upcase_length = io.size >> 1;}static int process_attrdef(ntfs_inode* attrdef, ntfs_u8* def){ int type = NTFS_GETU32(def+0x80); int check_type = 0; ntfs_volume *vol = attrdef->vol; ntfs_u16* name = (ntfs_u16*)def; if (!type) { ntfs_debug(DEBUG_OTHER, "process_atrdef: finished processing " "and returning 1\n"); return 1; } if (ntfs_ua_strncmp(name, "$STANDARD_INFORMATION", 64) == 0) { vol->at_standard_information = type; check_type = 0x10; } else if (ntfs_ua_strncmp(name, "$ATTRIBUTE_LIST", 64) == 0) { vol->at_attribute_list = type; check_type = 0x20; } else if (ntfs_ua_strncmp(name, "$FILE_NAME", 64) == 0) { vol->at_file_name = type; check_type = 0x30; } else if (ntfs_ua_strncmp(name, "$VOLUME_VERSION", 64) == 0) { vol->at_volume_version = type; check_type = 0x40; } else if (ntfs_ua_strncmp(name, "$SECURITY_DESCRIPTOR", 64) == 0) { vol->at_security_descriptor = type; check_type = 0x50; } else if (ntfs_ua_strncmp(name, "$VOLUME_NAME", 64) == 0) { vol->at_volume_name = type; check_type = 0x60; } else if (ntfs_ua_strncmp(name, "$VOLUME_INFORMATION", 64) == 0) { vol->at_volume_information = type; check_type = 0x70; } else if (ntfs_ua_strncmp(name, "$DATA", 64) == 0) { vol->at_data = type; check_type = 0x80; } else if (ntfs_ua_strncmp(name, "$INDEX_ROOT", 64) == 0) { vol->at_index_root = type; check_type = 0x90; } else if (ntfs_ua_strncmp(name, "$INDEX_ALLOCATION", 64) == 0) { vol->at_index_allocation = type; check_type = 0xA0; } else if (ntfs_ua_strncmp(name, "$BITMAP", 64) == 0) { vol->at_bitmap = type; check_type = 0xB0; } else if (ntfs_ua_strncmp(name, "$SYMBOLIC_LINK", 64) == 0 || ntfs_ua_strncmp(name, "$REPARSE_POINT", 64) == 0) { vol->at_symlink = type; check_type = 0xC0; } if (check_type && check_type != type) { ntfs_error("process_attrdef: unexpected type 0x%x for 0x%x\n", type, check_type); return -EINVAL; } ntfs_debug(DEBUG_OTHER, "process_attrdef: found %s attribute of type " "0x%x\n", check_type ? "known" : "unknown", type); return 0;}int ntfs_init_attrdef(ntfs_inode* attrdef){ ntfs_u8 *buf; ntfs_io io; __s64 offset; unsigned i; int error; ntfs_attribute *data; ntfs_debug(DEBUG_BSD, "Entered ntfs_init_attrdef()\n"); buf = ntfs_malloc(4050); /* 90*45 */ if (!buf) return -ENOMEM; io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.do_read = 1; offset = 0; data = ntfs_find_attr(attrdef, attrdef->vol->at_data, 0); ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to " "ntfs_find_attr.\n"); if (!data) { ntfs_free(buf); return -EINVAL; } do { io.param = buf; io.size = 4050; ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going to call " "ntfs_readwrite_attr.\n"); error = ntfs_readwrite_attr(attrdef, data, offset, &io); ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after call to " "ntfs_readwrite_attr.\n"); for (i = 0; !error && i <= io.size - 0xA0; i += 0xA0) { ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() going " "to call process_attrdef.\n"); error = process_attrdef(attrdef, buf + i); ntfs_debug(DEBUG_BSD, "In ntfs_init_attrdef() after " "call to process_attrdef.\n"); } offset += 4096; } while (!error && io.size); ntfs_debug(DEBUG_BSD, "Exiting ntfs_init_attrdef()\n"); ntfs_free(buf); return error == 1 ? 0 : error;}/* ntfs_get_version will determine the NTFS version of the volume and will * return the version in a BCD format, with the MSB being the major version * number and the LSB the minor one. Otherwise return <0 on error.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -