📄 dir.c
字号:
/* * dir.c * * Copyright (C) 1995-1997, 1999 Martin von L鰓is * Copyright (C) 1999 Steve Dodd * Copyright (C) 1999 Joseph Malicki * Copyright (C) 2001 Anton Altaparmakov (AIA) */#include "ntfstypes.h"#include "struct.h"#include "dir.h"#include "macros.h"#include <linux/errno.h>#include "super.h"#include "inode.h"#include "attr.h"#include "support.h"#include "util.h"#include <linux/smp_lock.h>#include <linux/bitops.h>static char I30[] = "$I30";/* An index record should start with INDX, and the last word in each block * should contain the check value. If it passes, the original values need to * be restored. */int ntfs_check_index_record(ntfs_inode *ino, char *record){ return ntfs_fixup_record(record, "INDX", ino->u.index.recordsize);}static inline int ntfs_is_top(ntfs_u64 stack){ return stack == 14;}static int ntfs_pop(ntfs_u64 *stack){ static int width[16] = {1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,-1}; int res = -1; switch (width[*stack & 15]) { case 1: res = (int)((*stack & 15) >> 1); *stack >>= 4; break; case 2: res = (int)(((*stack & 63) >> 2) + 7); *stack >>= 6; break; case 3: res = (int)(((*stack & 255) >> 3) + 23); *stack >>= 8; break; case 4: res = (int)(((*stack & 1023) >> 4) + 55); *stack >>= 10; break; default: ntfs_error("Unknown encoding\n"); } return res;}static inline unsigned int ntfs_top(void){ return 14;}static ntfs_u64 ntfs_push(ntfs_u64 stack, int i){ if (i < 7) return (stack << 4) | (i << 1); if (i < 23) return (stack << 6) | ((i - 7) << 2) | 1; if (i < 55) return (stack << 8) | ((i - 23) << 3) | 3; if (i < 120) return (stack << 10) | ((i - 55) << 4) | 7; ntfs_error("Too many entries\n"); return ~((ntfs_u64)0);}#if 0static void ntfs_display_stack(ntfs_u64 stack){ while(!ntfs_is_top(stack)) { printf("%d ", ntfs_pop(&stack)); } printf("\n");}#endif/* True if the entry points to another block of entries. */static inline int ntfs_entry_has_subnodes(char *entry){ return (NTFS_GETU16(entry + 0xc) & 1);}/* True if it is not the 'end of dir' entry. */static inline int ntfs_entry_is_used(char *entry){ return !(NTFS_GETU16(entry + 0xc) & 2);}/* * Removed RACE for allocating index blocks. But stil not too happy. * There might be more races afterwards. (AIA) */static int ntfs_allocate_index_block(ntfs_iterate_s *walk){ ntfs_attribute *allocation, *bitmap = 0; int error, size, i, bit; ntfs_u8 *bmap; ntfs_io io; ntfs_volume *vol = walk->dir->vol; /* Check for allocation attribute. */ allocation = ntfs_find_attr(walk->dir, vol->at_index_allocation, I30); if (!allocation) { ntfs_u8 bmp[8]; /* Create index allocation attribute. */ error = ntfs_create_attr(walk->dir, vol->at_index_allocation, I30, 0, 0, &allocation); if (error) goto err_ret; ntfs_bzero(bmp, sizeof(bmp)); error = ntfs_create_attr(walk->dir, vol->at_bitmap, I30, bmp, sizeof(bmp), &bitmap); if (error) goto err_ret; } else bitmap = ntfs_find_attr(walk->dir, vol->at_bitmap, I30); if (!bitmap) { ntfs_error("Directory w/o bitmap\n"); error = -EINVAL; goto err_ret; } size = bitmap->size; bmap = ntfs_malloc(size); if (!bmap) { error = -ENOMEM; goto err_ret; } io.fn_put = ntfs_put; io.fn_get = ntfs_get;try_again: io.param = bmap; io.size = size; error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, 0, &io); if (error || (io.size != size && (error = -EIO, 1))) goto err_fb_out; /* Allocate a bit. */ for (bit = i = 0; i < size; i++) { if (bmap[i] == 0xFF) continue; bit = ffz(bmap[i]); if (bit < 8) break; } if (i >= size) { /* FIXME: Extend bitmap. */ error = -EOPNOTSUPP; goto err_fb_out; } /* Get the byte containing our bit again, now taking the BKL. */ io.param = bmap; io.size = 1; lock_kernel(); error = ntfs_read_attr(walk->dir, vol->at_bitmap, I30, i, &io); if (error || (io.size != 1 && (error = -EIO, 1))) goto err_unl_out; if (ntfs_test_and_set_bit(bmap, bit)) { unlock_kernel(); /* Give other process(es) a chance to finish. */ schedule(); goto try_again; } walk->newblock = (i * 8 + bit) * walk->dir->u.index.clusters_per_record; io.param = bmap; error = ntfs_write_attr(walk->dir, vol->at_bitmap, I30, i, &io); if (error || (io.size != size && (error = -EIO, 1))) goto err_unl_out; /* Change inode on disk, required when bitmap is resident. */ error = ntfs_update_inode(walk->dir); if (error) goto err_unl_out; unlock_kernel(); ntfs_free(bmap); /* Check whether record is out of allocated range. */ size = allocation->size; if (walk->newblock * vol->cluster_size >= size) { /* Build index record. */ int hsize; int s1 = walk->dir->u.index.recordsize; int nr_fix = (s1 >> vol->sector_size) + 1; char *record = ntfs_malloc(s1); if (!record) { error = -ENOMEM; goto err_ret; } ntfs_bzero(record, s1); /* Magic */ ntfs_memcpy(record, "INDX", 4); /* Offset to fixups */ NTFS_PUTU16(record + 4, 0x28); /* Number of fixups. */ NTFS_PUTU16(record + 6, nr_fix); /* Log file sequence number - We don't do journalling so we * just set it to zero which should be the Right Thing. (AIA) */ NTFS_PUTU64(record + 8, 0); /* VCN of buffer */ NTFS_PUTU64(record + 0x10, walk->newblock); /* Header size. */ hsize = 0x10 + 2 * nr_fix; hsize = (hsize + 7) & ~7; /* Align. */ NTFS_PUTU16(record + 0x18, hsize); /* Total size of record. */ NTFS_PUTU32(record + 0x20, s1 - 0x18); /* Writing the data will extend the attribute. */ io.param = record; io.size = s1; io.do_read = 0; error = ntfs_readwrite_attr(walk->dir, allocation, size, &io); ntfs_free(record); if (error || (io.size != s1 && (error = -EIO, 1))) goto err_ret; error = ntfs_update_inode(walk->dir); if (error) goto err_ret; } return 0;err_unl_out: unlock_kernel();err_fb_out: ntfs_free(bmap);err_ret: return error;}/* Write an index block (root or allocation) back to storage. * Used is the total number of bytes in buf, including all headers. */static int ntfs_index_writeback(ntfs_iterate_s *walk, ntfs_u8 *buf, int block, int used){ ntfs_io io; int error; ntfs_attribute *a; ntfs_volume *vol = walk->dir->vol; io.fn_put = 0; io.fn_get = ntfs_get; io.param = buf; if (block == -1) { /* Index root. */ NTFS_PUTU16(buf + 0x14, used - 0x10); /* 0x18 is a copy thereof. */ NTFS_PUTU16(buf + 0x18, used - 0x10); io.size = used; error = ntfs_write_attr(walk->dir, vol->at_index_root, I30, 0, &io); if (error || (io.size != used && (error = -EIO, 1))) return error; /* Shrink if necessary. */ a = ntfs_find_attr(walk->dir, vol->at_index_root, I30); ntfs_resize_attr(walk->dir, a, used); } else { NTFS_PUTU16(buf + 0x1C, used - 0x18); io.size = walk->dir->u.index.recordsize; error = ntfs_insert_fixups(buf, io.size); if (error) { printk(KERN_ALERT "NTFS: ntfs_index_writeback() caught " "corrupt index record ntfs record " "header. Refusing to write corrupt " "data to disk. Unmount and run chkdsk " "immediately!\n"); return -EIO; } error = ntfs_write_attr(walk->dir, vol->at_index_allocation, I30, (__s64)block << vol->cluster_size_bits, &io); if (error || (io.size != walk->dir->u.index.recordsize && (error = -EIO, 1))) return error; } return 0;}static int ntfs_split_record(ntfs_iterate_s *walk, char *start, int bsize, int usize){ char *entry, *prev; ntfs_u8 *newbuf = 0, *middle = 0; int error, othersize, mlen; ntfs_io io; ntfs_volume *vol = walk->dir->vol; int oldblock; error = ntfs_allocate_index_block(walk); if (error) return error; /* This should not happen. */ if (walk->block == -1) { ntfs_error("Trying to split root"); return -EOPNOTSUPP; } entry = start + NTFS_GETU16(start + 0x18) + 0x18; for (prev = entry; entry - start < usize / 2; entry += NTFS_GETU16(entry + 8)) prev = entry; newbuf = ntfs_malloc(vol->index_record_size); if (!newbuf) return -ENOMEM; io.fn_put = ntfs_put; io.fn_get = ntfs_get; io.param = newbuf; io.size = vol->index_record_size; /* Read in old header. FIXME: Reading everything is overkill. */ error = ntfs_read_attr(walk->dir, vol->at_index_allocation, I30, (__s64)walk->newblock << vol->cluster_size_bits, &io); if (error) goto out; if (io.size != vol->index_record_size) { error = -EIO; goto out; } /* FIXME: Adjust header. */ /* Copy everything from entry to new block. */ othersize = usize - (entry - start); ntfs_memcpy(newbuf + NTFS_GETU16(newbuf + 0x18) + 0x18, entry, othersize); /* Copy flags. */ NTFS_PUTU32(newbuf + 0x24, NTFS_GETU32(start + 0x24)); error = ntfs_index_writeback(walk, newbuf, walk->newblock, othersize + NTFS_GETU16(newbuf + 0x18) + 0x18); if (error) goto out; /* Move prev to walk. */ mlen = NTFS_GETU16(prev + 0x8); /* Remember old child node. */ if (ntfs_entry_has_subnodes(prev)) oldblock = NTFS_GETU32(prev + mlen - 8); else oldblock = -1; /* Allow for pointer to subnode. */ middle = ntfs_malloc(ntfs_entry_has_subnodes(prev) ? mlen : mlen + 8); if (!middle){ error = -ENOMEM; goto out; } ntfs_memcpy(middle, prev, mlen); /* Set has_subnodes flag. */ NTFS_PUTU8(middle + 0xC, NTFS_GETU8(middle + 0xC) | 1); /* Middle entry points to block, parent entry will point to newblock. */ NTFS_PUTU64(middle + mlen - 8, walk->block); if (walk->new_entry) ntfs_error("Entry not reset"); walk->new_entry = middle; walk->u.flags |= ITERATE_SPLIT_DONE; /* Terminate old block. */ othersize = usize - (prev-start); NTFS_PUTU64(prev, 0); if (oldblock == -1) { NTFS_PUTU32(prev + 8, 0x10); NTFS_PUTU32(prev + 0xC, 2); othersize += 0x10; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -