📄 inode.c
字号:
data = ntfs_find_attr(ino, ino->vol->at_data, 0); if (!data || data->resident || data->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)) return -2; if (data->size <= (__s64)vcn << ino->vol->cluster_size_bits) return -2; if (data->initialized <= (__s64)vcn << ino->vol->cluster_size_bits) return -1; for (rnum = 0; rnum < data->d.r.len && vcn >= data->d.r.runlist[rnum].len; rnum++) vcn -= data->d.r.runlist[rnum].len; if (data->d.r.runlist[rnum].lcn >= 0) return data->d.r.runlist[rnum].lcn + vcn; return data->d.r.runlist[rnum].lcn + vcn;}static int allocate_store(ntfs_volume *vol, ntfs_disk_inode *store, int count){ int i; if (store->count > count) return 0; if (store->size < count) { ntfs_mft_record *n = ntfs_malloc((count + 4) * sizeof(ntfs_mft_record)); if (!n) return -ENOMEM; if (store->size) { for (i = 0; i < store->size; i++) n[i] = store->records[i]; ntfs_free(store->records); } store->size = count + 4; store->records = n; } for (i = store->count; i < count; i++) { store->records[i].record = ntfs_malloc(vol->mft_record_size); if (!store->records[i].record) return -ENOMEM; store->count++; } return 0;}static void deallocate_store(ntfs_disk_inode* store){ int i; for (i = 0; i < store->count; i++) ntfs_free(store->records[i].record); ntfs_free(store->records); store->count = store->size = 0; store->records = 0;}/** * layout_runs - compress runlist into mapping pairs array * @attr: attribute containing the runlist to compress * @rec: destination buffer to hold the mapping pairs array * @offs: current position in @rec (in/out variable) * @size: size of the buffer @rec * * layout_runs walks the runlist in @attr, compresses it and writes it out the * resulting mapping pairs array into @rec (up to a maximum of @size bytes are * written). On entry @offs is the offset in @rec at which to begin writing the * mapping pairs array. On exit, it contains the offset in @rec of the first * byte after the end of the mapping pairs array. */static int layout_runs(ntfs_attribute *attr, char *rec, int *offs, int size){ int i, len, offset, coffs; /* ntfs_cluster_t MUST be signed! (AIA) */ ntfs_cluster_t cluster, rclus; ntfs_runlist *rl = attr->d.r.runlist; cluster = 0; offset = *offs; for (i = 0; i < attr->d.r.len; i++) { /* * We cheat with this check on the basis that lcn will never * be less than -1 and the lcn delta will fit in signed * 32-bits (ntfs_cluster_t). (AIA) */ if (rl[i].lcn < (ntfs_cluster_t)-1) { ntfs_error("layout_runs() encountered an out of bounds " "cluster delta, lcn = %i.\n", rl[i].lcn); return -ERANGE; } rclus = rl[i].lcn - cluster; len = rl[i].len; rec[offset] = 0; if (offset + 9 > size) return -E2BIG; /* It might still fit, but this * simplifies testing. */ /* * Run length is stored as signed number, so deal with it * properly, i.e. observe that a negative number will have all * its most significant bits set to 1 but we don't store that * in the mapping pairs array. We store the smallest type of * negative number required, thus in the first if we check * whether len fits inside a signed byte and if so we store it * as such, the next ifs check for a signed short, then a signed * 24-bit and finally the full blown signed 32-bit. Same goes * for rlus below. (AIA) */ if (len >= -0x80 && len <= 0x7f) { NTFS_PUTU8(rec + offset + 1, len & 0xff); coffs = 1; } else if (len >= -0x8000 && len <= 0x7fff) { NTFS_PUTU16(rec + offset + 1, len & 0xffff); coffs = 2; } else if (len >= -0x800000 && len <= 0x7fffff) { NTFS_PUTU24(rec + offset + 1, len & 0xffffff); coffs = 3; } else /* if (len >= -0x80000000LL && len <= 0x7fffffff */ { NTFS_PUTU32(rec + offset + 1, len); coffs = 4; } /* else ... FIXME: When len becomes 64-bit we need to extend * the else if () statements. (AIA) */ *(rec + offset) |= coffs++; if (rl[i].lcn == (ntfs_cluster_t)-1) /* Compressed run. */ /* Nothing */; else if (rclus >= -0x80 && rclus <= 0x7f) { *(rec + offset) |= 0x10; NTFS_PUTS8(rec + offset + coffs, rclus & 0xff); coffs += 1; } else if (rclus >= -0x8000 && rclus <= 0x7fff) { *(rec + offset) |= 0x20; NTFS_PUTS16(rec + offset + coffs, rclus & 0xffff); coffs += 2; } else if (rclus >= -0x800000 && rclus <= 0x7fffff) { *(rec + offset) |= 0x30; NTFS_PUTS24(rec + offset + coffs, rclus & 0xffffff); coffs += 3; } else /* if (rclus >= -0x80000000LL && rclus <= 0x7fffffff)*/ { *(rec + offset) |= 0x40; NTFS_PUTS32(rec + offset + coffs, rclus /* & 0xffffffffLL */); coffs += 4; } /* FIXME: When rclus becomes 64-bit. else if (rclus >= -0x8000000000 && rclus <= 0x7FFFFFFFFF) { *(rec + offset) |= 0x50; NTFS_PUTS40(rec + offset + coffs, rclus & 0xffffffffffLL); coffs += 5; } else if (rclus >= -0x800000000000 && rclus <= 0x7FFFFFFFFFFF) { *(rec + offset) |= 0x60; NTFS_PUTS48(rec + offset + coffs, rclus & 0xffffffffffffLL); coffs += 6; } else if (rclus >= -0x80000000000000 && rclus <= 0x7FFFFFFFFFFFFF) { *(rec + offset) |= 0x70; NTFS_PUTS56(rec + offset + coffs, rclus & 0xffffffffffffffLL); coffs += 7; } else { *(rec + offset) |= 0x80; NTFS_PUTS64(rec + offset + coffs, rclus); coffs += 8; } */ offset += coffs; if (rl[i].lcn) cluster = rl[i].lcn; } if (offset >= size) return -E2BIG; /* Terminating null. */ *(rec + offset++) = 0; *offs = offset; return 0;}static void count_runs(ntfs_attribute *attr, char *buf){ ntfs_u32 first, count, last, i; first = 0; for (i = 0, count = 0; i < attr->d.r.len; i++) count += attr->d.r.runlist[i].len; last = first + count - 1; NTFS_PUTU64(buf + 0x10, first); NTFS_PUTU64(buf + 0x18, last);} /** * layout_attr - convert in memory attribute to on disk attribute record * @attr: in memory attribute to convert * @buf: destination buffer for on disk attribute record * @size: size of the destination buffer * @psize: size of converted on disk attribute record (out variable) * * layout_attr() takes the attribute @attr and converts it into the appropriate * on disk structure, writing it into @buf (up to @size bytes are written). * * On success we return 0 and set @*psize to the actual byte size of the on- * disk attribute that was written into @buf. */static int layout_attr(ntfs_attribute *attr, char *buf, int size, int *psize){ int nameoff, hdrsize, asize; if (attr->resident) { nameoff = 0x18; hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7; asize = (hdrsize + attr->size + 7) & ~7; if (size < asize) return -E2BIG; NTFS_PUTU32(buf + 0x10, attr->size); NTFS_PUTU8(buf + 0x16, attr->indexed); NTFS_PUTU16(buf + 0x14, hdrsize); if (attr->size) ntfs_memcpy(buf + hdrsize, attr->d.data, attr->size); } else { int error; if (attr->flags & ATTR_IS_COMPRESSED) nameoff = 0x48; else nameoff = 0x40; hdrsize = (nameoff + 2 * attr->namelen + 7) & ~7; if (size < hdrsize) return -E2BIG; /* Make asize point at the end of the attribute record header, i.e. at the beginning of the mapping pairs array. */ asize = hdrsize; error = layout_runs(attr, buf, &asize, size); /* Now, asize points one byte beyond the end of the mapping pairs array. */ if (error) return error; /* The next attribute has to begin on 8-byte boundary. */ asize = (asize + 7) & ~7; /* FIXME: fragments */ count_runs(attr, buf); NTFS_PUTU16(buf + 0x20, hdrsize); NTFS_PUTU16(buf + 0x22, attr->cengine); NTFS_PUTU32(buf + 0x24, 0); NTFS_PUTS64(buf + 0x28, attr->allocated); NTFS_PUTS64(buf + 0x30, attr->size); NTFS_PUTS64(buf + 0x38, attr->initialized); if (attr->flags & ATTR_IS_COMPRESSED) NTFS_PUTS64(buf + 0x40, attr->compsize); } NTFS_PUTU32(buf, attr->type); NTFS_PUTU32(buf + 4, asize); NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1); NTFS_PUTU8(buf + 9, attr->namelen); NTFS_PUTU16(buf + 0xa, nameoff); NTFS_PUTU16(buf + 0xc, attr->flags); NTFS_PUTU16(buf + 0xe, attr->attrno); if (attr->namelen) ntfs_memcpy(buf + nameoff, attr->name, 2 * attr->namelen); *psize = asize; return 0;}/** * layout_inode - convert an in-memory inode into on disk mft record(s) * @ino: in memory inode to convert * @store: on disk inode, contain buffers for the on disk mft record(s) * * layout_inode takes the in memory inode @ino, converts it into a (sequence of) * mft record(s) and writes them to the appropriate buffers in the @store. * * Return 0 on success, * the required mft record count (>0) if the inode does not fit, * -ENOMEM if memory allocation problem, or * -EOPNOTSUP if beyond our capabilities. * * TODO: We at the moment do not support extension mft records. (AIA) */int layout_inode(ntfs_inode *ino, ntfs_disk_inode *store){ int offset, i, size, psize, error, count, recno; ntfs_attribute *attr; unsigned char *rec; error = allocate_store(ino->vol, store, ino->record_count); if (error) return error; size = ino->vol->mft_record_size; count = i = 0; do { if (count < ino->record_count) { recno = ino->records[count]; } else { error = allocate_store(ino->vol, store, count + 1); if (error) return error; recno = -1; } /* * FIXME: We need to support extension records properly. * At the moment they wouldn't work. Probably would "just" get * corrupted if we write to them... (AIA) */ store->records[count].recno = recno; rec = store->records[count].record; count++; /* Copy mft record header. */ offset = NTFS_GETU16(ino->attr + 0x14); /* attrs_offset */ ntfs_memcpy(rec, ino->attr, offset); /* Copy attributes. */ while (i < ino->attr_count) { attr = ino->attrs + i; error = layout_attr(attr, rec + offset, size - offset - 8, &psize); if (error == -E2BIG && offset != NTFS_GETU16(ino->attr + 0x14)) break; if (error) return error; offset += psize; i++; } /* Terminating attribute. */ NTFS_PUTU32(rec + offset, 0xFFFFFFFF); offset += 4; NTFS_PUTU32(rec + offset, 0); offset += 4; NTFS_PUTU32(rec + 0x18, offset); } while (i < ino->attr_count || count < ino->record_count); return count - ino->record_count;}/* * FIXME: ntfs_update_inode() calls layout_inode() to create the mft record on * disk structure corresponding to the inode @ino. After that, ntfs_write_attr() * is called to write out the created mft record to disk. * We shouldn't need to re-layout every single time we are updating an mft * record. No wonder the ntfs driver is slow like hell. (AIA) */int ntfs_update_inode(ntfs_inode *ino){ int error, i; ntfs_disk_inode store; ntfs_io io; ntfs_bzero(&store, sizeof(store)); error = layout_inode(ino, &store); if (error == -E2BIG) { i = ntfs_split_indexroot(ino); if (i != -ENOTDIR) { if (!i) i = layout_inode(ino, &store); error = i; } } if (error == -E2BIG) { error = ntfs_attr_allnonresident(ino); if (!error) error = layout_inode(ino, &store); } if (error > 0) { /* FIXME: Introduce extension records. */ error = -E2BIG; } if (error) { if (error == -E2BIG) ntfs_error("Cannot handle saving inode 0x%x.\n", ino->i_number); deallocate_store(&store); return error; } io.fn_get = ntfs_get; io.fn_put = 0; for (i = 0; i < store.count; i++) { error = ntfs_insert_fixups(store.records[i].record, ino->vol->mft_record_size); if (error) { printk(KERN_ALERT "NTFS: ntfs_update_inode() caught " "corrupt %s mtf record ntfs record " "header. Refusing to write corrupt " "data to disk. Unmount and run chkdsk " "immediately!\n", i ? "extension": "base"); deallocate_store(&store); return -EIO; } io.param = store.records[i].record; io.size = ino->vol->mft_record_size; error = ntfs_write_attr(ino->vol->mft_ino, ino->vol->at_data, 0, (__s64)store.records[i].recno << ino->vol->mft_record_size_bits, &io); if (error || io.size != ino->vol->mft_record_size) { /* Big trouble, partially written file. */ ntfs_error("Please unmount: Write error in inode " "0x%x\n", ino->i_number); deallocate_store(&store); return error ? error : -EIO; } } deallocate_store(&store); return 0;} void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l){ int head, comp; int copied = 0; unsigned char *stop; int bits; int tag = 0; int clear_pos; while (1) { head = NTFS_GETU16(src) & 0xFFF; /* High bit indicates that compression was performed. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -