📄 dir.c
字号:
NTFS_PUTU32(prev + 8, 0x18); NTFS_PUTU32(prev + 0xC, 3); NTFS_PUTU64(prev + 0x10, oldblock); othersize += 0x18; } /* Write back original block. */ error = ntfs_index_writeback(walk, start, walk->block, othersize); out: if (newbuf) ntfs_free(newbuf); if (middle) ntfs_free(middle); return error;}static int ntfs_dir_insert(ntfs_iterate_s *walk, char *start, char* entry){ int blocksize, usedsize, error, offset; int do_split = 0; offset = entry - start; if (walk->block == -1) { /* index root */ blocksize = walk->dir->vol->mft_record_size; usedsize = NTFS_GETU16(start + 0x14) + 0x10; } else { blocksize = walk->dir->u.index.recordsize; usedsize = NTFS_GETU16(start + 0x1C) + 0x18; } if (usedsize + walk->new_entry_size > blocksize) { char* s1 = ntfs_malloc(blocksize + walk->new_entry_size); if (!s1) return -ENOMEM; ntfs_memcpy(s1, start, usedsize); do_split = 1; /* Adjust entry to s1. */ entry = s1 + (entry - start); start = s1; } ntfs_memmove(entry + walk->new_entry_size, entry, usedsize - offset); ntfs_memcpy(entry, walk->new_entry, walk->new_entry_size); usedsize += walk->new_entry_size; ntfs_free(walk->new_entry); walk->new_entry = 0; if (do_split) { error = ntfs_split_record(walk, start, blocksize, usedsize); ntfs_free(start); } else { error = ntfs_index_writeback(walk, start, walk->block,usedsize); if (error) return error; } return 0;}/* Try to split INDEX_ROOT attributes. Return -E2BIG if nothing changed. */int ntfs_split_indexroot(ntfs_inode *ino){ ntfs_attribute *ra; ntfs_u8 *root = 0, *index = 0; ntfs_io io; int error, off, i, bsize, isize; ntfs_iterate_s walk; ra = ntfs_find_attr(ino, ino->vol->at_index_root, I30); if (!ra) return -ENOTDIR; bsize = ino->vol->mft_record_size; root = ntfs_malloc(bsize); if (!root) return -E2BIG; io.fn_put = ntfs_put; io.param = root; io.size = bsize; error = ntfs_read_attr(ino, ino->vol->at_index_root, I30, 0, &io); if (error) goto out; off = 0x20; /* Count number of entries. */ for (i = 0; ntfs_entry_is_used(root + off); i++) off += NTFS_GETU16(root + off + 8); if (i <= 2) { /* We don't split small index roots. */ error = -E2BIG; goto out; } index = ntfs_malloc(ino->vol->index_record_size); if (!index) { error = -ENOMEM; goto out; } walk.dir = ino; walk.block = -1; walk.result = walk.new_entry = 0; walk.name = 0; error = ntfs_allocate_index_block(&walk); if (error) goto out; /* Write old root to new index block. */ io.param = index; io.size = ino->vol->index_record_size; error = ntfs_read_attr(ino, ino->vol->at_index_allocation, I30, (__s64)walk.newblock << ino->vol->cluster_size_bits, &io); if (error) goto out; isize = NTFS_GETU16(root + 0x18) - 0x10; ntfs_memcpy(index + NTFS_GETU16(index + 0x18) + 0x18, root+0x20, isize); /* Copy flags. */ NTFS_PUTU32(index + 0x24, NTFS_GETU32(root + 0x1C)); error = ntfs_index_writeback(&walk, index, walk.newblock, isize + NTFS_GETU16(index + 0x18) + 0x18); if (error) goto out; /* Mark root as split. */ NTFS_PUTU32(root + 0x1C, 1); /* Truncate index root. */ NTFS_PUTU64(root + 0x20, 0); NTFS_PUTU32(root + 0x28, 0x18); NTFS_PUTU32(root + 0x2C, 3); NTFS_PUTU64(root + 0x30, walk.newblock); error = ntfs_index_writeback(&walk, root, -1, 0x38); out: ntfs_free(root); ntfs_free(index); return error;}/* The entry has been found. Copy the result in the caller's buffer */static int ntfs_copyresult(char *dest, char *source){ int length = NTFS_GETU16(source + 8); ntfs_memcpy(dest, source, length); return 1;}/* Use $UpCase some day. */static inline unsigned short ntfs_my_toupper(ntfs_volume *vol, ntfs_u16 x){ /* We should read any pending rest of $UpCase here. */ if (x >= vol->upcase_length) return x; return vol->upcase[x];}/* Everything passed in walk and entry. */static int ntfs_my_strcmp(ntfs_iterate_s *walk, const unsigned char *entry){ int lu = *(entry + 0x50); int i; ntfs_u16* name = (ntfs_u16*)(entry + 0x52); ntfs_volume *vol = walk->dir->vol; for (i = 0; i < lu && i < walk->namelen; i++) if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) != ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i))) break; if (i == lu && i == walk->namelen) return 0; if (i == lu) return 1; if (i == walk->namelen) return -1; if (ntfs_my_toupper(vol, NTFS_GETU16(name + i)) < ntfs_my_toupper(vol, NTFS_GETU16(walk->name + i))) return 1; return -1;}/* Necessary forward declaration. */static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry);/* Parse a block of entries. Load the block, fix it up, and iterate over the * entries. The block is given as virtual cluster number. */static int ntfs_getdir_record(ntfs_iterate_s *walk, int block){ int length = walk->dir->u.index.recordsize; char *record = (char*)ntfs_malloc(length); char *offset; int retval,error; int oldblock; ntfs_io io; if (!record) return -ENOMEM; io.fn_put = ntfs_put; io.param = record; io.size = length; /* Read the block from the index allocation attribute. */ error = ntfs_read_attr(walk->dir, walk->dir->vol->at_index_allocation, I30, (__s64)block << walk->dir->vol->cluster_size_bits, &io); if (error || io.size != length) { ntfs_error("read failed\n"); ntfs_free(record); return 0; } if (!ntfs_check_index_record(walk->dir, record)) { ntfs_error("%x is not an index record\n", block); ntfs_free(record); return 0; } offset = record + NTFS_GETU16(record + 0x18) + 0x18; oldblock = walk->block; walk->block = block; retval = ntfs_getdir_iterate(walk, record, offset); walk->block = oldblock; ntfs_free(record); return retval;}/* Go down to the next block of entries. These collate before the current * entry. */static int ntfs_descend(ntfs_iterate_s *walk, ntfs_u8 *start, ntfs_u8 *entry){ int length = NTFS_GETU16(entry + 8); int nextblock = NTFS_GETU32(entry + length - 8); int error; if (!ntfs_entry_has_subnodes(entry)) { ntfs_error("illegal ntfs_descend call\n"); return 0; } error = ntfs_getdir_record(walk, nextblock); if (!error && walk->type == DIR_INSERT && (walk->u.flags & ITERATE_SPLIT_DONE)) { /* Split has occurred. Adjust entry, insert new_entry. */ NTFS_PUTU32(entry + length - 8, walk->newblock); /* Reset flags, as the current block might be split again. */ walk->u.flags &= ~ITERATE_SPLIT_DONE; error = ntfs_dir_insert(walk, start, entry); } return error;}static int ntfs_getdir_iterate_byposition(ntfs_iterate_s *walk, char* start, char *entry){ int retval = 0; int curpos = 0, destpos = 0; int length; if (walk->u.pos != 0) { if (ntfs_is_top(walk->u.pos)) return 0; destpos = ntfs_pop(&walk->u.pos); } while (1) { if (walk->u.pos == 0) { if (ntfs_entry_has_subnodes(entry)) ntfs_descend(walk, start, entry); else walk->u.pos = ntfs_top(); if (ntfs_is_top(walk->u.pos) && !ntfs_entry_is_used(entry)) return 1; walk->u.pos = ntfs_push(walk->u.pos, curpos); return 1; } if (curpos == destpos) { if (!ntfs_is_top(walk->u.pos) && ntfs_entry_has_subnodes(entry)) { retval = ntfs_descend(walk, start, entry); if (retval) { walk->u.pos = ntfs_push(walk->u.pos, curpos); return retval; } if (!ntfs_entry_is_used(entry)) return 0; walk->u.pos = 0; } if (ntfs_entry_is_used(entry)) { retval = ntfs_copyresult(walk->result, entry); walk->u.pos = 0; } else { walk->u.pos = ntfs_top(); return 0; } } curpos++; if (!ntfs_entry_is_used(entry)) break; length = NTFS_GETU16(entry + 8); if (!length) { ntfs_error("infinite loop\n"); break; } entry += length; } return -1;} /* Iterate over a list of entries, either from an index block, or from the * index root. * If searching BY_POSITION, pop the top index from the position. If the * position stack is empty then, return the item at the index and set the * position to the next entry. If the position stack is not empty, * recursively proceed for subnodes. If the entry at the position is the * 'end of dir' entry, return 'not found' and the empty stack. * If searching BY_NAME, walk through the items until found or until * one item is collated after the requested item. In the former case, return * the result. In the latter case, recursively proceed to the subnodes. * If 'end of dir' is reached, the name is not in the directory */static int ntfs_getdir_iterate(ntfs_iterate_s *walk, char *start, char *entry){ int length; int cmp; if (walk->type == BY_POSITION) return ntfs_getdir_iterate_byposition(walk, start, entry); do { /* If the current entry is a real one, compare with the * requested item. If the current entry is the last item, it * is always larger than the requested item. */ cmp = ntfs_entry_is_used(entry) ? ntfs_my_strcmp(walk,entry) : -1; switch (walk->type) { case BY_NAME: switch (cmp) { case -1: return ntfs_entry_has_subnodes(entry) ? ntfs_descend(walk, start, entry) : 0; case 0: return ntfs_copyresult(walk->result, entry); case 1: break; } break; case DIR_INSERT: switch (cmp) { case -1: return ntfs_entry_has_subnodes(entry) ? ntfs_descend(walk, start, entry) : ntfs_dir_insert(walk, start, entry); case 0: return -EEXIST; case 1: break; } break; default: ntfs_error("TODO\n"); /* FIXME: ? */ } if (!ntfs_entry_is_used(entry)) break; length = NTFS_GETU16(entry + 8); if (!length) { ntfs_error("infinite loop\n"); break; } entry += length; } while (1); return 0;}/* Tree walking is done using position numbers. The following numbers have a * special meaning: * 0 start (.) * -1 no more entries * -2 .. * All other numbers encode sequences of indices. The sequence a, b, c is * encoded as <stop><c><b><a>, where <foo> is the encoding of foo. The * first few integers are encoded as follows: * 0: 0000 1: 0010 2: 0100 3: 0110 * 4: 1000 5: 1010 6: 1100 stop: 1110 * 7: 000001 8: 000101 9: 001001 10: 001101 * The least significant bits give the width of this encoding, the other bits * encode the value, starting from the first value of the interval. * tag width first value last value * 0 3 0 6 * 01 4 7 22 * 011 5 23 54 * 0111 6 55 119
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -