📄 inode.c
字号:
/* * inode.c * * Copyright (C) 1995-1999 Martin von L鰓is * Copyright (C) 1996 Albert D. Cahalan * Copyright (C) 1996-1997 R間is Duchesne * Copyright (C) 1998 Joseph Malicki * Copyright (C) 1999 Steve Dodd * Copyright (C) 2000-2001 Anton Altaparmakov (AIA) */#include "ntfstypes.h"#include "ntfsendian.h"#include "struct.h"#include "inode.h"#include <linux/errno.h>#include "macros.h"#include "attr.h"#include "super.h"#include "dir.h"#include "support.h"#include "util.h"#include <linux/ntfs_fs.h>#include <linux/smp_lock.h>typedef struct { int recno; unsigned char *record;} ntfs_mft_record;typedef struct { int size; int count; ntfs_mft_record *records;} ntfs_disk_inode;static void ntfs_fill_mft_header(ntfs_u8 *mft, int rec_size, int seq_no, int links, int flags){ int fixup_ofs = 0x2a; int fixup_cnt = rec_size / NTFS_SECTOR_SIZE + 1; int attr_ofs = (fixup_ofs + 2 * fixup_cnt + 7) & ~7; NTFS_PUTU32(mft + 0x00, 0x454c4946); /* FILE */ NTFS_PUTU16(mft + 0x04, fixup_ofs); /* Offset to fixup. */ NTFS_PUTU16(mft + 0x06, fixup_cnt); /* Number of fixups. */ NTFS_PUTU64(mft + 0x08, 0); /* Logical sequence number. */ NTFS_PUTU16(mft + 0x10, seq_no); /* Sequence number. */ NTFS_PUTU16(mft + 0x12, links); /* Hard link count. */ NTFS_PUTU16(mft + 0x14, attr_ofs); /* Offset to attributes. */ NTFS_PUTU16(mft + 0x16, flags); /* Flags: 1 = In use, 2 = Directory. */ NTFS_PUTU32(mft + 0x18, attr_ofs + 8); /* Bytes in use. */ NTFS_PUTU32(mft + 0x1c, rec_size); /* Total allocated size. */ NTFS_PUTU64(mft + 0x20, 0); /* Base mft record. */ NTFS_PUTU16(mft + 0x28, 0); /* Next attr instance. */ NTFS_PUTU16(mft + fixup_ofs, 1); /* Fixup word. */ NTFS_PUTU32(mft + attr_ofs, (__u32)-1); /* End of attributes marker. */}/* * Search in an inode an attribute by type and name. * FIXME: Check that when attributes are inserted all attribute list * attributes are expanded otherwise need to modify this function to deal * with attribute lists. (AIA) */ntfs_attribute *ntfs_find_attr(ntfs_inode *ino, int type, char *name){ int i; if (!ino) { ntfs_error("ntfs_find_attr: NO INODE!\n"); return 0; } for (i = 0; i < ino->attr_count; i++) { if (type < ino->attrs[i].type) return 0; if (type == ino->attrs[i].type) { if (!name) { if (!ino->attrs[i].name) return ino->attrs + i; } else if (ino->attrs[i].name && !ntfs_ua_strncmp(ino->attrs[i].name, name, strlen(name))) return ino->attrs + i; } } return 0;}/* * Insert all attributes from the record mftno of the MFT in the inode ino. * If mftno is a base mft record we abort as soon as we find the attribute * list, but only on the first pass. We will get called later when the attribute * list attribute is being parsed so we need to distinguish the two cases. * FIXME: We should be performing structural consistency checks. (AIA) * Return 0 on success or -errno on error. */static int ntfs_insert_mft_attributes(ntfs_inode* ino, char *mft, int mftno){ int i, error, type, len, present = 0; char *it; /* Check for duplicate extension record. */ for(i = 0; i < ino->record_count; i++) if (ino->records[i] == mftno) { if (i) return 0; present = 1; break; } if (!present) { /* (re-)allocate space if necessary. */ if (ino->record_count % 8 == 0) { int *new; new = ntfs_malloc((ino->record_count + 8) * sizeof(int)); if (!new) return -ENOMEM; if (ino->records) { for (i = 0; i < ino->record_count; i++) new[i] = ino->records[i]; ntfs_free(ino->records); } ino->records = new; } ino->records[ino->record_count] = mftno; ino->record_count++; } it = mft + NTFS_GETU16(mft + 0x14); /* mft->attrs_offset */ do { type = NTFS_GETU32(it); len = NTFS_GETU32(it + 4); if (type != -1) { error = ntfs_insert_attribute(ino, it); if (error) return error; } /* If we have just processed the attribute list and this is * the first time we are parsing this (base) mft record then we * are done so that the attribute list gets parsed before the * entries in the base mft record. Otherwise we run into * problems with encountering attributes out of order and when * this happens with different attribute extents we die. )-: * This way we are ok as the attribute list is always sorted * fully and correctly. (-: */ if (type == 0x20 && !present) return 0; it += len; } while (type != -1); /* Attribute listing ends with type -1. */ return 0;}/* * Insert a single specific attribute from the record mftno of the MFT in the * inode ino. We disregard the attribute list assuming we have already parsed * it. * FIXME: We should be performing structural consistency checks. (AIA) * Return 0 on success or -errno on error. */static int ntfs_insert_mft_attribute(ntfs_inode* ino, int mftno, ntfs_u8 *attr){ int i, error, present = 0; /* Check for duplicate extension record. */ for(i = 0; i < ino->record_count; i++) if (ino->records[i] == mftno) { present = 1; break; } if (!present) { /* (re-)allocate space if necessary. */ if (ino->record_count % 8 == 0) { int *new; new = ntfs_malloc((ino->record_count + 8) * sizeof(int)); if (!new) return -ENOMEM; if (ino->records) { for (i = 0; i < ino->record_count; i++) new[i] = ino->records[i]; ntfs_free(ino->records); } ino->records = new; } ino->records[ino->record_count] = mftno; ino->record_count++; } if (NTFS_GETU32(attr) == -1) { ntfs_debug(DEBUG_FILE3, "ntfs_insert_mft_attribute: attribute " "type is -1.\n"); return 0; } error = ntfs_insert_attribute(ino, attr); if (error) return error; return 0;}/* Read and insert all the attributes of an 'attribute list' attribute. * Return the number of remaining bytes in *plen. */static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen){ ntfs_u8 *mft, *attr; int mftno, l, error; int last_mft = -1; int len = *plen; int tries = 0; if (!ino->attr) { ntfs_error("parse_attributes: called on inode 0x%x without a " "loaded base mft record.\n", ino->i_number); return -EINVAL; } mft = ntfs_malloc(ino->vol->mft_record_size); if (!mft) return -ENOMEM; while (len > 8) { l = NTFS_GETU16(alist + 4); if (l > len) break; /* Process an attribute description. */ mftno = NTFS_GETU32(alist + 0x10); /* FIXME: The mft reference (alist + 0x10) is __s64. * - Not a problem unless we encounter a huge partition. * - Should be consistency checking the sequence numbers * though! This should maybe happen in * ntfs_read_mft_record() itself and a hotfix could * then occur there or the user notified to run * ntfsck. (AIA) */ if (mftno != ino->i_number && mftno != last_mft) {continue_after_loading_mft_data: last_mft = mftno; error = ntfs_read_mft_record(ino->vol, mftno, mft); if (error) { if (error == -EINVAL && !tries) goto force_load_mft_data;failed_reading_mft_data: ntfs_debug(DEBUG_FILE3, "parse_attributes: " "ntfs_read_mft_record(mftno = 0x%x) " "failed\n", mftno); ntfs_free(mft); return error; } } attr = ntfs_find_attr_in_mft_rec( ino->vol, /* ntfs volume */ mftno == ino->i_number ?/* mft record is: */ ino->attr: /* base record */ mft, /* extension record */ NTFS_GETU32(alist + 0), /* type */ (wchar_t*)(alist + alist[7]), /* name */ alist[6], /* name length */ 1, /* ignore case */ NTFS_GETU16(alist + 24) /* instance number */ ); if (!attr) { ntfs_error("parse_attributes: mft records 0x%x and/or " "0x%x corrupt!\n", ino->i_number, mftno); ntfs_free(mft); return -EINVAL; /* FIXME: Better error code? (AIA) */ } error = ntfs_insert_mft_attribute(ino, mftno, attr); if (error) { ntfs_debug(DEBUG_FILE3, "parse_attributes: " "ntfs_insert_mft_attribute(mftno 0x%x, " "attribute type 0x%x) failed\n", mftno, NTFS_GETU32(alist + 0)); ntfs_free(mft); return error; } len -= l; alist += l; } ntfs_free(mft); *plen = len; return 0;force_load_mft_data:{ ntfs_u8 *mft2, *attr2; int mftno2; int last_mft2 = last_mft; int len2 = len; int error2; int found2 = 0; ntfs_u8 *alist2 = alist; /* * We only get here if $DATA wasn't found in $MFT which only happens * on volume mount when $MFT has an attribute list and there are * attributes before $DATA which are inside extent mft records. So * we just skip forward to the $DATA attribute and read that. Then we * restart which is safe as an attribute will not be inserted twice. * * This still will not fix the case where the attribute list is non- * resident, larger than 1024 bytes, and the $DATA attribute list entry * is not in the first 1024 bytes. FIXME: This should be implemented * somehow! Perhaps by passing special error code up to * ntfs_load_attributes() so it keeps going trying to get to $DATA * regardless. Then it would have to restart just like we do here. */ mft2 = ntfs_malloc(ino->vol->mft_record_size); if (!mft2) { ntfs_free(mft); return -ENOMEM; } ntfs_memcpy(mft2, mft, ino->vol->mft_record_size); while (len2 > 8) { l = NTFS_GETU16(alist2 + 4); if (l > len2) break; if (NTFS_GETU32(alist2 + 0x0) < ino->vol->at_data) { len2 -= l; alist2 += l; continue; } if (NTFS_GETU32(alist2 + 0x0) > ino->vol->at_data) { if (found2) break; /* Uh-oh! It really isn't there! */ ntfs_error("Either the $MFT is corrupt or, equally " "likely, the $MFT is too complex for " "the current driver to handle. Please " "email the ntfs maintainer that you " "saw this message. Thank you.\n"); goto failed_reading_mft_data; } /* Process attribute description. */ mftno2 = NTFS_GETU32(alist2 + 0x10); if (mftno2 != ino->i_number && mftno2 != last_mft2) { last_mft2 = mftno2; error2 = ntfs_read_mft_record(ino->vol, mftno2, mft2); if (error2) { ntfs_debug(DEBUG_FILE3, "parse_attributes: " "ntfs_read_mft_record(mftno2 = 0x%x) " "failed\n", mftno2); ntfs_free(mft2); goto failed_reading_mft_data; } } attr2 = ntfs_find_attr_in_mft_rec( ino->vol, /* ntfs volume */ mftno2 == ino->i_number ?/* mft record is: */ ino->attr: /* base record */ mft2, /* extension record */ NTFS_GETU32(alist2 + 0), /* type */ (wchar_t*)(alist2 + alist2[7]), /* name */ alist2[6], /* name length */ 1, /* ignore case */ NTFS_GETU16(alist2 + 24) /* instance number */ ); if (!attr2) { ntfs_error("parse_attributes: mft records 0x%x and/or " "0x%x corrupt!\n", ino->i_number, mftno2); ntfs_free(mft2); goto failed_reading_mft_data; } error2 = ntfs_insert_mft_attribute(ino, mftno2, attr2); if (error2) { ntfs_debug(DEBUG_FILE3, "parse_attributes: " "ntfs_insert_mft_attribute(mftno2 0x%x, " "attribute2 type 0x%x) failed\n", mftno2, NTFS_GETU32(alist2 + 0)); ntfs_free(mft2); goto failed_reading_mft_data; } len2 -= l; alist2 += l; found2 = 1; } ntfs_free(mft2); tries = 1; goto continue_after_loading_mft_data;}}static void ntfs_load_attributes(ntfs_inode *ino){ ntfs_attribute *alist; int datasize; int offset, len, delta; char *buf; ntfs_volume *vol = ino->vol; ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 1\n", ino->i_number); if (ntfs_insert_mft_attributes(ino, ino->attr, ino->i_number)) return; ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 2\n", ino->i_number); alist = ntfs_find_attr(ino, vol->at_attribute_list, 0); ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 3\n", ino->i_number); if (!alist) return; ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 4\n", ino->i_number); datasize = alist->size; ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: alist->size = 0x%x\n", ino->i_number, alist->size); if (alist->resident) { parse_attributes(ino, alist->d.data, &datasize); return; } ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 5\n", ino->i_number); buf = ntfs_malloc(1024); if (!buf) /* FIXME: Should be passing error code to caller. (AIA) */ return; delta = 0; for (offset = 0; datasize; datasize -= len, offset += len) { ntfs_io io; io.fn_put = ntfs_put;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -