Changes by: cha0smaster
Update of /cvsroot/linux-ntfs/ntfsprogs/libntfs
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29034/libntfs
Modified Files:
attrib.c bootsect.c dir.c index.c inode.c mft.c
Log Message:
Sorry it's very large commit (46K of diffs between my local tree and CVS HEAD
before commit), file and directory creation/deletion recursively requested many
changes. See ChangeLog for description of all changes.
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/attrib.c,v
retrieving revision 1.172
retrieving revision 1.173
diff -u -p -r1.172 -r1.173
--- attrib.c 4 Aug 2005 00:00:29 -0000 1.172
+++ attrib.c 14 Aug 2005 15:44:47 -0000 1.173
@@ -2573,7 +2573,10 @@ int ntfs_resident_attr_record_add(ntfs_i
a->instance = m->next_attr_instance;
a->value_length = 0;
a->value_offset = cpu_to_le16(length);
- a->resident_flags = 0;
+ if (type == AT_FILE_NAME)
+ a->resident_flags = RESIDENT_ATTR_IS_INDEXED;
+ else
+ a->resident_flags = 0;
if (name_len)
memcpy((u8*)a + le16_to_cpu(a->name_offset),
name, sizeof(ntfschar) * name_len);
Index: bootsect.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/bootsect.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -p -r1.15 -r1.16
--- bootsect.c 21 Jun 2005 09:55:15 -0000 1.15
+++ bootsect.c 14 Aug 2005 15:44:47 -0000 1.16
@@ -2,6 +2,7 @@
* bootsect.c - Boot sector handling code. Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2005 Anton Altaparmakov
+ * Copyright (c) 2005 Yura Pakhuchiy
*
* 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
@@ -225,7 +226,7 @@ int ntfs_boot_sector_parse(ntfs_volume *
if (c < 0)
vol->mft_record_size = 1 << -c;
else
- vol->mft_record_size = vol->cluster_size * c;
+ vol->mft_record_size = c << vol->cluster_size_bits;
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
Dprintf("Error: %s is not a valid NTFS partition! "
"mft_record_size is not a power of 2.\n",
@@ -235,6 +236,16 @@ int ntfs_boot_sector_parse(ntfs_volume *
vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
Dprintf("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size);
Dprintf("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
+ /* Same as above for INDX record. */
+ c = bs->clusters_per_index_record;
+ Dprintf("ClustersPerINDXRecord = 0x%x\n", c);
+ if (c < 0)
+ vol->indx_record_size = 1 << -c;
+ else
+ vol->indx_record_size = c << vol->cluster_size_bits;
+ vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
+ Dprintf("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
+ Dprintf("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
/*
* Work out the size of the MFT mirror in number of mft records. If the
* cluster size is less than or equal to the size taken by four mft
Index: dir.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/dir.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -p -r1.19 -r1.20
--- dir.c 25 Jul 2005 22:05:27 -0000 1.19
+++ dir.c 14 Aug 2005 15:44:47 -0000 1.20
@@ -2,6 +2,7 @@
* dir.c - Directory handling code. Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2005 Anton Altaparmakov
+ * Copyright (c) 2005 Yura Pakhuchiy
*
* 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
@@ -37,6 +38,10 @@
#include "inode.h"
#include "dir.h"
#include "volume.h"
+#include "mft.h"
+#include "index.h"
+#include "ntfstime.h"
+#include "lcnalloc.h"
/*
* The little endian Unicode string "$I30" as a global constant.
@@ -1054,3 +1059,356 @@ err_out:
return -1;
}
+/**
+ * ntfs_create - create file or directory on ntfs volume
+ * @dir_ni: ntfs inode for directory in which create new object
+ * @name: unicode name of new object
+ * @name_len: length of the name in unicode characters
+ * @type: type of the object to create
+ *
+ * @type can be either NTFS_DT_REG to create regular file or NTFS_DT_DIR to
+ * create directory, other valuer are invalid.
+ *
+ * Return opened ntfs inode that describes created file on success or NULL
+ * on error with errno set to the error code.
+ */
+ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
+ const unsigned type)
+{
+ ntfs_inode *ni;
+ ntfs_attr *na;
+ FILE_NAME_ATTR *fn = NULL;
+ STANDARD_INFORMATION *si = NULL;
+ int err, fn_len, si_len;
+
+ ntfs_debug("Entering.");
+ /* Sanity checks. */
+ if (!dir_ni || !name || !name_len ||
+ (type != NTFS_DT_REG && type != NTFS_DT_DIR)) {
+ ntfs_error(, "Invalid arguments.");
+ return NULL;
+ }
+ /* Allocate MFT record for new file. */
+ ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
+ if (!ni) {
+ ntfs_error(, "Failed to allocate new MFT record.");
+ return NULL;
+ }
+ /*
+ * Create STANDARD_INFORMATION attribute. Write STANDARD_INFORMATION
+ * version 1.2, windows will upgrade it to version 3 if needed.
+ */
+ si_len = offsetof(STANDARD_INFORMATION, v1_end);
+ si = calloc(1, si_len);
+ if (!si) {
+ err = errno;
+ ntfs_error(, "Not enough memory.");
+ goto err_out;
+ }
+ si->creation_time = utc2ntfs(ni->creation_time);
+ si->last_data_change_time = utc2ntfs(ni->last_data_change_time);
+ si->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
+ si->last_access_time = utc2ntfs(ni->last_access_time);
+ /* Add STANDARD_INFORMATION to inode. */
+ na = ntfs_attr_add(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, si_len);
+ if (!na) {
+ err = errno;
+ ntfs_error(, "Failed to add STANDARD_INFORMATION attribute.");
+ goto err_out;
+ }
+ if (ntfs_attr_pwrite(na, 0, si_len, si) != si_len) {
+ err = errno;
+ ntfs_error(, "Failed to initialize STANDARD_INFORMATION "
+ "attribute.");
+ goto err_out;
+ }
+ ntfs_attr_close(na);
+ if (type == NTFS_DT_DIR) {
+ INDEX_ROOT *ir = NULL;
+ INDEX_ENTRY *ie;
+ int ir_len, index_len;
+
+ /* Create INDEX_ROOT attribute. */
+ index_len = sizeof(INDEX_HEADER) + sizeof(INDEX_ENTRY_HEADER);
+ ir_len = offsetof(INDEX_ROOT, index) + index_len;
+ ir = calloc(1, ir_len);
+ if (!ir) {
+ err = errno;
+ ntfs_error(, "Not enough memory.");
+ goto err_out;
+ }
+ ir->type = AT_FILE_NAME;
+ ir->collation_rule = COLLATION_FILE_NAME;
+ ir->index_block_size = cpu_to_le32(ni->vol->indx_record_size);
+ if (ni->vol->cluster_size <= ni->vol->indx_record_size)
+ ir->clusters_per_index_block =
+ ni->vol->indx_record_size >>
+ ni->vol->cluster_size_bits;
+ else
+ ir->clusters_per_index_block =
+ -ni->vol->indx_record_size_bits;
+ ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER));
+ ir->index.index_length = cpu_to_le32(index_len);
+ ir->index.allocated_size = cpu_to_le32(index_len);
+ ie = (INDEX_ENTRY*)((u8*)ir + sizeof(INDEX_ROOT));
+ ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER));
+ ie->key_length = 0;
+ ie->flags = INDEX_ENTRY_END;
+ /* Add INDEX_ROOT attribute to inode. */
+ na = ntfs_attr_add(ni, AT_INDEX_ROOT, I30, 4, ir_len);
+ if (!na) {
+ err = errno;
+ free(ir);
+ ntfs_error(, "Failed to add INDEX_ROOT attribute.");
+ goto err_out;
+ }
+ if (ntfs_attr_pwrite(na, 0, ir_len, ir) != ir_len) {
+ err = errno;
+ free(ir);
+ ntfs_error(, "Failed to initialize INDEX_ROOT.");
+ goto err_out;
+ }
+ ntfs_attr_close(na);
+ } else {
+ /* Add DATA attribute to inode. */
+ na = ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, 0);
+ if (!na) {
+ err = errno;
+ ntfs_error(, "Failed to add DATA attribute.");
+ goto err_out;
+ }
+ ntfs_attr_close(na);
+ }
+ /* Create FILE_NAME attribute. */
+ fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
+ fn = calloc(1, fn_len);
+ if (!fn) {
+ err = errno;
+ ntfs_error(, "Not enough memory.");
+ goto err_out;
+ }
+ fn->parent_directory = MK_LE_MREF(dir_ni->mft_no,
+ le16_to_cpu(dir_ni->mrec->sequence_number));
+ fn->file_name_length = name_len;
+ fn->file_name_type = FILE_NAME_POSIX;
+ if (type == NTFS_DT_DIR)
+ fn->file_attributes = FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT;
+ fn->creation_time = utc2ntfs(ni->creation_time);
+ fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
+ fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
+ fn->last_access_time = utc2ntfs(ni->last_access_time);
+ memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
+ /* Add FILE_NAME attribute to inode. */
+ na = ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, fn_len);
+ if (!na) {
+ err = errno;
+ ntfs_error(, "Failed to add FILE_NAME attribute.");
+ goto err_out;
+ }
+ if (ntfs_attr_pwrite(na, 0, fn_len, fn) != fn_len) {
+ err = errno;
+ ntfs_error(, "Failed to initialize FILE_NAME attribute.");
+ goto err_out;
+ }
+ ntfs_attr_close(na);
+ /* Add FILE_NAME attribute to index. */
+ if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,
+ le16_to_cpu(ni->mrec->sequence_number)))) {
+ err = errno;
+ ntfs_error(, "Failed to add entry to the index.");
+ goto err_out;
+ }
+ /* Set hard links count and directory flag. */
+ ni->mrec->link_count = cpu_to_le16(1);
+ if (type == NTFS_DT_DIR)
+ ni->mrec->flags |= MFT_RECORD_IS_DIRECTORY;
+ ntfs_inode_mark_dirty(ni);
+ /* Done! */
+ free(fn);
+ free(si);
+ ntfs_debug("Done.");
+ return ni;
+err_out:
+ ntfs_debug("Failed.");
+ if (ntfs_mft_record_free(ni->vol, ni))
+ ntfs_error(, "Failed to free MFT record. "
+ "Leaving inconsist metadata. Run chkdsk.");
+ if (fn)
+ free(fn);
+ if (si)
+ free(si);
+ errno = err;
+ return NULL;
+}
+
+/**
+ * ntfs_delete - delete file or directory from ntfs volume
+ * @ni: ntfs inode for object to delte
+ * @dir_ni: ntfs inode for directory in which delete object
+ * @name: unicode name of the object to delete
+ * @name_len: length of the name in unicode characters
+ *
+ * @ni is always closed after using of this function (even if it failed),
+ * user do not need to call ntfs_inode_close himself.
+ *
+ * Return 0 on success or -1 on error with errno set to the error code.
+ */
+int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
+{
+ ntfs_attr_search_ctx *actx = NULL;
+ ntfs_index_context *ictx = NULL;
+ FILE_NAME_ATTR *fn = NULL;
+ BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
+ int err = 0;
+
+ ntfs_debug("Entering.");
+ if (!ni || !dir_ni || !name || !name_len) {
+ ntfs_error(, "Invalid arguments.");
+ errno = EINVAL;
+ goto err_out;
+ }
+ if (ni->nr_extents == -1)
+ ni = ni->base_ni;
+ if (dir_ni->nr_extents == -1)
+ dir_ni = dir_ni->base_ni;
+ /*
+ * Search for FILE_NAME attribute with such name. If it's in POSIX or
+ * WIN32_AND_DOS namespace, then simply remove it from index and inode.
+ * If filename in DOS or in WIN32 namespace, then remove DOS name first,
+ * only then remove WIN32 name. Mark WIN32 name as POSIX name to prevent
+ * chkdsk to complain about DOS name absentation, in case if DOS name
+ * had been successfully deleted, but WIN32 name removing failed.
+ */
+ actx = ntfs_attr_get_search_ctx(ni, NULL);
+ if (!actx)
+ goto err_out;
+search:
+ while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
+ 0, NULL, 0, actx)) {
+ errno = 0;
+ fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
+ le16_to_cpu(actx->attr->value_offset));
+ if (looking_for_dos_name && fn->file_name_type == FILE_NAME_DOS)
+ break;
+ if (looking_for_win32_name &&
+ fn->file_name_type == FILE_NAME_WIN32)
+ break;
+ if (dir_ni->mft_no == MREF_LE(fn->parent_directory) &&
+ ntfs_names_are_equal(fn->file_name,
+ fn->file_name_length, name,
+ name_len, (fn->file_name_type ==
+ FILE_NAME_POSIX) ? CASE_SENSITIVE : IGNORE_CASE,
+ ni->vol->upcase, ni->vol->upcase_len)) {
+ if (fn->file_name_type == FILE_NAME_WIN32) {
+ looking_for_dos_name = TRUE;
+ ntfs_attr_reinit_search_ctx(actx);
+ continue;
+ }
+ if (fn->file_name_type == FILE_NAME_DOS)
+ looking_for_dos_name = TRUE;
+ break;
+ }
+ }
+ if (errno)
+ goto err_out;
+ /* Search for such FILE_NAME in index. */
+ ictx = ntfs_index_ctx_get(dir_ni, I30, 4);
+ if (!ictx)
+ goto err_out;
+ if (ntfs_index_lookup(fn, le32_to_cpu(actx->attr->value_length), ictx))
+ goto err_out;
+ /* Set namespace to POSIX for WIN32 name. */
+ if (fn->file_name_type == FILE_NAME_WIN32) {
+ fn->file_name_type = FILE_NAME_POSIX;
+ ntfs_inode_mark_dirty(actx->ntfs_ino);
+ ((FILE_NAME_ATTR*)ictx->data)->file_name_type = FILE_NAME_POSIX;
+ ntfs_index_entry_mark_dirty(ictx);
+ }
+ /* Do not support reparse oint deletion yet. */
+ if (((FILE_NAME_ATTR*)ictx->data)->file_attributes &
+ FILE_ATTR_REPARSE_POINT) {
+ errno = EOPNOTSUPP;
+ goto err_out;
+ }
+ /* Remove FILE_NAME from index. */
+ if (ntfs_index_rm(ictx))
+ goto err_out;
+ ictx = NULL;
+ /* Remove FILE_NAME from inode. */
+ if (ntfs_attr_record_rm(actx))
+ goto err_out;
+ /* Decerement hard link count. */
+ ni->mrec->link_count = cpu_to_le16(le16_to_cpu(
+ ni->mrec->link_count) - 1);
+ ntfs_inode_mark_dirty(ni);
+ if (looking_for_dos_name) {
+ looking_for_dos_name = FALSE;
+ looking_for_win32_name = TRUE;
+ ntfs_attr_reinit_search_ctx(actx);
+ goto search;
+ }
+ /*
+ * If hard link count is not equal to zero then we are done. In other
+ * case there are no reference to this inode left, so we should free all
+ * non-resident atributes and mark inode as not in use.
+ */
+ if (ni->mrec->link_count)
+ goto out;
+ ntfs_attr_reinit_search_ctx(actx);
+ while (!ntfs_attrs_walk(actx)) {
+ if (actx->attr->non_resident) {
+ runlist *rl;
+
+ rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr,
+ NULL);
+ if (!rl) {
+ err = errno;
+ ntfs_error(, "Failed to decompress runlist. "
+ "Leaving inconsist metadata.");
+ continue;
+ }
+ if (ntfs_cluster_free_from_rl(ni->vol, rl)) {
+ err = errno;
+ ntfs_error(, "Failed to free clusters. "
+ "Leaving inconsist metadata.");
+ continue;
+ }
+ free(rl);
+ }
+ }
+ if (errno != ENOENT) {
+ err = errno;
+ ntfs_error(, "Atribute enumeration failed. "
+ "Probably leaving inconsist metadata.");
+ }
+ /* All extents should be attached after attribute walk. */
+ while (ni->nr_extents)
+ if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) {
+ err = errno;
+ ntfs_error(, "Failed to free extent MFT record. "
+ "Leaving inconsist metadata.");
+ }
+ if (ntfs_mft_record_free(ni->vol, ni)) {
+ err = errno;
+ ntfs_error(, "Failed to free base MFT record. "
+ "Leaving inconsist metadata.");
+ }
+ ni = NULL;
+out:
+ if (actx)
+ ntfs_attr_put_search_ctx(actx);
+ if (ictx)
+ ntfs_index_ctx_put(ictx);
+ if (ni)
+ ntfs_inode_close(ni);
+ if (err) {
+ ntfs_error(, "Failed.");
+ errno = err;
+ return -1;
+ }
+ ntfs_debug("Done.");
+ return 0;
+err_out:
+ err = errno;
+ goto out;
+}
Index: index.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/index.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -p -r1.8 -r1.9
--- index.c 23 Jul 2005 00:50:34 -0000 1.8
+++ index.c 14 Aug 2005 15:44:47 -0000 1.9
@@ -27,6 +27,7 @@
#include "debug.h"
#include "index.h"
#include "mst.h"
+#include "dir.h"
/**
* ntfs_index_ctx_get - allocate and initialize a new index context
@@ -91,6 +92,42 @@ void ntfs_index_ctx_put(ntfs_index_conte
}
/**
+ * ntfs_index_ctx_reinit - reinitialize an index context
+ * @ictx: index context to reinitialize
+ *
+ * Reintialize the index context @ictx so it can be used for ntfs_index_lookup.
+ */
+void ntfs_index_ctx_reinit(ntfs_index_context *ictx)
+{
+ if (ictx->entry) {
+ if (ictx->is_in_root) {
+ if (ictx->actx)
+ ntfs_attr_put_search_ctx(ictx->actx);
+ } else {
+ /* Write out index block it it's dirty. */
+ if (ictx->ia_dirty) {
+ if (ntfs_attr_mst_pwrite(ictx->ia_na,
+ ictx->ia_vcn <<
+ ictx->ni->vol->
+ cluster_size_bits,
+ 1, ictx->block_size,
+ ictx->ia) != 1)
+ ntfs_error(, "Failed to write out "
+ "index block.");
+ }
+ /* Free resources. */
+ free(ictx->ia);
+ ntfs_attr_close(ictx->ia_na);
+ }
+ }
+ *ictx = (ntfs_index_context) {
+ .ni = ictx->ni,
+ .name = ictx->name,
+ .name_len = ictx->name_len,
+ };
+}
+
+/**
* ntfs_index_lookup - find a key in an index and return its index entry
* @key: [IN] key for which to search in the index
* @key_len: [IN] length of @key in bytes
@@ -397,3 +434,195 @@ idx_err_out:
goto err_out;
}
+/**
+ * ntfs_index_add_filename - add filename to directory index
+ * @ni: ntfs inode describing directory to which index add filename
+ * @fn: FILE_NAME attribute to add
+ * @mref: reference of the inode which @fn describes
+ *
+ * NOTE: This function does not support all cases, so it can fail with
+ * EOPNOTSUPP error code.
+ *
+ * Return 0 on success or -1 on error with errno set to the error code.
+ */
+int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
+{
+ ntfs_index_context *ictx;
+ INDEX_ENTRY *ie;
+ INDEX_HEADER *ih;
+ int err, fn_size, ie_size, allocated_size = 0;
+
+ ntfs_debug("Entering.");
+ if (!ni || !fn) {
+ ntfs_error(, "Invalid arguments.");
+ err = EINVAL;
+ goto err_out;
+ }
+ ictx = ntfs_index_ctx_get(ni, I30, 4);
+ if (!ictx)
+ return -1;
+ fn_size = (fn->file_name_length * sizeof(ntfschar)) +
+ sizeof(FILE_NAME_ATTR);
+ ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7;
+retry:
+ /* Find place where insert new entry. */
+ if (!ntfs_index_lookup(fn, fn_size, ictx)) {
+ err = EEXIST;
+ ntfs_error(, "Index already have such entry.");
+ goto err_out;
+ }
+ if (errno != ENOENT) {
+ err = errno;
+ ntfs_error(, "Failed to find place where to insert new entry.");
+ goto err_out;
+ }
+ /* Some setup. */
+ if (ictx->is_in_root)
+ ih = &ictx->ir->index;
+ else
+ ih = &ictx->ia->index;
+ if (!allocated_size)
+ allocated_size = le16_to_cpu(ih->allocated_size);
+ /* Check whether we have enough space in the index. */
+ if (le16_to_cpu(ih->index_length) + ie_size > allocated_size) {
+ /* If we in the index root try to resize it. */
+ if (ictx->is_in_root) {
+ ntfs_attr *na;
+
+ allocated_size = le16_to_cpu(ih->index_length) +
+ ie_size;
+ na = ntfs_attr_open(ictx->ni, AT_INDEX_ROOT, ictx->name,
+ ictx->name_len);
+ if (!na) {
+ err = errno;
+ ntfs_error(, "Failed to open INDEX_ROOT.");
+ goto err_out;
+ }
+ if (ntfs_attr_truncate(na, allocated_size + offsetof(
+ INDEX_ROOT, index))) {
+ err = EOPNOTSUPP;
+ ntfs_attr_close(na);
+ ntfs_error(, "Failed to truncate INDEX_ROOT.");
+ goto err_out;
+ }
+ ntfs_attr_close(na);
+ ntfs_index_ctx_reinit(ictx);
+ goto retry;
+ }
+ ntfs_debug("Not implemented case.");
+ err = EOPNOTSUPP;
+ goto err_out;
+ }
+ /* Update allocated size if we in INDEX_ROOT. */
+ if (ictx->is_in_root)
+ ih->allocated_size = cpu_to_le16(allocated_size);
+ /* Create entry. */
+ ie = calloc(1, ie_size);
+ if (!ie) {
+ err = errno;
+ goto err_out;
+ }
+ ie->indexed_file = cpu_to_le64(mref);
+ ie->length = cpu_to_le16(ie_size);
+ ie->key_length = cpu_to_le16(fn_size);
+ memcpy(&ie->key, fn, fn_size);
+ /* Update index length, move following entries forard and copy entry. */
+ ih->index_length = cpu_to_le16(le16_to_cpu(ih->index_length) + ie_size);
+ memmove((u8*)ictx->entry + ie_size, ictx->entry,
+ le16_to_cpu(ih->index_length) -
+ ((u8*)ictx->entry - (u8*)ih) - ie_size);
+ memcpy(ictx->entry, ie, ie_size);
+ /* Done! */
+ ntfs_index_entry_mark_dirty(ictx);
+ ntfs_index_ctx_put(ictx);
+ free(ie);
+ ntfs_debug("Done.");
+ return 0;
+err_out:
+ ntfs_debug("Failed.");
+ ntfs_index_ctx_put(ictx);
+ errno = err;
+ return -1;
+}
+
+/**
+ * ntfs_index_rm - remove entry from the index
+ * @ictx: index context describing entry to delete
+ *
+ * Delete entry described by @ictx from the index. NOTE: This function does not
+ * support all cases, so it can fail with EOPNOTSUPP error code. In any case
+ * index context is always reinitialized after use of this function, so it can
+ * be used for index lookup once again.
+ *
+ * Return 0 on success or -1 on error with errno set to the error code.
+ */
+int ntfs_index_rm(ntfs_index_context *ictx)
+{
+ INDEX_HEADER *ih;
+ u32 new_index_length;
+ int err;
+
+ ntfs_debug("Entering.");
+ if (!ictx || (!ictx->ia && !ictx->ir) ||
+ ictx->entry->flags & INDEX_ENTRY_END) {
+ ntfs_error(, "Invalid arguments.");
+ err = EINVAL;
+ goto err_out;
+ }
+ if (ictx->is_in_root)
+ ih = &ictx->ir->index;
+ else
+ ih = &ictx->ia->index;
+ /* Don't support deletion of entries with subnodes yet. */
+ if (ictx->entry->flags & INDEX_ENTRY_NODE) {
+ err = EOPNOTSUPP;
+ goto err_out;
+ }
+ /* Calculate new length of the index. */
+ new_index_length = le32_to_cpu(ih->index_length) -
+ le16_to_cpu(ictx->entry->length);
+ /* Don't support deletion of the last entry in the allocation block. */
+ if (!ictx->is_in_root && (new_index_length <=
+ le32_to_cpu(ih->entries_offset) +
+ sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN))) {
+ err = EOPNOTSUPP;
+ goto err_out;
+ }
+ /* Update index length and remove index entry. */
+ ih->index_length = cpu_to_le32(new_index_length);
+ if (ictx->is_in_root)
+ ih->allocated_size = ih->index_length;
+ memmove(ictx->entry, (u8*)ictx->entry + le16_to_cpu(
+ ictx->entry->length), new_index_length -
+ ((u8*)ictx->entry - (u8*)ih));
+ ntfs_index_entry_mark_dirty(ictx);
+ /* Resize INDEX_ROOT attribute. */
+ if (ictx->is_in_root) {
+ ntfs_attr *na;
+
+ na = ntfs_attr_open(ictx->ni, AT_INDEX_ROOT, ictx->name,
+ ictx->name_len);
+ if (!na) {
+ err = errno;
+ ntfs_error(, "Failed to open INDEX_ROOT attribute. "
+ "Leaving inconsist metadata.");
+ goto err_out;
+ }
+ if (ntfs_attr_truncate(na, new_index_length + offsetof(
+ INDEX_ROOT, index))) {
+ err = errno;
+ ntfs_error(, "Failed to truncate INDEX_ROOT attribute. "
+ " Leaving inconsist metadata.");
+ goto err_out;
+ }
+ ntfs_attr_close(na);
+ }
+ ntfs_index_ctx_reinit(ictx);
+ ntfs_debug("Done.");
+ return 0;
+err_out:
+ ntfs_index_ctx_reinit(ictx);
+ ntfs_debug("Failed.");
+ errno = err;
+ return -1;
+}
Index: inode.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/inode.c,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -p -r1.64 -r1.65
--- inode.c 4 Aug 2005 09:59:43 -0000 1.64
+++ inode.c 14 Aug 2005 15:44:47 -0000 1.65
@@ -149,9 +149,10 @@ ntfs_inode *ntfs_inode_open(ntfs_volume
NInoSetEncrypted(ni);
if (std_info->file_attributes & FILE_ATTR_SPARSE_FILE)
NInoSetSparse(ni);
- ni->mtime = ntfs2utc(sle64_to_cpu(std_info->last_data_change_time));
- ni->ctime = ntfs2utc(sle64_to_cpu(std_info->last_mft_change_time));
- ni->atime = ntfs2utc(sle64_to_cpu(std_info->last_access_time));
+ ni->creation_time = ntfs2utc(std_info->creation_time);
+ ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time);
+ ni->last_mft_change_time = ntfs2utc(std_info->last_mft_change_time);
+ ni->last_access_time = ntfs2utc(std_info->last_access_time);
/* Set attribute list information. */
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) {
@@ -471,6 +472,10 @@ static int ntfs_inode_sync_standard_info
std_info->file_attributes |= FILE_ATTR_SPARSE_FILE;
else
std_info->file_attributes &= ~FILE_ATTR_SPARSE_FILE;
+ std_info->creation_time = utc2ntfs(ni->creation_time);
+ std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time);
+ std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
+ std_info->last_access_time = utc2ntfs(ni->last_access_time);
ntfs_inode_mark_dirty(ctx->ntfs_ino);
ntfs_attr_put_search_ctx(ctx);
return 0;
@@ -561,6 +566,10 @@ static int ntfs_inode_sync_file_name(ntf
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
if (ni->data_size != -1)
fn->data_size = cpu_to_sle64(ni->data_size);
+ fn->creation_time = utc2ntfs(ni->creation_time);
+ fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
+ fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
+ fn->last_access_time = utc2ntfs(ni->last_access_time);
ntfs_index_entry_mark_dirty(ictx);
ntfs_index_ctx_put(ictx);
ntfs_inode_close(index_ni);
@@ -616,7 +625,8 @@ int ntfs_inode_sync(ntfs_inode *ni)
__FUNCTION__, (long long) ni->mft_no);
/* Update STANDARD_INFORMATION. */
- if (ni->nr_extents != -1 && ntfs_inode_sync_standard_information(ni)) {
+ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
+ ntfs_inode_sync_standard_information(ni)) {
if (!err || errno == EIO) {
err = errno;
if (err != EIO)
@@ -627,7 +637,8 @@ int ntfs_inode_sync(ntfs_inode *ni)
}
/* Update FILE_NAME's in the index. */
- if (ni->nr_extents != -1 && NInoFileNameTestAndClearDirty(ni) &&
+ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
+ NInoFileNameTestAndClearDirty(ni) &&
ntfs_inode_sync_file_name(ni)) {
if (!err || errno == EIO) {
err = errno;
@@ -640,8 +651,8 @@ int ntfs_inode_sync(ntfs_inode *ni)
}
/* Write out attribute list from cache to disk. */
- if (ni->nr_extents != -1 && NInoAttrList(ni) &&
- NInoAttrListTestAndClearDirty(ni)) {
+ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
+ NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) {
ntfs_attr *na;
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
Index: mft.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/mft.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -p -r1.32 -r1.33
--- mft.c 1 Aug 2005 22:10:39 -0000 1.32
+++ mft.c 14 Aug 2005 15:44:47 -0000 1.33
@@ -2,6 +2,7 @@
* mft.c - Mft record handling code. Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2004 Anton Altaparmakov
+ * Copyright (c) 2005 Yura Pakhuchiy
*
* 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
@@ -25,6 +26,7 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <time.h>
#include "compat.h"
@@ -1361,7 +1363,7 @@ mft_rec_already_initialized:
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
ntfs_error(vol->sb, "Mft record 0x%llx was marked unused in "
"mft bitmap but is marked used itself. "
- "Corrupt filesystem or driver bug! "
+ "Corrupt filesystem or library bug! "
"Run chkdsk immediately!", (long long)bit);
free(m);
errno = EIO;
@@ -1435,6 +1437,11 @@ mft_rec_already_initialized:
}
/* Make sure the allocated inode is written out to disk later. */
ntfs_inode_mark_dirty(ni);
+ /* Initialize time, allocated and data size in ntfs_inode struct. */
+ ni->data_size = ni->allocated_size = -1;
+ ni->creation_time = ni->last_data_change_time =
+ ni->last_mft_change_time =
+ ni->last_access_time = time(NULL);
/* Update the default mft allocation position if it was used. */
if (!base_ni)
vol->mft_data_pos = bit + 1;
|