diff --git a/configure.ac b/configure.ac index 6f384d39..03b85204 100644 --- a/configure.ac +++ b/configure.ac @@ -149,6 +149,15 @@ AC_ARG_ENABLE(debug-logging, fi, ) +AC_ARG_ENABLE(rich, + AS_HELP_STRING(--enable-rich,enable Rich's "rm" test code), , + enable_rich=no +) +AM_CONDITIONAL(ENABLE_RICH, test "$enable_rich" = yes) +if test "$enable_rich" = "yes"; then + CFLAGS="$CFLAGS -DNTFS_RICH" +fi + # Use GNU extensions if available. AC_GNU_SOURCE diff --git a/include/ntfs/Makefile.am b/include/ntfs/Makefile.am index 11c6ed97..2725ae93 100644 --- a/include/ntfs/Makefile.am +++ b/include/ntfs/Makefile.am @@ -24,10 +24,12 @@ linux_ntfsinclude_HEADERS = \ logging.h \ mft.h \ mst.h \ + ntfstime.h \ + rich.h \ runlist.h \ security.h \ support.h \ - ntfstime.h \ + tree.h \ types.h \ unistr.h \ version.h \ diff --git a/include/ntfs/bitmap.h b/include/ntfs/bitmap.h index c18aa43b..041153f9 100644 --- a/include/ntfs/bitmap.h +++ b/include/ntfs/bitmap.h @@ -2,6 +2,7 @@ * bitmap.h - Exports for bitmap handling. Part of the Linux-NTFS project. * * Copyright (c) 2000-2004 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -130,4 +131,36 @@ static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit) return ntfs_bitmap_clear_run(na, bit, 1); } + +#ifdef NTFS_RICH + +#include "layout.h" +#include "inode.h" + +/** + * struct ntfs_bmp + * a cache for either dir/$BITMAP, $MFT/$BITMAP or $Bitmap/$DATA + */ +struct ntfs_bmp { + ntfs_volume *vol; + ntfs_attr *attr; + int count; + u8 **data; + VCN *data_vcn; +}; + + +int ntfs_bmp_rollback (struct ntfs_bmp *bmp); +int ntfs_bmp_commit (struct ntfs_bmp *bmp); +void ntfs_bmp_free (struct ntfs_bmp *bmp); +struct ntfs_bmp * ntfs_bmp_create (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len); +int ntfs_bmp_add_data (struct ntfs_bmp *bmp, VCN vcn, u8 *data); +u8 * ntfs_bmp_get_data (struct ntfs_bmp *bmp, VCN vcn); +int ntfs_bmp_set_range (struct ntfs_bmp *bmp, VCN vcn, s64 length, int value); +s64 ntfs_bmp_find_last_set (struct ntfs_bmp *bmp); +int ntfs_bmp_find_space (struct ntfs_bmp *bmp, LCN start, long size); + +#endif /* NTFS_RICH */ + #endif /* defined _NTFS_BITMAP_H */ + diff --git a/include/ntfs/dir.h b/include/ntfs/dir.h index 98b1b256..e6a65930 100644 --- a/include/ntfs/dir.h +++ b/include/ntfs/dir.h @@ -3,6 +3,7 @@ * * Copyright (c) 2002 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -73,5 +74,37 @@ typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name, extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir); +#ifdef NTFS_RICH + +/** + * struct ntfs_dir + */ +struct ntfs_dir { + ntfs_volume *vol; + struct ntfs_dir *parent; + ntfschar *name; + int name_len; + MFT_REF mft_num; + struct ntfs_dt *index; + struct ntfs_dir **children; + int child_count; + struct ntfs_bmp *bitmap; + ntfs_inode *inode; + ntfs_attr *iroot; + ntfs_attr *ialloc; + int index_size; +}; + + +int ntfs_dir_rollback (struct ntfs_dir *dir); +int ntfs_dir_truncate (ntfs_volume *vol, struct ntfs_dir *dir); +int ntfs_dir_commit (struct ntfs_dir *dir); +void ntfs_dir_free (struct ntfs_dir *dir); +struct ntfs_dir * ntfs_dir_create (ntfs_volume *vol, MFT_REF mft_num); +void ntfs_dir_add (struct ntfs_dir *parent, struct ntfs_dir *child); +struct ntfs_dir * ntfs_dir_find2 (struct ntfs_dir *dir, ntfschar *name, int name_len); + +#endif /* NTFS_RICH */ + #endif /* defined _NTFS_DIR_H */ diff --git a/include/ntfs/index.h b/include/ntfs/index.h index c4a78375..20ce386d 100644 --- a/include/ntfs/index.h +++ b/include/ntfs/index.h @@ -3,6 +3,7 @@ * * Copyright (c) 2004 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -121,4 +122,21 @@ static inline void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx) ictx->ia_dirty = TRUE; } + +#ifdef NTFS_RICH + +#include "layout.h" + +void ntfs_ie_free (INDEX_ENTRY *ie); +INDEX_ENTRY * ntfs_ie_create (void); +VCN ntfs_ie_get_vcn (INDEX_ENTRY *ie); +INDEX_ENTRY * ntfs_ie_copy (INDEX_ENTRY *ie); +INDEX_ENTRY * ntfs_ie_set_vcn (INDEX_ENTRY *ie, VCN vcn); +INDEX_ENTRY * ntfs_ie_remove_vcn (INDEX_ENTRY *ie); +INDEX_ENTRY * ntfs_ie_set_name (INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype); +INDEX_ENTRY * ntfs_ie_remove_name (INDEX_ENTRY *ie); + +#endif /* NTFS_RICH */ + #endif /* _NTFS_INDEX_H */ + diff --git a/include/ntfs/inode.h b/include/ntfs/inode.h index 05c4f07c..41fdf242 100644 --- a/include/ntfs/inode.h +++ b/include/ntfs/inode.h @@ -3,6 +3,7 @@ * * Copyright (c) 2001,2002 Anton Altaparmakov * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -184,4 +185,12 @@ extern int ntfs_inode_add_attrlist(ntfs_inode *ni); extern int ntfs_inode_free_space(ntfs_inode *ni, int size); +#ifdef NTFS_RICH + +int ntfs_inode_close2 (ntfs_inode *ni); +ntfs_inode * ntfs_inode_open2 (ntfs_volume *vol, const MFT_REF mref); +ntfs_inode * ntfs_inode_open3 (ntfs_volume *vol, const MFT_REF mref); + +#endif /* NTFS_RICH */ + #endif /* defined _NTFS_INODE_H */ diff --git a/include/ntfs/mft.h b/include/ntfs/mft.h index 4d842949..00d2088f 100644 --- a/include/ntfs/mft.h +++ b/include/ntfs/mft.h @@ -2,6 +2,7 @@ * mft.h - Exports for MFT record handling. Part of the Linux-NTFS project. * * Copyright (c) 2000-2002 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -110,5 +111,18 @@ extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni); extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni); +#ifdef NTFS_RICH + +#include "bitmap.h" +#include "dir.h" + +int ntfs_mft_remove_attr (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type); +ATTR_RECORD * ntfs_mft_add_attr (ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len); +int ntfs_mft_resize_resident (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len); +int ntfs_mft_free_space (struct ntfs_dir *dir); +int ntfs_mft_add_index (struct ntfs_dir *dir); + +#endif /* NTFS_RICH */ + #endif /* defined _NTFS_MFT_H */ diff --git a/include/ntfs/rich.h b/include/ntfs/rich.h new file mode 100644 index 00000000..e07451a7 --- /dev/null +++ b/include/ntfs/rich.h @@ -0,0 +1,50 @@ +/** + * rich.h - Temporary junk file. Part of the Linux-NTFS project. + * + * Copyright (c) 2004-2005 Richard Russon + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_RICH_H_ +#define _NTFS_RICH_H_ + +#include "layout.h" +#include "attrib.h" +#include "bitmap.h" + +// XXX Temporarily copied from utils.h +#define RED "\e[31m" +#define GREEN "\e[32m" +#define YELLOW "\e[33m" +#define BLUE "\e[34m" +#define MAGENTA "\e[35m" +#define CYAN "\e[36m" +#define BOLD "\e[01m" +#define END "\e[0m" + +#define ROUND_UP(num,bound) (((num)+((bound)-1)) & ~((bound)-1)) +#define ROUND_DOWN(num,bound) ((num) & ~((bound)-1)) +#define ATTR_SIZE(s) ROUND_UP(s,8) + +ATTR_RECORD * find_attribute (const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); +ATTR_RECORD * find_first_attribute (const ATTR_TYPES type, MFT_RECORD *mft); +int utils_free_non_residents3 (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr); +int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp); +void ntfs_name_print (ntfschar *name, int name_len); + +#endif /* _NTFS_RICH_H_ */ + diff --git a/include/ntfs/tree.h b/include/ntfs/tree.h new file mode 100644 index 00000000..76dda3b0 --- /dev/null +++ b/include/ntfs/tree.h @@ -0,0 +1,82 @@ +/** + * tree.h - Directory tree handling code. Part of the Linux-NTFS project. + * + * Copyright (c) 2004-2005 Richard Russon + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_TREE_H_ +#define _NTFS_TREE_H_ + +#include "layout.h" +#include "volume.h" + +struct ntfs_dir; + +/** + * struct ntfs_dt + */ +struct ntfs_dt { + struct ntfs_dir *dir; + struct ntfs_dt *parent; + u8 *data; + int data_len; + int child_count; + INDEX_ENTRY **children; + struct ntfs_dt **sub_nodes; + ntfs_inode **inodes; + VCN vcn; + INDEX_HEADER *header; + BOOL changed; +}; + + +void ntfs_dt_free (struct ntfs_dt *dt); +int ntfs_dt_rollback (struct ntfs_dt *dt); +int ntfs_dt_commit (struct ntfs_dt *dt); +BOOL ntfs_dt_create_children2 (struct ntfs_dt *dt, int count); +BOOL ntfs_dt_resize_children3 (struct ntfs_dt *dt, int new); +int ntfs_dt_root_count (struct ntfs_dt *dt); +int ntfs_dt_alloc_count (struct ntfs_dt *dt); +int ntfs_dt_initialise2 (ntfs_volume *vol, struct ntfs_dt *dt); +struct ntfs_dt * ntfs_dt_create (struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn); +MFT_REF ntfs_dt_find (struct ntfs_dt *dt, ntfschar *name, int name_len); +struct ntfs_dt * ntfs_dt_find2 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num); +struct ntfs_dt * ntfs_dt_find3 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num); +struct ntfs_dt * ntfs_dt_find4 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num); +void ntfs_dt_find_all (struct ntfs_dt *dt); +int ntfs_dt_find_parent (struct ntfs_dt *dt); +BOOL ntfs_dt_isroot (struct ntfs_dt *dt); +int ntfs_dt_root_freespace (struct ntfs_dt *dt); +int ntfs_dt_alloc_freespace (struct ntfs_dt *dt); +int ntfs_dt_transfer (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count); +int ntfs_dt_alloc_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count); +INDEX_ENTRY * ntfs_dt_alloc_insert2 (struct ntfs_dt *dt, int before, int count, int bytes); +int ntfs_dt_root_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count); +int ntfs_dt_alloc_remove2 (struct ntfs_dt *dt, int start, int count); +int ntfs_dt_root_remove2 (struct ntfs_dt *dt, int start, int count); +int ntfs_dt_transfer2 (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count); +int ntfs_dt_root_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie); +BOOL ntfs_dt_alloc_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie); +BOOL ntfs_dt_root_remove (struct ntfs_dt *del, int del_num); +BOOL ntfs_dt_alloc_remove (struct ntfs_dt *del, int del_num); +int ntfs_dt_alloc_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child); +int ntfs_dt_root_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child); +int ntfs_dt_add2 (INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded); + +#endif /* _NTFS_TREE_H_ */ + diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index 3c126732..17d1828c 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -3,6 +3,7 @@ * * Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -203,5 +204,16 @@ extern int ntfs_logfile_reset(ntfs_volume *vol); extern int ntfs_volume_write_flags(ntfs_volume *v, const u16 flags); +#ifdef NTFS_RICH + +int ntfs_volume_commit (ntfs_volume *vol); +int ntfs_volume_rollback (ntfs_volume *vol); +int ntfs_volume_umount2 (ntfs_volume *vol, const BOOL force); +ntfs_volume * ntfs_volume_mount2 (const char *device, unsigned long flags, BOOL force); +int utils_valid_device (const char *name, int force); +ntfs_volume * utils_mount_volume (const char *device, unsigned long flags, BOOL force); + +#endif /* NTFS_RICH */ + #endif /* defined _NTFS_VOLUME_H */ diff --git a/libntfs/Makefile.am b/libntfs/Makefile.am index 4828c850..f1fd592e 100644 --- a/libntfs/Makefile.am +++ b/libntfs/Makefile.am @@ -60,6 +60,10 @@ libntfs_la_SOURCES = \ version.c \ volume.c +if ENABLE_RICH +libntfs_la_SOURCES += rich.c tree.c +endif + if ENABLE_GNOME_VFS gnomevfsmoduleslibdir = $(libdir)/gnome-vfs-2.0/modules diff --git a/libntfs/bitmap.c b/libntfs/bitmap.c index 9bae43eb..79ca11c0 100644 --- a/libntfs/bitmap.c +++ b/libntfs/bitmap.c @@ -2,6 +2,7 @@ * bitmap.c - Bitmap handling code. Part of the Linux-NTFS project. * * Copyright (c) 2002-2004 Anton Altaparmakov + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -220,3 +221,388 @@ int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count) { return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0); } + + +#ifdef NTFS_RICH + +#include + +#include "layout.h" +#include "volume.h" +#include "bitmap.h" +#include "rich.h" + +/** + * ntfs_bmp_rollback + */ +int ntfs_bmp_rollback (struct ntfs_bmp *bmp) +{ + int i; + + if ((!bmp) || (bmp->count == 0)) + return 0; + + for (i = 0; i < bmp->count; i++) + free (bmp->data[i]); + + free (bmp->data); + free (bmp->data_vcn); + bmp->data = NULL; + bmp->data_vcn = NULL; + bmp->count = 0; + + return 0; +} + +/** + * ntfs_bmp_commit + */ +int ntfs_bmp_commit (struct ntfs_bmp *bmp) +{ + int i; + u32 cs; +#ifdef RM_WRITE + u32 ws; // write size +#endif + + if (!bmp) + return 0; + if (bmp->count == 0) + return 0; + +#if 0 + printf ("attr = 0x%02X\n", bmp->attr->type); + printf ("resident = %d\n", !NAttrNonResident (bmp->attr)); + printf ("\ta size = %lld\n", bmp->attr->allocated_size); + printf ("\td size = %lld\n", bmp->attr->data_size); + printf ("\ti size = %lld\n", bmp->attr->initialized_size); +#endif + + printf ("commit bmp inode %lld, 0x%02X (%sresident)\n", bmp->attr->ni->mft_no, bmp->attr->type, NAttrNonResident (bmp->attr) ? "non-" : ""); + + if (NAttrNonResident (bmp->attr)) { + cs = bmp->vol->cluster_size; + + // non-resident + for (i = 0; i < bmp->count; i++) { +#ifdef RM_WRITE + if (((bmp->data_vcn[i]+1) * cs) < bmp->attr->data_size) + ws = cs; + else + ws = bmp->attr->data_size & (cs - 1); + //printf ("writing %d bytes\n", ws); + ntfs_attr_pwrite (bmp->attr, bmp->data_vcn[i] * cs, ws, bmp->data[i]); // XXX retval +#endif + printf (RED "\tntfs_attr_pwrite (vcn %lld)\n" END, bmp->data_vcn[i]); + } + } else { + // resident +#ifdef RM_WRITE + ntfs_attr_pwrite (bmp->attr, bmp->data_vcn[0], bmp->attr->data_size, bmp->data[0]); // XXX retval +#endif + printf (RED "\tntfs_attr_pwrite resident (%lld)\n" END, bmp->attr->data_size); + } + + ntfs_bmp_rollback (bmp); + + return 0; +} + +/** + * ntfs_bmp_free + */ +void ntfs_bmp_free (struct ntfs_bmp *bmp) +{ + if (!bmp) + return; + + ntfs_bmp_rollback (bmp); + + ntfs_attr_close (bmp->attr); + + free (bmp); +} + +/** + * ntfs_bmp_create + */ +struct ntfs_bmp * ntfs_bmp_create (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len) +{ + struct ntfs_bmp *bmp; + ntfs_attr *attr; + + if (!inode) + return NULL; + + attr = ntfs_attr_open (inode, type, name, name_len); + if (!attr) + return NULL; + + bmp = calloc (1, sizeof (*bmp)); + if (!bmp) { + ntfs_attr_close (attr); + return NULL; + } + + bmp->vol = inode->vol; + bmp->attr = attr; + bmp->data = NULL; + bmp->data_vcn = NULL; + bmp->count = 0; + + return bmp; +} + +/** + * ntfs_bmp_add_data + */ +int ntfs_bmp_add_data (struct ntfs_bmp *bmp, VCN vcn, u8 *data) +{ + int i = 0; + int old; + int new; + + if (!bmp || !data) + return -1; + + old = ROUND_UP (bmp->count, 16); + bmp->count++; + new = ROUND_UP (bmp->count, 16); + + if (old != new) { + bmp->data = realloc (bmp->data, new * sizeof (*bmp->data)); + bmp->data_vcn = realloc (bmp->data_vcn , new * sizeof (*bmp->data_vcn)); + } + + for (i = 0; i < bmp->count-1; i++) + if (bmp->data_vcn[i] > vcn) + break; + + if ((bmp->count-i) > 0) { + memmove (&bmp->data[i+1], &bmp->data[i], (bmp->count-i) * sizeof (*bmp->data)); + memmove (&bmp->data_vcn[i+1], &bmp->data_vcn[i], (bmp->count-i) * sizeof (*bmp->data_vcn)); + } + + bmp->data[i] = data; + bmp->data_vcn[i] = vcn; + + return bmp->count; +} + +/** + * ntfs_bmp_get_data + */ +u8 * ntfs_bmp_get_data (struct ntfs_bmp *bmp, VCN vcn) +{ + u8 *buffer; + int i; + int cs; + int cb; + + if (!bmp) + return NULL; + + cs = bmp->vol->cluster_size; + cb = bmp->vol->cluster_size_bits; + + // XXX range check against vol,attr + // never compressed, so data = init + + vcn >>= (cb + 3); // convert to bitmap clusters + + for (i = 0; i < bmp->count; i++) { + if (vcn == bmp->data_vcn[i]) { + //printf ("reusing bitmap cluster %lld\n", vcn); + return bmp->data[i]; + } + } + + buffer = calloc (1, cs); // XXX could be smaller if attr size < cluster size + if (!buffer) + return NULL; + + //printf ("loading from bitmap cluster %lld\n", vcn); + //printf ("loading from bitmap byte %lld\n", vcn<attr, vcn<vol->cluster_size << 3; + + vcn_start = vcn; + vcn_finish = vcn + length - 1; + + //printf ("vcn_start = %d, vcn_finish = %d\n", vcn_start, vcn_finish); + a = ROUND_DOWN (vcn_start, csib); + b = ROUND_DOWN (vcn_finish, csib) + 1; + + //printf ("a = %lld, b = %lld\n", a, b); + + for (i = a; i < b; i += csib) { + //printf ("ntfs_bmp_get_data %lld\n", i); + buffer = ntfs_bmp_get_data (bmp, i); + if (!buffer) + return -1; + + block_start = i; + block_finish = block_start + csib - 1; + + mask_start = (0xFF << (vcn_start & 7)); + mask_finish = (0xFF >> (7 - (vcn_finish & 7))); + + if ((vcn_start >= block_start) && (vcn_start <= block_finish)) { + byte_start = (vcn_start - block_start) >> 3; + } else { + byte_start = 0; + mask_start = 0xFF; + } + + if ((vcn_finish >= block_start) && (vcn_finish <= block_finish)) { + byte_finish = (vcn_finish - block_start) >> 3; + } else { + byte_finish = bmp->vol->cluster_size - 1; + mask_finish = 0xFF; + } + + if ((byte_finish - byte_start) > 1) { + memset (buffer+byte_start+1, value, byte_finish-byte_start-1); + } else if (byte_finish == byte_start) { + mask_start &= mask_finish; + mask_finish = 0x00; + } + + if (value) { + buffer[byte_start] |= mask_start; + buffer[byte_finish] |= mask_finish; + } else { + buffer[byte_start] &= (~mask_start); + buffer[byte_finish] &= (~mask_finish); + } + } + +#if 1 + printf (GREEN "Modified: inode %lld, ", bmp->attr->ni->mft_no); + switch (bmp->attr->type) { + case AT_BITMAP: printf ("$BITMAP"); break; + case AT_DATA: printf ("$DATA"); break; + default: break; + } + printf (" vcn %lld-%lld\n" END, vcn>>12, (vcn+length-1)>>12); +#endif + return 1; +} + +/** + * ntfs_bmp_find_last_set + */ +s64 ntfs_bmp_find_last_set (struct ntfs_bmp *bmp) +{ + s64 clust_count; + s64 byte_count; + s64 clust; + int byte; + int bit; + int note; + u8 *buffer; + + if (!bmp) + return -2; + + // find byte size of bmp + // find cluster size of bmp + + byte_count = bmp->attr->data_size; + clust_count = ROUND_UP (byte_count, bmp->vol->cluster_size) >> bmp->vol->cluster_size_bits; + + //printf ("bitmap = %lld bytes\n", byte_count); + //printf ("bitmap = %lld buffers\n", clust_count); + + // for each cluster backwards + for (clust = clust_count-1; clust >= 0; clust--) { + //printf ("cluster %lld\n", clust); + //printf ("get vcn %lld\n", clust << (bmp->vol->cluster_size_bits + 3)); + buffer = ntfs_bmp_get_data (bmp, clust << (bmp->vol->cluster_size_bits + 3)); + //utils_dump_mem (buffer, 0, 8, DM_NO_ASCII); + if (!buffer) + return -2; + if ((clust == (clust_count-1) && ((byte_count % bmp->vol->cluster_size) != 0))) { + byte = byte_count % bmp->vol->cluster_size; + } else { + byte = bmp->vol->cluster_size; + } + //printf ("start byte = %d\n", byte); + // for each byte backward + for (byte--; byte >= 0; byte--) { + //printf ("\tbyte %d (%d)\n", byte, buffer[byte]); + // for each bit shift up + note = -1; + for (bit = 7; bit >= 0; bit--) { + //printf ("\t\tbit %d (%d)\n", (1<= 0) { + // if note, return value + //printf ("match %lld (c=%lld,b=%d,n=%d)\n", (((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note, clust, byte, note); + return ((((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note); + } + } + } + + return -1; +} + +/** + * ntfs_bmp_find_space + */ +int ntfs_bmp_find_space (struct ntfs_bmp *bmp, LCN start, long size) +{ + if (!bmp) + return 0; + + start = 0; + size = 0; + + /* + bmp find space - uncached bmp's + $Bitmap/$DATA free space on volume + dir/$BITMAP free index record + $MFT/$BITMAP free record in mft + */ + return 0; +} + + +#endif /* NTFS_RICH */ + diff --git a/libntfs/dir.c b/libntfs/dir.c index 3118f0ef..88c517b0 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -3,6 +3,7 @@ * * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -1506,3 +1507,391 @@ err_out: errno = err; return -1; } + + +#ifdef NTFS_RICH + +#include + +#include "layout.h" +#include "volume.h" +#include "inode.h" +#include "dir.h" +#include "tree.h" +#include "bitmap.h" +#include "index.h" +#include "rich.h" + +/** + * ntfs_dir_rollback + */ +int ntfs_dir_rollback (struct ntfs_dir *dir) +{ + int i; + + if (!dir) + return -1; + + if (ntfs_dt_rollback (dir->index) < 0) + return -1; + + if (ntfs_bmp_rollback (dir->bitmap) < 0) + return -1; + + for (i = 0; i < dir->child_count; i++) { + if (ntfs_dir_rollback (dir->children[i]) < 0) + return -1; + } + + return 0; +} + +/** + * ntfs_dir_truncate + */ +int ntfs_dir_truncate (ntfs_volume *vol, struct ntfs_dir *dir) +{ + //int i; + //u8 *buffer; + //int buf_count; + s64 last_bit; + INDEX_ENTRY *ie; + + if (!vol || !dir) + return -1; + + if ((dir->ialloc == NULL) || (dir->bitmap == NULL)) + return 0; + +#if 0 + buf_count = ROUND_UP (dir->bitmap->attr->allocated_size, vol->cluster_size) >> vol->cluster_size_bits; + printf ("alloc = %lld bytes\n", dir->ialloc->allocated_size); + printf ("alloc = %lld clusters\n", dir->ialloc->allocated_size >> vol->cluster_size_bits); + printf ("bitmap bytes 0 to %lld\n", ((dir->ialloc->allocated_size >> vol->cluster_size_bits)-1)>>3); + printf ("bitmap = %p\n", dir->bitmap); + printf ("bitmap = %lld bytes\n", dir->bitmap->attr->allocated_size); + printf ("bitmap = %d buffers\n", buf_count); +#endif + + last_bit = ntfs_bmp_find_last_set (dir->bitmap); + if (dir->ialloc->allocated_size == (dir->index_size * (last_bit + 1))) { + //printf ("nothing to do\n"); + return 0; + } + + printf (BOLD YELLOW "Truncation needed\n" END); + +#if 0 + printf ("\tlast bit = %lld\n", last_bit); + printf ("\tactual IALLOC size = %lld\n", dir->ialloc->allocated_size); + printf ("\tshould IALLOC size = %lld\n", dir->index_size * (last_bit + 1)); +#endif + + if ((dir->index_size * (last_bit + 1)) == 0) { + printf ("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); + //rollback all dts + //ntfs_dt_rollback (dir->index); + //dir->index = NULL; + // What about the ROOT dt? + + ie = ntfs_ie_copy (dir->index->children[0]); + if (!ie) { + printf (RED "IE copy failed\n" END); + return -1; + } + + ie = ntfs_ie_remove_vcn (ie); + if (!ie) { + printf (RED "IE remove vcn failed\n" END); + return -1; + } + + //utils_dump_mem (dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); printf ("\n"); + //utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS); printf ("\n"); + ntfs_dt_root_replace (dir->index, 0, dir->index->children[0], ie); + //utils_dump_mem (dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); printf ("\n"); + //printf ("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); + + ntfs_ie_free (ie); + ie = NULL; + + //index flags remove LARGE_INDEX + dir->index->header->flags = 0; + + //rollback dir's bmp + ntfs_bmp_free (dir->bitmap); + dir->bitmap = NULL; + + /* + for (i = 0; i < dir->index->child_count; i++) { + ntfs_dt_rollback (dir->index->sub_nodes[i]); + dir->index->sub_nodes[i] = NULL; + } + */ + + //printf ("dir->index->inodes[0] = %p\n", dir->index->inodes[0]); + + //remove 0xA0 attribute + ntfs_mft_remove_attr (vol->private_bmp2, dir->inode, AT_INDEX_ALLOCATION); + + //remove 0xB0 attribute + ntfs_mft_remove_attr (vol->private_bmp2, dir->inode, AT_BITMAP); + } else { + printf (RED "Cannot shrink directory\n" END); + //ntfs_dir_shrink_alloc + //ntfs_dir_shrink_bitmap + //make bitmap resident? + } + + /* + * Remove + * dt -> dead + * bitmap updated + * rollback dead dts + * commit bitmap + * commit dts + * commit dir + */ + /* + * Reuse + * search for lowest dead + * update bitmap + * init dt + * remove from dead + * insert into tree + * init INDX + */ + +#if 0 + buffer = ntfs_bmp_get_data (dir->bitmap, 0); + if (!buffer) + return -1; + + utils_dump_mem (buffer, 0, 8, DM_NO_ASCII); + for (i = buf_count-1; i >= 0; i--) { + if (buffer[i]) { + printf ("alloc in use\n"); + return 0; + } + } +#endif + + // /$BITMAP($I30) + // /$INDEX_ALLOCATION($I30) + // $Bitmap + + // Find the highest set bit in the directory bitmap + // can we free any clusters of the alloc? + // if yes, resize attribute + + // Are *any* bits set? + // If not remove ialloc + + return 0; +} + +/** + * ntfs_dir_commit + */ +int ntfs_dir_commit (struct ntfs_dir *dir) +{ + int i; + + if (!dir) + return 0; + + printf ("commit dir inode %llu\n", dir->inode->mft_no); + if (NInoDirty (dir->inode)) { +#ifdef RM_WRITE + ntfs_inode_sync (dir->inode); +#endif + printf (RED "\tntfs_inode_sync %llu\n" END, dir->inode->mft_no); + } + + if (ntfs_dt_commit (dir->index) < 0) + return -1; + + if (ntfs_bmp_commit (dir->bitmap) < 0) + return -1; + + for (i = 0; i < dir->child_count; i++) { + if (ntfs_dir_commit (dir->children[i]) < 0) + return -1; + } + + return 0; +} + +/** + * ntfs_dir_free + */ +void ntfs_dir_free (struct ntfs_dir *dir) +{ + struct ntfs_dir *parent; + int i; + + if (!dir) + return; + + ntfs_dir_rollback (dir); + + parent = dir->parent; + if (parent) { + for (i = 0; i < parent->child_count; i++) { + if (parent->children[i] == dir) { + parent->children[i] = NULL; + } + } + } + + ntfs_attr_close (dir->iroot); + ntfs_attr_close (dir->ialloc); + ntfs_inode_close2 (dir->inode); + + ntfs_dt_free (dir->index); + ntfs_bmp_free (dir->bitmap); + + for (i = 0; i < dir->child_count; i++) + ntfs_dir_free (dir->children[i]); + + free (dir->name); + free (dir->children); + free (dir); +} + +/** + * ntfs_dir_create + */ +struct ntfs_dir * ntfs_dir_create (ntfs_volume *vol, MFT_REF mft_num) +{ + struct ntfs_dir *dir = NULL; + ntfs_inode *inode = NULL; + ATTR_RECORD *rec = NULL; + INDEX_ROOT *ir = NULL; + FILE_NAME_ATTR *name = NULL; + + if (!vol) + return NULL; + + //printf ("ntfs_dir_create %lld\n", MREF (mft_num)); + inode = ntfs_inode_open2 (vol, mft_num); + if (!inode) + return NULL; + + dir = calloc (1, sizeof (*dir)); + if (!dir) { + ntfs_inode_close2 (inode); + return NULL; + } + + dir->inode = inode; + dir->iroot = ntfs_attr_open (inode, AT_INDEX_ROOT, I30, 4); + dir->ialloc = ntfs_attr_open (inode, AT_INDEX_ALLOCATION, I30, 4); + + if (!dir->iroot) { + ntfs_dir_free (dir); + return NULL; + } + + dir->vol = vol; + dir->parent = NULL; + dir->name = NULL; + dir->name_len = 0; + dir->index = NULL; + dir->children = NULL; + dir->child_count = 0; + dir->mft_num = mft_num; + + // This may not exist + dir->bitmap = ntfs_bmp_create (inode, AT_BITMAP, I30, 4); + + if (dir->iroot) { + rec = find_first_attribute (AT_INDEX_ROOT, inode->mrec); + ir = (INDEX_ROOT*) ((u8*)rec + rec->value_offset); + dir->index_size = ir->index_block_size; + } else { + // XXX !iroot? + dir->index_size = 0; + } + + // Finally, find the dir's name + rec = find_first_attribute (AT_FILE_NAME, inode->mrec); + name = (FILE_NAME_ATTR*) ((u8*)rec + rec->value_offset); + + dir->name_len = name->file_name_length; + dir->name = malloc (sizeof (ntfschar) * dir->name_len); + memcpy (dir->name, name->file_name, sizeof (ntfschar) * dir->name_len); + + return dir; +} + +/** + * ntfs_dir_add + */ +void ntfs_dir_add (struct ntfs_dir *parent, struct ntfs_dir *child) +{ + if (!parent || !child) + return; + + parent->child_count++; + //printf ("child count = %d\n", parent->child_count); + parent->children = realloc (parent->children, parent->child_count * sizeof (struct ntfs_dir*)); + child->parent = parent; + + parent->children[parent->child_count-1] = child; +} + +/** + * ntfs_dir_find2 + */ +struct ntfs_dir * ntfs_dir_find2 (struct ntfs_dir *dir, ntfschar *name, int name_len) +{ + int i; + struct ntfs_dir *child = NULL; + struct ntfs_dt *dt = NULL; + int dt_num = 0; + INDEX_ENTRY *ie; + MFT_REF mft_num; + + if (!dir || !name) + return NULL; + + if (!dir->index) { // XXX when will this happen? + printf ("ntfs_dir_find2 - directory has no index\n"); + return NULL; + } + + for (i = 0; i < dir->child_count; i++) { + if (0 == ntfs_names_collate (name, name_len, + dir->children[i]->name, + dir->children[i]->name_len, + 2, IGNORE_CASE, + dir->vol->upcase, + dir->vol->upcase_len)) + return dir->children[i]; + } + + dt = ntfs_dt_find2 (dir->index, name, name_len, &dt_num); + if (!dt) { + printf ("can't find name in dir\n"); + return NULL; + } + + ie = dt->children[dt_num]; + + mft_num = ie->indexed_file; + + child = ntfs_dir_create (dir->vol, mft_num); + if (!child) + return NULL; + + child->index = ntfs_dt_create (child, NULL, -1); + + ntfs_dir_add (dir, child); + + return child; +} + + +#endif /* NTFS_RICH */ + diff --git a/libntfs/index.c b/libntfs/index.c index 41786e6f..1824e478 100644 --- a/libntfs/index.c +++ b/libntfs/index.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004-2005 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -642,3 +643,228 @@ err_out: errno = err; return -1; } + + +#ifdef NTFS_RICH + +#include +#include + +#include "index.h" +#include "rich.h" + +/** + * ntfs_ie_free + */ +void ntfs_ie_free (INDEX_ENTRY *ie) +{ + free (ie); +} + +/** + * ntfs_ie_create + */ +INDEX_ENTRY * ntfs_ie_create (void) +{ + int length; + INDEX_ENTRY *ie; + + length = 16; + ie = calloc (1, length); + if (!ie) + return NULL; + + ie->indexed_file = 0; + ie->length = length; + ie->key_length = 0; + ie->flags = INDEX_ENTRY_END; + ie->reserved = 0; + return ie; +} + +/** + * ntfs_ie_get_vcn + */ +VCN ntfs_ie_get_vcn (INDEX_ENTRY *ie) +{ + if (!ie) + return -1; + if (!(ie->flags & INDEX_ENTRY_NODE)) + return -1; + + return *((VCN*) ((u8*) ie + ie->length - 8)); +} + +/** + * ntfs_ie_copy + */ +INDEX_ENTRY * ntfs_ie_copy (INDEX_ENTRY *ie) +{ + INDEX_ENTRY *copy = NULL; + + if (!ie) + return NULL; + + copy = malloc (ie->length); + if (!copy) + return NULL; + memcpy (copy, ie, ie->length); + + return copy; +} + +/** + * ntfs_ie_set_vcn + */ +INDEX_ENTRY * ntfs_ie_set_vcn (INDEX_ENTRY *ie, VCN vcn) +{ + if (!ie) + return 0; + + if (!(ie->flags & INDEX_ENTRY_NODE)) { + ie->length += 8; + ie = realloc (ie, ie->length); + if (!ie) + return NULL; + + ie->flags |= INDEX_ENTRY_NODE; + } + + *((VCN*) ((u8*) ie + ie->length - 8)) = vcn; + return ie; +} + +/** + * ntfs_ie_remove_vcn + */ +INDEX_ENTRY * ntfs_ie_remove_vcn (INDEX_ENTRY *ie) +{ + if (!ie) + return NULL; + if (!(ie->flags & INDEX_ENTRY_NODE)) + return ie; + + ie->length -= 8; + ie->flags &= ~INDEX_ENTRY_NODE; + ie = realloc (ie, ie->length); + return ie; +} + +/** + * ntfs_ie_set_name + */ +INDEX_ENTRY * ntfs_ie_set_name (INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype) +{ + FILE_NAME_ATTR *file; + int need; + BOOL wipe = FALSE; + VCN vcn = 0; + + if (!ie || !name) + return NULL; + + /* + * INDEX_ENTRY + * MFT_REF indexed_file; + * u16 length; + * u16 key_length; + * INDEX_ENTRY_FLAGS flags; + * u16 reserved; + * + * FILENAME + * MFT_REF parent_directory; + * s64 creation_time; + * s64 last_data_change_time; + * s64 last_mft_change_time; + * s64 last_access_time; + * s64 allocated_size; + * s64 data_size; + * FILE_ATTR_FLAGS file_attributes; + * u32 reserved; + * u8 file_name_length; + * FILE_NAME_TYPE_FLAGS file_name_type; + * ntfschar file_name[l]; + * u8 reserved[n] + * + * VCN vcn; + */ + + //printf ("key length = 0x%02X\n", ie->key_length); + //printf ("new name length = %d\n", namelen); + if (ie->key_length > 0) { + file = &ie->key.file_name; + //printf ("filename, length %d\n", file->file_name_length); + need = ATTR_SIZE (namelen * sizeof (ntfschar) + 2) - + ATTR_SIZE (file->file_name_length * sizeof (ntfschar) + 2); + } else { + //printf ("no filename\n"); + need = ATTR_SIZE (sizeof (FILE_NAME_ATTR) + (namelen * sizeof (ntfschar))); + wipe = TRUE; + } + + //printf ("need 0x%02X bytes\n", need); + + if (need != 0) { + if (ie->flags & INDEX_ENTRY_NODE) + vcn = ntfs_ie_get_vcn (ie); + + ie->length += need; + ie->key_length += need; + + //printf ("realloc 0x%02X\n", ie->length); + ie = realloc (ie, ie->length); + if (!ie) + return NULL; + + if (ie->flags & INDEX_ENTRY_NODE) + ie = ntfs_ie_set_vcn (ie, vcn); + + if (wipe) + memset (&ie->key.file_name, 0, sizeof (FILE_NAME_ATTR)); + if (need > 0) + memset ((u8*)ie + ie->length - need, 0, need); + } + + memcpy (ie->key.file_name.file_name, name, namelen * sizeof (ntfschar)); + + ie->key.file_name.file_name_length = namelen; + ie->key.file_name.file_name_type = nametype; + ie->flags &= ~INDEX_ENTRY_END; + + //printf ("ie->length = 0x%02X\n", ie->length); + //printf ("ie->key_length = 0x%02X\n", ie->key_length); + + return ie; +} + +/** + * ntfs_ie_remove_name + */ +INDEX_ENTRY * ntfs_ie_remove_name (INDEX_ENTRY *ie) +{ + VCN vcn = 0; + + if (!ie) + return NULL; + if (ie->key_length == 0) + return ie; + + if (ie->flags & INDEX_ENTRY_NODE) + vcn = ntfs_ie_get_vcn (ie); + + ie->length -= ATTR_SIZE (ie->key_length); + ie->key_length = 0; + ie->flags |= INDEX_ENTRY_END; + + ie = realloc (ie, ie->length); + if (!ie) + return NULL; + + if (ie->flags & INDEX_ENTRY_NODE) + ie = ntfs_ie_set_vcn (ie, vcn); + return ie; +} + + +#endif /* NTFS_RICH */ + diff --git a/libntfs/inode.c b/libntfs/inode.c index d91c870b..96a41854 100644 --- a/libntfs/inode.c +++ b/libntfs/inode.c @@ -3,6 +3,7 @@ * * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2004-2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -1083,3 +1084,121 @@ put_err_out: errno = err; return -1; } + + +#ifdef NTFS_RICH + +/** + * ntfs_inode_close2 + */ +int ntfs_inode_close2 (ntfs_inode *ni) +{ + if (!ni) + return 0; + + //printf (BOLD YELLOW "inode close %lld (%d)\n" END, ni->mft_no, ni->ref_count); + + ni->ref_count--; + if (ni->ref_count > 0) + return 0; + + // unlink + // ino->private_data + + // XXX temporary until we have commit/rollback + NInoClearDirty(ni); + + return ntfs_inode_close (ni); +} + +/** + * ntfs_inode_open2 + */ +ntfs_inode * ntfs_inode_open2 (ntfs_volume *vol, const MFT_REF mref) +{ + ntfs_inode *ino = NULL; + struct ntfs_dir *dir; + + if (!vol) + return NULL; + + switch (mref) { + case FILE_Bitmap: ino = vol->lcnbmp_ni; break; + case FILE_MFT: ino = vol->mft_ni; break; + case FILE_MFTMirr: ino = vol->mftmirr_ni; break; + case FILE_root: + dir = vol->private_data; + if (dir) + ino = dir->inode; + break; + } + + if (ino) { + //printf (BOLD YELLOW "inode reuse %lld\n" END, mref); + ino->ref_count++; + return ino; + } + + ino = ntfs_inode_open (vol, mref); + if (!ino) + return NULL; + + /* + if (mref != FILE_root) + ntfs_inode_dir_map (ino); + */ + + // link + // ino->private_data + + ino->private_data = NULL; + ino->ref_count = 1; + + //printf (BOLD YELLOW "inode open %lld\n" END, mref); + return ino; +} + +/** + * ntfs_inode_open3 + * open a deleted inode + */ +ntfs_inode * ntfs_inode_open3 (ntfs_volume *vol, const MFT_REF mref) +{ + ntfs_inode *ino = NULL; + + if (!vol) + return NULL; + + ino = calloc (1, sizeof (*ino)); + if (!ino) + return NULL; + + ino->mrec = malloc (vol->mft_record_size); + if (!ino->mrec) { + free (ino); + return NULL; + } + + ino->mft_no = mref; + ino->vol = vol; + + ino->data_size = -1; + ino->allocated_size = -1; + + ino->private_data = NULL; + ino->ref_count = 1; + + if (1 != ntfs_attr_mst_pread (vol->mft_na, MREF(mref) * vol->mft_record_size, 1, vol->mft_record_size, ino->mrec)) { + //ntfs_inode_close2 (ino); ??? + free (ino->mrec); + free (ino); + return NULL; + } + + NInoSetDirty (ino); + return ino; +} + + +#endif /* NTFS_RICH */ + diff --git a/libntfs/mft.c b/libntfs/mft.c index ce4ed5fb..beb682fc 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -3,6 +3,7 @@ * * Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2005 Yura Pakhuchiy + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -1543,3 +1544,340 @@ sync_rollback: errno = err; return -1; } + + +#ifdef NTFS_RICH + +#include "bitmap.h" +#include "dir.h" +#include "tree.h" +#include "index.h" +#include "rich.h" + +/** + * ntfs_mft_remove_attr + */ +int ntfs_mft_remove_attr (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type) +{ + ATTR_RECORD *attr20, *attrXX; + MFT_RECORD *mft; + u8 *src, *dst; + int len; + + if (!inode) + return 1; + + attr20 = find_first_attribute (AT_ATTRIBUTE_LIST, inode->mrec); + if (attr20) + return 1; + + printf ("remove inode %lld, attr 0x%02X\n", inode->mft_no, type); + + attrXX = find_first_attribute (type, inode->mrec); + if (!attrXX) + return 1; + + if (utils_free_non_residents3 (bmp, inode, attrXX)) + return 1; + + // remove entry + // inode->mrec + + mft = inode->mrec; + //utils_dump_mem (mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n"); + + //utils_dump_mem (attrXX, 0, attrXX->length, DM_DEFAULTS); printf ("\n"); + + //printf ("mrec = %p, attr = %p, diff = %d (0x%02X)\n", mft, attrXX, (u8*)attrXX - (u8*)mft, (u8*)attrXX - (u8*)mft); + // memmove + + dst = (u8*) attrXX; + src = dst + attrXX->length; + len = (((u8*) mft + mft->bytes_in_use) - src); + + // fix mft header + mft->bytes_in_use -= attrXX->length; + +#if 0 + printf ("dst = 0x%02X, src = 0x%02X, len = 0x%02X\n", (dst - (u8*)mft), (src - (u8*)mft), len); + printf ("attr %02X, len = 0x%02X\n", attrXX->type, attrXX->length); + printf ("bytes in use = 0x%02X\n", mft->bytes_in_use); + printf ("\n"); +#endif + + memmove (dst, src, len); + //utils_dump_mem (mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n"); + + NInoSetDirty(inode); + return 0; +} + +/** + * ntfs_mft_add_attr + */ +ATTR_RECORD * ntfs_mft_add_attr (ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len) +{ + MFT_RECORD *mrec; + ATTR_RECORD *attr; + u8 *ptr; + u8 *src; + u8 *dst; + int len; + int attr_size; + + if (!inode) + return NULL; + if (!data) + return NULL; + + attr_size = ATTR_SIZE (data_len); + + mrec = inode->mrec; + if (!mrec) + return NULL; + + if ((mrec->bytes_in_use + attr_size + 0x18) > mrec->bytes_allocated) { + printf ("attribute is too big to fit in the record\n"); + return NULL; + } + + ptr = (u8*) inode->mrec + mrec->attrs_offset; + while (1) { + attr = (ATTR_RECORD*) ptr; + + if (type < attr->type) + break; + + ptr += attr->length; + } + + //printf ("insert before attr 0x%02X\n", attr->type); + + len = ((u8*) mrec + mrec->bytes_in_use) - ((u8*) attr); + src = (u8*) attr; + dst = src + attr_size + 0x18; + + memmove (dst, src, len); + + src = data; + dst = (u8*) attr + 0x18; + len = data_len; + + // XXX wipe slack space after attr? + + memcpy (dst, src, len); + + mrec->bytes_in_use += attr_size + 0x18; + + memset (attr, 0, 0x18); + *(u32*)((u8*) attr + 0x00) = type; + *(u32*)((u8*) attr + 0x04) = attr_size + 0x18; + *(u16*)((u8*) attr + 0x0E) = mrec->next_attr_instance; + *(u32*)((u8*) attr + 0x10) = data_len; + *(u32*)((u8*) attr + 0x14) = 0x18; + + mrec->next_attr_instance++; + + return attr; +} + +/** + * ntfs_mft_resize_resident + */ +int ntfs_mft_resize_resident (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len) +{ + int mft_size; + int mft_usage; + int mft_free; + int attr_orig; + int attr_new; + u8 *src; + u8 *dst; + u8 *end; + int len; + ntfs_attr_search_ctx *ctx = NULL; + ATTR_RECORD *arec = NULL; + MFT_RECORD *mrec = NULL; + int res = -1; + + // XXX only works when attr is in base inode + + if ((!inode) || (!inode->mrec)) + return -1; + if ((!data) || (data_len < 0)) + return -1; + + mrec = inode->mrec; + + mft_size = mrec->bytes_allocated; + mft_usage = mrec->bytes_in_use; + mft_free = mft_size - mft_usage; + + //printf ("mft_size = %d\n", mft_size); + //printf ("mft_usage = %d\n", mft_usage); + //printf ("mft_free = %d\n", mft_free); + //printf ("\n"); + + ctx = ntfs_attr_get_search_ctx (NULL, mrec); + if (!ctx) + goto done; + + if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, ctx) != 0) + goto done; + + arec = ctx->attr; + + if (arec->non_resident) { + printf ("attribute isn't resident\n"); + goto done; + } + + attr_orig = arec->value_length; + attr_new = data_len; + + //printf ("attr orig = %d\n", attr_orig); + //printf ("attr new = %d\n", attr_new); + //printf ("\n"); + + if ((attr_new - attr_orig + mft_usage) > mft_size) { + printf ("attribute won't fit into mft record\n"); + goto done; + } + + //printf ("new free space = %d\n", mft_size - (attr_new - attr_orig + mft_usage)); + + src = (u8*)arec + arec->length; + dst = src + (attr_new - attr_orig); + end = (u8*)mrec + mft_usage; + len = end - src; + + //printf ("src = %d\n", src - (u8*)mrec); + //printf ("dst = %d\n", dst - (u8*)mrec); + //printf ("end = %d\n", end - (u8*)mrec); + //printf ("len = %d\n", len); + + if (src != dst) + memmove (dst, src, len); + + memcpy ((u8*)arec + arec->value_offset, data, data_len); + + mrec->bytes_in_use += (attr_new - attr_orig); + arec->length += (attr_new - attr_orig); + arec->value_length += (attr_new - attr_orig); + + memset ((u8*)mrec + mrec->bytes_in_use, 0, mft_size - mrec->bytes_in_use); + + mft_usage += (attr_new - attr_orig); + //utils_dump_mem (mrec, 0, mft_size, DM_DEFAULTS); + res = 0; +done: + ntfs_attr_put_search_ctx (ctx); + return res; +} + +/** + * ntfs_mft_free_space + */ +int ntfs_mft_free_space (struct ntfs_dir *dir) +{ + int res = 0; + MFT_RECORD *mft; + + if ((!dir) || (!dir->inode)) + return -1; + + mft = (MFT_RECORD*) dir->inode->mrec; + + res = mft->bytes_allocated - mft->bytes_in_use; + + return res; +} + +/** + * ntfs_mft_add_index + */ +int ntfs_mft_add_index (struct ntfs_dir *dir) +{ + ntfs_volume *vol; + u8 *buffer = NULL; + ATTR_RECORD *attr = NULL; + struct ntfs_dt *dt = NULL; + INDEX_ENTRY *ie = NULL; + + if (!dir) + return 1; + if (dir->bitmap && dir->ialloc) + return 0; + if (dir->bitmap || dir->ialloc) + return 1; + if (dir->index_size < 512) + return 1; + + vol = dir->vol; + printf ("add two attrs to " YELLOW); ntfs_name_print (dir->name, dir->name_len); printf (END "\n"); + printf ("index size = %d\n", dir->index_size); + + buffer = malloc (dir->index_size); + if (!buffer) + return 1; + + dt = ntfs_dt_create (dir, dir->index, -1); + if (!dt) + return 1; + + dt->vcn = 0; // New alloc record + + ie = ntfs_ie_copy (dir->index->children[dir->index->child_count-1]); + ie = ntfs_ie_set_vcn (ie, dt->vcn); + + // can't replace ie yet, there may not be room + ntfs_ie_free (ie); + + ntfs_dt_transfer2 (dir->index, dt, 0, dir->index->child_count - 1); + + printf ("root has %d children\n", dir->index->child_count); + printf ("node has %d children\n", dt->child_count); + + ntfs_dt_free (dt); + + // create a new dt + // attach dt to dir + // move entries into alloc + // shrink root + + // transfer keys to new node + // hook up root & alloc dts + + // need disk allocation before here + + // Index Allocation + memset (buffer, 0, 128); + attr = ntfs_mft_add_attr (dir->inode, AT_INDEX_ALLOCATION, buffer, 0x48); + + // Bitmap + memset (buffer, 0, 8); + buffer[0] = 0x01; + //printf ("inode = %p\n", dir->inode); + attr = ntfs_mft_add_attr (dir->inode, AT_BITMAP, buffer, 8); + + // attach alloc and bitmap to dir + // need to create ntfs_attr's for them + + // one indx record + // 8 bits of bitmap + + if (0) ntfs_bmp_find_space (NULL, 0, 0); + + //printf ("m1 = %lld\n", vol->mft_zone_start); + //printf ("m2 = %lld\n", vol->mft_zone_end); + //printf ("m3 = %lld\n", vol->mft_zone_pos); + //printf ("z1 = %lld\n", vol->data1_zone_pos); + //printf ("z2 = %lld\n", vol->data2_zone_pos); + + free (buffer); + return 0; +} + + +#endif /* NTFS_RICH */ + diff --git a/libntfs/rich.c b/libntfs/rich.c new file mode 100644 index 00000000..aefe4a3e --- /dev/null +++ b/libntfs/rich.c @@ -0,0 +1,177 @@ +/** + * rich.c - Temporary junk file. Part of the Linux-NTFS project. + * + * Copyright (c) 2004-2005 Richard Russon + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef NTFS_RICH + +#include +#include "rich.h" +#include "layout.h" + +/** + * find_attribute - Find an attribute of the given type + * @type: An attribute type, e.g. AT_FILE_NAME + * @ctx: A search context, created using ntfs_get_attr_search_ctx + * + * Using the search context to keep track, find the first/next occurrence of a + * given attribute type. + * + * N.B. This will return a pointer into @mft. As long as the search context + * has been created without an inode, it won't overflow the buffer. + * + * Return: Pointer Success, an attribute was found + * NULL Error, no matching attributes were found + */ +ATTR_RECORD * find_attribute (const ATTR_TYPES type, ntfs_attr_search_ctx *ctx) +{ + if (!ctx) { + errno = EINVAL; + return NULL; + } + + if (ntfs_attr_lookup(type, NULL, 0, 0, 0, NULL, 0, ctx) != 0) { + Dprintf ("find_attribute didn't find an attribute of type: 0x%02x.\n", type); + return NULL; /* None / no more of that type */ + } + + Dprintf ("find_attribute found an attribute of type: 0x%02x.\n", type); + return ctx->attr; +} + +/** + * find_first_attribute - Find the first attribute of a given type + * @type: An attribute type, e.g. AT_FILE_NAME + * @mft: A buffer containing a raw MFT record + * + * Search through a raw MFT record for an attribute of a given type. + * The return value is a pointer into the MFT record that was supplied. + * + * N.B. This will return a pointer into @mft. The pointer won't stray outside + * the buffer, since we created the search context without an inode. + * + * Return: Pointer Success, an attribute was found + * NULL Error, no matching attributes were found + */ +ATTR_RECORD * find_first_attribute (const ATTR_TYPES type, MFT_RECORD *mft) +{ + ntfs_attr_search_ctx *ctx; + ATTR_RECORD *rec; + + if (!mft) { + errno = EINVAL; + return NULL; + } + + ctx = ntfs_attr_get_search_ctx (NULL, mft); + if (!ctx) { + //XXX Eprintf ("Couldn't create a search context.\n"); + return NULL; + } + + rec = find_attribute (type, ctx); + ntfs_attr_put_search_ctx (ctx); + if (rec) + Dprintf ("find_first_attribute: found attr of type 0x%02x.\n", type); + else + Dprintf ("find_first_attribute: didn't find attr of type 0x%02x.\n", type); + return rec; +} + +/** + * ntfs_name_print + */ +void ntfs_name_print (ntfschar *name, int name_len) +{ + char *buffer = NULL; + + if (name_len) { + ntfs_ucstombs (name, name_len, &buffer, 0); + printf ("%s", buffer); + free (buffer); + } else { + printf ("!"); + } +} + +/** + * utils_free_non_residents3 + */ +int utils_free_non_residents3 (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr) +{ + ntfs_attr *na; + runlist_element *rl; + LCN size; + LCN count; + + if (!bmp) + return 1; + if (!inode) + return 1; + if (!attr) + return 1; + if (!attr->non_resident) + return 0; + + na = ntfs_attr_open (inode, attr->type, NULL, 0); + if (!na) + return 1; + + ntfs_attr_map_whole_runlist (na); + rl = na->rl; + size = na->allocated_size >> inode->vol->cluster_size_bits; + for (count = 0; count < size; count += rl->length, rl++) { + if (ntfs_bmp_set_range (bmp, rl->lcn, rl->length, 0) < 0) { + printf (RED "set range : %lld - %lld FAILED\n" END, rl->lcn, rl->lcn+rl->length-1); + } + } + ntfs_attr_close (na); + + return 0; +} + +/** + * utils_free_non_residents2 + */ +int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp) +{ + ntfs_attr_search_ctx *ctx; + + if (!inode) + return -1; + if (!bmp) + return -1; + + ctx = ntfs_attr_get_search_ctx (NULL, inode->mrec); + if (!ctx) { + printf ("can't create a search context\n"); + return -1; + } + + while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) { + utils_free_non_residents3 (bmp, inode, ctx->attr); + } + + ntfs_attr_put_search_ctx (ctx); + return 0; +} + + +#endif /* NTFS_RICH */ + diff --git a/libntfs/tree.c b/libntfs/tree.c new file mode 100644 index 00000000..dbbaec36 --- /dev/null +++ b/libntfs/tree.c @@ -0,0 +1,2119 @@ +/** + * tree.c - Directory tree handling code. Part of the Linux-NTFS project. + * + * Copyright (c) 2004-2005 Richard Russon + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef NTFS_RICH + +#include "config.h" + +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "volume.h" +#include "dir.h" + +#include "tree.h" +#include "bitmap.h" +#include "index.h" +#include "inode.h" +#include "rich.h" + +/** + * ntfs_dt_free + */ +void ntfs_dt_free (struct ntfs_dt *dt) +{ + int i; + + if (!dt) + return; + + for (i = 0; i < dt->child_count; i++) { + ntfs_dt_free (dt->sub_nodes[i]); + ntfs_inode_close2 (dt->inodes[i]); + } + + free (dt->sub_nodes); + free (dt->children); + free (dt->inodes); + free (dt->data); // XXX is this always ours? + free (dt); +} + +/** + * ntfs_dt_rollback + */ +int ntfs_dt_rollback (struct ntfs_dt *dt) +{ + int i; + + if (!dt) + return 0; + if (dt->child_count == 0) // No children or nothing mapped + return 0; + + if (dt->changed) { + // We can't trust anything below us in the tree + for (i = 0; i < dt->child_count; i++) { + ntfs_dt_free (dt->sub_nodes[i]); + ntfs_inode_close2 (dt->inodes[i]); + } + + dt->child_count = 0; + + free (dt->data); + free (dt->children); + free (dt->sub_nodes); + free (dt->inodes); + + dt->data = NULL; + dt->children = NULL; + dt->sub_nodes = NULL; + dt->inodes = NULL; + } else { + // This node is OK, check the su-nodes + for (i = 0; i < dt->child_count; i++) { + if (ntfs_dt_rollback (dt->sub_nodes[i])) { + ntfs_inode_close2 (dt->inodes[i]); + // Child was changed so unmap it + dt->sub_nodes[i] = NULL; + dt->inodes[i] = NULL; + } + } + } + + return (dt->child_count == 0); +} + +/** + * ntfs_dt_commit + */ +int ntfs_dt_commit (struct ntfs_dt *dt) +{ + ntfs_volume *vol; + ntfs_attr *attr; + struct ntfs_dir *dir; + int i; + int size; + + if (!dt) + return 0; + + dir = dt->dir; + if (!dir) + return -1; + + vol = dir->vol; // cluster size + + if (dt->changed) { + if (dt->parent) { + printf ("commit dt (alloc)\n"); + attr = dt->dir->ialloc; + size = dt->dir->index_size; + //utils_dump_mem (dt->data, 0, size, DM_DEFAULTS); +#ifdef RM_WRITE + ntfs_attr_mst_pwrite(attr, dt->vcn * vol->cluster_size, 1, size, dt->data); // XXX retval +#endif + } else { + printf ("commit dt (root)\n"); + attr = dt->dir->iroot; + size = dt->data_len; + //utils_dump_mem (dt->data, 0, size, DM_DEFAULTS); +#ifdef RM_WRITE + ntfs_attr_pwrite(attr, 0, size, dt->data); // XXX retval +#endif + } + + printf (RED "\tntfs_attr_pwrite (vcn %lld)\n" END, dt->vcn); + + dt->changed = FALSE; + } + + for (i = 0; i < dt->child_count; i++) { + if ((dt->inodes[i]) && (NInoDirty (dt->inodes[i]))) { + //utils_dump_mem (dt->inodes[i]->mrec, 0, vol->mft_record_size, DM_DEFAULTS); +#ifdef RM_WRITE + ntfs_inode_sync (dt->inodes[i]); +#endif + printf (RED "\tntfs_inode_sync %llu\n" END, dt->inodes[i]->mft_no); + } + + if (ntfs_dt_commit (dt->sub_nodes[i]) < 0) + return -1; + } + + return 0; +} + +/** + * ntfs_dt_create_children2 + */ +BOOL ntfs_dt_create_children2 (struct ntfs_dt *dt, int count) +{ + // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN) + + int old = (dt->child_count + 0x1e) & ~0x1f; + int new = (count + 0x1f) & ~0x1f; + + if (old == new) + return TRUE; + + dt->children = realloc (dt->children, new * sizeof (*dt->children)); + dt->sub_nodes = realloc (dt->sub_nodes, new * sizeof (*dt->sub_nodes)); + dt->inodes = realloc (dt->inodes, new * sizeof (*dt->inodes)); + + if (!dt->children || !dt->sub_nodes || !dt->inodes) + return FALSE; // dt->child_count = -1 ? + + memset ((u8*)dt->children + old, 0, (new - old) * sizeof (*dt->children)); + memset ((u8*)dt->sub_nodes + old, 0, (new - old) * sizeof (*dt->sub_nodes)); + memset ((u8*)dt->inodes + old, 0, (new - old) * sizeof (*dt->inodes)); + + return TRUE; +} + +/** + * ntfs_dt_resize_children3 + */ +BOOL ntfs_dt_resize_children3 (struct ntfs_dt *dt, int new) +{ + int old; + + // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN) + // XXX assumption: sizeof (*dt->children) == sizeof (*dt->sub_nodes) == sizeof (*dt->inodes) + // XXX put back blocking factor + + if (!dt) + return FALSE; + + old = dt->child_count; + if (old == new) + return TRUE; + + dt->child_count = new; + + old *= sizeof (*dt->children); + new *= sizeof (*dt->children); + + dt->children = realloc (dt->children, new); + dt->sub_nodes = realloc (dt->sub_nodes, new); + dt->inodes = realloc (dt->inodes, new); + + if (!dt->children || !dt->sub_nodes || !dt->inodes) + return FALSE; + + if (new > old) { + memset ((u8*)dt->children + old, 0, (new - old)); + memset ((u8*)dt->sub_nodes + old, 0, (new - old)); + memset ((u8*)dt->inodes + old, 0, (new - old)); + } + + return TRUE; +} + +/** + * ntfs_dt_root_count + */ +int ntfs_dt_root_count (struct ntfs_dt *dt) +{ + u8 *buffer = NULL; + u8 *ptr = NULL; + VCN vcn; + s64 size = 0; + char *name = NULL; + + INDEX_ROOT *root; + INDEX_HEADER *header; + INDEX_ENTRY *entry; + + if (!dt) + return -1; + + buffer = dt->data; + size = dt->data_len; + + root = (INDEX_ROOT*) buffer; + if (root->type != AT_FILE_NAME) + return -1; + + header = (INDEX_HEADER*) (buffer + 0x10); + if (header->index_length > size) + return -1; + + dt->child_count = 0; + ptr = buffer + header->entries_offset + 0x10; + + while (ptr < (buffer + size)) { + entry = (INDEX_ENTRY*) ptr; + + ntfs_dt_resize_children3 (dt, dt->child_count + 1); // XXX retval + + if (entry->flags & INDEX_ENTRY_NODE) { + vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr); + //printf ("VCN %lld\n", vcn); + } + + if (!(entry->flags & INDEX_ENTRY_END)) { + ntfs_ucstombs (entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0); + //printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name); + free (name); + name = NULL; + } + + //printf ("CC[%d] = %p\n", dt->child_count-1, entry); + dt->children[dt->child_count-1] = entry; + + ptr += entry->length; + } + + //printf ("count = %d\n\n", dt->child_count); + + return dt->child_count; +} + +/** + * ntfs_dt_alloc_count + */ +int ntfs_dt_alloc_count (struct ntfs_dt *dt) +{ + u8 *buffer = NULL; + u8 *ptr = NULL; + VCN vcn; + s64 size = 0; + char *name = NULL; + + INDEX_BLOCK *block; + INDEX_ENTRY *entry; + + if (!dt) + return -1; + + buffer = dt->data; + size = dt->data_len; + + //utils_dump_mem (buffer, 0, 128, DM_DEFAULTS); + + block = (INDEX_BLOCK*) buffer; + //printf ("INDX %lld\n", block->index_block_vcn); + + ptr = buffer + 0x18 + block->index.entries_offset; + + //printf ("block size %d\n", block->index.index_length); + dt->child_count = 0; + //printf ("start = 0x%02X, end = 0x%02X\n", 0x18 + block->index.entries_offset, 0x18 + block->index.index_length); + while (ptr < (buffer + 0x18 + block->index.index_length)) { + entry = (INDEX_ENTRY*) ptr; + + ntfs_dt_resize_children3 (dt, dt->child_count + 1); // XXX retval + + if (entry->flags & INDEX_ENTRY_NODE) { + vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr); + //printf ("\tVCN %lld\n", vcn); + } + + dt->children[dt->child_count-1] = entry; + + if (entry->flags & INDEX_ENTRY_END) { + break; + } else { + ntfs_ucstombs (entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0); + //printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name); + free (name); + name = NULL; + } + + ptr += entry->length; + } + //printf ("count = %d\n", dt->child_count); + + return dt->child_count; +} + +/** + * ntfs_dt_initialise2 + */ +int ntfs_dt_initialise2 (ntfs_volume *vol, struct ntfs_dt *dt) +{ + INDEX_ALLOCATION *alloc; + INDEX_ENTRY *entry; + + if (!vol) + return 1; + if (!dt) + return 1; + + memset (dt->data, 0, dt->data_len); + + alloc = (INDEX_ALLOCATION*) dt->data; + + alloc->magic = magic_INDX; + alloc->usa_ofs = 0x28; + alloc->usa_count = (dt->data_len >> vol->sector_size_bits) + 1; + alloc->lsn = 0; + alloc->index_block_vcn = 0; + + alloc->index.entries_offset = 0x28; + alloc->index.index_length = 0x10 + 0x28; + alloc->index.allocated_size = dt->data_len - 0x18; + alloc->index.flags = 0; + + entry = (INDEX_ENTRY*) (dt->data + 0x40); + + entry->indexed_file = 0; + entry->length = 0x10; + entry->key_length = 0; + entry->flags = INDEX_ENTRY_END; + + ntfs_dt_resize_children3 (dt, 1); // XXX retval + + dt->children[0] = entry; + + return 0; +} + +/** + * ntfs_dt_create + */ +struct ntfs_dt * ntfs_dt_create (struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn) +{ + struct ntfs_dt *dt = NULL; + //int i; + + if (!dir) + return NULL; + + dt = calloc (1, sizeof (*dt)); + if (!dt) + return NULL; + + dt->dir = dir; + dt->parent = parent; + dt->child_count = 0; + dt->children = NULL; + dt->sub_nodes = NULL; + dt->inodes = NULL; + dt->vcn = vcn; + dt->changed = FALSE; + + if (parent) { + //printf ("alloc a = %lld\n", dir->ialloc->allocated_size); + //printf ("alloc d = %lld\n", dir->ialloc->data_size); + //printf ("alloc i = %lld\n", dir->ialloc->initialized_size); + //printf ("vcn = %lld\n", vcn); + + dt->data_len = dt->dir->index_size; + //printf ("parent size = %d\n", dt->data_len); + dt->data = malloc (dt->data_len); + + if (vcn >= 0) { + //printf ("%lld\n", ntfs_attr_mst_pread (dir->ialloc, vcn*512, 1, dt->data_len, dt->data)); + ntfs_attr_mst_pread (dir->ialloc, vcn*512, 1, dt->data_len, dt->data); + } else { + ntfs_dt_initialise2 (dir->vol, dt); + } + + //utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS); + //printf ("\n"); + + ntfs_dt_alloc_count (dt); + + dt->header = &((INDEX_BLOCK*)dt->data)->index; + //printf ("USA = %d\n", ((INDEX_BLOCK*)dt->data)->usa_count); + +#if 0 + for (i = 0; i < dt->child_count; i++) { + INDEX_ENTRY *ie = dt->children[i]; + + printf ("%d\n", ((u8*)ie) - dt->data); + if (ie->flags & INDEX_ENTRY_END) + printf ("IE (%d)\n", ie->length); + else + printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length); + utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS); + printf ("\n"); + } +#endif + } else { + //printf ("root a = %lld\n", dir->iroot->allocated_size); + //printf ("root d = %lld\n", dir->iroot->data_size); + //printf ("root i = %lld\n", dir->iroot->initialized_size); + + dt->data_len = dir->iroot->allocated_size; + dt->data = malloc (dt->data_len); + //printf ("%lld\n", ntfs_attr_pread (dir->iroot, 0, dt->data_len, dt->data)); + ntfs_attr_pread (dir->iroot, 0, dt->data_len, dt->data); + //utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS); + //printf ("\n"); + + ntfs_dt_root_count (dt); + + dt->header = &((INDEX_ROOT*)dt->data)->index; + //dt->data_len = ((INDEX_ROOT*)dt->data)->index_block_size; + //printf ("IBS = %d\n", ((INDEX_ROOT*)dt->data)->index_block_size); + +#if 0 + for (i = 0; i < dt->child_count; i++) { + INDEX_ENTRY *ie = dt->children[i]; + + printf ("%d\n", ((u8*)ie) - dt->data); + if (ie->flags & INDEX_ENTRY_END) + printf ("IE (%d)\n", ie->length); + else + printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length); + utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS); + printf ("\n"); + } +#endif + } + //printf ("index_header (%d,%d)\n", dt->header.index_length, dt->header.allocated_size); + + return dt; +} + +/** + * ntfs_dt_find + * find dt by name, return MFT_REF + * maps dt's as necessary + */ +MFT_REF ntfs_dt_find (struct ntfs_dt *dt, ntfschar *name, int name_len) +{ + MFT_REF res = -1; + INDEX_ENTRY *ie; + struct ntfs_dt *sub; + VCN vcn; + int i; + int r; + + if (!dt || !name) + return -1; + + /* + * State Children Action + * ------------------------------------------- + * collates after - keep searching + * match name - return MREF + * collates before no return -1 + * collates before yes map & recurse + * end marker no return -1 + * end marker yes map & recurse + */ + + //printf ("child_count = %d\n", dt->child_count); + for (i = 0; i < dt->child_count; i++) { + ie = dt->children[i]; + + if (ie->flags & INDEX_ENTRY_END) { + r = -1; + } else { + //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); + r = ntfs_names_collate (name, name_len, + ie->key.file_name.file_name, + ie->key.file_name.file_name_length, + 2, IGNORE_CASE, + dt->dir->vol->upcase, + dt->dir->vol->upcase_len); + } + + //printf ("%d, %d\n", i, r); + + if (r == 1) { + //printf ("keep searching\n"); + continue; + } else if (r == 0) { + res = MREF (ie->indexed_file); + //printf ("match %lld\n", res); + } else if (r == -1) { + if (ie->flags & INDEX_ENTRY_NODE) { + //printf ("map & recurse\n"); + //printf ("sub %p\n", dt->sub_nodes); + if (!dt->sub_nodes[i]) { + vcn = ntfs_ie_get_vcn (ie); + //printf ("vcn = %lld\n", vcn); + sub = ntfs_dt_create (dt->dir, dt, vcn); + dt->sub_nodes[i] = sub; + } + res = ntfs_dt_find (dt->sub_nodes[i], name, name_len); + } else { + //printf ("ENOENT\n"); + } + } else { + printf ("error collating name\n"); + } + break; + } + + return res; +} + +/** + * ntfs_dt_find2 + * find dt by name, returns dt and index + * maps dt's as necessary + */ +struct ntfs_dt * ntfs_dt_find2 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) +{ + struct ntfs_dt *res = NULL; + INDEX_ENTRY *ie; + VCN vcn; + int i; + int r; + + if (!dt || !name) + return NULL; + + // XXX default index_num to -1 + + /* + * State Children Action + * ------------------------------------------- + * collates after - keep searching + * match name - return MREF + * collates before no return -1 + * collates before yes map & recurse + * end marker no return -1 + * end marker yes map & recurse + */ + + //printf ("child_count = %d\n", dt->child_count); + for (i = 0; i < dt->child_count; i++) { + ie = dt->children[i]; + + if (ie->flags & INDEX_ENTRY_END) { + r = -1; + } else { + //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); + r = ntfs_names_collate (name, name_len, + ie->key.file_name.file_name, + ie->key.file_name.file_name_length, + 2, IGNORE_CASE, + dt->dir->vol->upcase, + dt->dir->vol->upcase_len); + } + + //printf ("%d, %d\n", i, r); + + if (r == 1) { + //printf ("keep searching\n"); + continue; + } else if (r == 0) { + res = dt; + //printf ("match %p\n", res); + if (index_num) + *index_num = i; + } else if ((r == -1) && (ie->flags & INDEX_ENTRY_NODE)) { + //printf ("recurse\n"); + if (!dt->sub_nodes[i]) { + vcn = ntfs_ie_get_vcn (ie); + //printf ("vcn = %lld\n", vcn); + dt->sub_nodes[i] = ntfs_dt_create (dt->dir, dt, vcn); + } + res = ntfs_dt_find2 (dt->sub_nodes[i], name, name_len, index_num); + } else { + printf ("error collating name\n"); + } + break; + } + + return res; +} + +/** + * ntfs_dt_find3 + * find dt by name, returns dt and index + * does not map new dt's + */ +struct ntfs_dt * ntfs_dt_find3 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) +{ + struct ntfs_dt *res = NULL; + INDEX_ENTRY *ie; + int i; + int r; + + if (!dt || !name) + return NULL; + + //printf ("child_count = %d\n", dt->child_count); + for (i = 0; i < dt->child_count; i++) { + ie = dt->children[i]; + + if (ie->flags & INDEX_ENTRY_END) { + r = -1; + } else { + //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); + r = ntfs_names_collate (name, name_len, + ie->key.file_name.file_name, + ie->key.file_name.file_name_length, + 2, IGNORE_CASE, + dt->dir->vol->upcase, + dt->dir->vol->upcase_len); + } + + //printf ("%d, %d\n", i, r); + + if (r == 1) { + //printf ("keep searching\n"); + continue; + } else if (r == 0) { + res = dt; + //printf ("match %p\n", res); + if (index_num) + *index_num = i; + } else if (r == -1) { + if (ie->flags & INDEX_ENTRY_NODE) { + //printf ("recurse\n"); + res = ntfs_dt_find3 (dt->sub_nodes[i], name, name_len, index_num); + } else { + //printf ("no match\n"); + res = dt; + if (index_num) + *index_num = i; + } + } else { + printf ("error collating name\n"); + } + break; + } + + return res; +} + +/** + * ntfs_dt_find4 + * find successor to specified name, returns dt and index + * maps dt's as necessary + */ +struct ntfs_dt * ntfs_dt_find4 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) +{ + struct ntfs_dt *res = NULL; + struct ntfs_dt *sub = NULL; + INDEX_ENTRY *ie; + VCN vcn; + int i; + int r; + + if (!dt || !name) + return NULL; + + //printf ("child_count = %d\n", dt->child_count); + for (i = 0; i < dt->child_count; i++) { + ie = dt->children[i]; + + //printf ("ie->flags = %d\n", ie->flags); + if (ie->flags & INDEX_ENTRY_END) { + r = -1; + } else { + //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); + r = ntfs_names_collate (name, name_len, + ie->key.file_name.file_name, + ie->key.file_name.file_name_length, + 2, IGNORE_CASE, + dt->dir->vol->upcase, + dt->dir->vol->upcase_len); + } + + //printf ("%d, %d\n", i, r); + + if (r == 1) { + //printf ("keep searching\n"); + } else if (r == 0) { + //res = dt; + //printf ("match\n"); + // ignore + } else if (r == -1) { + if (ie->flags & INDEX_ENTRY_NODE) { + //printf ("recurse\n"); + if (!dt->sub_nodes[i]) { + vcn = ntfs_ie_get_vcn (ie); + //printf ("vcn = %lld\n", vcn); + sub = ntfs_dt_create (dt->dir, dt, vcn); + dt->sub_nodes[i] = sub; + } + res = ntfs_dt_find4 (dt->sub_nodes[i], name, name_len, index_num); + } else { + //printf ("no match\n"); + res = dt; + if (index_num) + *index_num = i; + } + break; + } else { + printf ("error collating name\n"); + } + //break; + } + + return res; +} + +/** + * ntfs_dt_find_all + * maps all dt's into memory + */ +void ntfs_dt_find_all (struct ntfs_dt *dt) +{ + INDEX_ENTRY *ie; + VCN vcn; + int i; + + if (!dt) + return; + + for (i = 0; i < dt->child_count; i++) { + ie = dt->children[i]; + + if (ie->flags & INDEX_ENTRY_NODE) { + if (!dt->sub_nodes[i]) { + vcn = ntfs_ie_get_vcn (ie); + dt->sub_nodes[i] = ntfs_dt_create (dt->dir, dt, vcn); + } + ntfs_dt_find_all (dt->sub_nodes[i]); + } + } +} + +/** + * ntfs_dt_find_parent + */ +int ntfs_dt_find_parent (struct ntfs_dt *dt) +{ + int i; + struct ntfs_dt *parent; + + if (!dt) + return -1; + + parent = dt->parent; + if (!parent) + return -1; + + for (i = 0; i < parent->child_count; i++) + if (parent->sub_nodes[i] == dt) + return i; + + return -1; +} + +/** + * ntfs_dt_isroot + */ +BOOL ntfs_dt_isroot (struct ntfs_dt *dt) +{ + if (!dt) + return FALSE; + return (dt->parent == NULL); +} + +/** + * ntfs_dt_root_freespace + */ +int ntfs_dt_root_freespace (struct ntfs_dt *dt) +{ + int recsize; + int inuse; + MFT_RECORD *mrec; + + if (!dt) + return -1; + + recsize = dt->dir->inode->vol->mft_record_size; + + mrec = (MFT_RECORD*) dt->dir->inode->mrec; + inuse = mrec->bytes_in_use; + + return recsize - inuse; +} + +/** + * ntfs_dt_alloc_freespace + */ +int ntfs_dt_alloc_freespace (struct ntfs_dt *dt) +{ + int recsize; + int inuse; + INDEX_BLOCK *block; + + if (!dt) + return -1; + + recsize = dt->dir->index_size; + + block = (INDEX_BLOCK*) dt->data; + inuse = block->index.index_length + 24; + + return recsize - inuse; +} + +/** + * ntfs_dt_transfer + */ +int ntfs_dt_transfer (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count) +{ + int i; + int need; + int space; + INDEX_ENTRY *mov_ie; + u8 *src; + u8 *dst; + int len; + int insert; + //FILE_NAME_ATTR *file; + + //XXX check len > 0 + + if (!old || !new) + return -1; + + if ((start < 0) || ((start+count) >= old->child_count)) + return -1; + + printf ("\n"); + printf (BOLD YELLOW "Transferring children\n" END); + + need = 0; + for (i = start; i < (start+count+1); i++) { + mov_ie = old->children[i]; + need += mov_ie->length; + //file = &mov_ie->key.file_name; printf ("\ttrn name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); + } + + if (ntfs_dt_isroot (new)) + space = ntfs_dt_root_freespace (new); + else + space = ntfs_dt_alloc_freespace (new); + + // XXX if this is an index root, it'll go badly wrong + // restrict to allocs only? + + printf ("\tneed = %d\n", need); + printf ("\tspace = %d\n", space); + + if (space < need) + return -1; + + if (new->child_count == 1) { + i = -1; + } else { + ntfschar *n1, *n2; + int l1, l2; + + n1 = new->children[0]->key.file_name.file_name; + l1 = new->children[0]->key.file_name.file_name_length; + + n2 = old->children[start]->key.file_name.file_name; + l2 = old->children[start]->key.file_name.file_name_length; + + i = ntfs_names_collate (n1, l1, n2, l2, + 2, IGNORE_CASE, + old->dir->vol->upcase, + old->dir->vol->upcase_len); + } + + if ((i == 0) || (i == 2)) + return -1; + + // determine the insertion point + if (i == 1) + insert = 0; + else + insert = new->child_count-1; + + src = (u8*) new->children[insert]; + dst = src + need; + len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src; + + //printf ("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len); + memmove (dst, src, len); + + dst = src; + src = (u8*) old->children[start]; + len = need; + + memcpy (dst, src, len); + + src = (u8*) old->children[start+count-1]; + dst = (u8*) old->children[start]; + len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src; + + //printf ("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len); + memmove (dst, src, len); + + dst += len; + len = old->data + old->dir->index_size - dst; + + //printf ("dst = %d, len = %d\n", dst - old->data, len); + memset (dst, 0, len); + + if (!ntfs_dt_resize_children3 (new, new->child_count + count)) + return -1; + + src = (u8*) &old->sub_nodes[start+count-1]; + dst = (u8*) &old->sub_nodes[start]; + len = (old->child_count - start - count + 1) * sizeof (struct ntfs_dt*); + + memmove (dst, src, len); + + src = (u8*) &new->sub_nodes[insert]; + dst = (u8*) &new->sub_nodes[insert+count-1]; + len = (new->child_count - insert - count + 1) * sizeof (struct ntfs_dt*); + + memmove (dst, src, len); + + if (!ntfs_dt_resize_children3 (old, old->child_count - count)) + return -1; + + src = (u8*) new->children[0]; + for (i = 0; i < new->child_count; i++) { + new->children[i] = (INDEX_ENTRY*) src; + src += new->children[i]->length; + } + + src = (u8*) old->children[0]; + for (i = 0; i < old->child_count; i++) { + old->children[i] = (INDEX_ENTRY*) src; + src += old->children[i]->length; + } + + old->header->index_length -= need; + new->header->index_length += need; + + // resize children and sub_nodes + // memmove keys in new + // memcpy old to new + // memmove keys in old + // rebuild old/new children/sub_nodes without destroying tree + // update old/new headers + + old->changed = TRUE; + new->changed = TRUE; + + printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1); + printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1); + + return 0; +} + +/** + * ntfs_dt_alloc_insert + */ +int ntfs_dt_alloc_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count) +{ + // XXX don't bother measuring, just subtract the children pointers + + int i; + int need; + INDEX_ENTRY *ie; + INDEX_ALLOCATION *alloc; + u8 *src; + u8 *dst; + int len; + + if (!dt) + return 1; + if (!first) + return 1; + + need = 0; + ie = first; + for (i = 0; i < count; i++) { + need += ie->length; + ie = (INDEX_ENTRY*) ((u8*)ie + ie->length); + } + + printf ("alloc insert %d bytes\n", need); + + alloc = (INDEX_ALLOCATION*) dt->data; + printf ("entries_offset = %d\n", alloc->index.entries_offset); + printf ("index_length = %d\n", alloc->index.index_length); + printf ("allocated_size = %d\n", alloc->index.allocated_size); + + printf ("insert has %d children\n", dt->child_count); + printf ("children = %p\n", dt->children); + //utils_dump_mem (dt->data, 0, 128, DM_DEFAULTS); + + ie = dt->children[dt->child_count-1]; + + printf ("last child = %p (%ld)\n", ie, (long)ie - (long)dt->data); + printf ("size = %d\n", ie->length); + + src = (u8*) ie; + dst = src + need; + len = ie->length; + + memmove (dst, src, len); + + src = (u8*) first; + dst = (u8*) ie; + len = need; + + memcpy (dst, src, len); + + // use create children + // measure need and update children list + // adjust headers + + //utils_dump_mem (dt->data, 0, 256, DM_DEFAULTS); + return 0; +} + +/** + * ntfs_dt_alloc_insert2 + */ +INDEX_ENTRY * ntfs_dt_alloc_insert2 (struct ntfs_dt *dt, int before, int count, int bytes) +{ + int space; + u8 *src; + u8 *dst; + int len; + + // XXX don't bother measuring, just subtract the children pointers + + if (!dt) + return NULL; + if (before < 0) + return NULL; + if (count < 1) + return NULL; + if (bytes < 1) + return NULL; + + // check alloc has enough space + space = ntfs_dt_alloc_freespace (dt); + if (bytes > space) + return NULL; + + // move data + src = (u8*) dt->children[before]; + dst = src + bytes; + len = dt->header->index_length - ((int)dt->children[before] - (int)dt->data) + 24; + + //printf ("%d, %d, %d\n", (int)src - (int)dt->data, (int)dst - (int)dt->data, len); + + memmove (dst, src, len); + memset (dst, 0, bytes); + + // resize arrays + ntfs_dt_resize_children3 (dt, dt->child_count + count); + + // move keys (children) + src = (u8*) (dt->children + before); + dst = src + (count * sizeof (u8*)); + len = (dt->child_count - count - before) * sizeof (u8*); + + memmove (dst, src, len); + memset (src, 0, count * sizeof (u8*)); + + // move keys (inodes) + src = (u8*) (dt->inodes + before); + dst = src + (count * sizeof (u8*)); + len = (dt->child_count - count - before) * sizeof (u8*); + + memmove (dst, src, len); + memset (src, 0, count * sizeof (u8*)); + + // move keys (sub_nodes) + src = (u8*) (dt->sub_nodes + before); + dst = src + (count * sizeof (u8*)); + len = (dt->child_count - count - before) * sizeof (u8*); + + memmove (dst, src, len); + memset (src, 0, count * sizeof (u8*)); + + return NULL; +} + +/** + * ntfs_dt_root_insert + */ +int ntfs_dt_root_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count) +{ + if (!dt) + return 1; + if (!first) + return 1; + + return count; +} + +/** + * ntfs_dt_alloc_remove2 + */ +int ntfs_dt_alloc_remove2 (struct ntfs_dt *dt, int start, int count) +{ + int i; + int size; + + if (!dt) + return 1; + + size = 0; + for (i = start; i < (start+count); i++) { + size += dt->children[i]->length; + } + + return start + count; +} + +/** + * ntfs_dt_root_remove2 + */ +int ntfs_dt_root_remove2 (struct ntfs_dt *dt, int start, int count) +{ + int i; + int size; + + if (!dt) + return -1; + if ((start < 0) || (start >= dt->child_count)) + return -1; + if ((count < 1) || ((start + count - 1) >= dt->child_count)) + return -1; + + printf ("s c/t %d %d/%d\n", start, count, dt->child_count); + + size = 0; + for (i = start; i < (start + count); i++) + size += dt->children[i]->length; + printf ("size1 = %d\n", size); + + size = (int) dt->children[start+count] - (int) dt->children[start]; + printf ("size2 = %d\n", size); + + size = (int) dt->children[start+count-1] - (int) dt->children[start] + dt->children[start+count-1]->length; + printf ("size3 = %d\n", size); + + // XXX what shall we do with the inodes? + // transfer them to the dir (commit them for now) + // are they _our_ responsibility? probably not + + // rearrange arrays + // shrink attribute + + ntfs_dt_resize_children3 (dt, dt->child_count - count); + + printf ("ntfs_dt_root_remove2\n"); + return dt->child_count; +} + +/** + * ntfs_dt_transfer2 + */ +int ntfs_dt_transfer2 (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count) +{ + int i; + int need; + int space; + INDEX_ENTRY *mov_ie; + u8 *src; + u8 *dst; + int len; + int insert; + //FILE_NAME_ATTR *file; + + if (!old || !new) + return -1; + + if ((start < 0) || (count < 0)) + return -1; + + if ((start + count) >= old->child_count) + return -1; + + printf ("\n"); + printf (BOLD YELLOW "Transferring children\n" END); + + need = 0; + for (i = start; i < (start+count); i++) { + mov_ie = old->children[i]; + need += mov_ie->length; + //file = &mov_ie->key.file_name; printf ("\ttrn name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); + } + + if (ntfs_dt_isroot (new)) + space = ntfs_dt_root_freespace (new); + else + space = ntfs_dt_alloc_freespace (new); + + printf ("\tneed = %d\n", need); + printf ("\tspace = %d\n", space); + + if (need > space) + return -1; + + if (ntfs_dt_isroot (new)) + ntfs_dt_root_insert (new, old->children[0], count); + else + ntfs_dt_alloc_insert2 (new, 0, count, need); + + if (ntfs_dt_isroot (old)) + ntfs_dt_root_remove2 (old, 0, count); + else + ntfs_dt_alloc_remove2 (old, 0, count); + + if (1) return -1; + if (0) ntfs_dt_alloc_insert (NULL, NULL, 0); + + if (new->child_count == 1) { + i = -1; + } else { + ntfschar *n1, *n2; + int l1, l2; + + n1 = new->children[0]->key.file_name.file_name; + l1 = new->children[0]->key.file_name.file_name_length; + + n2 = old->children[start]->key.file_name.file_name; + l2 = old->children[start]->key.file_name.file_name_length; + + i = ntfs_names_collate (n1, l1, n2, l2, + 2, IGNORE_CASE, + old->dir->vol->upcase, + old->dir->vol->upcase_len); + } + + if ((i == 0) || (i == 2)) + return -1; + + // determine the insertion point + if (i == 1) + insert = 0; + else + insert = new->child_count-1; + + src = (u8*) new->children[insert]; + dst = src + need; + len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src; + + //printf ("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len); + memmove (dst, src, len); + + dst = src; + src = (u8*) old->children[start]; + len = need; + + memcpy (dst, src, len); + + src = (u8*) old->children[start+count-1]; + dst = (u8*) old->children[start]; + len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src; + + //printf ("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len); + memmove (dst, src, len); + + dst += len; + len = old->data + old->dir->index_size - dst; + + //printf ("dst = %d, len = %d\n", dst - old->data, len); + memset (dst, 0, len); + + if (!ntfs_dt_resize_children3 (new, new->child_count + count)) + return -1; + + src = (u8*) &old->sub_nodes[start+count-1]; + dst = (u8*) &old->sub_nodes[start]; + len = (old->child_count - start - count + 1) * sizeof (struct ntfs_dt*); + + memmove (dst, src, len); + + src = (u8*) &new->sub_nodes[insert]; + dst = (u8*) &new->sub_nodes[insert+count-1]; + len = (new->child_count - insert - count + 1) * sizeof (struct ntfs_dt*); + + memmove (dst, src, len); + + if (!ntfs_dt_resize_children3 (old, old->child_count - count)) + return -1; + + src = (u8*) new->children[0]; + for (i = 0; i < new->child_count; i++) { + new->children[i] = (INDEX_ENTRY*) src; + src += new->children[i]->length; + } + + src = (u8*) old->children[0]; + for (i = 0; i < old->child_count; i++) { + old->children[i] = (INDEX_ENTRY*) src; + src += old->children[i]->length; + } + + old->header->index_length -= need; + new->header->index_length += need; + + // resize children and sub_nodes + // memmove keys in new + // memcpy old to new + // memmove keys in old + // rebuild old/new children/sub_nodes without destroying tree + // update old/new headers + + old->changed = TRUE; + new->changed = TRUE; + + printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1); + printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1); + + return 0; +} + +/** + * ntfs_dt_root_replace + */ +int ntfs_dt_root_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie) +{ + u8 *src; + u8 *dst; + u8 *attr; + int len; + int i; + + if (!del || !del_ie || !suc_ie) + return FALSE; + + //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); + //printf ("\n"); + + attr = malloc (del->data_len + suc_ie->length - del_ie->length); + + dst = attr; + src = del->data; + len = (u8*) del_ie - del->data; + + memcpy (dst, src, len); + + dst += len; + src = (u8*) suc_ie; + len = suc_ie->length; + + memcpy (dst, src, len); + + dst += len; + src = (u8*) del_ie + del_ie->length; + len = del->data_len + (del->data - (u8*) del_ie) - del_ie->length; + + memcpy (dst, src, len); + + src = (u8*) del->data; + dst = attr; + + len = suc_ie->length - del_ie->length; + free (del->data); + del->data = attr; + del->data_len += len; + del->header = (INDEX_HEADER*) (del->data + 0x10); + del->header->index_length += len; + del->header->allocated_size += len; + + ntfs_mft_resize_resident (del->dir->inode, AT_INDEX_ROOT, I30, 4, del->data, del->data_len); + + //utils_dump_mem (attr, 0, del->data_len, DM_DEFAULTS); + + //printf ("\n"); + //printf (BOLD YELLOW "Adjust children\n" END); + //for (i = 0; i < del->child_count; i++) + // printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags); + //printf ("\n"); + + //printf ("src = %p, dst = %p, len = %d\n", src, dst, len); fflush (stdout); + + for (i = 0; i < del->child_count; i++) + del->children[i] = (INDEX_ENTRY*) (dst + ((u8*) del->children[i] - src)); + + for (i = del_num+1; i < del->child_count; i++) + del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len); + + //for (i = 0; i < del->child_count; i++) + // printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags); + //printf ("\n"); + + //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); + //printf ("\n"); + + del->changed = TRUE; + + printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no); + return TRUE; +} + +/** + * ntfs_dt_alloc_replace + */ +BOOL ntfs_dt_alloc_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie) +{ + u8 *src; + u8 *dst; + int len; + int i; + + if (!del || !del_ie || !suc_ie) + return FALSE; + + //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); + + src = (u8*) del_ie + del_ie->length; + dst = (u8*) del_ie + suc_ie->length; + len = del->header->index_length + 24 + (del->data - src); + //printf ("src = %d\n", src - del->data); + //printf ("dst = %d\n", dst - del->data); + //printf ("len = %d\n", len); + + if (src != dst) + memmove (dst, src, len); + + src = (u8*) suc_ie; + dst = (u8*) del_ie; + len = suc_ie->length; + + memcpy (dst, src, len); + + //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); + + del->header->index_length += suc_ie->length - del_ie->length; + + dst = del->data + del->header->index_length + 24; + len = del->data_len - del->header->index_length - 24; + + memset (dst, 0, len); + + //for (i = 0; i < del->child_count; i++) + // printf ("Child %d %p\n", i, del->children[i]); + //printf ("\n"); + + len = suc_ie->length - del_ie->length; + //printf ("len = %d\n", len); + + for (i = del_num+1; i < del->child_count; i++) + del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len); + + //for (i = 0; i < del->child_count; i++) + // printf ("Child %d %p\n", i, del->children[i]); + //printf ("\n"); + + //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); + + del->changed = TRUE; + + printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1); + return TRUE; +} + +/** + * ntfs_dt_root_remove + */ +BOOL ntfs_dt_root_remove (struct ntfs_dt *del, int del_num) +{ + INDEX_ENTRY *del_ie = NULL; + u8 *src; + u8 *dst; + u8 *old; + int len; + int del_len; + int i; + //int off; + + if (!del) + return FALSE; + + //utils_dump_mem (del->data, 0, del->header->index_length+16, DM_RED); + //printf ("\n"); + +#if 0 + off = (u8*) del->children[0] - del->data; + for (i = 0; i < del->child_count; i++) { + del_ie = del->children[i]; + + printf ("%2d %4d ", i+1, off); + off += del_ie->length; + + if (del_ie->flags & INDEX_ENTRY_END) { + printf ("END (%d)\n", del_ie->length); + break; + } + + ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); + printf (" (%d)\n", del_ie->length); + } + printf ("total = %d\n", off); +#endif + + del_ie = del->children[del_num]; + del_len = del_ie->length; + + src = (u8*) del_ie + del_len; + dst = (u8*) del_ie; + len = del->header->index_length + 16 - (src - del->data); + + //printf ("src = %d\n", src - del->data); + //printf ("dst = %d\n", dst - del->data); + //printf ("len = %d\n", len); + + memmove (dst, src, len); + + del->data_len -= del_len; + del->child_count--; + + del->header->index_length = del->data_len - 16; + del->header->allocated_size = del->data_len - 16; + + ntfs_mft_resize_resident (del->dir->inode, AT_INDEX_ROOT, I30, 4, del->data, del->data_len); + old = del->data; + del->data = realloc (del->data, del->data_len); + del->header = (INDEX_HEADER*) (del->data + 0x10); + + //utils_dump_mem (del->data, 0, del->data_len, DM_GREEN | DM_RED); + + src = (u8*) (&del->children[del_num+1]); + dst = (u8*) (&del->children[del_num]); + len = (del->child_count - del_num) * sizeof (INDEX_ENTRY*); + + //printf ("src = %d\n", src - (u8*) del->children); + //printf ("dst = %d\n", dst - (u8*) del->children); + //printf ("len = %d\n", len); + + memmove (dst, src, len); + + src = (u8*) (&del->sub_nodes[del_num+1]); + dst = (u8*) (&del->sub_nodes[del_num]); + len = (del->child_count - del_num) * sizeof (struct ntfs_dt*); + + //printf ("src = %d\n", src - (u8*) del->children); + //printf ("dst = %d\n", dst - (u8*) del->children); + //printf ("len = %d\n", len); + + memmove (dst, src, len); + + //printf ("del_num = %d\n", del_num); + for (i = 0; i < del->child_count; i++) + del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - old + del->data); + for (i = del_num; i < del->child_count; i++) + del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_len); + + if (!ntfs_dt_create_children2 (del, del->child_count)) + return FALSE; + +#if 0 + off = (u8*) del->children[0] - del->data; + for (i = 0; i < del->child_count; i++) { + del_ie = del->children[i]; + + printf ("%2d %4d ", i+1, off); + off += del_len; + + if (del_ie->flags & INDEX_ENTRY_END) { + printf ("END (%d)\n", del_len); + break; + } + + ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); + printf (" (%d)\n", del_len); + } + printf ("total = %d\n", off); +#endif + + //utils_dump_mem (del->data, 0, del->header->index_length+16, DM_DEFAULTS); + + del->changed = TRUE; + + printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no); + return TRUE; +} + +/** + * ntfs_dt_alloc_remove + */ +BOOL ntfs_dt_alloc_remove (struct ntfs_dt *del, int del_num) +{ + INDEX_ENTRY *del_ie = NULL; + u8 *dst; + u8 *src; + int len; + int i; + //int off; + + if (!del) + return FALSE; + +#if 0 + off = (u8*)del->children[0] - del->data; + for (i = 0; i < del->child_count; i++) { + del_ie = del->children[i]; + + printf ("%2d %4d ", i, off); + off += del_ie->length; + + if (del_ie->flags & INDEX_ENTRY_END) { + printf ("END (%d)\n", del_ie->length); + break; + } + + ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); + printf (" (%d)\n", del_ie->length); + } + printf ("total = %d\n", off); + printf ("\n"); +#endif + + //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); + //printf ("\n"); + + del_ie = del->children[del_num]; + + src = (u8*) del_ie + del_ie->length; + dst = (u8*) del_ie; + len = del->header->index_length + 24 - (src - del->data); + + //printf ("src = %d\n", src - del->data); + //printf ("dst = %d\n", dst - del->data); + //printf ("len = %d\n", len); + + memmove (dst, src, len); + + del->header->index_length -= src - dst; + del->child_count--; + + dst += len; + len = del->data_len - del->header->index_length - 24; + + //printf ("dst = %d\n", dst - del->data); + //printf ("len = %d\n", len); + + memset (dst, 0, len); + + src = (u8*) (&del->children[del_num+1]); + dst = (u8*) (&del->children[del_num]); + len = (del->child_count - del_num) * sizeof (INDEX_ENTRY*); + + //printf ("src = %d\n", src - (u8*) del->children); + //printf ("dst = %d\n", dst - (u8*) del->children); + //printf ("len = %d\n", len); + + memmove (dst, src, len); + + src = (u8*) (&del->sub_nodes[del_num+1]); + dst = (u8*) (&del->sub_nodes[del_num]); + len = (del->child_count - del_num) * sizeof (struct ntfs_dt*); + + //printf ("src = %d\n", src - (u8*) del->children); + //printf ("dst = %d\n", dst - (u8*) del->children); + //printf ("len = %d\n", len); + + memmove (dst, src, len); + + //printf ("del_num = %d\n", del_num); + for (i = del_num; i < del->child_count; i++) + del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_ie->length); + + if (!ntfs_dt_create_children2 (del, del->child_count)) + return FALSE; + + //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); + +#if 0 + off = (u8*)del->children[0] - del->data; + for (i = 0; i < del->child_count; i++) { + del_ie = del->children[i]; + + printf ("%2d %4d ", i, off); + off += del_ie->length; + + if (del_ie->flags & INDEX_ENTRY_END) { + printf ("END (%d)\n", del_ie->length); + break; + } + + ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); + printf (" (%d)\n", del_ie->length); + } + printf ("total = %d\n", off); + printf ("\n"); +#endif + + del->changed = TRUE; + + printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1); + + if (del->child_count < 2) { + printf ("indx is empty\n"); + ntfs_bmp_set_range (del->dir->bitmap, del->vcn, 1, 0); + } + + return TRUE; +} + +/** + * ntfs_dt_alloc_add + */ +int ntfs_dt_alloc_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child) +{ + INDEX_BLOCK *block; + INDEX_ENTRY *entry; + int need; + int space; + u8 *src; + u8 *dst; + int len; + + if (!parent || !ie) + return 0; + + block = (INDEX_BLOCK*) parent->data; + + need = ie->length; + space = parent->data_len - block->index.index_length - 24; + + printf ("need %d, have %d\n", need, space); + if (need > space) { + printf ("no room"); + return 0; + } + + //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); + //printf ("\n"); + + src = (u8*) parent->children[index_num]; + dst = src + need; + len = parent->data + parent->data_len - src - space; + //printf ("src = %d\n", src - parent->data); + //printf ("dst = %d\n", dst - parent->data); + //printf ("len = %d\n", len); + + memmove (dst, src, len); + + dst = src; + src = (u8*) ie; + len = need; + + memcpy (dst, src, len); + + block->index.index_length += len; + + dst = parent->data + block->index.index_length + 24; + len = parent->data_len - block->index.index_length - 24; + + memset (dst, 0, len); + + //realloc children, sub_nodes + ntfs_dt_create_children2 (parent, parent->child_count + 1); + + // regen children pointers + parent->child_count = 0; + + src = parent->data + 0x18 + parent->header->entries_offset; + len = parent->data_len - 0x18 - parent->header->entries_offset; + + while (src < (parent->data + parent->data_len)) { + entry = (INDEX_ENTRY*) src; + + parent->children[parent->child_count] = entry; + parent->child_count++; + + if (entry->flags & INDEX_ENTRY_END) + break; + + src += entry->length; + } + printf ("count = %d\n", parent->child_count); + + src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1]; + dst = (u8*) &parent->sub_nodes[index_num]; + len = (parent->child_count - index_num - 1) * sizeof (struct ntfs_dt*); + + memmove (dst, src, len); + + //insert sub_node pointer + parent->sub_nodes[index_num] = child; + + //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); + //printf ("\n"); + return 0; +} + +/** + * ntfs_dt_root_add + */ +int ntfs_dt_root_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child) +{ + INDEX_ROOT *root; + INDEX_ENTRY *entry; + int need; + int space; + u8 *attr; + u8 *src; + u8 *dst; + int len; + + if (!parent || !ie) + return 0; + + root = (INDEX_ROOT*) parent->data; + + //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); + printf ("\n"); + + need = ie->length; + space = ntfs_mft_free_space (parent->dir); + + printf ("need %d, have %d\n", need, space); + if (need > space) { + printf ("no room"); + return 0; + } + + attr = malloc (parent->data_len + need); + + src = parent->data; + dst = attr; + len = root->index.entries_offset + 16; + + memcpy (dst, src, len); + + dst += len; + src = (u8*) ie; + len = ie->length; + + memcpy (dst, src, len); + + dst += len; + src = (u8*) parent->children[index_num]; + len = parent->data + parent->data_len - src; + + memcpy (dst, src, len); + + free (parent->data); + parent->data = attr; + parent->data_len += need; + + root = (INDEX_ROOT*) parent->data; + root->index.index_length = parent->data_len - 16; + root->index.allocated_size = parent->data_len - 16; + + //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); + printf ("\n"); + + ntfs_mft_resize_resident (parent->dir->inode, AT_INDEX_ROOT, I30, 4, parent->data, parent->data_len); + + //realloc children, sub_nodes + ntfs_dt_create_children2 (parent, parent->child_count + 1); + + // regen children pointers + parent->child_count = 0; + + src = parent->data + 0x18 + parent->header->entries_offset; + len = parent->data_len - 0x18 - parent->header->entries_offset; + + // XXX can we rebase the children more simply? (in alloc_add too) + while (src < (parent->data + parent->data_len)) { + entry = (INDEX_ENTRY*) src; + + parent->children[parent->child_count] = entry; + parent->child_count++; + + if (entry->flags & INDEX_ENTRY_END) + break; + + src += entry->length; + } + printf ("count = %d\n", parent->child_count); + + src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1]; + dst = (u8*) &parent->sub_nodes[index_num]; + len = (parent->child_count - index_num - 1) * sizeof (struct ntfs_dt*); + + memmove (dst, src, len); + + //insert sub_node pointer + parent->sub_nodes[index_num] = child; + + return 0; +} + +/** + * ntfs_dt_add2 + */ +int ntfs_dt_add2 (INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded) +{ + int need; + int space; + int median; + struct ntfs_dt *new = NULL; + struct ntfs_dt *chl; + INDEX_ENTRY *med_ie = NULL; + //FILE_NAME_ATTR *file; + VCN vcn = 0; + //int i; + + if (!ie || !suc) + return -1; + + printf ("\n"); + printf (BOLD YELLOW "Add key to leaf\n" END); + + //utils_dump_mem (suc->data, 0, suc->data_len, DM_DEFAULTS); + + chl = NULL; +ascend: + //XXX replace with while/break? + +#if 0 + for (; ded; ded = ded->sub_nodes[0]) { + printf ("\tded vcn = %lld\n", ded->vcn); + } +#endif + + /* + * ADD + * room in current node? + * yes, add, done + * no, split, ascend + */ + need = ie->length; + + if (ntfs_dt_isroot (suc)) + space = ntfs_dt_root_freespace (suc); + else + space = ntfs_dt_alloc_freespace (suc); + + printf ("\tneed %d\n", need); + printf ("\tspace %d\n", space); + + if (space >= need) { + if (ntfs_dt_isroot (suc)) + ntfs_dt_root_add (suc, suc_num, ie, chl); + else + ntfs_dt_alloc_add (suc, suc_num, ie, chl); + goto done; + } + + /* + * SPLIT + * any dead? + * yes reuse + * no alloc + */ + if (ded) { + new = ded; + vcn = ded->vcn; + ded = ded->sub_nodes[0]; + printf ("\treusing vcn %lld\n", new->vcn); + } else { + ntfs_mft_add_index (suc->dir); + /* + * ALLOC + * any unused records? + * yes, enable first + * no, extend + */ + /* + * ENABLE + * modify bitmap + * init indx record + */ + /* + * EXTEND + * room in bitmap + * yes, do nothing + * no, extend bitmap + * extend alloc + */ + /* + * EXTEND BITMAP + * extend bitmap + * init bitmap + */ + } + + //printf ("\tnode has %d children\n", suc->child_count); + + // initialise new node + // XXX ntfs_dt_initialise (new, vcn); + + goto done; + + // find median key + median = (suc->child_count+1) / 2; + med_ie = ntfs_ie_copy (suc->children[median]); + //file = &med_ie->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); + + ntfs_ie_free (med_ie); + med_ie = NULL; + + //printf ("suc key count = %d\n", suc->child_count); + //printf ("new key count = %d\n", new->child_count); + + //printf ("median's child = %p\n", suc->sub_nodes[median]); + // need to pass the child when ascending + chl = suc->sub_nodes[median]; + + // transfer keys + if (ntfs_dt_transfer (suc, new, 0, median-1) < 0) + goto done; + + //printf ("suc key count = %d\n", suc->child_count); + //printf ("new key count = %d\n", new->child_count); + + //file = &suc->children[0]->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); + + // can this be a root node? + if (ntfs_dt_isroot (suc)) + ntfs_dt_root_remove (suc, 0); + else + ntfs_dt_alloc_remove (suc, 0); + + //file = &suc->children[0]->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); + //printf ("suc key count = %d\n", suc->child_count); + //printf ("new key count = %d\n", new->child_count); + + // remove the median key + + // split when median has children + // median child given to new ! + // median child is new + // ascend + + med_ie = ntfs_ie_set_vcn (med_ie, new->vcn); + if (!med_ie) + goto done; + + //printf ("median child = %lld\n", ntfs_ie_get_vcn (med_ie)); + //printf ("new's vcn = %lld\n", new->vcn); + + // adjust parents + // attach new to median + // escape clause for root node? + // goto ascend + + // ie = insert + // child = child + // suc = successor + // suc_num = insert point + + ie = med_ie; + suc = suc->parent; + suc_num = 0; + + printf ("\n"); + printf (BOLD YELLOW "Ascend\n" END); + goto ascend; +done: + return 0; +} + + +#endif /* NTFS_RICH */ + diff --git a/libntfs/volume.c b/libntfs/volume.c index 8c1108aa..00cf6c47 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -3,6 +3,7 @@ * * Copyright (c) 2000-2005 Anton Altaparmakov * Copyright (c) 2002-2005 Szabolcs Szakacsits + * Copyright (c) 2004-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -1531,3 +1532,332 @@ err_out: ntfs_attr_put_search_ctx(ctx); return ret; } + + +#ifdef NTFS_RICH + +#include "tree.h" + +// XXX temp +#define Eprintf printf +#define Vprintf printf +#define Qprintf printf + +/** + * utils_valid_device - Perform some safety checks on the device, before we start + * @name: Full pathname of the device/file to work with + * @force: Continue regardless of problems + * + * Check that the name refers to a device and that is isn't already mounted. + * These checks can be overridden by using the force option. + * + * Return: 1 Success, we can continue + * 0 Error, we cannot use this device + */ +int utils_valid_device (const char *name, int force) +{ + unsigned long mnt_flags = 0; + struct stat st; + +#ifdef __CYGWIN32__ + /* FIXME: This doesn't work for Cygwin, so just return success for now... */ + return 1; +#endif + if (!name) { + errno = EINVAL; + return 0; + } + + if (stat (name, &st) == -1) { + if (errno == ENOENT) { + Eprintf ("The device %s doesn't exist\n", name); + } else { + Eprintf ("Error getting information about %s: %s\n", name, strerror (errno)); + } + return 0; + } + + if (!S_ISBLK (st.st_mode)) { + Vprintf ("%s is not a block device.\n", name); + if (!force) { + Eprintf ("Use the force option to work with files.\n"); + return 0; + } + Vprintf ("Forced to continue.\n"); + } + + /* Make sure the file system is not mounted. */ + if (ntfs_check_if_mounted (name, &mnt_flags)) { + Vprintf ("Failed to determine whether %s is mounted: %s\n", name, strerror (errno)); + if (!force) { + Eprintf ("Use the force option to ignore this error.\n"); + return 0; + } + Vprintf ("Forced to continue.\n"); + } else if (mnt_flags & NTFS_MF_MOUNTED) { + Vprintf ("The device %s, is mounted.\n", name); + if (!force) { + Eprintf ("Use the force option to work a mounted filesystem.\n"); + return 0; + } + Vprintf ("Forced to continue.\n"); + } + + return 1; +} + +/** + * utils_mount_volume + */ +ntfs_volume * utils_mount_volume (const char *device, unsigned long flags, BOOL force) +{ + ntfs_volume *vol; + + if (!device) { + errno = EINVAL; + return NULL; + } + + if (!utils_valid_device (device, force)) + return NULL; + + vol = ntfs_mount (device, flags); + if (!vol) { + int err; + + err = errno; + Eprintf("Couldn't mount device '%s': %s\n", device, + strerror(err)); + if (err == EOPNOTSUPP) + Eprintf("Windows was either hibernated or did not " + "shut down properly. Try to mount " + "volume in windows, shut down and try " + "again.\n"); + return NULL; + } + + if (vol->flags & VOLUME_IS_DIRTY) { + Qprintf ("Volume is dirty.\n"); + if (!force) { + Eprintf ("Run chkdsk and try again, or use the --force option.\n"); + ntfs_umount (vol, FALSE); + return NULL; + } + Qprintf ("Forced to continue.\n"); + } + + return vol; +} + +/** + * ntfs_volume_commit + */ +int ntfs_volume_commit (ntfs_volume *vol) +{ + if (!vol) + return -1; + + printf ("commit volume\n"); + if (ntfs_bmp_commit (vol->private_bmp1) < 0) + return -1; + + if (ntfs_bmp_commit (vol->private_bmp2) < 0) + return -1; + + if (ntfs_dir_commit (vol->private_data) < 0) + return -1; + + return 0; +} + +/** + * ntfs_volume_rollback + */ +int ntfs_volume_rollback (ntfs_volume *vol) +{ + if (!vol) + return -1; + + if (ntfs_bmp_rollback (vol->private_bmp1) < 0) + return -1; + + if (ntfs_bmp_rollback (vol->private_bmp2) < 0) + return -1; + + if (ntfs_dir_rollback (vol->private_data) < 0) + return -1; + + return 0; +} + +/** + * ntfs_volume_umount2 + */ +int ntfs_volume_umount2 (ntfs_volume *vol, const BOOL force) +{ + struct ntfs_dir *dir; + struct ntfs_bmp *bmp; + + if (!vol) + return 0; + + ntfs_volume_rollback (vol); + + dir = (struct ntfs_dir *) vol->private_data; + vol->private_data = NULL; + ntfs_dir_free (dir); + + bmp = (struct ntfs_bmp *) vol->private_bmp1; + vol->private_bmp1 = NULL; + ntfs_bmp_free (bmp); + + bmp = (struct ntfs_bmp *) vol->private_bmp2; + vol->private_bmp2 = NULL; + ntfs_bmp_free (bmp); + + return ntfs_umount (vol, force); +} + +/** + * ntfs_volume_mount2 + */ +ntfs_volume * ntfs_volume_mount2 (const char *device, unsigned long flags, BOOL force) +{ + // XXX can we replace these and search by mft number? Hmm... NO. + // unless I have a recursive search for an MFT number + static ntfschar bmp[8] = { + const_cpu_to_le16('$'), + const_cpu_to_le16('B'), + const_cpu_to_le16('i'), + const_cpu_to_le16('t'), + const_cpu_to_le16('m'), + const_cpu_to_le16('a'), + const_cpu_to_le16('p'), + const_cpu_to_le16(0) + }; + + static ntfschar mft[5] = { + const_cpu_to_le16('$'), + const_cpu_to_le16('M'), + const_cpu_to_le16('F'), + const_cpu_to_le16('T'), + const_cpu_to_le16(0) + }; + + static ntfschar mftmirr[9] = { + const_cpu_to_le16('$'), + const_cpu_to_le16('M'), + const_cpu_to_le16('F'), + const_cpu_to_le16('T'), + const_cpu_to_le16('M'), + const_cpu_to_le16('i'), + const_cpu_to_le16('r'), + const_cpu_to_le16('r'), + const_cpu_to_le16(0) + }; + + static ntfschar dot[2] = { + const_cpu_to_le16('.'), + const_cpu_to_le16(0) + }; + + ntfs_volume *vol; + struct ntfs_dir *dir; + struct ntfs_dt *root; + struct ntfs_dt *found; + int num; + + vol = utils_mount_volume (device, flags, force); + if (!vol) + return NULL; + + vol->lcnbmp_ni ->ref_count = 1; + vol->mft_ni ->ref_count = 1; + vol->mftmirr_ni->ref_count = 1; + + vol->lcnbmp_ni ->private_data = NULL; + vol->mft_ni ->private_data = NULL; + vol->mftmirr_ni->private_data = NULL; + + dir = ntfs_dir_create (vol, FILE_root); + if (!dir) { + ntfs_volume_umount2 (vol, FALSE); + vol = NULL; + goto done; + } + + dir->index = ntfs_dt_create (dir, NULL, -1); + + root = dir->index; + + //$Bitmap + num = -1; + found = ntfs_dt_find2 (root, bmp, sizeof (bmp) - 1, &num); + if ((!found) || (num < 0)) { + printf ("can't find $Bitmap\n"); + ntfs_volume_umount2 (vol, FALSE); + vol = NULL; + goto done; + } + vol->lcnbmp_ni->ref_count++; + vol->lcnbmp_ni->private_data = found->dir; + found->inodes[num] = vol->lcnbmp_ni; + + //$MFT + num = -1; + found = ntfs_dt_find2 (root, mft, sizeof (mft) - 1, &num); + if ((!found) || (num < 0)) { + printf ("can't find $MFT\n"); + ntfs_volume_umount2 (vol, FALSE); + vol = NULL; + goto done; + } + vol->mft_ni->ref_count++; + vol->mft_ni->private_data = found->dir; + found->inodes[num] = vol->mft_ni; + + //$MFTMirr + num = -1; + found = ntfs_dt_find2 (root, mftmirr, sizeof (mftmirr) - 1, &num); + if ((!found) || (num < 0)) { + printf ("can't find $MFTMirr\n"); + ntfs_volume_umount2 (vol, FALSE); + vol = NULL; + goto done; + } + vol->mftmirr_ni->ref_count++; + vol->mftmirr_ni->private_data = found->dir; + found->inodes[num] = vol->mftmirr_ni; + + // root directory + num = -1; + found = ntfs_dt_find2 (root, dot, 1, &num); + if ((!found) || (num < 0)) { + printf ("can't find the root directory\n"); + ntfs_volume_umount2 (vol, FALSE); + vol = NULL; + goto done; + } + + vol->private_data = found->dir; + found->inodes[num] = dir->inode; + dir->inode->private_data = found; + dir->inode->ref_count = 2; + + vol->private_bmp1 = ntfs_bmp_create (vol->mft_ni, AT_BITMAP, NULL, 0); + vol->private_bmp2 = ntfs_bmp_create (vol->lcnbmp_ni, AT_DATA, NULL, 0); + + if (!vol->private_bmp1 || !vol->private_bmp2) { + printf ("can't find the bitmaps\n"); + ntfs_volume_umount2 (vol, FALSE); + vol = NULL; + goto done; + } + +done: + return vol; +} + + +#endif /* NTFS_RICH */ + diff --git a/ntfsprogs/Makefile.am b/ntfsprogs/Makefile.am index 3dfd19ed..8ce5aad3 100644 --- a/ntfsprogs/Makefile.am +++ b/ntfsprogs/Makefile.am @@ -15,7 +15,7 @@ bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \ ntfscp EXTRA_PROGRAMS = ntfsdump_logfile ntfswipe ntfstruncate ntfsmove \ - ntfsrm ntfsmftalloc ntfscmp + ntfsmftalloc ntfscmp man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 \ ntfsundelete.8 ntfsresize.8 ntfsprogs.8 ntfsls.8 \ @@ -37,6 +37,10 @@ if ENABLE_CRYPTO EXTRA_PROGRAMS += ntfsdecrypt endif +if ENABLE_RICH +EXTRA_PROGRAMS += ntfsrm +endif + # Set the include path. AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs $(all_includes) @@ -93,9 +97,11 @@ endif # We don't distribute these +if ENABLE_RICH ntfsrm_SOURCES = ntfsrm.c ntfsrm.h utils.c utils.h ntfsrm_LDADD = $(AM_LIBS) ntfsrm_LDFLAGS = $(AM_LFLAGS) +endif ntfstruncate_SOURCES = attrdef.c ntfstruncate.c utils.c utils.h ntfstruncate_LDADD = $(AM_LIBS) diff --git a/ntfsprogs/ntfsrm.c b/ntfsprogs/ntfsrm.c index 46c0ded0..1b564a2c 100644 --- a/ntfsprogs/ntfsrm.c +++ b/ntfsprogs/ntfsrm.c @@ -1,7 +1,6 @@ /** * ntfsrm - Part of the Linux-NTFS project. * - * Copyright (c) 2005 Anton Altaparmakov * Copyright (c) 2004-2005 Richard Russon * * This utility will delete files from an NTFS volume. @@ -40,14 +39,18 @@ #include #endif -#include "utils.h" #include "ntfsrm.h" +#include "rich.h" +#include "utils.h" #include "debug.h" #include "dir.h" #include "lcnalloc.h" #include "mft.h" #include "ntfstime.h" #include "version.h" +#include "tree.h" +#include "index.h" +#include "inode.h" static const char *EXEC_NAME = "ntfsrm"; static struct options opts; @@ -210,22 +213,6 @@ static int parse_options (int argc, char **argv) } -/** - * ntfs_name_print - */ -static void ntfs_name_print (ntfschar *name, int name_len) -{ - char *buffer = NULL; - - if (name_len) { - ntfs_ucstombs (name, name_len, &buffer, 0); - printf ("%s", buffer); - free (buffer); - } else { - printf ("!"); - } -} - /** * ntfs_dir_print */ @@ -263,1733 +250,6 @@ static void ntfs_dt_print (struct ntfs_dt *dt, int indent) } -/** - * ntfs_bmp_rollback - */ -static int ntfs_bmp_rollback (struct ntfs_bmp *bmp) -{ - int i; - - if ((!bmp) || (bmp->count == 0)) - return 0; - - for (i = 0; i < bmp->count; i++) - free (bmp->data[i]); - - free (bmp->data); - free (bmp->data_vcn); - bmp->data = NULL; - bmp->data_vcn = NULL; - bmp->count = 0; - - return 0; -} - -/** - * ntfs_bmp_commit - */ -static int ntfs_bmp_commit (struct ntfs_bmp *bmp) -{ - int i; - u32 cs; -#ifdef RM_WRITE - u32 ws; // write size -#endif - - if (!bmp) - return 0; - if (bmp->count == 0) - return 0; - -#if 0 - printf ("attr = 0x%02X\n", bmp->attr->type); - printf ("resident = %d\n", !NAttrNonResident (bmp->attr)); - printf ("\ta size = %lld\n", bmp->attr->allocated_size); - printf ("\td size = %lld\n", bmp->attr->data_size); - printf ("\ti size = %lld\n", bmp->attr->initialized_size); -#endif - - printf ("commit bmp inode %lld, 0x%02X (%sresident)\n", bmp->attr->ni->mft_no, bmp->attr->type, NAttrNonResident (bmp->attr) ? "non-" : ""); - - if (NAttrNonResident (bmp->attr)) { - cs = bmp->vol->cluster_size; - - // non-resident - for (i = 0; i < bmp->count; i++) { -#ifdef RM_WRITE - if (((bmp->data_vcn[i]+1) * cs) < bmp->attr->data_size) - ws = cs; - else - ws = bmp->attr->data_size & (cs - 1); - //printf ("writing %d bytes\n", ws); - ntfs_attr_pwrite (bmp->attr, bmp->data_vcn[i] * cs, ws, bmp->data[i]); // XXX retval -#endif - printf (RED "\tntfs_attr_pwrite (vcn %lld)\n" END, bmp->data_vcn[i]); - } - } else { - // resident -#ifdef RM_WRITE - ntfs_attr_pwrite (bmp->attr, bmp->data_vcn[0], bmp->attr->data_size, bmp->data[0]); // XXX retval -#endif - printf (RED "\tntfs_attr_pwrite resident (%lld)\n" END, bmp->attr->data_size); - } - - ntfs_bmp_rollback (bmp); - - return 0; -} - -/** - * ntfs_bmp_free - */ -static void ntfs_bmp_free (struct ntfs_bmp *bmp) -{ - if (!bmp) - return; - - ntfs_bmp_rollback (bmp); - - ntfs_attr_close (bmp->attr); - - free (bmp); -} - -/** - * ntfs_bmp_create - */ -static struct ntfs_bmp * ntfs_bmp_create (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len) -{ - struct ntfs_bmp *bmp; - ntfs_attr *attr; - - if (!inode) - return NULL; - - attr = ntfs_attr_open (inode, type, name, name_len); - if (!attr) - return NULL; - - bmp = calloc (1, sizeof (*bmp)); - if (!bmp) { - ntfs_attr_close (attr); - return NULL; - } - - bmp->vol = inode->vol; - bmp->attr = attr; - bmp->data = NULL; - bmp->data_vcn = NULL; - bmp->count = 0; - - return bmp; -} - -/** - * ntfs_bmp_add_data - */ -static int ntfs_bmp_add_data (struct ntfs_bmp *bmp, VCN vcn, u8 *data) -{ - int i = 0; - int old; - int new; - - if (!bmp || !data) - return -1; - - old = ROUND_UP (bmp->count, 16); - bmp->count++; - new = ROUND_UP (bmp->count, 16); - - if (old != new) { - bmp->data = realloc (bmp->data, new * sizeof (*bmp->data)); - bmp->data_vcn = realloc (bmp->data_vcn , new * sizeof (*bmp->data_vcn)); - } - - for (i = 0; i < bmp->count-1; i++) - if (bmp->data_vcn[i] > vcn) - break; - - if ((bmp->count-i) > 0) { - memmove (&bmp->data[i+1], &bmp->data[i], (bmp->count-i) * sizeof (*bmp->data)); - memmove (&bmp->data_vcn[i+1], &bmp->data_vcn[i], (bmp->count-i) * sizeof (*bmp->data_vcn)); - } - - bmp->data[i] = data; - bmp->data_vcn[i] = vcn; - - return bmp->count; -} - -/** - * ntfs_bmp_get_data - */ -static u8 * ntfs_bmp_get_data (struct ntfs_bmp *bmp, VCN vcn) -{ - u8 *buffer; - int i; - int cs; - int cb; - - if (!bmp) - return NULL; - - cs = bmp->vol->cluster_size; - cb = bmp->vol->cluster_size_bits; - - // XXX range check against vol,attr - // never compressed, so data = init - - vcn >>= (cb + 3); // convert to bitmap clusters - - for (i = 0; i < bmp->count; i++) { - if (vcn == bmp->data_vcn[i]) { - //printf ("reusing bitmap cluster %lld\n", vcn); - return bmp->data[i]; - } - } - - buffer = calloc (1, cs); // XXX could be smaller if attr size < cluster size - if (!buffer) - return NULL; - - //printf ("loading from bitmap cluster %lld\n", vcn); - //printf ("loading from bitmap byte %lld\n", vcn<attr, vcn<vol->cluster_size << 3; - - vcn_start = vcn; - vcn_finish = vcn + length - 1; - - //printf ("vcn_start = %d, vcn_finish = %d\n", vcn_start, vcn_finish); - a = ROUND_DOWN (vcn_start, csib); - b = ROUND_DOWN (vcn_finish, csib) + 1; - - //printf ("a = %lld, b = %lld\n", a, b); - - for (i = a; i < b; i += csib) { - //printf ("ntfs_bmp_get_data %lld\n", i); - buffer = ntfs_bmp_get_data (bmp, i); - if (!buffer) - return -1; - - block_start = i; - block_finish = block_start + csib - 1; - - mask_start = (0xFF << (vcn_start & 7)); - mask_finish = (0xFF >> (7 - (vcn_finish & 7))); - - if ((vcn_start >= block_start) && (vcn_start <= block_finish)) { - byte_start = (vcn_start - block_start) >> 3; - } else { - byte_start = 0; - mask_start = 0xFF; - } - - if ((vcn_finish >= block_start) && (vcn_finish <= block_finish)) { - byte_finish = (vcn_finish - block_start) >> 3; - } else { - byte_finish = bmp->vol->cluster_size - 1; - mask_finish = 0xFF; - } - - if ((byte_finish - byte_start) > 1) { - memset (buffer+byte_start+1, value, byte_finish-byte_start-1); - } else if (byte_finish == byte_start) { - mask_start &= mask_finish; - mask_finish = 0x00; - } - - if (value) { - buffer[byte_start] |= mask_start; - buffer[byte_finish] |= mask_finish; - } else { - buffer[byte_start] &= (~mask_start); - buffer[byte_finish] &= (~mask_finish); - } - } - -#if 1 - printf (GREEN "Modified: inode %lld, ", bmp->attr->ni->mft_no); - switch (bmp->attr->type) { - case AT_BITMAP: printf ("$BITMAP"); break; - case AT_DATA: printf ("$DATA"); break; - default: break; - } - printf (" vcn %lld-%lld\n" END, vcn>>12, (vcn+length-1)>>12); -#endif - return 1; -} - -/** - * ntfs_bmp_find_last_set - */ -static s64 ntfs_bmp_find_last_set (struct ntfs_bmp *bmp) -{ - s64 clust_count; - s64 byte_count; - s64 clust; - int byte; - int bit; - int note; - u8 *buffer; - - if (!bmp) - return -2; - - // find byte size of bmp - // find cluster size of bmp - - byte_count = bmp->attr->data_size; - clust_count = ROUND_UP (byte_count, bmp->vol->cluster_size) >> bmp->vol->cluster_size_bits; - - //printf ("bitmap = %lld bytes\n", byte_count); - //printf ("bitmap = %lld buffers\n", clust_count); - - // for each cluster backwards - for (clust = clust_count-1; clust >= 0; clust--) { - //printf ("cluster %lld\n", clust); - //printf ("get vcn %lld\n", clust << (bmp->vol->cluster_size_bits + 3)); - buffer = ntfs_bmp_get_data (bmp, clust << (bmp->vol->cluster_size_bits + 3)); - //utils_dump_mem (buffer, 0, 8, DM_NO_ASCII); - if (!buffer) - return -2; - if ((clust == (clust_count-1) && ((byte_count % bmp->vol->cluster_size) != 0))) { - byte = byte_count % bmp->vol->cluster_size; - } else { - byte = bmp->vol->cluster_size; - } - //printf ("start byte = %d\n", byte); - // for each byte backward - for (byte--; byte >= 0; byte--) { - //printf ("\tbyte %d (%d)\n", byte, buffer[byte]); - // for each bit shift up - note = -1; - for (bit = 7; bit >= 0; bit--) { - //printf ("\t\tbit %d (%d)\n", (1<= 0) { - // if note, return value - //printf ("match %lld (c=%lld,b=%d,n=%d)\n", (((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note, clust, byte, note); - return ((((clust << bmp->vol->cluster_size_bits) + byte) << 3) + note); - } - } - } - - return -1; -} - -/** - * ntfs_bmp_find_space - */ -static int ntfs_bmp_find_space (struct ntfs_bmp *bmp, LCN start, long size) -{ - if (!bmp) - return 0; - - start = 0; - size = 0; - - /* - bmp find space - uncached bmp's - $Bitmap/$DATA free space on volume - dir/$BITMAP free index record - $MFT/$BITMAP free record in mft - */ - return 0; -} - - -/** - * ntfs_ie_free - */ -static void ntfs_ie_free (INDEX_ENTRY *ie) -{ - free (ie); -} - -/** - * ntfs_ie_create - */ -static INDEX_ENTRY * ntfs_ie_create (void) -{ - int length; - INDEX_ENTRY *ie; - - length = 16; - ie = calloc (1, length); - if (!ie) - return NULL; - - ie->indexed_file = 0; - ie->length = length; - ie->key_length = 0; - ie->flags = INDEX_ENTRY_END; - ie->reserved = 0; - return ie; -} - -/** - * ntfs_ie_get_vcn - */ -static VCN ntfs_ie_get_vcn (INDEX_ENTRY *ie) -{ - if (!ie) - return -1; - if (!(ie->flags & INDEX_ENTRY_NODE)) - return -1; - - return *((VCN*) ((u8*) ie + ie->length - 8)); -} - -/** - * ntfs_ie_copy - */ -static INDEX_ENTRY * ntfs_ie_copy (INDEX_ENTRY *ie) -{ - INDEX_ENTRY *copy = NULL; - - if (!ie) - return NULL; - - copy = malloc (ie->length); - if (!copy) - return NULL; - memcpy (copy, ie, ie->length); - - return copy; -} - -/** - * ntfs_ie_set_vcn - */ -static INDEX_ENTRY * ntfs_ie_set_vcn (INDEX_ENTRY *ie, VCN vcn) -{ - if (!ie) - return 0; - - if (!(ie->flags & INDEX_ENTRY_NODE)) { - ie->length += 8; - ie = realloc (ie, ie->length); - if (!ie) - return NULL; - - ie->flags |= INDEX_ENTRY_NODE; - } - - *((VCN*) ((u8*) ie + ie->length - 8)) = vcn; - return ie; -} - -/** - * ntfs_ie_remove_vcn - */ -static INDEX_ENTRY * ntfs_ie_remove_vcn (INDEX_ENTRY *ie) -{ - if (!ie) - return NULL; - if (!(ie->flags & INDEX_ENTRY_NODE)) - return ie; - - ie->length -= 8; - ie->flags &= ~INDEX_ENTRY_NODE; - ie = realloc (ie, ie->length); - return ie; -} - -/** - * ntfs_ie_set_name - */ -static INDEX_ENTRY * ntfs_ie_set_name (INDEX_ENTRY *ie, ntfschar *name, int namelen, FILE_NAME_TYPE_FLAGS nametype) -{ - FILE_NAME_ATTR *file; - int need; - BOOL wipe = FALSE; - VCN vcn = 0; - - if (!ie || !name) - return NULL; - - /* - * INDEX_ENTRY - * MFT_REF indexed_file; - * u16 length; - * u16 key_length; - * INDEX_ENTRY_FLAGS flags; - * u16 reserved; - * - * FILENAME - * MFT_REF parent_directory; - * s64 creation_time; - * s64 last_data_change_time; - * s64 last_mft_change_time; - * s64 last_access_time; - * s64 allocated_size; - * s64 data_size; - * FILE_ATTR_FLAGS file_attributes; - * u32 reserved; - * u8 file_name_length; - * FILE_NAME_TYPE_FLAGS file_name_type; - * ntfschar file_name[l]; - * u8 reserved[n] - * - * VCN vcn; - */ - - //printf ("key length = 0x%02X\n", ie->key_length); - //printf ("new name length = %d\n", namelen); - if (ie->key_length > 0) { - file = &ie->key.file_name; - //printf ("filename, length %d\n", file->file_name_length); - need = ATTR_SIZE (namelen * sizeof (ntfschar) + 2) - - ATTR_SIZE (file->file_name_length * sizeof (ntfschar) + 2); - } else { - //printf ("no filename\n"); - need = ATTR_SIZE (sizeof (FILE_NAME_ATTR) + (namelen * sizeof (ntfschar))); - wipe = TRUE; - } - - //printf ("need 0x%02X bytes\n", need); - - if (need != 0) { - if (ie->flags & INDEX_ENTRY_NODE) - vcn = ntfs_ie_get_vcn (ie); - - ie->length += need; - ie->key_length += need; - - //printf ("realloc 0x%02X\n", ie->length); - ie = realloc (ie, ie->length); - if (!ie) - return NULL; - - if (ie->flags & INDEX_ENTRY_NODE) - ie = ntfs_ie_set_vcn (ie, vcn); - - if (wipe) - memset (&ie->key.file_name, 0, sizeof (FILE_NAME_ATTR)); - if (need > 0) - memset ((u8*)ie + ie->length - need, 0, need); - } - - memcpy (ie->key.file_name.file_name, name, namelen * sizeof (ntfschar)); - - ie->key.file_name.file_name_length = namelen; - ie->key.file_name.file_name_type = nametype; - ie->flags &= ~INDEX_ENTRY_END; - - //printf ("ie->length = 0x%02X\n", ie->length); - //printf ("ie->key_length = 0x%02X\n", ie->key_length); - - return ie; -} - -/** - * ntfs_ie_remove_name - */ -static INDEX_ENTRY * ntfs_ie_remove_name (INDEX_ENTRY *ie) -{ - VCN vcn = 0; - - if (!ie) - return NULL; - if (ie->key_length == 0) - return ie; - - if (ie->flags & INDEX_ENTRY_NODE) - vcn = ntfs_ie_get_vcn (ie); - - ie->length -= ATTR_SIZE (ie->key_length); - ie->key_length = 0; - ie->flags |= INDEX_ENTRY_END; - - ie = realloc (ie, ie->length); - if (!ie) - return NULL; - - if (ie->flags & INDEX_ENTRY_NODE) - ie = ntfs_ie_set_vcn (ie, vcn); - return ie; -} - - -/** - * ntfs_inode_close2 - */ -static int ntfs_inode_close2 (ntfs_inode *ni) -{ - if (!ni) - return 0; - - //printf (BOLD YELLOW "inode close %lld (%d)\n" END, ni->mft_no, ni->ref_count); - - ni->ref_count--; - if (ni->ref_count > 0) - return 0; - - // unlink - // ino->private_data - - // XXX temporary until we have commit/rollback - NInoClearDirty(ni); - - return ntfs_inode_close (ni); -} - - -/** - * ntfs_dt_free - */ -static void ntfs_dt_free (struct ntfs_dt *dt) -{ - int i; - - if (!dt) - return; - - for (i = 0; i < dt->child_count; i++) { - ntfs_dt_free (dt->sub_nodes[i]); - ntfs_inode_close2 (dt->inodes[i]); - } - - free (dt->sub_nodes); - free (dt->children); - free (dt->inodes); - free (dt->data); // XXX is this always ours? - free (dt); -} - -/** - * ntfs_dt_rollback - */ -static int ntfs_dt_rollback (struct ntfs_dt *dt) -{ - int i; - - if (!dt) - return 0; - if (dt->child_count == 0) // No children or nothing mapped - return 0; - - if (dt->changed) { - // We can't trust anything below us in the tree - for (i = 0; i < dt->child_count; i++) { - ntfs_dt_free (dt->sub_nodes[i]); - ntfs_inode_close2 (dt->inodes[i]); - } - - dt->child_count = 0; - - free (dt->data); - free (dt->children); - free (dt->sub_nodes); - free (dt->inodes); - - dt->data = NULL; - dt->children = NULL; - dt->sub_nodes = NULL; - dt->inodes = NULL; - } else { - // This node is OK, check the su-nodes - for (i = 0; i < dt->child_count; i++) { - if (ntfs_dt_rollback (dt->sub_nodes[i])) { - ntfs_inode_close2 (dt->inodes[i]); - // Child was changed so unmap it - dt->sub_nodes[i] = NULL; - dt->inodes[i] = NULL; - } - } - } - - return (dt->child_count == 0); -} - -/** - * ntfs_dt_commit - */ -static int ntfs_dt_commit (struct ntfs_dt *dt) -{ - ntfs_volume *vol; - ntfs_attr *attr; - struct ntfs_dir *dir; - int i; - int size; - - if (!dt) - return 0; - - dir = dt->dir; - if (!dir) - return -1; - - vol = dir->vol; // cluster size - - if (dt->changed) { - if (dt->parent) { - printf ("commit dt (alloc)\n"); - attr = dt->dir->ialloc; - size = dt->dir->index_size; - //utils_dump_mem (dt->data, 0, size, DM_DEFAULTS); -#ifdef RM_WRITE - ntfs_attr_mst_pwrite(attr, dt->vcn * vol->cluster_size, 1, size, dt->data); // XXX retval -#endif - } else { - printf ("commit dt (root)\n"); - attr = dt->dir->iroot; - size = dt->data_len; - //utils_dump_mem (dt->data, 0, size, DM_DEFAULTS); -#ifdef RM_WRITE - ntfs_attr_pwrite(attr, 0, size, dt->data); // XXX retval -#endif - } - - printf (RED "\tntfs_attr_pwrite (vcn %lld)\n" END, dt->vcn); - - dt->changed = FALSE; - } - - for (i = 0; i < dt->child_count; i++) { - if ((dt->inodes[i]) && (NInoDirty (dt->inodes[i]))) { - //utils_dump_mem (dt->inodes[i]->mrec, 0, vol->mft_record_size, DM_DEFAULTS); -#ifdef RM_WRITE - ntfs_inode_sync (dt->inodes[i]); -#endif - printf (RED "\tntfs_inode_sync %llu\n" END, dt->inodes[i]->mft_no); - } - - if (ntfs_dt_commit (dt->sub_nodes[i]) < 0) - return -1; - } - - return 0; -} - -/** - * ntfs_dt_create_children2 - */ -static BOOL ntfs_dt_create_children2 (struct ntfs_dt *dt, int count) -{ - // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN) - - int old = (dt->child_count + 0x1e) & ~0x1f; - int new = (count + 0x1f) & ~0x1f; - - if (old == new) - return TRUE; - - dt->children = realloc (dt->children, new * sizeof (*dt->children)); - dt->sub_nodes = realloc (dt->sub_nodes, new * sizeof (*dt->sub_nodes)); - dt->inodes = realloc (dt->inodes, new * sizeof (*dt->inodes)); - - if (!dt->children || !dt->sub_nodes || !dt->inodes) - return FALSE; // dt->child_count = -1 ? - - memset ((u8*)dt->children + old, 0, (new - old) * sizeof (*dt->children)); - memset ((u8*)dt->sub_nodes + old, 0, (new - old) * sizeof (*dt->sub_nodes)); - memset ((u8*)dt->inodes + old, 0, (new - old) * sizeof (*dt->inodes)); - - return TRUE; -} - -/** - * ntfs_dt_resize_children3 - */ -static BOOL ntfs_dt_resize_children3 (struct ntfs_dt *dt, int new) -{ - int old; - - // XXX calculate for 2K and 4K indexes max and min filenames (inc/exc VCN) - // XXX assumption: sizeof (*dt->children) == sizeof (*dt->sub_nodes) == sizeof (*dt->inodes) - // XXX put back blocking factor - - if (!dt) - return FALSE; - - old = dt->child_count; - if (old == new) - return TRUE; - - dt->child_count = new; - - old *= sizeof (*dt->children); - new *= sizeof (*dt->children); - - dt->children = realloc (dt->children, new); - dt->sub_nodes = realloc (dt->sub_nodes, new); - dt->inodes = realloc (dt->inodes, new); - - if (!dt->children || !dt->sub_nodes || !dt->inodes) - return FALSE; - - if (new > old) { - memset ((u8*)dt->children + old, 0, (new - old)); - memset ((u8*)dt->sub_nodes + old, 0, (new - old)); - memset ((u8*)dt->inodes + old, 0, (new - old)); - } - - return TRUE; -} - -/** - * ntfs_dt_root_count - */ -static int ntfs_dt_root_count (struct ntfs_dt *dt) -{ - u8 *buffer = NULL; - u8 *ptr = NULL; - VCN vcn; - s64 size = 0; - char *name = NULL; - - INDEX_ROOT *root; - INDEX_HEADER *header; - INDEX_ENTRY *entry; - - if (!dt) - return -1; - - buffer = dt->data; - size = dt->data_len; - - root = (INDEX_ROOT*) buffer; - if (root->type != AT_FILE_NAME) - return -1; - - header = (INDEX_HEADER*) (buffer + 0x10); - if (header->index_length > size) - return -1; - - dt->child_count = 0; - ptr = buffer + header->entries_offset + 0x10; - - while (ptr < (buffer + size)) { - entry = (INDEX_ENTRY*) ptr; - - ntfs_dt_resize_children3 (dt, dt->child_count + 1); // XXX retval - - if (entry->flags & INDEX_ENTRY_NODE) { - vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr); - //printf ("VCN %lld\n", vcn); - } - - if (!(entry->flags & INDEX_ENTRY_END)) { - ntfs_ucstombs (entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0); - //printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name); - free (name); - name = NULL; - } - - //printf ("CC[%d] = %p\n", dt->child_count-1, entry); - dt->children[dt->child_count-1] = entry; - - ptr += entry->length; - } - - //printf ("count = %d\n\n", dt->child_count); - - return dt->child_count; -} - -/** - * ntfs_dt_alloc_count - */ -static int ntfs_dt_alloc_count (struct ntfs_dt *dt) -{ - u8 *buffer = NULL; - u8 *ptr = NULL; - VCN vcn; - s64 size = 0; - char *name = NULL; - - INDEX_BLOCK *block; - INDEX_ENTRY *entry; - - if (!dt) - return -1; - - buffer = dt->data; - size = dt->data_len; - - //utils_dump_mem (buffer, 0, 128, DM_DEFAULTS); - - block = (INDEX_BLOCK*) buffer; - //printf ("INDX %lld\n", block->index_block_vcn); - - ptr = buffer + 0x18 + block->index.entries_offset; - - //printf ("block size %d\n", block->index.index_length); - dt->child_count = 0; - //printf ("start = 0x%02X, end = 0x%02X\n", 0x18 + block->index.entries_offset, 0x18 + block->index.index_length); - while (ptr < (buffer + 0x18 + block->index.index_length)) { - entry = (INDEX_ENTRY*) ptr; - - ntfs_dt_resize_children3 (dt, dt->child_count + 1); // XXX retval - - if (entry->flags & INDEX_ENTRY_NODE) { - vcn = ntfs_ie_get_vcn ((INDEX_ENTRY*) ptr); - //printf ("\tVCN %lld\n", vcn); - } - - dt->children[dt->child_count-1] = entry; - - if (entry->flags & INDEX_ENTRY_END) { - break; - } else { - ntfs_ucstombs (entry->key.file_name.file_name, entry->key.file_name.file_name_length, &name, 0); - //printf ("\tinode %8lld %s\n", MREF (entry->indexed_file), name); - free (name); - name = NULL; - } - - ptr += entry->length; - } - //printf ("count = %d\n", dt->child_count); - - return dt->child_count; -} - -/** - * ntfs_dt_initialise2 - */ -static int ntfs_dt_initialise2 (ntfs_volume *vol, struct ntfs_dt *dt) -{ - INDEX_ALLOCATION *alloc; - INDEX_ENTRY *entry; - - if (!vol) - return 1; - if (!dt) - return 1; - - memset (dt->data, 0, dt->data_len); - - alloc = (INDEX_ALLOCATION*) dt->data; - - alloc->magic = magic_INDX; - alloc->usa_ofs = 0x28; - alloc->usa_count = (dt->data_len >> vol->sector_size_bits) + 1; - alloc->lsn = 0; - alloc->index_block_vcn = 0; - - alloc->index.entries_offset = 0x28; - alloc->index.index_length = 0x10 + 0x28; - alloc->index.allocated_size = dt->data_len - 0x18; - alloc->index.flags = 0; - - entry = (INDEX_ENTRY*) (dt->data + 0x40); - - entry->indexed_file = 0; - entry->length = 0x10; - entry->key_length = 0; - entry->flags = INDEX_ENTRY_END; - - ntfs_dt_resize_children3 (dt, 1); // XXX retval - - dt->children[0] = entry; - - return 0; -} - -/** - * ntfs_dt_create - */ -static struct ntfs_dt * ntfs_dt_create (struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn) -{ - struct ntfs_dt *dt = NULL; - //int i; - - if (!dir) - return NULL; - - dt = calloc (1, sizeof (*dt)); - if (!dt) - return NULL; - - dt->dir = dir; - dt->parent = parent; - dt->child_count = 0; - dt->children = NULL; - dt->sub_nodes = NULL; - dt->inodes = NULL; - dt->vcn = vcn; - dt->changed = FALSE; - - if (parent) { - //printf ("alloc a = %lld\n", dir->ialloc->allocated_size); - //printf ("alloc d = %lld\n", dir->ialloc->data_size); - //printf ("alloc i = %lld\n", dir->ialloc->initialized_size); - //printf ("vcn = %lld\n", vcn); - - dt->data_len = dt->dir->index_size; - //printf ("parent size = %d\n", dt->data_len); - dt->data = malloc (dt->data_len); - - if (vcn >= 0) { - //printf ("%lld\n", ntfs_attr_mst_pread (dir->ialloc, vcn*512, 1, dt->data_len, dt->data)); - ntfs_attr_mst_pread (dir->ialloc, vcn*512, 1, dt->data_len, dt->data); - } else { - ntfs_dt_initialise2 (dir->vol, dt); - } - - //utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS); - //printf ("\n"); - - ntfs_dt_alloc_count (dt); - - dt->header = &((INDEX_BLOCK*)dt->data)->index; - //printf ("USA = %d\n", ((INDEX_BLOCK*)dt->data)->usa_count); - -#if 0 - for (i = 0; i < dt->child_count; i++) { - INDEX_ENTRY *ie = dt->children[i]; - - printf ("%d\n", ((u8*)ie) - dt->data); - if (ie->flags & INDEX_ENTRY_END) - printf ("IE (%d)\n", ie->length); - else - printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length); - utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS); - printf ("\n"); - } -#endif - } else { - //printf ("root a = %lld\n", dir->iroot->allocated_size); - //printf ("root d = %lld\n", dir->iroot->data_size); - //printf ("root i = %lld\n", dir->iroot->initialized_size); - - dt->data_len = dir->iroot->allocated_size; - dt->data = malloc (dt->data_len); - //printf ("%lld\n", ntfs_attr_pread (dir->iroot, 0, dt->data_len, dt->data)); - ntfs_attr_pread (dir->iroot, 0, dt->data_len, dt->data); - //utils_dump_mem (dt->data, 0, dt->data_len, DM_DEFAULTS); - //printf ("\n"); - - ntfs_dt_root_count (dt); - - dt->header = &((INDEX_ROOT*)dt->data)->index; - //dt->data_len = ((INDEX_ROOT*)dt->data)->index_block_size; - //printf ("IBS = %d\n", ((INDEX_ROOT*)dt->data)->index_block_size); - -#if 0 - for (i = 0; i < dt->child_count; i++) { - INDEX_ENTRY *ie = dt->children[i]; - - printf ("%d\n", ((u8*)ie) - dt->data); - if (ie->flags & INDEX_ENTRY_END) - printf ("IE (%d)\n", ie->length); - else - printf ("IE %lld (%d)\n", MREF (ie->key.file_name.parent_directory), ie->length); - utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS); - printf ("\n"); - } -#endif - } - //printf ("index_header (%d,%d)\n", dt->header.index_length, dt->header.allocated_size); - - return dt; -} - -/** - * ntfs_dt_find - * find dt by name, return MFT_REF - * maps dt's as necessary - */ -static MFT_REF ntfs_dt_find (struct ntfs_dt *dt, ntfschar *name, int name_len) -{ - MFT_REF res = -1; - INDEX_ENTRY *ie; - struct ntfs_dt *sub; - VCN vcn; - int i; - int r; - - if (!dt || !name) - return -1; - - /* - * State Children Action - * ------------------------------------------- - * collates after - keep searching - * match name - return MREF - * collates before no return -1 - * collates before yes map & recurse - * end marker no return -1 - * end marker yes map & recurse - */ - - //printf ("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); - r = ntfs_names_collate (name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //printf ("%d, %d\n", i, r); - - if (r == 1) { - //printf ("keep searching\n"); - continue; - } else if (r == 0) { - res = MREF (ie->indexed_file); - //printf ("match %lld\n", res); - } else if (r == -1) { - if (ie->flags & INDEX_ENTRY_NODE) { - //printf ("map & recurse\n"); - //printf ("sub %p\n", dt->sub_nodes); - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn (ie); - //printf ("vcn = %lld\n", vcn); - sub = ntfs_dt_create (dt->dir, dt, vcn); - dt->sub_nodes[i] = sub; - } - res = ntfs_dt_find (dt->sub_nodes[i], name, name_len); - } else { - //printf ("ENOENT\n"); - } - } else { - printf ("error collating name\n"); - } - break; - } - - return res; -} - -/** - * ntfs_dt_find2 - * find dt by name, returns dt and index - * maps dt's as necessary - */ -static struct ntfs_dt * ntfs_dt_find2 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) -{ - struct ntfs_dt *res = NULL; - INDEX_ENTRY *ie; - VCN vcn; - int i; - int r; - - if (!dt || !name) - return NULL; - - // XXX default index_num to -1 - - /* - * State Children Action - * ------------------------------------------- - * collates after - keep searching - * match name - return MREF - * collates before no return -1 - * collates before yes map & recurse - * end marker no return -1 - * end marker yes map & recurse - */ - - //printf ("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); - r = ntfs_names_collate (name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //printf ("%d, %d\n", i, r); - - if (r == 1) { - //printf ("keep searching\n"); - continue; - } else if (r == 0) { - res = dt; - //printf ("match %p\n", res); - if (index_num) - *index_num = i; - } else if ((r == -1) && (ie->flags & INDEX_ENTRY_NODE)) { - //printf ("recurse\n"); - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn (ie); - //printf ("vcn = %lld\n", vcn); - dt->sub_nodes[i] = ntfs_dt_create (dt->dir, dt, vcn); - } - res = ntfs_dt_find2 (dt->sub_nodes[i], name, name_len, index_num); - } else { - printf ("error collating name\n"); - } - break; - } - - return res; -} - -/** - * ntfs_dt_find3 - * find dt by name, returns dt and index - * does not map new dt's - */ -static struct ntfs_dt * ntfs_dt_find3 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) -{ - struct ntfs_dt *res = NULL; - INDEX_ENTRY *ie; - int i; - int r; - - if (!dt || !name) - return NULL; - - //printf ("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); - r = ntfs_names_collate (name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //printf ("%d, %d\n", i, r); - - if (r == 1) { - //printf ("keep searching\n"); - continue; - } else if (r == 0) { - res = dt; - //printf ("match %p\n", res); - if (index_num) - *index_num = i; - } else if (r == -1) { - if (ie->flags & INDEX_ENTRY_NODE) { - //printf ("recurse\n"); - res = ntfs_dt_find3 (dt->sub_nodes[i], name, name_len, index_num); - } else { - //printf ("no match\n"); - res = dt; - if (index_num) - *index_num = i; - } - } else { - printf ("error collating name\n"); - } - break; - } - - return res; -} - -/** - * ntfs_dt_find4 - * find successor to specified name, returns dt and index - * maps dt's as necessary - */ -static struct ntfs_dt * ntfs_dt_find4 (struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num) -{ - struct ntfs_dt *res = NULL; - struct ntfs_dt *sub = NULL; - INDEX_ENTRY *ie; - VCN vcn; - int i; - int r; - - if (!dt || !name) - return NULL; - - //printf ("child_count = %d\n", dt->child_count); - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - //printf ("ie->flags = %d\n", ie->flags); - if (ie->flags & INDEX_ENTRY_END) { - r = -1; - } else { - //printf ("\t"); ntfs_name_print (ie->key.file_name.file_name, ie->key.file_name.file_name_length); printf ("\n"); - r = ntfs_names_collate (name, name_len, - ie->key.file_name.file_name, - ie->key.file_name.file_name_length, - 2, IGNORE_CASE, - dt->dir->vol->upcase, - dt->dir->vol->upcase_len); - } - - //printf ("%d, %d\n", i, r); - - if (r == 1) { - //printf ("keep searching\n"); - } else if (r == 0) { - //res = dt; - //printf ("match\n"); - // ignore - } else if (r == -1) { - if (ie->flags & INDEX_ENTRY_NODE) { - //printf ("recurse\n"); - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn (ie); - //printf ("vcn = %lld\n", vcn); - sub = ntfs_dt_create (dt->dir, dt, vcn); - dt->sub_nodes[i] = sub; - } - res = ntfs_dt_find4 (dt->sub_nodes[i], name, name_len, index_num); - } else { - //printf ("no match\n"); - res = dt; - if (index_num) - *index_num = i; - } - break; - } else { - printf ("error collating name\n"); - } - //break; - } - - return res; -} - -/** - * ntfs_dt_find_all - * maps all dt's into memory - */ -static void ntfs_dt_find_all (struct ntfs_dt *dt) -{ - INDEX_ENTRY *ie; - VCN vcn; - int i; - - if (!dt) - return; - - for (i = 0; i < dt->child_count; i++) { - ie = dt->children[i]; - - if (ie->flags & INDEX_ENTRY_NODE) { - if (!dt->sub_nodes[i]) { - vcn = ntfs_ie_get_vcn (ie); - dt->sub_nodes[i] = ntfs_dt_create (dt->dir, dt, vcn); - } - ntfs_dt_find_all (dt->sub_nodes[i]); - } - } -} - -/** - * ntfs_dt_find_parent - */ -static int ntfs_dt_find_parent (struct ntfs_dt *dt) -{ - int i; - struct ntfs_dt *parent; - - if (!dt) - return -1; - - parent = dt->parent; - if (!parent) - return -1; - - for (i = 0; i < parent->child_count; i++) - if (parent->sub_nodes[i] == dt) - return i; - - return -1; -} - -/** - * ntfs_dt_isroot - */ -static BOOL ntfs_dt_isroot (struct ntfs_dt *dt) -{ - if (!dt) - return FALSE; - return (dt->parent == NULL); -} - -/** - * ntfs_dt_root_freespace - */ -static int ntfs_dt_root_freespace (struct ntfs_dt *dt) -{ - int recsize; - int inuse; - MFT_RECORD *mrec; - - if (!dt) - return -1; - - recsize = dt->dir->inode->vol->mft_record_size; - - mrec = (MFT_RECORD*) dt->dir->inode->mrec; - inuse = mrec->bytes_in_use; - - return recsize - inuse; -} - -/** - * ntfs_dt_alloc_freespace - */ -static int ntfs_dt_alloc_freespace (struct ntfs_dt *dt) -{ - int recsize; - int inuse; - INDEX_BLOCK *block; - - if (!dt) - return -1; - - recsize = dt->dir->index_size; - - block = (INDEX_BLOCK*) dt->data; - inuse = block->index.index_length + 24; - - return recsize - inuse; -} - -/** - * ntfs_dt_transfer - */ -static int ntfs_dt_transfer (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count) -{ - int i; - int need; - int space; - INDEX_ENTRY *mov_ie; - u8 *src; - u8 *dst; - int len; - int insert; - //FILE_NAME_ATTR *file; - - //XXX check len > 0 - - if (!old || !new) - return -1; - - if ((start < 0) || ((start+count) >= old->child_count)) - return -1; - - printf ("\n"); - printf (BOLD YELLOW "Transferring children\n" END); - - need = 0; - for (i = start; i < (start+count+1); i++) { - mov_ie = old->children[i]; - need += mov_ie->length; - //file = &mov_ie->key.file_name; printf ("\ttrn name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); - } - - if (ntfs_dt_isroot (new)) - space = ntfs_dt_root_freespace (new); - else - space = ntfs_dt_alloc_freespace (new); - - // XXX if this is an index root, it'll go badly wrong - // restrict to allocs only? - - printf ("\tneed = %d\n", need); - printf ("\tspace = %d\n", space); - - if (space < need) - return -1; - - if (new->child_count == 1) { - i = -1; - } else { - ntfschar *n1, *n2; - int l1, l2; - - n1 = new->children[0]->key.file_name.file_name; - l1 = new->children[0]->key.file_name.file_name_length; - - n2 = old->children[start]->key.file_name.file_name; - l2 = old->children[start]->key.file_name.file_name_length; - - i = ntfs_names_collate (n1, l1, n2, l2, - 2, IGNORE_CASE, - old->dir->vol->upcase, - old->dir->vol->upcase_len); - } - - if ((i == 0) || (i == 2)) - return -1; - - // determine the insertion point - if (i == 1) - insert = 0; - else - insert = new->child_count-1; - - src = (u8*) new->children[insert]; - dst = src + need; - len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src; - - //printf ("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len); - memmove (dst, src, len); - - dst = src; - src = (u8*) old->children[start]; - len = need; - - memcpy (dst, src, len); - - src = (u8*) old->children[start+count-1]; - dst = (u8*) old->children[start]; - len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src; - - //printf ("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len); - memmove (dst, src, len); - - dst += len; - len = old->data + old->dir->index_size - dst; - - //printf ("dst = %d, len = %d\n", dst - old->data, len); - memset (dst, 0, len); - - if (!ntfs_dt_resize_children3 (new, new->child_count + count)) - return -1; - - src = (u8*) &old->sub_nodes[start+count-1]; - dst = (u8*) &old->sub_nodes[start]; - len = (old->child_count - start - count + 1) * sizeof (struct ntfs_dt*); - - memmove (dst, src, len); - - src = (u8*) &new->sub_nodes[insert]; - dst = (u8*) &new->sub_nodes[insert+count-1]; - len = (new->child_count - insert - count + 1) * sizeof (struct ntfs_dt*); - - memmove (dst, src, len); - - if (!ntfs_dt_resize_children3 (old, old->child_count - count)) - return -1; - - src = (u8*) new->children[0]; - for (i = 0; i < new->child_count; i++) { - new->children[i] = (INDEX_ENTRY*) src; - src += new->children[i]->length; - } - - src = (u8*) old->children[0]; - for (i = 0; i < old->child_count; i++) { - old->children[i] = (INDEX_ENTRY*) src; - src += old->children[i]->length; - } - - old->header->index_length -= need; - new->header->index_length += need; - - // resize children and sub_nodes - // memmove keys in new - // memcpy old to new - // memmove keys in old - // rebuild old/new children/sub_nodes without destroying tree - // update old/new headers - - old->changed = TRUE; - new->changed = TRUE; - - printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1); - printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1); - - return 0; -} - - -/** - * ntfs_dt_alloc_insert - */ -static int ntfs_dt_alloc_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count) -{ - // XXX don't bother measuring, just subtract the children pointers - - int i; - int need; - INDEX_ENTRY *ie; - INDEX_ALLOCATION *alloc; - u8 *src; - u8 *dst; - int len; - - if (!dt) - return 1; - if (!first) - return 1; - - need = 0; - ie = first; - for (i = 0; i < count; i++) { - need += ie->length; - ie = (INDEX_ENTRY*) ((u8*)ie + ie->length); - } - - printf ("alloc insert %d bytes\n", need); - - alloc = (INDEX_ALLOCATION*) dt->data; - printf ("entries_offset = %d\n", alloc->index.entries_offset); - printf ("index_length = %d\n", alloc->index.index_length); - printf ("allocated_size = %d\n", alloc->index.allocated_size); - - printf ("insert has %d children\n", dt->child_count); - printf ("children = %p\n", dt->children); - //utils_dump_mem (dt->data, 0, 128, DM_DEFAULTS); - - ie = dt->children[dt->child_count-1]; - - printf ("last child = %p (%ld)\n", ie, (long)ie - (long)dt->data); - printf ("size = %d\n", ie->length); - - src = (u8*) ie; - dst = src + need; - len = ie->length; - - memmove (dst, src, len); - - src = (u8*) first; - dst = (u8*) ie; - len = need; - - memcpy (dst, src, len); - - // use create children - // measure need and update children list - // adjust headers - - utils_dump_mem (dt->data, 0, 256, DM_DEFAULTS); - return 0; -} - -/** - * ntfs_dt_alloc_insert2 - */ -static INDEX_ENTRY * ntfs_dt_alloc_insert2 (struct ntfs_dt *dt, int before, int count, int bytes) -{ - int space; - u8 *src; - u8 *dst; - int len; - - // XXX don't bother measuring, just subtract the children pointers - - if (!dt) - return NULL; - if (before < 0) - return NULL; - if (count < 1) - return NULL; - if (bytes < 1) - return NULL; - - // check alloc has enough space - space = ntfs_dt_alloc_freespace (dt); - if (bytes > space) - return NULL; - - // move data - src = (u8*) dt->children[before]; - dst = src + bytes; - len = dt->header->index_length - ((int)dt->children[before] - (int)dt->data) + 24; - - //printf ("%d, %d, %d\n", (int)src - (int)dt->data, (int)dst - (int)dt->data, len); - - memmove (dst, src, len); - memset (dst, 0, bytes); - - // resize arrays - ntfs_dt_resize_children3 (dt, dt->child_count + count); - - // move keys (children) - src = (u8*) (dt->children + before); - dst = src + (count * sizeof (u8*)); - len = (dt->child_count - count - before) * sizeof (u8*); - - memmove (dst, src, len); - memset (src, 0, count * sizeof (u8*)); - - // move keys (inodes) - src = (u8*) (dt->inodes + before); - dst = src + (count * sizeof (u8*)); - len = (dt->child_count - count - before) * sizeof (u8*); - - memmove (dst, src, len); - memset (src, 0, count * sizeof (u8*)); - - // move keys (sub_nodes) - src = (u8*) (dt->sub_nodes + before); - dst = src + (count * sizeof (u8*)); - len = (dt->child_count - count - before) * sizeof (u8*); - - memmove (dst, src, len); - memset (src, 0, count * sizeof (u8*)); - - return NULL; -} - -/** - * ntfs_dt_root_insert - */ -static int ntfs_dt_root_insert (struct ntfs_dt *dt, INDEX_ENTRY *first, int count) -{ - if (!dt) - return 1; - if (!first) - return 1; - - return count; -} - - /** * utils_array_insert */ @@ -2046,2027 +306,6 @@ static int utils_array_remove (void *ptr, int asize, int first, int count) } -/** - * ntfs_dt_alloc_remove2 - */ -static int ntfs_dt_alloc_remove2 (struct ntfs_dt *dt, int start, int count) -{ - int i; - int size; - - if (!dt) - return 1; - - size = 0; - for (i = start; i < (start+count); i++) { - size += dt->children[i]->length; - } - - return start + count; -} - -/** - * ntfs_dt_root_remove2 - */ -static int ntfs_dt_root_remove2 (struct ntfs_dt *dt, int start, int count) -{ - int i; - int size; - - if (!dt) - return -1; - if ((start < 0) || (start >= dt->child_count)) - return -1; - if ((count < 1) || ((start + count - 1) >= dt->child_count)) - return -1; - - printf ("s c/t %d %d/%d\n", start, count, dt->child_count); - - size = 0; - for (i = start; i < (start + count); i++) - size += dt->children[i]->length; - printf ("size1 = %d\n", size); - - size = (int) dt->children[start+count] - (int) dt->children[start]; - printf ("size2 = %d\n", size); - - size = (int) dt->children[start+count-1] - (int) dt->children[start] + dt->children[start+count-1]->length; - printf ("size3 = %d\n", size); - - // XXX what shall we do with the inodes? - // transfer them to the dir (commit them for now) - // are they _our_ responsibility? probably not - - // rearrange arrays - // shrink attribute - - ntfs_dt_resize_children3 (dt, dt->child_count - count); - - printf ("ntfs_dt_root_remove2\n"); - return dt->child_count; -} - -/** - * ntfs_dt_transfer2 - */ -static int ntfs_dt_transfer2 (struct ntfs_dt *old, struct ntfs_dt *new, int start, int count) -{ - int i; - int need; - int space; - INDEX_ENTRY *mov_ie; - u8 *src; - u8 *dst; - int len; - int insert; - //FILE_NAME_ATTR *file; - - if (!old || !new) - return -1; - - if ((start < 0) || (count < 0)) - return -1; - - if ((start + count) >= old->child_count) - return -1; - - printf ("\n"); - printf (BOLD YELLOW "Transferring children\n" END); - - need = 0; - for (i = start; i < (start+count); i++) { - mov_ie = old->children[i]; - need += mov_ie->length; - //file = &mov_ie->key.file_name; printf ("\ttrn name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); - } - - if (ntfs_dt_isroot (new)) - space = ntfs_dt_root_freespace (new); - else - space = ntfs_dt_alloc_freespace (new); - - printf ("\tneed = %d\n", need); - printf ("\tspace = %d\n", space); - - if (need > space) - return -1; - - if (ntfs_dt_isroot (new)) - ntfs_dt_root_insert (new, old->children[0], count); - else - ntfs_dt_alloc_insert2 (new, 0, count, need); - - if (ntfs_dt_isroot (old)) - ntfs_dt_root_remove2 (old, 0, count); - else - ntfs_dt_alloc_remove2 (old, 0, count); - - if (1) return -1; - if (0) ntfs_dt_alloc_insert (NULL, NULL, 0); - - if (new->child_count == 1) { - i = -1; - } else { - ntfschar *n1, *n2; - int l1, l2; - - n1 = new->children[0]->key.file_name.file_name; - l1 = new->children[0]->key.file_name.file_name_length; - - n2 = old->children[start]->key.file_name.file_name; - l2 = old->children[start]->key.file_name.file_name_length; - - i = ntfs_names_collate (n1, l1, n2, l2, - 2, IGNORE_CASE, - old->dir->vol->upcase, - old->dir->vol->upcase_len); - } - - if ((i == 0) || (i == 2)) - return -1; - - // determine the insertion point - if (i == 1) - insert = 0; - else - insert = new->child_count-1; - - src = (u8*) new->children[insert]; - dst = src + need; - len = (u8*) new->children[new->child_count-1] + new->children[new->child_count-1]->length - src; - - //printf ("src = %d, dst = %d, len = %d\n", src - new->data, dst - new->data, len); - memmove (dst, src, len); - - dst = src; - src = (u8*) old->children[start]; - len = need; - - memcpy (dst, src, len); - - src = (u8*) old->children[start+count-1]; - dst = (u8*) old->children[start]; - len = (u8*) old->children[old->child_count-1] + old->children[old->child_count-1]->length - src; - - //printf ("src = %d, dst = %d, len = %d\n", src - old->data, dst - old->data, len); - memmove (dst, src, len); - - dst += len; - len = old->data + old->dir->index_size - dst; - - //printf ("dst = %d, len = %d\n", dst - old->data, len); - memset (dst, 0, len); - - if (!ntfs_dt_resize_children3 (new, new->child_count + count)) - return -1; - - src = (u8*) &old->sub_nodes[start+count-1]; - dst = (u8*) &old->sub_nodes[start]; - len = (old->child_count - start - count + 1) * sizeof (struct ntfs_dt*); - - memmove (dst, src, len); - - src = (u8*) &new->sub_nodes[insert]; - dst = (u8*) &new->sub_nodes[insert+count-1]; - len = (new->child_count - insert - count + 1) * sizeof (struct ntfs_dt*); - - memmove (dst, src, len); - - if (!ntfs_dt_resize_children3 (old, old->child_count - count)) - return -1; - - src = (u8*) new->children[0]; - for (i = 0; i < new->child_count; i++) { - new->children[i] = (INDEX_ENTRY*) src; - src += new->children[i]->length; - } - - src = (u8*) old->children[0]; - for (i = 0; i < old->child_count; i++) { - old->children[i] = (INDEX_ENTRY*) src; - src += old->children[i]->length; - } - - old->header->index_length -= need; - new->header->index_length += need; - - // resize children and sub_nodes - // memmove keys in new - // memcpy old to new - // memmove keys in old - // rebuild old/new children/sub_nodes without destroying tree - // update old/new headers - - old->changed = TRUE; - new->changed = TRUE; - - printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, old->dir->inode->mft_no, old->vcn, old->vcn + (old->dir->index_size>>9) - 1); - printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, new->dir->inode->mft_no, new->vcn, new->vcn + (new->dir->index_size>>9) - 1); - - return 0; -} - - -/** - * utils_free_non_residents3 - */ -static int utils_free_non_residents3 (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr) -{ - ntfs_attr *na; - runlist_element *rl; - LCN size; - LCN count; - - if (!bmp) - return 1; - if (!inode) - return 1; - if (!attr) - return 1; - if (!attr->non_resident) - return 0; - - na = ntfs_attr_open (inode, attr->type, NULL, 0); - if (!na) - return 1; - - ntfs_attr_map_whole_runlist (na); - rl = na->rl; - size = na->allocated_size >> inode->vol->cluster_size_bits; - for (count = 0; count < size; count += rl->length, rl++) { - if (ntfs_bmp_set_range (bmp, rl->lcn, rl->length, 0) < 0) { - printf (RED "set range : %lld - %lld FAILED\n" END, rl->lcn, rl->lcn+rl->length-1); - } - } - ntfs_attr_close (na); - - return 0; -} - -/** - * utils_free_non_residents2 - */ -static int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp) -{ - ntfs_attr_search_ctx *ctx; - - if (!inode) - return -1; - if (!bmp) - return -1; - - ctx = ntfs_attr_get_search_ctx (inode, NULL); - if (!ctx) { - printf ("can't create a search context\n"); - return -1; - } - - while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) { - utils_free_non_residents3 (bmp, inode, ctx->attr); - } - - ntfs_attr_put_search_ctx (ctx); - return 0; -} - - -/** - * ntfs_mft_remove_attr - */ -static int ntfs_mft_remove_attr (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type) -{ - ATTR_RECORD *attr20, *attrXX; - MFT_RECORD *mft; - u8 *src, *dst; - int len; - - if (!inode) - return 1; - - attr20 = find_first_attribute (AT_ATTRIBUTE_LIST, inode->mrec); - if (attr20) - return 1; - - printf ("remove inode %lld, attr 0x%02X\n", inode->mft_no, type); - - attrXX = find_first_attribute (type, inode->mrec); - if (!attrXX) - return 1; - - if (utils_free_non_residents3 (bmp, inode, attrXX)) - return 1; - - // remove entry - // inode->mrec - - mft = inode->mrec; - //utils_dump_mem (mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n"); - - //utils_dump_mem (attrXX, 0, attrXX->length, DM_DEFAULTS); printf ("\n"); - - //printf ("mrec = %p, attr = %p, diff = %d (0x%02X)\n", mft, attrXX, (u8*)attrXX - (u8*)mft, (u8*)attrXX - (u8*)mft); - // memmove - - dst = (u8*) attrXX; - src = dst + attrXX->length; - len = (((u8*) mft + mft->bytes_in_use) - src); - - // fix mft header - mft->bytes_in_use -= attrXX->length; - -#if 0 - printf ("dst = 0x%02X, src = 0x%02X, len = 0x%02X\n", (dst - (u8*)mft), (src - (u8*)mft), len); - printf ("attr %02X, len = 0x%02X\n", attrXX->type, attrXX->length); - printf ("bytes in use = 0x%02X\n", mft->bytes_in_use); - printf ("\n"); -#endif - - memmove (dst, src, len); - //utils_dump_mem (mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n"); - - NInoSetDirty(inode); - return 0; -} - -/** - * ntfs_mft_add_attr - */ -static ATTR_RECORD * ntfs_mft_add_attr (ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len) -{ - MFT_RECORD *mrec; - ATTR_RECORD *attr; - u8 *ptr; - u8 *src; - u8 *dst; - int len; - int attr_size; - - if (!inode) - return NULL; - if (!data) - return NULL; - - attr_size = ATTR_SIZE (data_len); - - mrec = inode->mrec; - if (!mrec) - return NULL; - - if ((mrec->bytes_in_use + attr_size + 0x18) > mrec->bytes_allocated) { - printf ("attribute is too big to fit in the record\n"); - return NULL; - } - - ptr = (u8*) inode->mrec + mrec->attrs_offset; - while (1) { - attr = (ATTR_RECORD*) ptr; - - if (type < attr->type) - break; - - ptr += attr->length; - } - - //printf ("insert before attr 0x%02X\n", attr->type); - - len = ((u8*) mrec + mrec->bytes_in_use) - ((u8*) attr); - src = (u8*) attr; - dst = src + attr_size + 0x18; - - memmove (dst, src, len); - - src = data; - dst = (u8*) attr + 0x18; - len = data_len; - - // XXX wipe slack space after attr? - - memcpy (dst, src, len); - - mrec->bytes_in_use += attr_size + 0x18; - - memset (attr, 0, 0x18); - *(u32*)((u8*) attr + 0x00) = type; - *(u32*)((u8*) attr + 0x04) = attr_size + 0x18; - *(u16*)((u8*) attr + 0x0E) = mrec->next_attr_instance; - *(u32*)((u8*) attr + 0x10) = data_len; - *(u32*)((u8*) attr + 0x14) = 0x18; - - mrec->next_attr_instance++; - - return attr; -} - -/** - * ntfs_mft_resize_resident - */ -static int ntfs_mft_resize_resident (ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len) -{ - int mft_size; - int mft_usage; - int mft_free; - int attr_orig; - int attr_new; - u8 *src; - u8 *dst; - u8 *end; - int len; - ntfs_attr_search_ctx *ctx = NULL; - ATTR_RECORD *arec = NULL; - MFT_RECORD *mrec = NULL; - int res = -1; - - // XXX only works when attr is in base inode - - if ((!inode) || (!inode->mrec)) - return -1; - if ((!data) || (data_len < 0)) - return -1; - - mrec = inode->mrec; - - mft_size = mrec->bytes_allocated; - mft_usage = mrec->bytes_in_use; - mft_free = mft_size - mft_usage; - - //printf ("mft_size = %d\n", mft_size); - //printf ("mft_usage = %d\n", mft_usage); - //printf ("mft_free = %d\n", mft_free); - //printf ("\n"); - - ctx = ntfs_attr_get_search_ctx (inode, NULL); - if (!ctx) - goto done; - - if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, ctx) != 0) - goto done; - - arec = ctx->attr; - - if (arec->non_resident) { - printf ("attribute isn't resident\n"); - goto done; - } - - attr_orig = arec->value_length; - attr_new = data_len; - - //printf ("attr orig = %d\n", attr_orig); - //printf ("attr new = %d\n", attr_new); - //printf ("\n"); - - if ((attr_new - attr_orig + mft_usage) > mft_size) { - printf ("attribute won't fit into mft record\n"); - goto done; - } - - //printf ("new free space = %d\n", mft_size - (attr_new - attr_orig + mft_usage)); - - src = (u8*)arec + arec->length; - dst = src + (attr_new - attr_orig); - end = (u8*)mrec + mft_usage; - len = end - src; - - //printf ("src = %d\n", src - (u8*)mrec); - //printf ("dst = %d\n", dst - (u8*)mrec); - //printf ("end = %d\n", end - (u8*)mrec); - //printf ("len = %d\n", len); - - if (src != dst) - memmove (dst, src, len); - - memcpy ((u8*)arec + arec->value_offset, data, data_len); - - mrec->bytes_in_use += (attr_new - attr_orig); - arec->length += (attr_new - attr_orig); - arec->value_length += (attr_new - attr_orig); - - memset ((u8*)mrec + mrec->bytes_in_use, 0, mft_size - mrec->bytes_in_use); - - mft_usage += (attr_new - attr_orig); - //utils_dump_mem (mrec, 0, mft_size, DM_DEFAULTS); - res = 0; -done: - ntfs_attr_put_search_ctx (ctx); - return res; -} - -/** - * ntfs_mft_free_space - */ -static int ntfs_mft_free_space (struct ntfs_dir *dir) -{ - int res = 0; - MFT_RECORD *mft; - - if ((!dir) || (!dir->inode)) - return -1; - - mft = (MFT_RECORD*) dir->inode->mrec; - - res = mft->bytes_allocated - mft->bytes_in_use; - - return res; -} - -/** - * ntfs_mft_add_index - */ -static int ntfs_mft_add_index (struct ntfs_dir *dir) -{ - ntfs_volume *vol; - u8 *buffer = NULL; - ATTR_RECORD *attr = NULL; - struct ntfs_dt *dt = NULL; - INDEX_ENTRY *ie = NULL; - - if (!dir) - return 1; - if (dir->bitmap && dir->ialloc) - return 0; - if (dir->bitmap || dir->ialloc) - return 1; - if (dir->index_size < 512) - return 1; - - vol = dir->vol; - printf ("add two attrs to " YELLOW); ntfs_name_print (dir->name, dir->name_len); printf (END "\n"); - printf ("index size = %d\n", dir->index_size); - - buffer = malloc (dir->index_size); - if (!buffer) - return 1; - - dt = ntfs_dt_create (dir, dir->index, -1); - if (!dt) - return 1; - - dt->vcn = 0; // New alloc record - - ie = ntfs_ie_copy (dir->index->children[dir->index->child_count-1]); - ie = ntfs_ie_set_vcn (ie, dt->vcn); - - // can't replace ie yet, there may not be room - ntfs_ie_free (ie); - - ntfs_dt_transfer2 (dir->index, dt, 0, dir->index->child_count - 1); - - printf ("root has %d children\n", dir->index->child_count); - printf ("node has %d children\n", dt->child_count); - - ntfs_dt_free (dt); - - // create a new dt - // attach dt to dir - // move entries into alloc - // shrink root - - // transfer keys to new node - // hook up root & alloc dts - - // need disk allocation before here - - // Index Allocation - memset (buffer, 0, 128); - attr = ntfs_mft_add_attr (dir->inode, AT_INDEX_ALLOCATION, buffer, 0x48); - - // Bitmap - memset (buffer, 0, 8); - buffer[0] = 0x01; - //printf ("inode = %p\n", dir->inode); - attr = ntfs_mft_add_attr (dir->inode, AT_BITMAP, buffer, 8); - - // attach alloc and bitmap to dir - // need to create ntfs_attr's for them - - // one indx record - // 8 bits of bitmap - - if (0) ntfs_bmp_find_space (NULL, 0, 0); - - //printf ("m1 = %lld\n", vol->mft_zone_start); - //printf ("m2 = %lld\n", vol->mft_zone_end); - //printf ("m3 = %lld\n", vol->mft_zone_pos); - //printf ("z1 = %lld\n", vol->data1_zone_pos); - //printf ("z2 = %lld\n", vol->data2_zone_pos); - - free (buffer); - return 0; -} - - -/** - * ntfs_inode_open2 - */ -static ntfs_inode * ntfs_inode_open2 (ntfs_volume *vol, const MFT_REF mref) -{ - ntfs_inode *ino = NULL; - struct ntfs_dir *dir; - - if (!vol) - return NULL; - - switch (mref) { - case FILE_Bitmap: ino = vol->lcnbmp_ni; break; - case FILE_MFT: ino = vol->mft_ni; break; - case FILE_MFTMirr: ino = vol->mftmirr_ni; break; - case FILE_root: - dir = vol->private_data; - if (dir) - ino = dir->inode; - break; - } - - if (ino) { - //printf (BOLD YELLOW "inode reuse %lld\n" END, mref); - ino->ref_count++; - return ino; - } - - ino = ntfs_inode_open (vol, mref); - if (!ino) - return NULL; - - /* - if (mref != FILE_root) - ntfs_inode_dir_map (ino); - */ - - // link - // ino->private_data - - ino->private_data = NULL; - ino->ref_count = 1; - - //printf (BOLD YELLOW "inode open %lld\n" END, mref); - return ino; -} - -/** - * ntfs_inode_open3 - * open a deleted inode - */ -static ntfs_inode * ntfs_inode_open3 (ntfs_volume *vol, const MFT_REF mref) -{ - ntfs_inode *ino = NULL; - - if (!vol) - return NULL; - - ino = calloc (1, sizeof (*ino)); - if (!ino) - return NULL; - - ino->mrec = malloc (vol->mft_record_size); - if (!ino->mrec) { - free (ino); - return NULL; - } - - ino->mft_no = mref; - ino->vol = vol; - - ino->data_size = -1; - ino->allocated_size = -1; - - ino->private_data = NULL; - ino->ref_count = 1; - - if (1 != ntfs_attr_mst_pread (vol->mft_na, MREF(mref) * vol->mft_record_size, 1, vol->mft_record_size, ino->mrec)) { - //ntfs_inode_close2 (ino); ??? - free (ino->mrec); - free (ino); - return NULL; - } - - NInoSetDirty (ino); - return ino; -} - - -/** - * ntfs_dt_root_replace - */ -static int ntfs_dt_root_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie) -{ - u8 *src; - u8 *dst; - u8 *attr; - int len; - int i; - - if (!del || !del_ie || !suc_ie) - return FALSE; - - //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); - //printf ("\n"); - - attr = malloc (del->data_len + suc_ie->length - del_ie->length); - - dst = attr; - src = del->data; - len = (u8*) del_ie - del->data; - - memcpy (dst, src, len); - - dst += len; - src = (u8*) suc_ie; - len = suc_ie->length; - - memcpy (dst, src, len); - - dst += len; - src = (u8*) del_ie + del_ie->length; - len = del->data_len + (del->data - (u8*) del_ie) - del_ie->length; - - memcpy (dst, src, len); - - src = (u8*) del->data; - dst = attr; - - len = suc_ie->length - del_ie->length; - free (del->data); - del->data = attr; - del->data_len += len; - del->header = (INDEX_HEADER*) (del->data + 0x10); - del->header->index_length += len; - del->header->allocated_size += len; - - ntfs_mft_resize_resident (del->dir->inode, AT_INDEX_ROOT, I30, 4, del->data, del->data_len); - - //utils_dump_mem (attr, 0, del->data_len, DM_DEFAULTS); - - //printf ("\n"); - //printf (BOLD YELLOW "Adjust children\n" END); - //for (i = 0; i < del->child_count; i++) - // printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags); - //printf ("\n"); - - //printf ("src = %p, dst = %p, len = %d\n", src, dst, len); fflush (stdout); - - for (i = 0; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) (dst + ((u8*) del->children[i] - src)); - - for (i = del_num+1; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len); - - //for (i = 0; i < del->child_count; i++) - // printf ("\tChild %d %p %d\n", i, del->children[i], del->children[i]->flags); - //printf ("\n"); - - //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); - //printf ("\n"); - - del->changed = TRUE; - - printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no); - return TRUE; -} - -/** - * ntfs_dt_alloc_replace - */ -static BOOL ntfs_dt_alloc_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie) -{ - u8 *src; - u8 *dst; - int len; - int i; - - if (!del || !del_ie || !suc_ie) - return FALSE; - - //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); - - src = (u8*) del_ie + del_ie->length; - dst = (u8*) del_ie + suc_ie->length; - len = del->header->index_length + 24 + (del->data - src); - //printf ("src = %d\n", src - del->data); - //printf ("dst = %d\n", dst - del->data); - //printf ("len = %d\n", len); - - if (src != dst) - memmove (dst, src, len); - - src = (u8*) suc_ie; - dst = (u8*) del_ie; - len = suc_ie->length; - - memcpy (dst, src, len); - - //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); - - del->header->index_length += suc_ie->length - del_ie->length; - - dst = del->data + del->header->index_length + 24; - len = del->data_len - del->header->index_length - 24; - - memset (dst, 0, len); - - //for (i = 0; i < del->child_count; i++) - // printf ("Child %d %p\n", i, del->children[i]); - //printf ("\n"); - - len = suc_ie->length - del_ie->length; - //printf ("len = %d\n", len); - - for (i = del_num+1; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] + len); - - //for (i = 0; i < del->child_count; i++) - // printf ("Child %d %p\n", i, del->children[i]); - //printf ("\n"); - - //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); - - del->changed = TRUE; - - printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1); - return TRUE; -} - -/** - * ntfs_dt_root_remove - */ -static BOOL ntfs_dt_root_remove (struct ntfs_dt *del, int del_num) -{ - INDEX_ENTRY *del_ie = NULL; - u8 *src; - u8 *dst; - u8 *old; - int len; - int del_len; - int i; - //int off; - - if (!del) - return FALSE; - - //utils_dump_mem (del->data, 0, del->header->index_length+16, DM_RED); - //printf ("\n"); - -#if 0 - off = (u8*) del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - printf ("%2d %4d ", i+1, off); - off += del_ie->length; - - if (del_ie->flags & INDEX_ENTRY_END) { - printf ("END (%d)\n", del_ie->length); - break; - } - - ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - printf (" (%d)\n", del_ie->length); - } - printf ("total = %d\n", off); -#endif - - del_ie = del->children[del_num]; - del_len = del_ie->length; - - src = (u8*) del_ie + del_len; - dst = (u8*) del_ie; - len = del->header->index_length + 16 - (src - del->data); - - //printf ("src = %d\n", src - del->data); - //printf ("dst = %d\n", dst - del->data); - //printf ("len = %d\n", len); - - memmove (dst, src, len); - - del->data_len -= del_len; - del->child_count--; - - del->header->index_length = del->data_len - 16; - del->header->allocated_size = del->data_len - 16; - - ntfs_mft_resize_resident (del->dir->inode, AT_INDEX_ROOT, I30, 4, del->data, del->data_len); - old = del->data; - del->data = realloc (del->data, del->data_len); - del->header = (INDEX_HEADER*) (del->data + 0x10); - - //utils_dump_mem (del->data, 0, del->data_len, DM_GREEN | DM_RED); - - src = (u8*) (&del->children[del_num+1]); - dst = (u8*) (&del->children[del_num]); - len = (del->child_count - del_num) * sizeof (INDEX_ENTRY*); - - //printf ("src = %d\n", src - (u8*) del->children); - //printf ("dst = %d\n", dst - (u8*) del->children); - //printf ("len = %d\n", len); - - memmove (dst, src, len); - - src = (u8*) (&del->sub_nodes[del_num+1]); - dst = (u8*) (&del->sub_nodes[del_num]); - len = (del->child_count - del_num) * sizeof (struct ntfs_dt*); - - //printf ("src = %d\n", src - (u8*) del->children); - //printf ("dst = %d\n", dst - (u8*) del->children); - //printf ("len = %d\n", len); - - memmove (dst, src, len); - - //printf ("del_num = %d\n", del_num); - for (i = 0; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - old + del->data); - for (i = del_num; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_len); - - if (!ntfs_dt_create_children2 (del, del->child_count)) - return FALSE; - -#if 0 - off = (u8*) del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - printf ("%2d %4d ", i+1, off); - off += del_len; - - if (del_ie->flags & INDEX_ENTRY_END) { - printf ("END (%d)\n", del_len); - break; - } - - ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - printf (" (%d)\n", del_len); - } - printf ("total = %d\n", off); -#endif - - //utils_dump_mem (del->data, 0, del->header->index_length+16, DM_DEFAULTS); - - del->changed = TRUE; - - printf (GREEN "Modified: inode %lld, $INDEX_ROOT\n" END, del->dir->inode->mft_no); - return TRUE; -} - -/** - * ntfs_dt_alloc_remove - */ -static BOOL ntfs_dt_alloc_remove (struct ntfs_dt *del, int del_num) -{ - INDEX_ENTRY *del_ie = NULL; - u8 *dst; - u8 *src; - int len; - int i; - //int off; - - if (!del) - return FALSE; - -#if 0 - off = (u8*)del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - printf ("%2d %4d ", i, off); - off += del_ie->length; - - if (del_ie->flags & INDEX_ENTRY_END) { - printf ("END (%d)\n", del_ie->length); - break; - } - - ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - printf (" (%d)\n", del_ie->length); - } - printf ("total = %d\n", off); - printf ("\n"); -#endif - - //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); - //printf ("\n"); - - del_ie = del->children[del_num]; - - src = (u8*) del_ie + del_ie->length; - dst = (u8*) del_ie; - len = del->header->index_length + 24 - (src - del->data); - - //printf ("src = %d\n", src - del->data); - //printf ("dst = %d\n", dst - del->data); - //printf ("len = %d\n", len); - - memmove (dst, src, len); - - del->header->index_length -= src - dst; - del->child_count--; - - dst += len; - len = del->data_len - del->header->index_length - 24; - - //printf ("dst = %d\n", dst - del->data); - //printf ("len = %d\n", len); - - memset (dst, 0, len); - - src = (u8*) (&del->children[del_num+1]); - dst = (u8*) (&del->children[del_num]); - len = (del->child_count - del_num) * sizeof (INDEX_ENTRY*); - - //printf ("src = %d\n", src - (u8*) del->children); - //printf ("dst = %d\n", dst - (u8*) del->children); - //printf ("len = %d\n", len); - - memmove (dst, src, len); - - src = (u8*) (&del->sub_nodes[del_num+1]); - dst = (u8*) (&del->sub_nodes[del_num]); - len = (del->child_count - del_num) * sizeof (struct ntfs_dt*); - - //printf ("src = %d\n", src - (u8*) del->children); - //printf ("dst = %d\n", dst - (u8*) del->children); - //printf ("len = %d\n", len); - - memmove (dst, src, len); - - //printf ("del_num = %d\n", del_num); - for (i = del_num; i < del->child_count; i++) - del->children[i] = (INDEX_ENTRY*) ((u8*) del->children[i] - del_ie->length); - - if (!ntfs_dt_create_children2 (del, del->child_count)) - return FALSE; - - //utils_dump_mem (del->data, 0, del->data_len, DM_DEFAULTS); - -#if 0 - off = (u8*)del->children[0] - del->data; - for (i = 0; i < del->child_count; i++) { - del_ie = del->children[i]; - - printf ("%2d %4d ", i, off); - off += del_ie->length; - - if (del_ie->flags & INDEX_ENTRY_END) { - printf ("END (%d)\n", del_ie->length); - break; - } - - ntfs_name_print (del_ie->key.file_name.file_name, del_ie->key.file_name.file_name_length); - printf (" (%d)\n", del_ie->length); - } - printf ("total = %d\n", off); - printf ("\n"); -#endif - - del->changed = TRUE; - - printf (GREEN "Modified: inode %lld, $INDEX_ALLOCATION vcn %lld-%lld\n" END, del->dir->inode->mft_no, del->vcn, del->vcn + (del->dir->index_size>>9) - 1); - - if (del->child_count < 2) { - printf ("indx is empty\n"); - ntfs_bmp_set_range (del->dir->bitmap, del->vcn, 1, 0); - } - - return TRUE; -} - -/** - * ntfs_dt_alloc_add - */ -static int ntfs_dt_alloc_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child) -{ - INDEX_BLOCK *block; - INDEX_ENTRY *entry; - int need; - int space; - u8 *src; - u8 *dst; - int len; - - if (!parent || !ie) - return 0; - - block = (INDEX_BLOCK*) parent->data; - - need = ie->length; - space = parent->data_len - block->index.index_length - 24; - - printf ("need %d, have %d\n", need, space); - if (need > space) { - printf ("no room"); - return 0; - } - - //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); - //printf ("\n"); - - src = (u8*) parent->children[index_num]; - dst = src + need; - len = parent->data + parent->data_len - src - space; - //printf ("src = %d\n", src - parent->data); - //printf ("dst = %d\n", dst - parent->data); - //printf ("len = %d\n", len); - - memmove (dst, src, len); - - dst = src; - src = (u8*) ie; - len = need; - - memcpy (dst, src, len); - - block->index.index_length += len; - - dst = parent->data + block->index.index_length + 24; - len = parent->data_len - block->index.index_length - 24; - - memset (dst, 0, len); - - //realloc children, sub_nodes - ntfs_dt_create_children2 (parent, parent->child_count + 1); - - // regen children pointers - parent->child_count = 0; - - src = parent->data + 0x18 + parent->header->entries_offset; - len = parent->data_len - 0x18 - parent->header->entries_offset; - - while (src < (parent->data + parent->data_len)) { - entry = (INDEX_ENTRY*) src; - - parent->children[parent->child_count] = entry; - parent->child_count++; - - if (entry->flags & INDEX_ENTRY_END) - break; - - src += entry->length; - } - printf ("count = %d\n", parent->child_count); - - src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1]; - dst = (u8*) &parent->sub_nodes[index_num]; - len = (parent->child_count - index_num - 1) * sizeof (struct ntfs_dt*); - - memmove (dst, src, len); - - //insert sub_node pointer - parent->sub_nodes[index_num] = child; - - //utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); - //printf ("\n"); - return 0; -} - -/** - * ntfs_dt_root_add - */ -static int ntfs_dt_root_add (struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child) -{ - INDEX_ROOT *root; - INDEX_ENTRY *entry; - int need; - int space; - u8 *attr; - u8 *src; - u8 *dst; - int len; - - if (!parent || !ie) - return 0; - - root = (INDEX_ROOT*) parent->data; - - utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); - printf ("\n"); - - need = ie->length; - space = ntfs_mft_free_space (parent->dir); - - printf ("need %d, have %d\n", need, space); - if (need > space) { - printf ("no room"); - return 0; - } - - attr = malloc (parent->data_len + need); - - src = parent->data; - dst = attr; - len = root->index.entries_offset + 16; - - memcpy (dst, src, len); - - dst += len; - src = (u8*) ie; - len = ie->length; - - memcpy (dst, src, len); - - dst += len; - src = (u8*) parent->children[index_num]; - len = parent->data + parent->data_len - src; - - memcpy (dst, src, len); - - free (parent->data); - parent->data = attr; - parent->data_len += need; - - root = (INDEX_ROOT*) parent->data; - root->index.index_length = parent->data_len - 16; - root->index.allocated_size = parent->data_len - 16; - - utils_dump_mem (parent->data, 0, parent->data_len, DM_DEFAULTS); - printf ("\n"); - - ntfs_mft_resize_resident (parent->dir->inode, AT_INDEX_ROOT, I30, 4, parent->data, parent->data_len); - - //realloc children, sub_nodes - ntfs_dt_create_children2 (parent, parent->child_count + 1); - - // regen children pointers - parent->child_count = 0; - - src = parent->data + 0x18 + parent->header->entries_offset; - len = parent->data_len - 0x18 - parent->header->entries_offset; - - // XXX can we rebase the children more simply? (in alloc_add too) - while (src < (parent->data + parent->data_len)) { - entry = (INDEX_ENTRY*) src; - - parent->children[parent->child_count] = entry; - parent->child_count++; - - if (entry->flags & INDEX_ENTRY_END) - break; - - src += entry->length; - } - printf ("count = %d\n", parent->child_count); - - src = (u8*) &parent->sub_nodes[index_num+parent->child_count-1]; - dst = (u8*) &parent->sub_nodes[index_num]; - len = (parent->child_count - index_num - 1) * sizeof (struct ntfs_dt*); - - memmove (dst, src, len); - - //insert sub_node pointer - parent->sub_nodes[index_num] = child; - - return 0; -} - -/** - * ntfs_dt_add2 - */ -static int ntfs_dt_add2 (INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded) -{ - int need; - int space; - int median; - struct ntfs_dt *new = NULL; - struct ntfs_dt *chl; - INDEX_ENTRY *med_ie = NULL; - //FILE_NAME_ATTR *file; - VCN vcn = 0; - //int i; - - if (!ie || !suc) - return -1; - - printf ("\n"); - printf (BOLD YELLOW "Add key to leaf\n" END); - - //utils_dump_mem (suc->data, 0, suc->data_len, DM_DEFAULTS); - - chl = NULL; -ascend: - //XXX replace with while/break? - -#if 0 - for (; ded; ded = ded->sub_nodes[0]) { - printf ("\tded vcn = %lld\n", ded->vcn); - } -#endif - - /* - * ADD - * room in current node? - * yes, add, done - * no, split, ascend - */ - need = ie->length; - - if (ntfs_dt_isroot (suc)) - space = ntfs_dt_root_freespace (suc); - else - space = ntfs_dt_alloc_freespace (suc); - - printf ("\tneed %d\n", need); - printf ("\tspace %d\n", space); - - if (space >= need) { - if (ntfs_dt_isroot (suc)) - ntfs_dt_root_add (suc, suc_num, ie, chl); - else - ntfs_dt_alloc_add (suc, suc_num, ie, chl); - goto done; - } - - /* - * SPLIT - * any dead? - * yes reuse - * no alloc - */ - if (ded) { - new = ded; - vcn = ded->vcn; - ded = ded->sub_nodes[0]; - printf ("\treusing vcn %lld\n", new->vcn); - } else { - ntfs_mft_add_index (suc->dir); - /* - * ALLOC - * any unused records? - * yes, enable first - * no, extend - */ - /* - * ENABLE - * modify bitmap - * init indx record - */ - /* - * EXTEND - * room in bitmap - * yes, do nothing - * no, extend bitmap - * extend alloc - */ - /* - * EXTEND BITMAP - * extend bitmap - * init bitmap - */ - } - - //printf ("\tnode has %d children\n", suc->child_count); - - // initialise new node - // XXX ntfs_dt_initialise (new, vcn); - - goto done; - - // find median key - median = (suc->child_count+1) / 2; - med_ie = ntfs_ie_copy (suc->children[median]); - //file = &med_ie->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); - - ntfs_ie_free (med_ie); - med_ie = NULL; - - //printf ("suc key count = %d\n", suc->child_count); - //printf ("new key count = %d\n", new->child_count); - - //printf ("median's child = %p\n", suc->sub_nodes[median]); - // need to pass the child when ascending - chl = suc->sub_nodes[median]; - - // transfer keys - if (ntfs_dt_transfer (suc, new, 0, median-1) < 0) - goto done; - - //printf ("suc key count = %d\n", suc->child_count); - //printf ("new key count = %d\n", new->child_count); - - //file = &suc->children[0]->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); - - // can this be a root node? - if (ntfs_dt_isroot (suc)) - ntfs_dt_root_remove (suc, 0); - else - ntfs_dt_alloc_remove (suc, 0); - - //file = &suc->children[0]->key.file_name; printf ("\tmed name: "); ntfs_name_print (file->file_name, file->file_name_length); printf ("\n"); - //printf ("suc key count = %d\n", suc->child_count); - //printf ("new key count = %d\n", new->child_count); - - // remove the median key - - // split when median has children - // median child given to new ! - // median child is new - // ascend - - med_ie = ntfs_ie_set_vcn (med_ie, new->vcn); - if (!med_ie) - goto done; - - //printf ("median child = %lld\n", ntfs_ie_get_vcn (med_ie)); - //printf ("new's vcn = %lld\n", new->vcn); - - // adjust parents - // attach new to median - // escape clause for root node? - // goto ascend - - // ie = insert - // child = child - // suc = successor - // suc_num = insert point - - ie = med_ie; - suc = suc->parent; - suc_num = 0; - - printf ("\n"); - printf (BOLD YELLOW "Ascend\n" END); - goto ascend; -done: - return 0; -} - - -/** - * ntfs_dir_rollback - */ -static int ntfs_dir_rollback (struct ntfs_dir *dir) -{ - int i; - - if (!dir) - return -1; - - if (ntfs_dt_rollback (dir->index) < 0) - return -1; - - if (ntfs_bmp_rollback (dir->bitmap) < 0) - return -1; - - for (i = 0; i < dir->child_count; i++) { - if (ntfs_dir_rollback (dir->children[i]) < 0) - return -1; - } - - return 0; -} - -/** - * ntfs_dir_truncate - */ -static int ntfs_dir_truncate (ntfs_volume *vol, struct ntfs_dir *dir) -{ - //int i; - //u8 *buffer; - //int buf_count; - s64 last_bit; - INDEX_ENTRY *ie; - - if (!vol || !dir) - return -1; - - if ((dir->ialloc == NULL) || (dir->bitmap == NULL)) - return 0; - -#if 0 - buf_count = ROUND_UP (dir->bitmap->attr->allocated_size, vol->cluster_size) >> vol->cluster_size_bits; - printf ("alloc = %lld bytes\n", dir->ialloc->allocated_size); - printf ("alloc = %lld clusters\n", dir->ialloc->allocated_size >> vol->cluster_size_bits); - printf ("bitmap bytes 0 to %lld\n", ((dir->ialloc->allocated_size >> vol->cluster_size_bits)-1)>>3); - printf ("bitmap = %p\n", dir->bitmap); - printf ("bitmap = %lld bytes\n", dir->bitmap->attr->allocated_size); - printf ("bitmap = %d buffers\n", buf_count); -#endif - - last_bit = ntfs_bmp_find_last_set (dir->bitmap); - if (dir->ialloc->allocated_size == (dir->index_size * (last_bit + 1))) { - //printf ("nothing to do\n"); - return 0; - } - - printf (BOLD YELLOW "Truncation needed\n" END); - -#if 0 - printf ("\tlast bit = %lld\n", last_bit); - printf ("\tactual IALLOC size = %lld\n", dir->ialloc->allocated_size); - printf ("\tshould IALLOC size = %lld\n", dir->index_size * (last_bit + 1)); -#endif - - if ((dir->index_size * (last_bit + 1)) == 0) { - printf ("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); - //rollback all dts - //ntfs_dt_rollback (dir->index); - //dir->index = NULL; - // What about the ROOT dt? - - ie = ntfs_ie_copy (dir->index->children[0]); - if (!ie) { - printf (RED "IE copy failed\n" END); - return -1; - } - - ie = ntfs_ie_remove_vcn (ie); - if (!ie) { - printf (RED "IE remove vcn failed\n" END); - return -1; - } - - //utils_dump_mem (dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); printf ("\n"); - //utils_dump_mem (ie, 0, ie->length, DM_DEFAULTS); printf ("\n"); - ntfs_dt_root_replace (dir->index, 0, dir->index->children[0], ie); - //utils_dump_mem (dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); printf ("\n"); - //printf ("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); - - ntfs_ie_free (ie); - ie = NULL; - - //index flags remove LARGE_INDEX - dir->index->header->flags = 0; - - //rollback dir's bmp - ntfs_bmp_free (dir->bitmap); - dir->bitmap = NULL; - - /* - for (i = 0; i < dir->index->child_count; i++) { - ntfs_dt_rollback (dir->index->sub_nodes[i]); - dir->index->sub_nodes[i] = NULL; - } - */ - - //printf ("dir->index->inodes[0] = %p\n", dir->index->inodes[0]); - - //remove 0xA0 attribute - ntfs_mft_remove_attr (vol->private_bmp2, dir->inode, AT_INDEX_ALLOCATION); - - //remove 0xB0 attribute - ntfs_mft_remove_attr (vol->private_bmp2, dir->inode, AT_BITMAP); - } else { - printf (RED "Cannot shrink directory\n" END); - //ntfs_dir_shrink_alloc - //ntfs_dir_shrink_bitmap - //make bitmap resident? - } - - /* - * Remove - * dt -> dead - * bitmap updated - * rollback dead dts - * commit bitmap - * commit dts - * commit dir - */ - /* - * Reuse - * search for lowest dead - * update bitmap - * init dt - * remove from dead - * insert into tree - * init INDX - */ - -#if 0 - buffer = ntfs_bmp_get_data (dir->bitmap, 0); - if (!buffer) - return -1; - - utils_dump_mem (buffer, 0, 8, DM_NO_ASCII); - for (i = buf_count-1; i >= 0; i--) { - if (buffer[i]) { - printf ("alloc in use\n"); - return 0; - } - } -#endif - - // /$BITMAP($I30) - // /$INDEX_ALLOCATION($I30) - // $Bitmap - - // Find the highest set bit in the directory bitmap - // can we free any clusters of the alloc? - // if yes, resize attribute - - // Are *any* bits set? - // If not remove ialloc - - return 0; -} - -/** - * ntfs_dir_commit - */ -static int ntfs_dir_commit (struct ntfs_dir *dir) -{ - int i; - - if (!dir) - return 0; - - printf ("commit dir inode %llu\n", dir->inode->mft_no); - if (NInoDirty (dir->inode)) { -#ifdef RM_WRITE - ntfs_inode_sync (dir->inode); -#endif - printf (RED "\tntfs_inode_sync %llu\n" END, dir->inode->mft_no); - } - - if (ntfs_dt_commit (dir->index) < 0) - return -1; - - if (ntfs_bmp_commit (dir->bitmap) < 0) - return -1; - - for (i = 0; i < dir->child_count; i++) { - if (ntfs_dir_commit (dir->children[i]) < 0) - return -1; - } - - return 0; -} - -/** - * ntfs_dir_free - */ -static void ntfs_dir_free (struct ntfs_dir *dir) -{ - struct ntfs_dir *parent; - int i; - - if (!dir) - return; - - ntfs_dir_rollback (dir); - - parent = dir->parent; - if (parent) { - for (i = 0; i < parent->child_count; i++) { - if (parent->children[i] == dir) { - parent->children[i] = NULL; - } - } - } - - ntfs_attr_close (dir->iroot); - ntfs_attr_close (dir->ialloc); - ntfs_inode_close2 (dir->inode); - - ntfs_dt_free (dir->index); - ntfs_bmp_free (dir->bitmap); - - for (i = 0; i < dir->child_count; i++) - ntfs_dir_free (dir->children[i]); - - free (dir->name); - free (dir->children); - free (dir); -} - -/** - * ntfs_dir_create - */ -static struct ntfs_dir * ntfs_dir_create (ntfs_volume *vol, MFT_REF mft_num) -{ - struct ntfs_dir *dir = NULL; - ntfs_inode *inode = NULL; - ATTR_RECORD *rec = NULL; - INDEX_ROOT *ir = NULL; - FILE_NAME_ATTR *name = NULL; - - if (!vol) - return NULL; - - //printf ("ntfs_dir_create %lld\n", MREF (mft_num)); - inode = ntfs_inode_open2 (vol, mft_num); - if (!inode) - return NULL; - - dir = calloc (1, sizeof (*dir)); - if (!dir) { - ntfs_inode_close2 (inode); - return NULL; - } - - dir->inode = inode; - dir->iroot = ntfs_attr_open (inode, AT_INDEX_ROOT, I30, 4); - dir->ialloc = ntfs_attr_open (inode, AT_INDEX_ALLOCATION, I30, 4); - - if (!dir->iroot) { - ntfs_dir_free (dir); - return NULL; - } - - dir->vol = vol; - dir->parent = NULL; - dir->name = NULL; - dir->name_len = 0; - dir->index = NULL; - dir->children = NULL; - dir->child_count = 0; - dir->mft_num = mft_num; - - // This may not exist - dir->bitmap = ntfs_bmp_create (inode, AT_BITMAP, I30, 4); - - if (dir->iroot) { - rec = find_first_attribute (AT_INDEX_ROOT, inode->mrec); - ir = (INDEX_ROOT*) ((u8*)rec + rec->value_offset); - dir->index_size = ir->index_block_size; - } else { - // XXX !iroot? - dir->index_size = 0; - } - - // Finally, find the dir's name - rec = find_first_attribute (AT_FILE_NAME, inode->mrec); - name = (FILE_NAME_ATTR*) ((u8*)rec + rec->value_offset); - - dir->name_len = name->file_name_length; - dir->name = malloc (sizeof (ntfschar) * dir->name_len); - memcpy (dir->name, name->file_name, sizeof (ntfschar) * dir->name_len); - - return dir; -} - -/** - * ntfs_dir_add - */ -static void ntfs_dir_add (struct ntfs_dir *parent, struct ntfs_dir *child) -{ - if (!parent || !child) - return; - - parent->child_count++; - //printf ("child count = %d\n", parent->child_count); - parent->children = realloc (parent->children, parent->child_count * sizeof (struct ntfs_dir*)); - child->parent = parent; - - parent->children[parent->child_count-1] = child; -} - -/** - * ntfs_dir_find2 - */ -static struct ntfs_dir * ntfs_dir_find2 (struct ntfs_dir *dir, ntfschar *name, int name_len) -{ - int i; - struct ntfs_dir *child = NULL; - struct ntfs_dt *dt = NULL; - int dt_num = 0; - INDEX_ENTRY *ie; - MFT_REF mft_num; - - if (!dir || !name) - return NULL; - - if (!dir->index) { // XXX when will this happen? - printf ("ntfs_dir_find2 - directory has no index\n"); - return NULL; - } - - for (i = 0; i < dir->child_count; i++) { - if (0 == ntfs_names_collate (name, name_len, - dir->children[i]->name, - dir->children[i]->name_len, - 2, IGNORE_CASE, - dir->vol->upcase, - dir->vol->upcase_len)) - return dir->children[i]; - } - - dt = ntfs_dt_find2 (dir->index, name, name_len, &dt_num); - if (!dt) { - printf ("can't find name in dir\n"); - return NULL; - } - - ie = dt->children[dt_num]; - - mft_num = ie->indexed_file; - - child = ntfs_dir_create (dir->vol, mft_num); - if (!child) - return NULL; - - child->index = ntfs_dt_create (child, NULL, -1); - - ntfs_dir_add (dir, child); - - return child; -} - - -/** - * ntfs_volume_commit - */ -static int ntfs_volume_commit (ntfs_volume *vol) -{ - if (!vol) - return -1; - - printf ("commit volume\n"); - if (ntfs_bmp_commit (vol->private_bmp1) < 0) - return -1; - - if (ntfs_bmp_commit (vol->private_bmp2) < 0) - return -1; - - if (ntfs_dir_commit (vol->private_data) < 0) - return -1; - - return 0; -} - -/** - * ntfs_volume_rollback - */ -static int ntfs_volume_rollback (ntfs_volume *vol) -{ - if (!vol) - return -1; - - if (ntfs_bmp_rollback (vol->private_bmp1) < 0) - return -1; - - if (ntfs_bmp_rollback (vol->private_bmp2) < 0) - return -1; - - if (ntfs_dir_rollback (vol->private_data) < 0) - return -1; - - return 0; -} - -/** - * ntfs_volume_umount2 - */ -static int ntfs_volume_umount2 (ntfs_volume *vol, const BOOL force) -{ - struct ntfs_dir *dir; - struct ntfs_bmp *bmp; - - if (!vol) - return 0; - - ntfs_volume_rollback (vol); - - dir = (struct ntfs_dir *) vol->private_data; - vol->private_data = NULL; - ntfs_dir_free (dir); - - bmp = (struct ntfs_bmp *) vol->private_bmp1; - vol->private_bmp1 = NULL; - ntfs_bmp_free (bmp); - - bmp = (struct ntfs_bmp *) vol->private_bmp2; - vol->private_bmp2 = NULL; - ntfs_bmp_free (bmp); - - return ntfs_umount (vol, force); -} - -/** - * ntfs_volume_mount2 - */ -static ntfs_volume * ntfs_volume_mount2 (const char *device, unsigned long flags, BOOL force) -{ - // XXX can we replace these and search by mft number? Hmm... NO. - // unless I have a recursive search for an MFT number - static ntfschar bmp[8] = { - const_cpu_to_le16('$'), - const_cpu_to_le16('B'), - const_cpu_to_le16('i'), - const_cpu_to_le16('t'), - const_cpu_to_le16('m'), - const_cpu_to_le16('a'), - const_cpu_to_le16('p'), - const_cpu_to_le16(0) - }; - - static ntfschar mft[5] = { - const_cpu_to_le16('$'), - const_cpu_to_le16('M'), - const_cpu_to_le16('F'), - const_cpu_to_le16('T'), - const_cpu_to_le16(0) - }; - - static ntfschar mftmirr[9] = { - const_cpu_to_le16('$'), - const_cpu_to_le16('M'), - const_cpu_to_le16('F'), - const_cpu_to_le16('T'), - const_cpu_to_le16('M'), - const_cpu_to_le16('i'), - const_cpu_to_le16('r'), - const_cpu_to_le16('r'), - const_cpu_to_le16(0) - }; - - static ntfschar dot[2] = { - const_cpu_to_le16('.'), - const_cpu_to_le16(0) - }; - - ntfs_volume *vol; - struct ntfs_dir *dir; - struct ntfs_dt *root; - struct ntfs_dt *found; - int num; - - vol = utils_mount_volume (device, flags, force); - if (!vol) - return NULL; - - vol->lcnbmp_ni ->ref_count = 1; - vol->mft_ni ->ref_count = 1; - vol->mftmirr_ni->ref_count = 1; - - vol->lcnbmp_ni ->private_data = NULL; - vol->mft_ni ->private_data = NULL; - vol->mftmirr_ni->private_data = NULL; - - dir = ntfs_dir_create (vol, FILE_root); - if (!dir) { - ntfs_volume_umount2 (vol, FALSE); - vol = NULL; - goto done; - } - - dir->index = ntfs_dt_create (dir, NULL, -1); - - root = dir->index; - - //$Bitmap - num = -1; - found = ntfs_dt_find2 (root, bmp, sizeof (bmp) - 1, &num); - if ((!found) || (num < 0)) { - printf ("can't find $Bitmap\n"); - ntfs_volume_umount2 (vol, FALSE); - vol = NULL; - goto done; - } - vol->lcnbmp_ni->ref_count++; - vol->lcnbmp_ni->private_data = found->dir; - found->inodes[num] = vol->lcnbmp_ni; - - //$MFT - num = -1; - found = ntfs_dt_find2 (root, mft, sizeof (mft) - 1, &num); - if ((!found) || (num < 0)) { - printf ("can't find $MFT\n"); - ntfs_volume_umount2 (vol, FALSE); - vol = NULL; - goto done; - } - vol->mft_ni->ref_count++; - vol->mft_ni->private_data = found->dir; - found->inodes[num] = vol->mft_ni; - - //$MFTMirr - num = -1; - found = ntfs_dt_find2 (root, mftmirr, sizeof (mftmirr) - 1, &num); - if ((!found) || (num < 0)) { - printf ("can't find $MFTMirr\n"); - ntfs_volume_umount2 (vol, FALSE); - vol = NULL; - goto done; - } - vol->mftmirr_ni->ref_count++; - vol->mftmirr_ni->private_data = found->dir; - found->inodes[num] = vol->mftmirr_ni; - - // root directory - num = -1; - found = ntfs_dt_find2 (root, dot, 1, &num); - if ((!found) || (num < 0)) { - printf ("can't find the root directory\n"); - ntfs_volume_umount2 (vol, FALSE); - vol = NULL; - goto done; - } - - vol->private_data = found->dir; - found->inodes[num] = dir->inode; - dir->inode->private_data = found; - dir->inode->ref_count = 2; - - vol->private_bmp1 = ntfs_bmp_create (vol->mft_ni, AT_BITMAP, NULL, 0); - vol->private_bmp2 = ntfs_bmp_create (vol->lcnbmp_ni, AT_DATA, NULL, 0); - - if (!vol->private_bmp1 || !vol->private_bmp2) { - printf ("can't find the bitmaps\n"); - ntfs_volume_umount2 (vol, FALSE); - vol = NULL; - goto done; - } - -done: - return vol; -} - /** * utils_pathname_to_inode2 */ diff --git a/ntfsprogs/ntfsrm.h b/ntfsprogs/ntfsrm.h index cd1186e0..c37e55b8 100644 --- a/ntfsprogs/ntfsrm.h +++ b/ntfsprogs/ntfsrm.h @@ -1,7 +1,7 @@ /* * ntfsrm - Part of the Linux-NTFS project. * - * Copyright (c) 2004 Richard Russon + * Copyright (c) 2004-2005 Richard Russon * * This utility will delete files from an NTFS volume. * @@ -26,6 +26,11 @@ #include "types.h" #include "layout.h" +#include "volume.h" +#include "inode.h" + +struct ntfs_dir; +struct ntfs_dt; /** * struct options @@ -42,54 +47,6 @@ struct options { int nodirty; /* Do not mark volume dirty */ }; -/** - * struct ntfs_bmp - * a cache for either dir/$BITMAP, $MFT/$BITMAP or $Bitmap/$DATA - */ -struct ntfs_bmp { - ntfs_volume *vol; - ntfs_attr *attr; - int count; - u8 **data; - VCN *data_vcn; -}; - -/** - * struct ntfs_dt - */ -struct ntfs_dt { - struct ntfs_dir *dir; - struct ntfs_dt *parent; - u8 *data; - int data_len; - int child_count; - INDEX_ENTRY **children; - struct ntfs_dt **sub_nodes; - ntfs_inode **inodes; - VCN vcn; - INDEX_HEADER *header; - BOOL changed; -}; - -/** - * struct ntfs_dir - */ -struct ntfs_dir { - ntfs_volume *vol; - struct ntfs_dir *parent; - ntfschar *name; - int name_len; - MFT_REF mft_num; - struct ntfs_dt *index; - struct ntfs_dir **children; - int child_count; - struct ntfs_bmp *bitmap; - ntfs_inode *inode; - ntfs_attr *iroot; - ntfs_attr *ialloc; - int index_size; -}; - /** * struct ntfs_find */ @@ -102,18 +59,5 @@ struct ntfs_find { }; -#define RED "" -#define GREEN "" -#define YELLOW "" -#define BLUE "" -#define MAGENTA "" -#define CYAN "" -#define BOLD "" -#define END "" - -#define ROUND_UP(num,bound) (((num)+((bound)-1)) & ~((bound)-1)) -#define ROUND_DOWN(num,bound) ((num) & ~((bound)-1)) -#define ATTR_SIZE(s) ROUND_UP(s,8) - #endif /* _NTFSRM_H_ */ diff --git a/ntfsprogs/utils.c b/ntfsprogs/utils.c index 88981d54..fd409371 100644 --- a/ntfsprogs/utils.c +++ b/ntfsprogs/utils.c @@ -97,6 +97,7 @@ int utils_set_locale (void) } } +#ifndef NTFS_RICH /** * utils_valid_device - Perform some safety checks on the device, before we start * @name: Full pathname of the device/file to work with @@ -206,6 +207,7 @@ ntfs_volume * utils_mount_volume (const char *device, unsigned long flags, BOOL return vol; } +#endif /** * utils_parse_size - Convert a string representing a size * @value: String to be parsed @@ -327,6 +329,7 @@ int utils_parse_range (const char *string, s64 *start, s64 *finish, BOOL scale) return 1; } +#ifndef NTFS_RICH /** * find_attribute - Find an attribute of the given type * @type: An attribute type, e.g. AT_FILE_NAME @@ -396,6 +399,7 @@ ATTR_RECORD * find_first_attribute (const ATTR_TYPES type, MFT_RECORD *mft) return rec; } +#endif /** * utils_inode_get_name * diff --git a/ntfsprogs/utils.h b/ntfsprogs/utils.h index 3aaa11bf..e6490961 100644 --- a/ntfsprogs/utils.h +++ b/ntfsprogs/utils.h @@ -1,7 +1,7 @@ /* * utils.h - Part of the Linux-NTFS project. * - * Copyright (c) 2002-2003 Richard Russon + * Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2004 Anton Altaparmakov * * A set of shared functions for ntfs utilities @@ -77,9 +77,7 @@ extern DEC_PRINTF(Eprintf) extern DEC_PRINTF(Vprintf) extern DEC_PRINTF(Qprintf) -int utils_valid_device (const char *name, int force); int utils_set_locale (void); -ntfs_volume * utils_mount_volume (const char *device, unsigned long flags, BOOL force); int utils_parse_size (const char *value, s64 *size, BOOL scale); int utils_parse_range (const char *string, s64 *start, s64 *finish, BOOL scale); int utils_inode_get_name (ntfs_inode *inode, char *buffer, int bufsize); @@ -89,8 +87,15 @@ int utils_mftrec_in_use (ntfs_volume *vol, MFT_REF mref); int utils_is_metadata (ntfs_inode *inode); void utils_dump_mem (void *buf, int start, int length, int ascii); +#ifndef _RICH_H_ ATTR_RECORD * find_attribute (const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); ATTR_RECORD * find_first_attribute (const ATTR_TYPES type, MFT_RECORD *mft); +#endif + +#if !(defined (_NTFS_VOLUME_H) && defined (NTFS_RICH)) +int utils_valid_device (const char *name, int force); +ntfs_volume * utils_mount_volume (const char *device, unsigned long flags, BOOL force); +#endif /** * defines... @@ -131,4 +136,27 @@ int mft_next_record (struct mft_search_ctx *ctx); #define DM_BLUE (1 << 5) #define DM_BOLD (1 << 6) +#ifdef NTFS_RICH + +#include "layout.h" +#include "volume.h" +#include "inode.h" +#include "bitmap.h" +#include "dir.h" + +#define RED "\e[31m" +#define GREEN "\e[32m" +#define YELLOW "\e[33m" +#define BLUE "\e[34m" +#define MAGENTA "\e[35m" +#define CYAN "\e[36m" +#define BOLD "\e[01m" +#define END "\e[0m" + +#define ROUND_UP(num,bound) (((num)+((bound)-1)) & ~((bound)-1)) +#define ROUND_DOWN(num,bound) ((num) & ~((bound)-1)) +#define ATTR_SIZE(s) ROUND_UP(s,8) + +#endif /* NTFS_RICH */ + #endif /* _NTFS_UTILS_H_ */