Changes by: flatcap
Update of /cvsroot/linux-ntfs/ntfsprogs/libntfs
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21510/libntfs
Modified Files:
Makefile.am bitmap.c dir.c index.c inode.c mft.c volume.c
Added Files:
rich.c tree.c
Log Message:
ntfsrm has been split up and merged into libntfs.
currently it's #ifdef'd out.
tree.c - code for handling directory trees
rich.c - a few helpers without a home (this file will go away soon)
Note: ntfsrm isn't in the build any more (you need to ./configure --enable-rich; make extras). When rm is less intrusive, again, I'll put it back in the build.
--- NEW FILE ---
/**
* 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 <stdlib.h>
#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 */
--- NEW FILE ---
/**
* 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
[...2080 lines suppressed...]
// 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 */
Index: Makefile.am
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/Makefile.am,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -p -r1.33 -r1.34
--- Makefile.am 16 Oct 2005 21:57:00 -0000 1.33
+++ Makefile.am 16 Oct 2005 23:33:04 -0000 1.34
@@ -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
Index: bitmap.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/bitmap.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -p -r1.13 -r1.14
--- bitmap.c 28 Sep 2005 13:47:48 -0000 1.13
+++ bitmap.c 16 Oct 2005 23:33:04 -0000 1.14
@@ -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,
{
return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0);
}
+
+
+#ifdef NTFS_RICH
+
+#include <stdlib.h>
+
+#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<<cb);
+ if (ntfs_attr_pread (bmp->attr, vcn<<cb, cs, buffer) < 0) {
+ free (buffer);
+ return NULL;
+ }
+
+ ntfs_bmp_add_data (bmp, vcn, buffer); // XXX retval
+ return buffer;
+}
+
+/**
+ * ntfs_bmp_set_range
+ */
+int ntfs_bmp_set_range (struct ntfs_bmp *bmp, VCN vcn, s64 length, int value)
+{
+ // shouldn't all the vcns be lcns?
+ s64 i;
+ u8 *buffer;
+ int csib; // cluster size in bits
+
+ int block_start, block_finish; // rename to c[sf] (rename to clust_)
+ int vcn_start, vcn_finish; // rename to v[sf]
+ int byte_start, byte_finish; // rename to b[sf]
+ u8 mask_start, mask_finish; // rename to m[sf]
+
+ s64 a,b;
+
+ if (!bmp)
+ return -1;
+
+ if (value)
+ value = 0xFF;
+
+ csib = bmp->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<<bit), buffer[byte] & (1<<bit));
+ if (buffer[byte] & (1<<bit)) {
+ // if set, keep note
+ note = bit;
+ break;
+ }
+ }
+ if (note >= 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 */
+
Index: dir.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/dir.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -p -r1.28 -r1.29
--- dir.c 16 Oct 2005 19:21:47 -0000 1.28
+++ dir.c 16 Oct 2005 23:33:04 -0000 1.29
@@ -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 <stdlib.h>
+
+#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
+
+ // <dir>/$BITMAP($I30)
+ // <dir>/$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 */
+
Index: index.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/index.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -p -r1.14 -r1.15
--- index.c 16 Oct 2005 00:07:14 -0000 1.14
+++ index.c 16 Oct 2005 23:33:04 -0000 1.15
@@ -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 <stdlib.h>
+#include <string.h>
+
+#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 */
+
Index: inode.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/inode.c,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -p -r1.68 -r1.69
--- inode.c 16 Oct 2005 19:21:47 -0000 1.68
+++ inode.c 16 Oct 2005 23:33:04 -0000 1.69
@@ -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 */
+
Index: mft.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/mft.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -p -r1.34 -r1.35
--- mft.c 28 Sep 2005 13:47:48 -0000 1.34
+++ mft.c 16 Oct 2005 23:33:04 -0000 1.35
@@ -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 */
+
Index: volume.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/volume.c,v
retrieving revision 1.58
retrieving revision 1.59
diff -u -p -r1.58 -r1.59
--- volume.c 15 Oct 2005 23:13:50 -0000 1.58
+++ volume.c 16 Oct 2005 23:33:04 -0000 1.59
@@ -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 */
+
|