📄 inode.c
字号:
io.fn_get = 0; io.param = buf + delta; len = 1024 - delta; if (len > datasize) len = datasize; ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: len = %i\n", ino->i_number, len); ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: delta = %i\n", ino->i_number, delta); io.size = len; if (ntfs_read_attr(ino, vol->at_attribute_list, 0, offset, &io)) ntfs_error("error in load_attributes\n"); delta += len; ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: after += len, " "delta = %i\n", ino->i_number, delta); parse_attributes(ino, buf, &delta); ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x: after " "parse_attr, delta = %i\n", ino->i_number, delta); if (delta) /* Move remaining bytes to buffer start. */ ntfs_memmove(buf, buf + len - delta, delta); } ntfs_debug(DEBUG_FILE2, "load_attributes 0x%x 6\n", ino->i_number); ntfs_free(buf);} int ntfs_init_inode(ntfs_inode *ino, ntfs_volume *vol, int inum){ char *buf; int error; ntfs_debug(DEBUG_FILE1, "Initializing inode 0x%x\n", inum); ino->i_number = inum; ino->vol = vol; ino->attr = buf = ntfs_malloc(vol->mft_record_size); if (!buf) return -ENOMEM; error = ntfs_read_mft_record(vol, inum, ino->attr); if (error) { ntfs_debug(DEBUG_OTHER, "Init inode: 0x%x failed\n", inum); return error; } ntfs_debug(DEBUG_FILE2, "Init inode: got mft 0x%x\n", inum); ino->sequence_number = NTFS_GETU16(buf + 0x10); ino->attr_count = 0; ino->record_count = 0; ino->records = 0; ino->attrs = 0; ntfs_load_attributes(ino); ntfs_debug(DEBUG_FILE2, "Init inode: done 0x%x\n", inum); return 0;}void ntfs_clear_inode(ntfs_inode *ino){ int i; if (!ino->attr) { ntfs_error("ntfs_clear_inode: double free\n"); return; } ntfs_free(ino->attr); ino->attr = 0; ntfs_free(ino->records); ino->records = 0; for (i = 0; i < ino->attr_count; i++) { if (ino->attrs[i].name) ntfs_free(ino->attrs[i].name); if (ino->attrs[i].resident) { if (ino->attrs[i].d.data) ntfs_free(ino->attrs[i].d.data); } else { if (ino->attrs[i].d.r.runlist) ntfs_vfree(ino->attrs[i].d.r.runlist); } } ntfs_free(ino->attrs); ino->attrs = 0;}/* Check and fixup a MFT record. */int ntfs_check_mft_record(ntfs_volume *vol, char *record){ return ntfs_fixup_record(record, "FILE", vol->mft_record_size);}/* Return (in result) the value indicating the next available attribute * chunk number. Works for inodes w/o extension records only. */int ntfs_allocate_attr_number(ntfs_inode *ino, int *result){ if (ino->record_count != 1) return -EOPNOTSUPP; *result = NTFS_GETU16(ino->attr + 0x28); NTFS_PUTU16(ino->attr + 0x28, (*result) + 1); return 0;}/* Find the location of an attribute in the inode. A name of NULL indicates * unnamed attributes. Return pointer to attribute or NULL if not found. */char *ntfs_get_attr(ntfs_inode *ino, int attr, char *name){ /* Location of first attribute. */ char *it = ino->attr + NTFS_GETU16(ino->attr + 0x14); int type; int len; /* Only check for magic DWORD here, fixup should have happened before.*/ if (!IS_MFT_RECORD(ino->attr)) return 0; do { type = NTFS_GETU32(it); len = NTFS_GETU16(it + 4); /* We found the attribute type. Is the name correct, too? */ if (type == attr) { int namelen = NTFS_GETU8(it + 9); char *name_it, *n = name; /* Match given name and attribute name if present. Make sure attribute name is Unicode. */ if (!name) { goto check_namelen; } else if (namelen) { for (name_it = it + NTFS_GETU16(it + 10); namelen; n++, name_it += 2, namelen--) if (*name_it != *n || name_it[1]) break;check_namelen: if (!namelen) break; } } it += len; } while (type != -1); /* List of attributes ends with type -1. */ if (type == -1) return 0; return it;}__s64 ntfs_get_attr_size(ntfs_inode *ino, int type, char *name){ ntfs_attribute *attr = ntfs_find_attr(ino, type, name); if (!attr) return 0; return attr->size;} int ntfs_attr_is_resident(ntfs_inode *ino, int type, char *name){ ntfs_attribute *attr = ntfs_find_attr(ino, type, name); if (!attr) return 0; return attr->resident;} /* * A run is coded as a type indicator, an unsigned length, and a signed cluster * offset. * . To save space, length and offset are fields of variable length. The low * nibble of the type indicates the width of the length :), the high nibble * the width of the offset. * . The first offset is relative to cluster 0, later offsets are relative to * the previous cluster. * * This function decodes a run. Length is an output parameter, data and cluster * are in/out parameters. */int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster, int *ctype){ unsigned char type = *(*data)++; *ctype = 0; switch (type & 0xF) { case 1: *length = NTFS_GETS8(*data); break; case 2: *length = NTFS_GETS16(*data); break; case 3: *length = NTFS_GETS24(*data); break; case 4: *length = NTFS_GETS32(*data); break; /* Note: cases 5-8 are probably pointless to code, since how * many runs > 4GB of length are there? At the most, cases 5 * and 6 are probably necessary, and would also require making * length 64-bit throughout. */ default: ntfs_error("Can't decode run type field 0x%x\n", type); return -1; }// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: length = 0x%x\n",*length); if (*length < 0) { ntfs_error("Negative run length decoded\n"); return -1; } *data += (type & 0xF); switch (type & 0xF0) { case 0: *ctype = 2; break; case 0x10: *cluster += NTFS_GETS8(*data); break; case 0x20: *cluster += NTFS_GETS16(*data); break; case 0x30: *cluster += NTFS_GETS24(*data); break; case 0x40: *cluster += NTFS_GETS32(*data); break;#if 0 /* Keep for future, in case ntfs_cluster_t ever becomes 64bit. */ case 0x50: *cluster += NTFS_GETS40(*data); break; case 0x60: *cluster += NTFS_GETS48(*data); break; case 0x70: *cluster += NTFS_GETS56(*data); break; case 0x80: *cluster += NTFS_GETS64(*data); break;#endif default: ntfs_error("Can't decode run type field 0x%x\n", type); return -1; }// ntfs_debug(DEBUG_FILE3, "ntfs_decompress_run: cluster = 0x%x\n",// *cluster); *data += (type >> 4); return 0;}static void dump_runlist(const ntfs_runlist *rl, const int rlen);/* * FIXME: ntfs_readwrite_attr() has the effect of writing @dest to @offset of * the attribute value of the attribute @attr in the in memory inode @ino. * If the attribute value of @attr is non-resident the value's contents at * @offset are actually written to disk (from @dest). The on disk mft record * describing the non-resident attribute value is not updated! * If the attribute value is resident then the value is written only in * memory. The on disk mft record containing the value is not written to disk. * A possible fix would be to call ntfs_update_inode() before returning. (AIA) *//* Reads l bytes of the attribute (attr, name) of ino starting at offset on * vol into buf. Returns the number of bytes read in the ntfs_io struct. * Returns 0 on success, errno on failure */int ntfs_readwrite_attr(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset, ntfs_io *dest){ int rnum, s_vcn, error, clustersizebits; ntfs_cluster_t cluster, s_cluster, vcn, len; __s64 l, chunk, copied; ntfs_debug(DEBUG_FILE3, "%s(): %s 0x%x bytes at offset " "0x%Lx %s inode 0x%x, attr type 0x%x.\n", __FUNCTION__, dest->do_read ? "Read" : "Write", dest->size, offset, dest->do_read ? "from" : "to", ino->i_number, attr->type); l = dest->size; if (l == 0) return 0; if (dest->do_read) { /* If read _starts_ beyond end of stream, return nothing. */ if (offset >= attr->size) { dest->size = 0; return 0; } /* If read _extends_ beyond end of stream, return as much * initialised data as we have. */ if (offset + l >= attr->size) l = dest->size = attr->size - offset; } else { /* * If write extends beyond _allocated_ size, extend attribute, * updating attr->allocated and attr->size in the process. (AIA) */ if ((!attr->resident && offset + l > attr->allocated) || (attr->resident && offset + l > attr->size)) { error = ntfs_resize_attr(ino, attr, offset + l); if (error) return error; } if (!attr->resident) { /* Has amount of data increased? */ if (offset + l > attr->size) attr->size = offset + l; /* Has amount of initialised data increased? */ if (offset + l > attr->initialized) { /* FIXME: Clear the section between the old * initialised length and the write start. * (AIA) */ attr->initialized = offset + l; } } } if (attr->resident) { if (dest->do_read) dest->fn_put(dest, (ntfs_u8*)attr->d.data + offset, l); else dest->fn_get((ntfs_u8*)attr->d.data + offset, dest, l); dest->size = l; return 0; } if (dest->do_read) { /* Read uninitialized data. */ if (offset >= attr->initialized) return ntfs_read_zero(dest, l); if (offset + l > attr->initialized) { dest->size = chunk = attr->initialized - offset; error = ntfs_readwrite_attr(ino, attr, offset, dest); if (error || (dest->size != chunk && (error = -EIO, 1))) return error; dest->size += l - chunk; return ntfs_read_zero(dest, l - chunk); } if (attr->flags & ATTR_IS_COMPRESSED) return ntfs_read_compressed(ino, attr, offset, dest); } else { if (attr->flags & ATTR_IS_COMPRESSED) return ntfs_write_compressed(ino, attr, offset, dest); } vcn = 0; clustersizebits = ino->vol->cluster_size_bits; s_vcn = offset >> clustersizebits; for (rnum = 0; rnum < attr->d.r.len && vcn + attr->d.r.runlist[rnum].len <= s_vcn; rnum++) vcn += attr->d.r.runlist[rnum].len; if (rnum == attr->d.r.len) { ntfs_debug(DEBUG_FILE3, "%s(): EOPNOTSUPP: " "inode = 0x%x, rnum = %i, offset = 0x%Lx, vcn = 0x%x, " "s_vcn = 0x%x.\n", __FUNCTION__, ino->i_number, rnum, offset, vcn, s_vcn); dump_runlist(attr->d.r.runlist, attr->d.r.len); /*FIXME: Should extend runlist. */ return -EOPNOTSUPP; } copied = 0; while (l) { s_vcn = offset >> clustersizebits; cluster = attr->d.r.runlist[rnum].lcn; len = attr->d.r.runlist[rnum].len; s_cluster = cluster + s_vcn - vcn; chunk = ((__s64)(vcn + len) << clustersizebits) - offset; if (chunk > l) chunk = l; dest->size = chunk; error = ntfs_getput_clusters(ino->vol, s_cluster, offset - ((__s64)s_vcn << clustersizebits), dest); if (error) { ntfs_error("Read/write error.\n"); dest->size = copied; return error; } l -= chunk; copied += chunk; offset += chunk; if (l && offset >= ((__s64)(vcn + len) << clustersizebits)) { rnum++; vcn += len; cluster = attr->d.r.runlist[rnum].lcn; len = attr->d.r.runlist[rnum].len; } } dest->size = copied; return 0;}int ntfs_read_attr(ntfs_inode *ino, int type, char *name, __s64 offset, ntfs_io *buf){ ntfs_attribute *attr; buf->do_read = 1; attr = ntfs_find_attr(ino, type, name); if (!attr) { ntfs_debug(DEBUG_FILE3, "%s(): attr 0x%x not found in inode " "0x%x\n", __FUNCTION__, type, ino->i_number); return -EINVAL; } return ntfs_readwrite_attr(ino, attr, offset, buf);}int ntfs_write_attr(ntfs_inode *ino, int type, char *name, __s64 offset, ntfs_io *buf){ ntfs_attribute *attr; buf->do_read = 0; attr = ntfs_find_attr(ino, type, name); if (!attr) { ntfs_debug(DEBUG_FILE3, "%s(): attr 0x%x not found in inode " "0x%x\n", __FUNCTION__, type, ino->i_number); return -EINVAL; } return ntfs_readwrite_attr(ino, attr, offset, buf);}/* -2 = error, -1 = hole, >= 0 means real disk cluster (lcn). */int ntfs_vcn_to_lcn(ntfs_inode *ino, int vcn){ int rnum; ntfs_attribute *data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -