diff --git a/ntfsprogs/ntfsrm.c b/ntfsprogs/ntfsrm.c
index 1bbb20ea..55651471 100644
--- a/ntfsprogs/ntfsrm.c
+++ b/ntfsprogs/ntfsrm.c
@@ -44,10 +44,6 @@ GEN_PRINTF (Qprintf, stdout, &opts.quiet, FALSE)
//#define RM_WRITE 1
-static int ntfs_inode_close2 (ntfs_inode *ni);
-static int ntfs_dt_root_replace (struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie);
-static int ntfs_dir_truncate (ntfs_volume *vol, struct ntfs_dir *dir);
-
/**
* version - Print version information about the program
*
@@ -286,6 +282,108 @@ static const char *ntfsinfo_time_to_str(const s64 sle_ntfs_clock)
return ctime(&unix_clock);
}
+/**
+ * ntfs_inode_dir_map
+ */
+static void ntfs_inode_dir_map (ntfs_inode *ino)
+{
+ ATTR_RECORD *rec;
+ FILE_NAME_ATTR *fn;
+ ntfs_inode *parent;
+
+ if (!ino)
+ return;
+
+ printf ("open inode %lld\n", ino->mft_no);
+
+ if (ino->mft_no == FILE_root) {
+ printf ("done\n");
+ return;
+ }
+
+ rec = find_first_attribute (AT_FILE_NAME, ino->mrec);
+ if (!rec)
+ return;
+
+ fn = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu (rec->value_offset));
+
+ parent = ntfs_inode_open (ino->vol, fn->parent_directory);
+ if (parent) {
+ ntfs_inode_dir_map (parent);
+ ntfs_inode_close (parent);
+ }
+}
+
+/**
+ * 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_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_bmp_rollback
@@ -947,6 +1045,123 @@ static int ntfs_ie_test (void)
}
+/**
+ * ntfs_dt_rollback
+ */
+static int ntfs_dt_rollback (struct ntfs_dt *dt)
+{
+ int i;
+
+ if (!dt)
+ return -1;
+
+ return 0; // TEMP
+
+ for (i = 0; i < dt->child_count; i++) {
+ if (dt->sub_nodes)
+ ntfs_dt_rollback (dt->sub_nodes[i]);
+ if (dt->inodes)
+ ntfs_inode_close2 (dt->inodes[i]);
+ }
+
+ 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;
+
+ return 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 * 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]))) {
+#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_free
+ */
+static void ntfs_dt_free (struct ntfs_dt *dt)
+{
+ int i;
+
+ if (!dt)
+ return;
+
+ ntfs_dt_rollback (dt);
+
+ for (i = 0; i < dt->child_count; i++) {
+ //if (dt->sub_nodes)
+ ntfs_dt_free (dt->sub_nodes[i]);
+ //if (dt->inodes)
+ 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_alloc_children
*/
@@ -1114,123 +1329,6 @@ static int ntfs_dt_count_alloc (struct ntfs_dt *dt)
return dt->child_count;
}
-/**
- * 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 * 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]))) {
-#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_rollback
- */
-static int ntfs_dt_rollback (struct ntfs_dt *dt)
-{
- int i;
-
- if (!dt)
- return -1;
-
- return 0; // TEMP
-
- for (i = 0; i < dt->child_count; i++) {
- if (dt->sub_nodes)
- ntfs_dt_rollback (dt->sub_nodes[i]);
- if (dt->inodes)
- ntfs_inode_close2 (dt->inodes[i]);
- }
-
- 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;
-
- return 0;
-}
-
-/**
- * ntfs_dt_free
- */
-static void ntfs_dt_free (struct ntfs_dt *dt)
-{
- int i;
-
- if (!dt)
- return;
-
- ntfs_dt_rollback (dt);
-
- for (i = 0; i < dt->child_count; i++) {
- //if (dt->sub_nodes)
- ntfs_dt_free (dt->sub_nodes[i]);
- //if (dt->inodes)
- 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_alloc
*/
@@ -1896,108 +1994,50 @@ static int ntfs_dt_transfer (struct ntfs_dt *old, struct ntfs_dt *new, int start
/**
- * ntfs_inode_dir_map
+ * utils_free_non_residents
*/
-static void ntfs_inode_dir_map (ntfs_inode *ino)
+static int utils_free_non_residents (ntfs_inode *inode)
{
- ATTR_RECORD *rec;
- FILE_NAME_ATTR *fn;
- ntfs_inode *parent;
+ // XXX need to do this in memory
- if (!ino)
- return;
+ ntfs_attr_search_ctx *ctx;
+ ntfs_attr *na;
+ ATTR_RECORD *arec;
- printf ("open inode %lld\n", ino->mft_no);
+ if (!inode)
+ return -1;
- if (ino->mft_no == FILE_root) {
- printf ("done\n");
- return;
+ ctx = ntfs_attr_get_search_ctx (NULL, inode->mrec);
+ if (!ctx) {
+ printf ("can't create a search context\n");
+ return -1;
}
- rec = find_first_attribute (AT_FILE_NAME, ino->mrec);
- if (!rec)
- return;
-
- fn = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu (rec->value_offset));
-
- parent = ntfs_inode_open (ino->vol, fn->parent_directory);
- if (parent) {
- ntfs_inode_dir_map (parent);
- ntfs_inode_close (parent);
+ while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) {
+ arec = ctx->attr;
+ if (arec->non_resident) {
+ na = ntfs_attr_open (inode, arec->type, NULL, 0);
+ if (na) {
+ runlist_element *rl;
+ LCN size;
+ LCN count;
+ 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++) {
+ //printf ("rl(%llu,%llu,%lld)\n", rl->vcn, rl->lcn, rl->length);
+ //printf ("freed %d\n", ntfs_cluster_free (inode->vol, na, rl->vcn, rl->length));
+ ntfs_cluster_free (inode->vol, na, rl->vcn, rl->length);
+ }
+ ntfs_attr_close (na);
+ }
+ }
}
+
+ ntfs_attr_put_search_ctx (ctx);
+ 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_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);
-}
-
-
/**
* utils_free_non_residents3
*/
@@ -2035,729 +2075,32 @@ static int utils_free_non_residents3 (struct ntfs_bmp *bmp, ntfs_inode *inode, A
}
/**
- * ntfs_mft_remove_attr
+ * utils_free_non_residents2
*/
-static int ntfs_mft_remove_attr (struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type)
+static int utils_free_non_residents2 (ntfs_inode *inode, struct ntfs_bmp *bmp)
{
- ATTR_RECORD *attr20, *attrXX;
- MFT_RECORD *mft;
- u8 *src, *dst;
- int len;
+ ntfs_attr_search_ctx *ctx;
if (!inode)
- return 1;
+ return -1;
+ if (!bmp)
+ return -1;
- attr20 = find_first_attribute (AT_ATTRIBUTE_LIST, inode->mrec);
- if (attr20)
- return 1;
+ ctx = ntfs_attr_get_search_ctx (NULL, inode->mrec);
+ if (!ctx) {
+ printf ("can't create a search context\n");
+ return -1;
+ }
- printf ("remove inode %lld, attr 0x%02X\n", inode->mft_no, type);
+ while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) {
+ utils_free_non_residents3 (bmp, inode, ctx->attr);
+ }
- 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 ((u8*)mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n");
-
- //utils_dump_mem ((u8*)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 ((u8*)mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n");
-
- NInoSetDirty(inode);
+ ntfs_attr_put_search_ctx (ctx);
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);
- }
-
- ntfs_dir_truncate (dir->vol, dir);
-
- 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_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_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->children);
- free (dir);
-}
-
-/**
- * ntfs_dir_alloc
- */
-static struct ntfs_dir * ntfs_dir_alloc (ntfs_volume *vol, MFT_REF mft_num)
-{
- struct ntfs_dir *dir = NULL;
- ntfs_inode *inode = NULL;
- ATTR_RECORD *rec = NULL;
- INDEX_ROOT *ir = NULL;
-
- if (!vol)
- return NULL;
-
- //printf ("ntfs_dir_alloc %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);
-
- 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_alloc (inode, AT_BITMAP, I30, 4);
-
- if (dir->ialloc) {
- 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 {
- dir->index_size = 0;
- }
-
- if (!dir->iroot) {
- ntfs_dir_free (dir);
- return NULL;
- }
-
- 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_find
- */
-static MFT_REF ntfs_dir_find (struct ntfs_dir *dir, char *name)
-{
- MFT_REF mft_num;
- ntfschar *uname = NULL;
- int len;
-
- if (!dir || !name)
- return -1;
-
- len = ntfs_mbstoucs (name, &uname, 0);
- if (len < 0)
- return -1;
-
- if (!dir->index)
- dir->index = ntfs_dt_alloc (dir, NULL, -1);
-
- //printf ("dir->index = %p\n", dir->index);
- //printf ("dir->child_count = %d\n", dir->child_count);
- //printf ("uname = %p\n", uname);
- mft_num = ntfs_dt_find (dir->index, uname, len);
-
- free (uname);
- return mft_num;
-}
-
-/**
- * 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_alloc (dir->vol, mft_num);
- if (!child)
- return NULL;
-
- child->index = ntfs_dt_alloc (child, NULL, -1);
-
- ntfs_dir_add (dir, child);
-
- return child;
-}
-
-/**
- * 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 ((u8*)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);
-
- 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;
-}
-
-
-/**
- * utils_volume_commit
- */
-static int utils_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;
-}
-
-/**
- * utils_volume_rollback
- */
-static int utils_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_umount2
- */
-static int ntfs_umount2 (ntfs_volume *vol, const BOOL force)
-{
- struct ntfs_dir *dir;
- struct ntfs_bmp *bmp;
-
- if (!vol)
- return 0;
-
- utils_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);
-}
-
-/**
- * utils_mount_volume2
- */
-static ntfs_volume * utils_mount_volume2 (const char *device, unsigned long flags, BOOL force)
-{
- // XXX can we replace these and search by mft number? Hmm... NO.
- 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_alloc (vol, FILE_root);
- if (!dir) {
- ntfs_umount2 (vol, FALSE);
- vol = NULL;
- goto done;
- }
-
- dir->index = ntfs_dt_alloc (dir, NULL, -1);
-
- root = dir->index;
-
- //$Bitmap
- num = -1;
- found = ntfs_dt_find2 (root, bmp, 7, &num);
- if ((!found) || (num < 0)) {
- printf ("can't find $Bitmap\n");
- ntfs_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, 4, &num);
- if ((!found) || (num < 0)) {
- printf ("can't find $MFT\n");
- ntfs_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, 8, &num);
- if ((!found) || (num < 0)) {
- printf ("can't find $MFTMirr\n");
- ntfs_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_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_alloc (vol->mft_ni, AT_BITMAP, NULL, 0);
- vol->private_bmp2 = ntfs_bmp_alloc (vol->lcnbmp_ni, AT_DATA, NULL, 0);
-
- if (!vol->private_bmp1 || !vol->private_bmp2) {
- printf ("can't find the bitmaps\n");
- ntfs_umount2 (vol, FALSE);
- vol = NULL;
- goto done;
- }
-
-done:
- return vol;
-}
-
-
-/**
- * utils_pathname_to_mftref
- */
-static MFT_REF utils_pathname_to_mftref (ntfs_volume *vol, struct ntfs_dir *parent, const char *pathname, struct ntfs_dir **finddir)
-{
- MFT_REF mft_num;
- MFT_REF result = -1;
- char *p, *q;
- char *ascii = NULL;
- struct ntfs_dir *dir = NULL;
-
- if (!vol || !parent || !pathname) {
- errno = EINVAL;
- return -1;
- }
-
- ascii = strdup (pathname); // Work with a r/w copy
- if (!ascii) {
- Eprintf ("Out of memory.\n");
- goto close;
- }
-
- p = ascii;
- while (p && *p && *p == PATH_SEP) // Remove leading /'s
- p++;
- while (p && *p) {
- q = strchr (p, PATH_SEP); // Find the end of the first token
- if (q != NULL) {
- *q = '\0';
- q++;
- }
-
- //printf ("looking for %s in %p\n", p, parent);
- mft_num = ntfs_dir_find (parent, p);
- if (mft_num == (u64)-1) {
- Eprintf ("Couldn't find name '%s' in pathname '%s'.\n", p, pathname);
- goto close;
- }
-
- if (q) {
- dir = ntfs_dir_alloc (vol, mft_num);
- if (!dir) {
- Eprintf ("Couldn't allocate a new directory (%lld).\n", mft_num);
- goto close;
- }
-
- ntfs_dir_add (parent, dir);
- parent = dir;
- } else {
- //printf ("file %s\n", p);
- result = mft_num;
- if (finddir)
- *finddir = dir ? dir : parent;
- break;
- }
-
- p = q;
- while (p && *p && *p == PATH_SEP)
- p++;
- }
-
-close:
- free (ascii); // from strdup
- return result;
-}
-
/**
* utils_mftrec_mark_free
*/
@@ -2915,184 +2258,65 @@ static int utils_mftrec_mark_free5 (ntfs_inode *inode, struct ntfs_bmp *bmp, MFT
return 0;
}
-/**
- * utils_free_non_residents
- */
-static int utils_free_non_residents (ntfs_inode *inode)
-{
- // XXX need to do this in memory
-
- ntfs_attr_search_ctx *ctx;
- ntfs_attr *na;
- ATTR_RECORD *arec;
-
- if (!inode)
- 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) {
- arec = ctx->attr;
- if (arec->non_resident) {
- na = ntfs_attr_open (inode, arec->type, NULL, 0);
- if (na) {
- runlist_element *rl;
- LCN size;
- LCN count;
- 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++) {
- //printf ("rl(%llu,%llu,%lld)\n", rl->vcn, rl->lcn, rl->length);
- //printf ("freed %d\n", ntfs_cluster_free (inode->vol, na, rl->vcn, rl->length));
- ntfs_cluster_free (inode->vol, na, rl->vcn, rl->length);
- }
- ntfs_attr_close (na);
- }
- }
- }
-
- ntfs_attr_put_search_ctx (ctx);
- return 0;
-}
/**
- * utils_free_non_residents2
+ * ntfs_mft_remove_attr
*/
-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 (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;
-}
-
-/**
- * utils_pathname_to_inode2
- */
-static BOOL utils_pathname_to_inode2 (ntfs_volume *vol, struct ntfs_dir *parent, const char *pathname, struct ntfs_find *found)
+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;
- char *p, *q;
- ntfschar *unicode = NULL;
- char *ascii = NULL;
- struct ntfs_dir *dir = NULL;
- struct ntfs_dir *child = NULL;
- struct ntfs_dt *dt = NULL;
- int dt_num;
- BOOL result = FALSE;
- if (!vol || !pathname || !found) {
- errno = EINVAL;
- return FALSE;
- }
+ if (!inode)
+ return 1;
- memset (found, 0, sizeof (*found));
+ attr20 = find_first_attribute (AT_ATTRIBUTE_LIST, inode->mrec);
+ if (attr20)
+ return 1;
- if (parent) {
- dir = parent;
- } else {
- dir = (struct ntfs_dir *) vol->private_data;
- if (!dir) {
- Eprintf ("Couldn't open the inode of the root directory.\n");
- goto close;
- }
- }
+ printf ("remove inode %lld, attr 0x%02X\n", inode->mft_no, type);
- unicode = malloc (MAX_PATH * sizeof (ntfschar));
- ascii = strdup (pathname); // Work with a r/w copy
- if (!unicode || !ascii) {
- Eprintf ("Out of memory.\n");
- goto close;
- }
+ attrXX = find_first_attribute (type, inode->mrec);
+ if (!attrXX)
+ return 1;
- p = ascii;
- while (p && *p && *p == PATH_SEP) // Remove leading /'s
- p++;
- while (p && *p) {
- q = strchr (p, PATH_SEP); // Find the end of the first token
- if (q != NULL) {
- *q = '\0';
- q++;
- }
+ if (utils_free_non_residents3 (bmp, inode, attrXX))
+ return 1;
- len = ntfs_mbstoucs (p, &unicode, MAX_PATH);
- if (len < 0) {
- Eprintf ("Couldn't convert name to Unicode: %s.\n", p);
- goto close;
- }
+ // remove entry
+ // inode->mrec
- //printf ("looking for %s\n", p);
- if (q) {
- child = ntfs_dir_find2 (dir, unicode, len);
- if (!child) {
- printf ("can't find %s in %s\n", p, pathname);
- goto close;
- }
- } else {
- //printf ("file: %s\n", p);
+ mft = inode->mrec;
+ //utils_dump_mem ((u8*)mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n");
- dt = ntfs_dt_find2 (dir->index, unicode, len, &dt_num);
- if (!dt) {
- printf ("can't find %s in %s (2)\n", p, pathname);
- goto close;
- }
+ //utils_dump_mem ((u8*)attrXX, 0, attrXX->length, DM_DEFAULTS); printf ("\n");
- if (dt->inodes[dt_num] == NULL) {
- dt->inodes[dt_num] = ntfs_inode_open (dir->vol, dt->children[dt_num]->indexed_file);
- if (!dt->inodes[dt_num]) {
- printf ("Can't open inode %lld\n", MREF (dt->children[dt_num]->indexed_file));
- goto close;
- }
- dt->inodes[dt_num]->ref_count = 2;
- dt->inodes[dt_num]->private_data = dt;
- }
+ //printf ("mrec = %p, attr = %p, diff = %d (0x%02X)\n", mft, attrXX, (u8*)attrXX - (u8*)mft, (u8*)attrXX - (u8*)mft);
+ // memmove
- //printf ("dt = %p,%d\n", dt, dt_num);
+ dst = (u8*) attrXX;
+ src = dst + attrXX->length;
+ len = (((u8*) mft + mft->bytes_in_use) - src);
- break;
- }
+ // fix mft header
+ mft->bytes_in_use -= attrXX->length;
- dir = child;
- child = NULL;
- p = q;
- while (p && *p && *p == PATH_SEP)
- p++;
- }
+#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
- found->dir = dir;
- found->dt = dt;
- found->dt_index = dt_num;
- found->inode = dt->inodes[dt_num];
- found->mref = found->inode->mft_no;
- result = TRUE;
- //printf ("dir %p, dt %p, num %d, ino %p, %lld\n", dir, dt, dt_num, dt->inodes[dt_num], MREF (found->inode->mft_no));
-close:
- free (ascii); // from strdup
- free (unicode);
- return result;
+ memmove (dst, src, len);
+ //utils_dump_mem ((u8*)mft, 0, mft->bytes_in_use, DM_DEFAULTS); printf ("\n");
+
+ NInoSetDirty(inode);
+ return 0;
}
-
/**
* ntfs_mft_resize_resident
*/
@@ -4481,6 +3705,777 @@ done:
}
+/**
+ * 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 ((u8*)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);
+
+ 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);
+ }
+
+ ntfs_dir_truncate (dir->vol, dir);
+
+ 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->children);
+ free (dir);
+}
+
+/**
+ * ntfs_dir_alloc
+ */
+static struct ntfs_dir * ntfs_dir_alloc (ntfs_volume *vol, MFT_REF mft_num)
+{
+ struct ntfs_dir *dir = NULL;
+ ntfs_inode *inode = NULL;
+ ATTR_RECORD *rec = NULL;
+ INDEX_ROOT *ir = NULL;
+
+ if (!vol)
+ return NULL;
+
+ //printf ("ntfs_dir_alloc %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);
+
+ 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_alloc (inode, AT_BITMAP, I30, 4);
+
+ if (dir->ialloc) {
+ 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 {
+ dir->index_size = 0;
+ }
+
+ if (!dir->iroot) {
+ ntfs_dir_free (dir);
+ return NULL;
+ }
+
+ 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_find
+ */
+static MFT_REF ntfs_dir_find (struct ntfs_dir *dir, char *name)
+{
+ MFT_REF mft_num;
+ ntfschar *uname = NULL;
+ int len;
+
+ if (!dir || !name)
+ return -1;
+
+ len = ntfs_mbstoucs (name, &uname, 0);
+ if (len < 0)
+ return -1;
+
+ if (!dir->index)
+ dir->index = ntfs_dt_alloc (dir, NULL, -1);
+
+ //printf ("dir->index = %p\n", dir->index);
+ //printf ("dir->child_count = %d\n", dir->child_count);
+ //printf ("uname = %p\n", uname);
+ mft_num = ntfs_dt_find (dir->index, uname, len);
+
+ free (uname);
+ return mft_num;
+}
+
+/**
+ * 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_alloc (dir->vol, mft_num);
+ if (!child)
+ return NULL;
+
+ child->index = ntfs_dt_alloc (child, NULL, -1);
+
+ ntfs_dir_add (dir, child);
+
+ return child;
+}
+
+
+/**
+ * utils_volume_commit
+ */
+static int utils_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;
+}
+
+/**
+ * utils_volume_rollback
+ */
+static int utils_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;
+}
+
+/**
+ * utils_pathname_to_mftref
+ */
+static MFT_REF utils_pathname_to_mftref (ntfs_volume *vol, struct ntfs_dir *parent, const char *pathname, struct ntfs_dir **finddir)
+{
+ MFT_REF mft_num;
+ MFT_REF result = -1;
+ char *p, *q;
+ char *ascii = NULL;
+ struct ntfs_dir *dir = NULL;
+
+ if (!vol || !parent || !pathname) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ascii = strdup (pathname); // Work with a r/w copy
+ if (!ascii) {
+ Eprintf ("Out of memory.\n");
+ goto close;
+ }
+
+ p = ascii;
+ while (p && *p && *p == PATH_SEP) // Remove leading /'s
+ p++;
+ while (p && *p) {
+ q = strchr (p, PATH_SEP); // Find the end of the first token
+ if (q != NULL) {
+ *q = '\0';
+ q++;
+ }
+
+ //printf ("looking for %s in %p\n", p, parent);
+ mft_num = ntfs_dir_find (parent, p);
+ if (mft_num == (u64)-1) {
+ Eprintf ("Couldn't find name '%s' in pathname '%s'.\n", p, pathname);
+ goto close;
+ }
+
+ if (q) {
+ dir = ntfs_dir_alloc (vol, mft_num);
+ if (!dir) {
+ Eprintf ("Couldn't allocate a new directory (%lld).\n", mft_num);
+ goto close;
+ }
+
+ ntfs_dir_add (parent, dir);
+ parent = dir;
+ } else {
+ //printf ("file %s\n", p);
+ result = mft_num;
+ if (finddir)
+ *finddir = dir ? dir : parent;
+ break;
+ }
+
+ p = q;
+ while (p && *p && *p == PATH_SEP)
+ p++;
+ }
+
+close:
+ free (ascii); // from strdup
+ return result;
+}
+
+/**
+ * ntfs_umount2
+ */
+static int ntfs_umount2 (ntfs_volume *vol, const BOOL force)
+{
+ struct ntfs_dir *dir;
+ struct ntfs_bmp *bmp;
+
+ if (!vol)
+ return 0;
+
+ utils_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);
+}
+
+/**
+ * utils_mount_volume2
+ */
+static ntfs_volume * utils_mount_volume2 (const char *device, unsigned long flags, BOOL force)
+{
+ // XXX can we replace these and search by mft number? Hmm... NO.
+ 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_alloc (vol, FILE_root);
+ if (!dir) {
+ ntfs_umount2 (vol, FALSE);
+ vol = NULL;
+ goto done;
+ }
+
+ dir->index = ntfs_dt_alloc (dir, NULL, -1);
+
+ root = dir->index;
+
+ //$Bitmap
+ num = -1;
+ found = ntfs_dt_find2 (root, bmp, 7, &num);
+ if ((!found) || (num < 0)) {
+ printf ("can't find $Bitmap\n");
+ ntfs_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, 4, &num);
+ if ((!found) || (num < 0)) {
+ printf ("can't find $MFT\n");
+ ntfs_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, 8, &num);
+ if ((!found) || (num < 0)) {
+ printf ("can't find $MFTMirr\n");
+ ntfs_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_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_alloc (vol->mft_ni, AT_BITMAP, NULL, 0);
+ vol->private_bmp2 = ntfs_bmp_alloc (vol->lcnbmp_ni, AT_DATA, NULL, 0);
+
+ if (!vol->private_bmp1 || !vol->private_bmp2) {
+ printf ("can't find the bitmaps\n");
+ ntfs_umount2 (vol, FALSE);
+ vol = NULL;
+ goto done;
+ }
+
+done:
+ return vol;
+}
+
+/**
+ * utils_pathname_to_inode2
+ */
+static BOOL utils_pathname_to_inode2 (ntfs_volume *vol, struct ntfs_dir *parent, const char *pathname, struct ntfs_find *found)
+{
+ int len;
+ char *p, *q;
+ ntfschar *unicode = NULL;
+ char *ascii = NULL;
+ struct ntfs_dir *dir = NULL;
+ struct ntfs_dir *child = NULL;
+ struct ntfs_dt *dt = NULL;
+ int dt_num;
+ BOOL result = FALSE;
+
+ if (!vol || !pathname || !found) {
+ errno = EINVAL;
+ return FALSE;
+ }
+
+ memset (found, 0, sizeof (*found));
+
+ if (parent) {
+ dir = parent;
+ } else {
+ dir = (struct ntfs_dir *) vol->private_data;
+ if (!dir) {
+ Eprintf ("Couldn't open the inode of the root directory.\n");
+ goto close;
+ }
+ }
+
+ unicode = malloc (MAX_PATH * sizeof (ntfschar));
+ ascii = strdup (pathname); // Work with a r/w copy
+ if (!unicode || !ascii) {
+ Eprintf ("Out of memory.\n");
+ goto close;
+ }
+
+ p = ascii;
+ while (p && *p && *p == PATH_SEP) // Remove leading /'s
+ p++;
+ while (p && *p) {
+ q = strchr (p, PATH_SEP); // Find the end of the first token
+ if (q != NULL) {
+ *q = '\0';
+ q++;
+ }
+
+ len = ntfs_mbstoucs (p, &unicode, MAX_PATH);
+ if (len < 0) {
+ Eprintf ("Couldn't convert name to Unicode: %s.\n", p);
+ goto close;
+ }
+
+ //printf ("looking for %s\n", p);
+ if (q) {
+ child = ntfs_dir_find2 (dir, unicode, len);
+ if (!child) {
+ printf ("can't find %s in %s\n", p, pathname);
+ goto close;
+ }
+ } else {
+ //printf ("file: %s\n", p);
+
+ dt = ntfs_dt_find2 (dir->index, unicode, len, &dt_num);
+ if (!dt) {
+ printf ("can't find %s in %s (2)\n", p, pathname);
+ goto close;
+ }
+
+ if (dt->inodes[dt_num] == NULL) {
+ dt->inodes[dt_num] = ntfs_inode_open (dir->vol, dt->children[dt_num]->indexed_file);
+ if (!dt->inodes[dt_num]) {
+ printf ("Can't open inode %lld\n", MREF (dt->children[dt_num]->indexed_file));
+ goto close;
+ }
+ dt->inodes[dt_num]->ref_count = 2;
+ dt->inodes[dt_num]->private_data = dt;
+ }
+
+ //printf ("dt = %p,%d\n", dt, dt_num);
+
+ break;
+ }
+
+ dir = child;
+ child = NULL;
+ p = q;
+ while (p && *p && *p == PATH_SEP)
+ p++;
+ }
+
+ found->dir = dir;
+ found->dt = dt;
+ found->dt_index = dt_num;
+ found->inode = dt->inodes[dt_num];
+ found->mref = found->inode->mft_no;
+ result = TRUE;
+ //printf ("dir %p, dt %p, num %d, ino %p, %lld\n", dir, dt, dt_num, dt->inodes[dt_num], MREF (found->inode->mft_no));
+close:
+ free (ascii); // from strdup
+ free (unicode);
+ return result;
+}
+
+
/**
* ntfsrm
*/
@@ -5174,3 +5169,4 @@ done:
return result;
}
+