[PATCH] Patch for NTFS Kernel tree. To add simple create and unlink operation.

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[PATCH] Patch for NTFS Kernel tree. To add simple create and unlink operation.

高志刚
From: Zhigang Gao <gzg1984@icloud .com>

---
 fs/ntfs/Makefile |   25 +-
 fs/ntfs/aops.h   |    2 +
 fs/ntfs/attrib.c |   26 +-
 fs/ntfs/dir.c    |  602 ++++++++++++++++++++++++
 fs/ntfs/file.c   |    6 +
 fs/ntfs/index.h  |    1 +
 fs/ntfs/mft.c    |   80 ++++
 fs/ntfs/mft.h    |    1 +
 fs/ntfs/namei.c  | 1364 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 2102 insertions(+), 5 deletions(-)

diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index 2ff263e..3edb4e2 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -1,14 +1,33 @@
 # Rules for making the NTFS driver.
-
+ifneq ($(KERNELRELEASE),)
 obj-$(CONFIG_NTFS_FS) += ntfs.o
 
 ntfs-y := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
-  index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
-  unistr.o upcase.o
+  index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
+  unistr.o upcase.o
 
 ntfs-$(CONFIG_NTFS_RW) += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
 
 ccflags-y := -DNTFS_VERSION=\"2.1.32\"
 ccflags-$(CONFIG_NTFS_DEBUG) += -DDEBUG
 ccflags-$(CONFIG_NTFS_RW) += -DNTFS_RW
+else
+
+KERNEL ?= /lib/modules/`uname -r`/build
+
+default:
+ CONFIG_NTFS_FS=m CONFIG_NTFS_RW=y CONFIG_NTFS_DEBUG=y $(MAKE) -C $(KERNEL) M=$$PWD
+
+
+.PHONY : install help clean
+help:
+ $(MAKE) -C $(KERNEL) M=$$PWD help
+
+install : default
+ $(MAKE) -C $(KERNEL) M=$$PWD modules_install
+ depmod -A
+
+clean:
+ make -C $(KERNEL) M=`pwd` clean
 
+endif
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
index 820d6ea..4805986 100644
--- a/fs/ntfs/aops.h
+++ b/fs/ntfs/aops.h
@@ -39,8 +39,10 @@
  */
 static inline void ntfs_unmap_page(struct page *page)
 {
+ ntfs_debug("Entering .");
  kunmap(page);
  put_page(page);
+ ntfs_debug("done .");
 }
 
 /**
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 44a39a0..0092d14 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -599,20 +599,41 @@ static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
  * Iterate over attributes in mft record starting at @ctx->attr, or the
  * attribute following that, if @ctx->is_first is 'true'.
  */
+ ntfs_debug("Entering. type=[0x%x] is_first[%d]", type,ctx->is_first);
  if (ctx->is_first) {
  a = ctx->attr;
  ctx->is_first = false;
- } else
+ }
+ else
+ {
  a = (ATTR_RECORD*)((u8*)ctx->attr +
  le32_to_cpu(ctx->attr->length));
+ }
+
  for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
  if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +
  le32_to_cpu(ctx->mrec->bytes_allocated))
+ {
+ ntfs_error(vol->sb, "IN LOOP breaker."
+ "type=[0x%x],a->type[0x%x],a->length[%d],"
+ "a[%p],ctx->mrec[%p],ctx->mrec->bytes_allocated[%d]"
+ ,type,a->type,a->length,
+ a,ctx->mrec,le32_to_cpu(ctx->mrec->bytes_allocated));
  break;
+ }
  ctx->attr = a;
+ if (type != AT_UNUSED)
+ {
  if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
  a->type == AT_END))
  return -ENOENT;
+ }
+ else
+ {
+ if ( a->type == AT_END)
+ return -ENOENT;
+ }
+
  if (unlikely(!a->length))
  break;
  if (a->type != type)
@@ -1434,6 +1455,8 @@ int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type)
  */
 int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
 {
+ BUG_ON(!m);
+ BUG_ON(!a);
  ntfs_debug("Entering for new_size %u.", new_size);
  /* Align to 8 bytes if it is not already done. */
  if (new_size & 7)
@@ -1455,6 +1478,7 @@ int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
  if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length))
  a->length = cpu_to_le32(new_size);
  }
+ ntfs_debug("Done.");
  return 0;
 }
 
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index 0ee19ec..caf57c15 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -77,6 +77,608 @@ ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
  *       removes them again after the write is complete after which it
  *       unlocks the page.
  */
+#include "index.h"
+#include "layout.h"
+#include "types.h"
+
+/* Author: Gzged
+ * Caller is in namei.c
+ */
+int ntfs_lookup_inode_by_key (const void *key, const int key_len, ntfs_index_context *ictx)
+{
+ ntfs_inode* dir_ni = ictx->idx_ni ;
+ const ntfschar* uname = ((FILE_NAME_ATTR *)key)->file_name ;
+ const int uname_len = ((FILE_NAME_ATTR *)key)->file_name_length;
+
+ ntfs_volume *vol = dir_ni->vol;
+ struct super_block *sb = vol->sb;
+ MFT_RECORD *m;
+ INDEX_ROOT *ir;
+ INDEX_ENTRY *ie;
+ INDEX_ALLOCATION *ia;
+ u8 *index_end;
+ /*
+ u64 mref;
+ */
+ ntfs_attr_search_ctx *ctx;
+ int err, rc;
+ VCN vcn, old_vcn;
+ struct address_space *ia_mapping;
+ struct page *page;
+ u8 *kaddr;
+
+ ntfs_debug("Entering.");
+ BUG_ON(!S_ISDIR(VFS_I(dir_ni)->i_mode));
+ BUG_ON(NInoAttr(dir_ni));
+ /* Get hold of the mft record for the directory. */
+ m = map_mft_record(dir_ni);
+ if (IS_ERR(m))
+ {
+ ntfs_error(sb, "map_mft_record() failed with error code %ld.",
+ -PTR_ERR(m));
+ return ERR_MREF(PTR_ERR(m));
+ }
+ ctx = ntfs_attr_get_search_ctx(dir_ni, m);
+ if (unlikely(!ctx)) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ /* Find the index root attribute in the mft record. */
+ err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
+ 0, ctx);
+ if (unlikely(err)) {
+ if (err == -ENOENT) {
+ ntfs_error(sb, "Index root attribute missing in "
+ "directory inode 0x%lx.",
+ dir_ni->mft_no);
+ err = -EIO;
+ }
+ goto err_out;
+ }
+ /* Get to the index root value (it's been verified in read_inode). */
+ ir = (INDEX_ROOT*)((u8*)ctx->attr +
+ le16_to_cpu(ctx->attr->data.resident.value_offset));
+ index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
+ /* The first index entry. */
+ ie = (INDEX_ENTRY*)((u8*)&ir->index +
+ le32_to_cpu(ir->index.entries_offset));
+ /*
+ * Loop until we exceed valid memory (corruption case) or until we
+ * reach the last entry.
+ */
+ for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
+ /* Bounds checks. */
+ ictx->is_in_root = true;
+ ictx->ir = ir;
+ ictx->entry = ie;
+ ictx->base_ni = dir_ni;
+ ictx->actx = ctx;
+ ictx->ia = NULL;
+ ictx->page = NULL;
+
+ if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
+ sizeof(INDEX_ENTRY_HEADER) > index_end ||
+ (u8*)ie + le16_to_cpu(ie->key_length) >
+ index_end)
+ goto dir_err_out;
+ /*
+ * The last entry cannot contain a name. It can however contain
+ * a pointer to a child node in the B+tree so we just break out.
+ */
+ if (ie->flags & INDEX_ENTRY_END)
+ break;
+ /*
+ * We perform a case sensitive comparison and if that matches
+ * we are done and return the mft reference of the inode (i.e.
+ * the inode number together with the sequence number for
+ * consistency checking). We convert it to cpu format before
+ * returning.
+ */
+
+ if (ntfs_are_names_equal(uname, uname_len,
+ (ntfschar*)&ie->key.file_name.file_name,
+ ie->key.file_name.file_name_length,
+ CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
+found_it:
+ /*
+ * We have a perfect match, so we don't need to care
+ * about having matched imperfectly before, so we can
+ * free name and set *res to NULL.
+ * However, if the perfect match is a short file name,
+ * we need to signal this through *res, so that
+ * ntfs_lookup() can fix dcache aliasing issues.
+ * As an optimization we just reuse an existing
+ * allocation of *res.
+ */
+ /*FIXME:Shut for now and maybe work in future. Author:Gzged
+ if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
+ if (!name) {
+ name = kmalloc(sizeof(ntfs_name),
+ GFP_NOFS);
+ if (!name) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ }
+ name->mref = le64_to_cpu(
+ ie->data.dir.indexed_file);
+ name->type = FILE_NAME_DOS;
+ name->len = 0;
+ *res = name;
+ } else {
+ kfree(name);
+ *res = NULL;
+ }
+ */
+ /*FIXME: Gzged mod
+ mref = le64_to_cpu(ie->data.dir.indexed_file);
+ ntfs_attr_put_search_ctx(ctx);
+ unmap_mft_record(dir_ni);
+ return mref;
+ */
+
+done:
+            ictx->data = (u8*)ie +
+                    le16_to_cpu(ie->data.vi.data_offset);
+            ictx->data_len = le16_to_cpu(ie->data.vi.data_length);
+            ntfs_debug("Done.");
+            return err;
+
+ }
+ /*
+ * For a case insensitive mount, we also perform a case
+ * insensitive comparison (provided the file name is not in the
+ * POSIX namespace). If the comparison matches, and the name is
+ * in the WIN32 namespace, we cache the filename in *res so
+ * that the caller, ntfs_lookup(), can work on it. If the
+ * comparison matches, and the name is in the DOS namespace, we
+ * only cache the mft reference and the file name type (we set
+ * the name length to zero for simplicity).
+ */
+// if (!NVolCaseSensitive(vol) &&
+// ie->key.file_name.file_name_type &&
+// ntfs_are_names_equal(uname, uname_len,
+// (ntfschar*)&ie->key.file_name.file_name,
+// ie->key.file_name.file_name_length,
+// IGNORE_CASE, vol->upcase, vol->upcase_len)) {
+// int name_size = sizeof(ntfs_name);
+// u8 type = ie->key.file_name.file_name_type;
+// u8 len = ie->key.file_name.file_name_length;
+//
+// /* Only one case insensitive matching name allowed. */
+// if (name) {
+// ntfs_error(sb, "Found already allocated name "
+// "in phase 1. Please run chkdsk "
+// "and if that doesn't find any "
+// "errors please report you saw "
+// "this message to "
+// "linux-ntfs-dev@lists."
+// "sourceforge.net.");
+// goto dir_err_out;
+// }
+//
+// if (type != FILE_NAME_DOS)
+// name_size += len * sizeof(ntfschar);
+// name = kmalloc(name_size, GFP_NOFS);
+// if (!name) {
+// err = -ENOMEM;
+// goto err_out;
+// }
+// name->mref = le64_to_cpu(ie->data.dir.indexed_file);
+// name->type = type;
+// if (type != FILE_NAME_DOS) {
+// name->len = len;
+// memcpy(name->name, ie->key.file_name.file_name,
+// len * sizeof(ntfschar));
+// } else
+// name->len = 0;
+// *res = name;
+// }
+ /*
+ * Not a perfect match, need to do full blown collation so we
+ * know which way in the B+tree we have to go.
+ */
+ rc = ntfs_collate_names(uname, uname_len,
+ (ntfschar*)&ie->key.file_name.file_name,
+ ie->key.file_name.file_name_length, 1,
+ IGNORE_CASE, vol->upcase, vol->upcase_len);
+ /*
+ * If uname collates before the name of the current entry, there
+ * is definitely no such name in this index but we might need to
+ * descend into the B+tree so we just break out of the loop.
+ */
+ if (rc == -1)
+ break;
+ /* The names are not equal, continue the search. */
+ if (rc)
+ continue;
+ /*
+ * Names match with case insensitive comparison, now try the
+ * case sensitive comparison, which is required for proper
+ * collation.
+ */
+ rc = ntfs_collate_names(uname, uname_len,
+ (ntfschar*)&ie->key.file_name.file_name,
+ ie->key.file_name.file_name_length, 1,
+ CASE_SENSITIVE, vol->upcase, vol->upcase_len);
+ if (rc == -1)
+ break;
+ if (rc)
+ continue;
+ /*
+ * Perfect match, this will never happen as the
+ * ntfs_are_names_equal() call will have gotten a match but we
+ * still treat it correctly.
+ */
+ goto found_it;
+ }
+ /*
+ * We have finished with this index without success. Check for the
+ * presence of a child node and if not present return -ENOENT, unless
+ * we have got a matching name cached in name in which case return the
+ * mft reference associated with it.
+ */
+ if (!(ie->flags & INDEX_ENTRY_NODE)) {
+ /* FIXME:Gzged shut
+ if (name) {
+ ntfs_attr_put_search_ctx(ctx);
+ unmap_mft_record(dir_ni);
+ return name->mref;
+ }
+ ********/
+ ntfs_debug("Entry not found. ictx->is_in_root[%d]",ictx->is_in_root);
+
+ /*FIXME:Gzged set
+ ictx->is_in_root = true;
+ ictx->ir = ir;
+ ictx->entry = ie;
+ ictx->base_ni = dir_ni;
+ ictx->actx = ctx;
+ ictx->ia = NULL;
+ ictx->page = NULL;
+ */
+ /*FIXME: Gzged mod ; do not release actx ....and so on
+ goto err_out;
+ */
+ return -ENOENT;
+ } /* Child node present, descend into it. */
+ /* Consistency check: Verify that an index allocation exists. */
+ if (!NInoIndexAllocPresent(dir_ni)) {
+ ntfs_error(sb, "No index allocation attribute but index entry "
+ "requires one. Directory inode 0x%lx is "
+ "corrupt or driver bug.", dir_ni->mft_no);
+ goto err_out;
+ }
+ /* Get the starting vcn of the index_block holding the child node. */
+ vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
+ ia_mapping = VFS_I(dir_ni)->i_mapping;
+ /*
+ * We are done with the index root and the mft record. Release them,
+ * otherwise we deadlock with ntfs_map_page().
+ */
+ ntfs_attr_put_search_ctx(ctx);
+ unmap_mft_record(dir_ni);
+ m = NULL;
+ ctx = NULL;
+descend_into_child_node:
+ /*
+ * Convert vcn to index into the index allocation attribute in units
+ * of PAGE_SIZE and map the page cache page, reading it from
+ * disk if necessary.
+ */
+ page = ntfs_map_page(ia_mapping, vcn <<
+ dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
+ if (IS_ERR(page)) {
+ ntfs_error(sb, "Failed to map directory index page, error %ld.",
+ -PTR_ERR(page));
+ err = PTR_ERR(page);
+ goto err_out;
+ }
+ lock_page(page);
+ kaddr = (u8*)page_address(page);
+fast_descend_into_child_node:
+ /* Get to the index allocation block. */
+ ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
+ dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
+ /* Bounds checks. */
+ if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
+ ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
+ "inode 0x%lx or driver bug.", dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ /* Catch multi sector transfer fixup errors. */
+ if (unlikely(!ntfs_is_indx_record(ia->magic))) {
+ ntfs_error(sb, "Directory index record with vcn 0x%llx is "
+ "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
+ (unsigned long long)vcn, dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
+ ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
+ "different from expected VCN (0x%llx). "
+ "Directory inode 0x%lx is corrupt or driver "
+ "bug.", (unsigned long long)
+ sle64_to_cpu(ia->index_block_vcn),
+ (unsigned long long)vcn, dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
+ dir_ni->itype.index.block_size) {
+ ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
+ "0x%lx has a size (%u) differing from the "
+ "directory specified size (%u). Directory "
+ "inode is corrupt or driver bug.",
+ (unsigned long long)vcn, dir_ni->mft_no,
+ le32_to_cpu(ia->index.allocated_size) + 0x18,
+ dir_ni->itype.index.block_size);
+ goto unm_err_out;
+ }
+ index_end = (u8*)ia + dir_ni->itype.index.block_size;
+ if (index_end > kaddr + PAGE_SIZE) {
+ ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
+ "0x%lx crosses page boundary. Impossible! "
+ "Cannot access! This is probably a bug in the "
+ "driver.", (unsigned long long)vcn,
+ dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
+ if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
+ ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
+ "inode 0x%lx exceeds maximum size.",
+ (unsigned long long)vcn, dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ /* The first index entry. */
+ ie = (INDEX_ENTRY*)((u8*)&ia->index +
+ le32_to_cpu(ia->index.entries_offset));
+ /*
+ * Iterate similar to above big loop but applied to index buffer, thus
+ * loop until we exceed valid memory (corruption case) or until we
+ * reach the last entry.
+ */
+ for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
+ /* Bounds check. */
+ if ((u8*)ie < (u8*)ia || (u8*)ie +
+ sizeof(INDEX_ENTRY_HEADER) > index_end ||
+ (u8*)ie + le16_to_cpu(ie->key_length) >
+ index_end) {
+ ntfs_error(sb, "Index entry out of bounds in "
+ "directory inode 0x%lx.",
+ dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ /*FIXME:Gzged set */
+ ictx->is_in_root = false;
+ ictx->ia = ia;
+ ictx->entry = ie;
+ ictx->actx = NULL;
+ ictx->base_ni = NULL;
+ ictx->page = page;
+ /*
+ * The last entry cannot contain a name. It can however contain
+ * a pointer to a child node in the B+tree so we just break out.
+ */
+ if (ie->flags & INDEX_ENTRY_END)
+ break;
+ /*
+ * We perform a case sensitive comparison and if that matches
+ * we are done and return the mft reference of the inode (i.e.
+ * the inode number together with the sequence number for
+ * consistency checking). We convert it to cpu format before
+ * returning.
+ */
+ BUG_ON(!PageLocked(ictx->page));
+
+ if (ntfs_are_names_equal(uname, uname_len,
+ (ntfschar*)&ie->key.file_name.file_name,
+ ie->key.file_name.file_name_length,
+ CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
+found_it2:
+ /*
+ * We have a perfect match, so we don't need to care
+ * about having matched imperfectly before, so we can
+ * free name and set *res to NULL.
+ * However, if the perfect match is a short file name,
+ * we need to signal this through *res, so that
+ * ntfs_lookup() can fix dcache aliasing issues.
+ * As an optimization we just reuse an existing
+ * allocation of *res.
+ */
+ /* Gzged shut
+ if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
+ if (!name) {
+ name = kmalloc(sizeof(ntfs_name),
+ GFP_NOFS);
+ if (!name) {
+ err = -ENOMEM;
+ goto unm_err_out;
+ }
+ }
+ name->mref = le64_to_cpu(
+ ie->data.dir.indexed_file);
+ name->type = FILE_NAME_DOS;
+ name->len = 0;
+ *res = name;
+ } else {
+ kfree(name);
+ *res = NULL;
+ }
+ */
+ /*Gzged shut
+ mref = le64_to_cpu(ie->data.dir.indexed_file);
+ unlock_page(page);
+ ntfs_unmap_page(page);
+ * return mref;
+ * */
+            goto done;
+ }
+ /*
+ * For a case insensitive mount, we also perform a case
+ * insensitive comparison (provided the file name is not in the
+ * POSIX namespace). If the comparison matches, and the name is
+ * in the WIN32 namespace, we cache the filename in *res so
+ * that the caller, ntfs_lookup(), can work on it. If the
+ * comparison matches, and the name is in the DOS namespace, we
+ * only cache the mft reference and the file name type (we set
+ * the name length to zero for simplicity).
+// */
+// if (!NVolCaseSensitive(vol) &&
+// ie->key.file_name.file_name_type &&
+// ntfs_are_names_equal(uname, uname_len,
+// (ntfschar*)&ie->key.file_name.file_name,
+// ie->key.file_name.file_name_length,
+// IGNORE_CASE, vol->upcase, vol->upcase_len)) {
+// int name_size = sizeof(ntfs_name);
+// u8 type = ie->key.file_name.file_name_type;
+// u8 len = ie->key.file_name.file_name_length;
+//
+// /* Only one case insensitive matching name allowed. */
+// if (name) {
+// ntfs_error(sb, "Found already allocated name "
+// "in phase 2. Please run chkdsk "
+// "and if that doesn't find any "
+// "errors please report you saw "
+// "this message to "
+// "linux-ntfs-dev@lists."
+// "sourceforge.net.");
+// unlock_page(page);
+// ntfs_unmap_page(page);
+// goto dir_err_out;
+// }
+//
+// if (type != FILE_NAME_DOS)
+// name_size += len * sizeof(ntfschar);
+// name = kmalloc(name_size, GFP_NOFS);
+// if (!name) {
+// err = -ENOMEM;
+// goto unm_err_out;
+// }
+// name->mref = le64_to_cpu(ie->data.dir.indexed_file);
+// name->type = type;
+// if (type != FILE_NAME_DOS) {
+// name->len = len;
+// memcpy(name->name, ie->key.file_name.file_name,
+// len * sizeof(ntfschar));
+// } else
+// name->len = 0;
+// *res = name;
+// }
+ /*
+ * Not a perfect match, need to do full blown collation so we
+ * know which way in the B+tree we have to go.
+ */
+ rc = ntfs_collate_names(uname, uname_len,
+ (ntfschar*)&ie->key.file_name.file_name,
+ ie->key.file_name.file_name_length, 1,
+ IGNORE_CASE, vol->upcase, vol->upcase_len);
+ /*
+ * If uname collates before the name of the current entry, there
+ * is definitely no such name in this index but we might need to
+ * descend into the B+tree so we just break out of the loop.
+ */
+ if (rc == -1)
+ break;
+ /* The names are not equal, continue the search. */
+ if (rc)
+ continue;
+ /*
+ * Names match with case insensitive comparison, now try the
+ * case sensitive comparison, which is required for proper
+ * collation.
+ */
+ rc = ntfs_collate_names(uname, uname_len,
+ (ntfschar*)&ie->key.file_name.file_name,
+ ie->key.file_name.file_name_length, 1,
+ CASE_SENSITIVE, vol->upcase, vol->upcase_len);
+ if (rc == -1)
+ break;
+ if (rc)
+ continue;
+ /*
+ * Perfect match, this will never happen as the
+ * ntfs_are_names_equal() call will have gotten a match but we
+ * still treat it correctly.
+ */
+ goto found_it2;
+ }
+ /*
+ * We have finished with this index buffer without success. Check for
+ * the presence of a child node.
+ */
+ if (ie->flags & INDEX_ENTRY_NODE) {
+ if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
+ ntfs_error(sb, "Index entry with child node found in "
+ "a leaf node in directory inode 0x%lx.",
+ dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ /* Child node present, descend into it. */
+ old_vcn = vcn;
+ vcn = sle64_to_cpup((sle64*)((u8*)ie +
+ le16_to_cpu(ie->length) - 8));
+ if (vcn >= 0) {
+ /* If vcn is in the same page cache page as old_vcn we
+ * recycle the mapped page. */
+ if (old_vcn << vol->cluster_size_bits >>
+ PAGE_SHIFT == vcn <<
+ vol->cluster_size_bits >>
+ PAGE_SHIFT)
+ goto fast_descend_into_child_node;
+ unlock_page(page);
+ ntfs_unmap_page(page);
+ goto descend_into_child_node;
+ }
+ ntfs_error(sb, "Negative child node vcn in directory inode "
+ "0x%lx.", dir_ni->mft_no);
+ goto unm_err_out;
+ }
+ /*
+ * No child node present, return -ENOENT, unless we have got a matching
+ * name cached in name in which case return the mft reference
+ * associated with it.
+ */
+/********
+ if (name) {
+ unlock_page(page);
+ ntfs_unmap_page(page);
+ return name->mref;
+ }
+ *******/
+ ntfs_debug("Entry not found.");
+ err = -ENOENT;
+/*
+ if (!err)
+ err = -EIO;
+ if (ctx)
+ ntfs_attr_put_search_ctx(ctx);
+ if (m)
+ unmap_mft_record(dir_ni);
+ */
+ return ERR_MREF(err);
+
+unm_err_out:
+ unlock_page(page);
+ ntfs_unmap_page(page);
+err_out:
+ if (!err)
+ err = -EIO;
+ if (ctx)
+ ntfs_attr_put_search_ctx(ctx);
+ if (m)
+ unmap_mft_record(dir_ni);
+ /*Gzged shut
+ if (name) {
+ kfree(name);
+ *res = NULL;
+ }
+ */
+ ntfs_debug("done.");
+ return ERR_MREF(err);
+dir_err_out:
+ ntfs_error(sb, "Corrupt directory.  Aborting lookup.");
+ goto err_out;
+}
 MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
  const int uname_len, ntfs_name **res)
 {
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index c4f68c3..1475243 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -24,7 +24,13 @@
 #include <linux/gfp.h>
 #include <linux/pagemap.h>
 #include <linux/pagevec.h>
+#include <linux/sched.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
 #include <linux/sched/signal.h>
+#endif
+
 #include <linux/swap.h>
 #include <linux/uio.h>
 #include <linux/writeback.h>
diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
index 8745469..b7d75ce 100644
--- a/fs/ntfs/index.h
+++ b/fs/ntfs/index.h
@@ -88,6 +88,7 @@ typedef struct {
 extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni);
 extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
 
+extern int ntfs_lookup_inode_by_key (const void *key, const int key_len, ntfs_index_context *ictx);
 extern int ntfs_index_lookup(const void *key, const int key_len,
  ntfs_index_context *ictx);
 
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index b6f4021..dbe7f21 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -2915,4 +2915,84 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
  mark_mft_record_dirty(ni);
  return err;
 }
+/**
+ * ntfs_mft_record_free - free an mft record on an ntfs volume
+ * @vol: volume on which to free the mft record
+ * @ni: open ntfs inode of the mft record to free
+ *
+ * Free the mft record of the open inode @ni on the mounted ntfs volume @vol.
+ * Note that this function calls ntfs_inode_close() internally and hence you
+ * cannot use the pointer @ni any more after this function returns success.
+ *
+ * On success return 0 and on error return -1 with errno set to the error code.
+ */
+int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni,MFT_RECORD* mrec)
+{
+ u64 mft_no;
+ int err;
+ u16 seq_no, old_seq_no;
+
+ ntfs_debug("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
+
+ if (!vol || !vol->mftbmp_ino || !ni)
+ {
+ return -EINVAL;
+ }
+
+ /* Cache the mft reference for later. */
+ mft_no = ni->mft_no;
+
+ /* Mark the mft record as not in use. */
+ mrec->flags &= ~MFT_RECORD_IN_USE;
+
+ /* Increment the sequence number, skipping zero, if it is not zero. */
+ old_seq_no = mrec->sequence_number;
+
+ seq_no = le16_to_cpu(old_seq_no);
+ if (seq_no == 0xffff)
+ seq_no = 1;
+ else if (seq_no)
+ seq_no++;
+ mrec->sequence_number = cpu_to_le16(seq_no);
+
+ /* Set the inode dirty and write it out. */
+ flush_dcache_mft_record_page(ni);
+ mark_mft_record_dirty(ni);
+
+ /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
+ ntfs_debug("before down_write...");
+ //down_write(&vol->mftbmp_lock);
+ if ( (err = ntfs_bitmap_clear_bit(vol->mftbmp_ino, mft_no )))
+ //up_write(&vol->mftbmp_lock);
+ {
+ // FIXME: If ntfs_bitmap_clear_run() guarantees rollback on
+ //  error, this could be changed to goto sync_rollback;
+ goto bitmap_rollback;
+ }
+
+ /* Throw away the now freed inode.
+ if (!ntfs_inode_close(ni)) {
+ vol->free_mft_records++;
+ return 0;
+ }
+ err = errno;*/
+ flush_dcache_mft_record_page(ni);
+ mark_mft_record_dirty(ni);
+ return 0;
+
+ /* Rollback what we did... */
+bitmap_rollback:
+ down_write(&vol->mftbmp_lock);
+ if (ntfs_bitmap_set_bit(vol->mftbmp_ino, mft_no))
+ up_write(&vol->mftbmp_lock);
+ {
+ ntfs_debug("Eeek! Rollback failed in ntfs_mft_record_free().  "
+ "Leaving inconsistent metadata!\n");
+ }
+ mrec->flags |= MFT_RECORD_IN_USE;
+ mrec->sequence_number = old_seq_no;
+ flush_dcache_mft_record_page(ni);
+ mark_mft_record_dirty(ni);
+ return err;
+}
 #endif /* NTFS_RW */
diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h
index b52bf87..f6a95ba 100644
--- a/fs/ntfs/mft.h
+++ b/fs/ntfs/mft.h
@@ -118,6 +118,7 @@ extern bool ntfs_may_write_mft_record(ntfs_volume *vol,
 extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
  ntfs_inode *base_ni, MFT_RECORD **mrec);
 extern int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m);
+extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni,MFT_RECORD* mrec);
 
 #endif /* NTFS_RW */
 
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
index 4690cd7..a737cf5 100644
--- a/fs/ntfs/namei.c
+++ b/fs/ntfs/namei.c
@@ -159,7 +159,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
  PTR_ERR(dent_inode));
  kfree(name);
  /* Return the error code. */
- return ERR_CAST(dent_inode);
+ return (struct dentry *)dent_inode;
  }
  /* It is guaranteed that @name is no longer allocated at this point. */
  if (MREF_ERR(mref) == -ENOENT) {
@@ -273,11 +273,1373 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
    }
 }
 
+
+#include "index.h"
+
+#define STATUS_OK               (0)
+#define STATUS_ERROR                (-1)
+
+/**
+ *  Insert @ie index entry at @pos entry. Used @ih values should be ok already.
+ */
+static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos)
+{
+ int ie_size = le16_to_cpu(ie->length);
+ ntfs_debug("Entering");
+ ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size);
+ memmove((u8 *)pos + ie_size, pos, le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - ie_size);
+ memcpy(pos, ie, ie_size);
+ ntfs_debug("done");
+}
+/**
+ * ntfs_ir_truncate - Truncate index root attribute
+ *
+ * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR.
+ */
+static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
+{  
+/*
+ ntfs_attr *na;
+ */
+ int ret;
+
+ ntfs_debug("Entering");
+
+/**
+ na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len);
+ if (!na) {
+ ntfs_log_perror("Failed to open INDEX_ROOT");
+ return STATUS_ERROR;
+ }
+ */
+ /*
+ *  INDEX_ROOT must be resident and its entries can be moved to
+ *  INDEX_BLOCK, so ENOSPC isn't a real error.
+ */
+ ret = ntfs_resident_attr_value_resize(icx->actx->mrec, icx->actx->attr, data_size + offsetof(INDEX_ROOT, index) );
+ /*Gzged changed
+ ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index));
+ */
+ if (ret == STATUS_OK)
+ {
+ /*
+ icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
+ if (!icx->ir)
+ return STATUS_ERROR;
+ */
+
+ icx->ir->index.allocated_size = cpu_to_le32(data_size);
+
+ } else if (ret == -EPERM)
+ {
+ ntfs_debug("Failed to truncate INDEX_ROOT");
+ }
+
+/**
+ ntfs_attr_close(na);
+ */
+ return ret;
+}
+
+/**
+ * ntfs_ir_make_space - Make more space for the index root attribute
+ *
+ * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
+ * On error return STATUS_ERROR.
+ */
+static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size)
+{  
+ int ret;
+ ntfs_debug("Entering");
+ ret = ntfs_ir_truncate(icx, data_size);
+ /* TODO
+ if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT)
+ {
+ ret = ntfs_ir_reparent(icx);
+ if (ret == STATUS_OK)
+ ret = STATUS_KEEP_SEARCHING;
+ else
+ ntfs_log_perror("Failed to nodify INDEX_ROOT");
+ }
+ */
+ ntfs_debug("Done ");
+ return ret;
+}
+
+
+static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
+{
+ INDEX_HEADER *ih;
+ int allocated_size, new_size;
+ int ret = STATUS_ERROR;
+ ntfs_inode *idx_ni = icx->idx_ni;
+ ntfs_debug("Entering. ");
+ while (1)
+ {
+ /* ret = ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx) ; */
+ ntfs_debug("new loop ");
+ ret = ntfs_lookup_inode_by_key(&ie->key, le16_to_cpu(ie->key_length), icx) ;
+ ntfs_debug("ntfs_lookup_inode_by_key ret[%d]",ret);
+ if (!ret)
+ {
+ ntfs_debug("Index already have such entry");
+ goto err_out;
+ }
+ if (ret != -ENOENT)
+ {
+ ntfs_debug("Failed to find place for new entry");
+ goto err_out;
+ }
+ /*
+ ntfs_debug("here icx[%p] icx->is_in_root[%d]",icx,icx->is_in_root);
+ */
+ if (icx->is_in_root)
+ {
+ BUG_ON(!icx->ir);
+ ih = &(icx->ir->index);
+ }
+ else
+ {
+ BUG_ON(!icx->ia);
+ ih = &(icx->ia->index);
+ }
+
+ allocated_size = le32_to_cpu(ih->allocated_size);
+ new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length);
+
+ ntfs_debug("index block sizes: allocated: %d  needed: %d", allocated_size, new_size);
+ if (new_size <= allocated_size)
+ {
+ break;
+ }
+ /** else  it will make space for new index entry **/
+
+ if (icx->is_in_root)
+ {
+ if ( (ret = ntfs_ir_make_space(icx, new_size) ) )
+ {
+ ntfs_debug("ntfs_ir_make_space err ");
+ goto err_out;
+ }
+ else
+ {
+ ntfs_debug("ntfs_ir_make_space done ");
+ }
+ }
+ else
+ {
+ ntfs_debug("should run ntfs_ib_split ");
+ ret = -ENOSPC;
+ goto err_out;
+
+ /* Gzged shut
+ if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR)
+ {
+ ntfs_debug("ntfs_ib_split err ");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+ **/
+ }
+
+ /*FIXME: Gzged mod
+ ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
+ ***/
+ /*FIXME: Gzged will fix these in furture */
+ ntfs_debug("Before flush_dcache_mft_record_page ");/*****die here *****/
+ flush_dcache_mft_record_page(icx->actx->ntfs_ino);
+
+ ntfs_debug("Before mark_mft_record_dirty ");
+ mark_mft_record_dirty(icx->actx->ntfs_ino);
+
+ /*FIXME: Gzged mod ntfs_index_ctx_reinit(icx); ***/
+ ntfs_index_ctx_put(icx);
+ ntfs_index_ctx_get(idx_ni);
+ }
+
+ ntfs_ie_insert(ih, ie, icx->entry);
+ ntfs_index_entry_flush_dcache_page(icx);
+ ntfs_index_entry_mark_dirty(icx);
+
+ ret = STATUS_OK;
+err_out:
+ ntfs_debug("%s", ret ? "Failed" : "Done");
+ return ret;
+}
+/**
+ * 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
+ *
+ * Return 0 on success or -1 on error with errno set to the error code.
+ */
+ntfs_index_context * ntfs_index_ctx_get_I30(ntfs_inode *idx_ni)
+{
+    static ntfschar I30[5] = { cpu_to_le16('$'),
+            cpu_to_le16('I'),
+            cpu_to_le16('3'),
+            cpu_to_le16('0'),
+ 0 };
+
+    struct inode * tmp_ino = ntfs_index_iget(VFS_I(idx_ni), I30, 4);
+    if (IS_ERR(tmp_ino)) {
+        ntfs_debug("Failed to load $I30 index.");
+        return NULL;
+    }
+
+ return ntfs_index_ctx_get(NTFS_I(tmp_ino));
+}
+void ntfs_index_ctx_put_I30(ntfs_index_context *ictx)
+{
+ ntfs_commit_inode(VFS_I(ictx->idx_ni));
+ iput(VFS_I(ictx->idx_ni));
+ ntfs_index_ctx_put(ictx);
+}
+static int ntfs_index_add_filename(ntfs_inode *dir_ni, FILE_NAME_ATTR *fn, MFT_REF mref)
+{
+ INDEX_ENTRY *ie;
+ ntfs_index_context *icx;
+ int ret = -1;
+
+ ntfs_debug("Entering");
+
+ if (!dir_ni || !fn)
+ {
+ ntfs_error((VFS_I(dir_ni))->i_sb,"Invalid arguments.");
+ return -EINVAL;
+ }
+
+ {/** create and set INDEX_entry **/
+ int fn_size, ie_size;
+ fn_size = (fn->file_name_length * sizeof(ntfschar)) + sizeof(FILE_NAME_ATTR);
+ ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7;
+
+ ie = kcalloc(1,ie_size,GFP_KERNEL);
+ if (!ie)
+ {
+ return -ENOMEM;
+ }
+
+ ie->data.dir.indexed_file = cpu_to_le64(mref);
+ ie->length = cpu_to_le16(ie_size);
+ ie->key_length = cpu_to_le16(fn_size);
+ ie->flags = cpu_to_le16(0);
+ memcpy(&(ie->key.file_name), fn, fn_size);
+ }/**  END of create and set INDEX_entry **/
+
+ icx =  ntfs_index_ctx_get(dir_ni);
+ if (!icx)
+ {
+ ret = PTR_ERR(icx);
+ goto out;
+ }
+
+ ret = ntfs_ie_add(icx, ie);
+out:
+ if(icx)
+ {
+ ntfs_index_ctx_put(icx);
+ }
+ if(ie)
+ {
+ kfree(ie);
+ }
+ ntfs_debug("done");
+ return ret;
+}
+
+
+/**
+ * __ntfs_create - create object 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
+ *
+ * Internal, use ntfs_create{,_device,_symlink} wrappers instead.
+ *
+ * @type can be:
+ * S_IFREG to create regular file
+ *
+ * Return opened ntfs inode that describes created object on success
+ * or ERR_PTR(errno) on error
+ */
+
+static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni,
+ ntfschar *name, u8 name_len, dev_t type )
+{
+ ntfs_inode *ni =NULL;/** this is for new inode **/
+ FILE_NAME_ATTR *fn = NULL;
+ STANDARD_INFORMATION *si = NULL;
+ SECURITY_DESCRIPTOR_ATTR *sd =NULL;
+ int err;
+
+ /*Author:Gzged */
+ MFT_RECORD* mrec;
+ int new_temp_offset ;
+ char* temp_new_record;
+
+ ntfs_debug("Entering.");
+
+ /* Sanity checks. */
+ if (!dir_ni || !name || !name_len)
+ {
+ ntfs_error((VFS_I(dir_ni))->i_sb,"Invalid arguments.");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* TODO : not support REPARSE_POINT **/
+
+ /** alloc new mft record for new file **/
+ ni = ntfs_mft_record_alloc(dir_ni->vol, type,NULL,&mrec);
+ if (IS_ERR(ni))
+ {
+ ntfs_debug("ntfs_mft_record_alloc error [%ld]",PTR_ERR(ni));
+ return ni;
+ }
+ else
+ {
+ new_temp_offset = mrec->attrs_offset ;
+ /** ntfs_mft_record_alloc{} had map ni to mrec */
+ temp_new_record=(char*)mrec;
+ ntfs_debug("mrec->mft_record_number [%d]",mrec->mft_record_number);
+ }
+
+
+/**************** Begin from here , error must goto err_out *****************/
+ { /************************ STANDARD_INFORMATION start ******************/
+ /*
+ * Create STANDARD_INFORMATION attribute. Write STANDARD_INFORMATION
+ * version 1.2, windows will upgrade it to version 3 if needed.
+ */
+ ATTR_REC attr_si;
+ int si_len,attr_si_len;
+
+ /*** $STANDARD_INFORMATION (0x10)  **/
+ si_len = offsetof(STANDARD_INFORMATION, ver) + sizeof(si->ver.v1.reserved12);
+ si = kcalloc(1,si_len,GFP_KERNEL );
+ if (!si)
+ {
+ err = -ENOMEM;
+ goto err_out;
+ }
+#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
+ si->creation_time = NTFS_TIME_OFFSET ;
+ si->last_data_change_time = NTFS_TIME_OFFSET ;
+ si->last_mft_change_time = NTFS_TIME_OFFSET ;
+ si->last_access_time = NTFS_TIME_OFFSET ;
+
+ /** set attr **/
+ attr_si_len = offsetof(ATTR_REC, data) + sizeof(attr_si.data.resident) ;
+ attr_si= (ATTR_REC )
+ {
+ .type = AT_STANDARD_INFORMATION ,
+ .length = attr_si_len +  si_len ,
+ .non_resident = 0,
+ .name_length = 0,
+ .name_offset = 0,
+ .flags =  0 ,
+ .instance = (mrec->next_attr_instance) ++ ,
+ .data=
+ {
+ .resident=
+ {
+ .value_length = si_len,
+ .value_offset = attr_si_len  ,
+ .flags = 0 ,
+ }
+ },
+ };
+ /*
+ attr_si.data.resident.value_length=si_len
+ attr_si.data.resident.flags = 0;
+ */
+
+ /* Add STANDARD_INFORMATION to inode. */
+ memcpy(&(temp_new_record[new_temp_offset]),&attr_si, attr_si_len  );
+ new_temp_offset += attr_si_len;
+ memcpy(&(temp_new_record[new_temp_offset]),  si,  si_len);
+ new_temp_offset += si_len;
+
+ ntfs_debug("new_temp_offset [%d]",new_temp_offset);
+
+ kfree(si);
+ si=NULL;
+ } /****************************** end of STANDARD_INFORMATION *************/
+
+ /*
+ if (ntfs_sd_add_everyone(ni)) {
+ err = errno;
+ goto err_out;
+ }
+ rollback_sd = 1;
+ */
+
+
+
+ { /****************************** start of FILE_NAME *************/
+
+ ATTR_REC attr_fna;
+ int fn_len , attr_fna_len;
+ /** create FILE_NAME_ATTR **/
+ fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
+ fn = kcalloc(1,fn_len,GFP_KERNEL);
+ if (!fn)
+ {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, le16_to_cpu(dir_ni->seq_no));
+ fn->file_name_length = name_len;
+ fn->file_name_type = FILE_NAME_POSIX;
+ fn->creation_time = NTFS_TIME_OFFSET;
+ fn->last_data_change_time = NTFS_TIME_OFFSET;
+ fn->last_mft_change_time = NTFS_TIME_OFFSET;
+ fn->last_access_time = NTFS_TIME_OFFSET;
+ fn->data_size = cpu_to_sle64(ni->initialized_size);
+ fn->allocated_size = cpu_to_sle64(ni->allocated_size);
+ memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
+
+ /* Create FILE_NAME attribute. */
+ attr_fna_len = offsetof(ATTR_REC, data) + sizeof(attr_fna.data.resident) ;
+ attr_fna=(ATTR_REC)
+ {
+ .type = AT_FILE_NAME ,
+ .length = ( attr_fna_len + fn_len + 7 ) & ~7 ,
+ .non_resident = 0,
+ .name_length = 0,
+ .name_offset = 0,
+ .flags =  RESIDENT_ATTR_IS_INDEXED ,
+ .instance = (mrec->next_attr_instance) ++ ,
+ .data=
+ {
+ .resident=
+ {
+ .value_length = fn_len,
+ .value_offset = attr_fna_len  ,
+ .flags = 0 ,
+ }
+ },
+ };
+
+ /** insert FILE_NAME into new_file_record **/
+ memcpy(&(temp_new_record[new_temp_offset]) , &attr_fna,  attr_fna_len);
+ memcpy(&(temp_new_record[new_temp_offset + attr_fna_len]),fn,fn_len);
+ new_temp_offset += attr_fna.length;
+
+ ntfs_debug("new_temp_offset [%d]",new_temp_offset);
+
+/**********add to index ********************************************/
+ /* Add FILE_NAME attribute to index. */
+ if ((err = ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, le16_to_cpu(ni->seq_no))) ))
+ {
+ ntfs_error((VFS_I(dir_ni))->i_sb,"Failed to add entry to the index");
+ goto err_out;
+ }
+/*********************************************************/
+
+ kfree(fn);
+ fn=NULL;
+ } /****************************** end of FILE_NAME *************/
+
+ { /****************************** start of SECURITY_DESCRIPTOR *************/
+ ACL *acl;
+ ACCESS_ALLOWED_ACE *ace;
+ SID *sid;
+ ATTR_REC attr_sd;
+ int sd_len, attr_sd_len;
+
+ /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
+ /*
+ * Calculate security descriptor length. We have 2 sub-authorities in
+ * owner and group SIDs, but structure SID contain only one, so add
+ * 4 bytes to every SID.
+ */
+ sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
+ sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
+ sd = kcalloc(1,sd_len,GFP_KERNEL);
+ if (!sd)
+ {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ sd->revision = 1;
+ sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
+
+ sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
+ sid->revision = 1;
+ sid->sub_authority_count = 2;
+ sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
+ sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
+ sid->identifier_authority.value[5] = 5;
+ sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd);
+
+ sid = (SID *)((u8 *)sid + sizeof(SID) + 4);
+ sid->revision = 1;
+ sid->sub_authority_count = 2;
+ sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
+ sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
+ sid->identifier_authority.value[5] = 5;
+ sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd);
+
+ acl = (ACL *)((u8 *)sid + sizeof(SID) + 4);
+ acl->revision = 2;
+ acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
+ acl->ace_count = cpu_to_le16(1);
+ sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd);
+
+ ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL));
+ ace->type = ACCESS_ALLOWED_ACE_TYPE;
+ ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+ ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
+ ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */
+ ace->sid.revision = 1;
+ ace->sid.sub_authority_count = 1;
+ ace->sid.sub_authority[0] = 0;
+ ace->sid.identifier_authority.value[5] = 1;
+
+ /* Create the attribute */
+ attr_sd_len = offsetof(ATTR_REC, data) + sizeof(attr_sd.data.resident) ;
+ attr_sd=(ATTR_REC)
+ {
+ .type = AT_SECURITY_DESCRIPTOR  ,
+ .length = ( attr_sd_len + sd_len + 7 ) & ~7 ,
+ .non_resident = 0,
+ .name_length = 0,
+ .name_offset = 0,
+ .flags =  0 ,
+ .instance = (mrec->next_attr_instance) ++ ,
+ .data=
+ {
+ .resident=
+ {
+ .value_length = sd_len,
+ .value_offset = attr_sd_len  ,
+ .flags = 0 ,
+ }
+ },
+ };
+
+ /** insert FILE_NAME into new_file_record **/
+ memcpy(&(temp_new_record[new_temp_offset]) , &attr_sd,  attr_sd_len);
+ memcpy(&(temp_new_record[new_temp_offset + attr_sd_len]), sd ,sd_len);
+ new_temp_offset += attr_sd.length;
+ ntfs_debug("new_temp_offset [%d]",new_temp_offset);
+/************************/
+
+ kfree(sd);
+ sd=NULL;
+ } /****************************** end of SECURITY_DESCRIPTOR *************/
+
+ { /****************************** start of DATA *************/
+ /***  $DATA (0x80)   **/
+ ATTR_REC attr_data;
+ int attr_data_len= offsetof(ATTR_REC, data) + sizeof(attr_data.data.resident) ;
+ attr_data=(ATTR_REC)
+ {
+ .type = AT_DATA ,
+ .length = attr_data_len,
+ .non_resident = 0,
+ .name_length = 0,
+ .name_offset = 0,
+ .flags =  0 ,
+ .instance = (mrec->next_attr_instance) ++ ,
+ .data=
+ {
+ .resident=
+ {
+ .value_length = 0,
+ .value_offset = attr_data_len  ,
+ .flags = 0 ,
+ }
+ },
+ };
+ /** insert DATA into new_file_record **/
+ memcpy(&(temp_new_record[new_temp_offset]),&attr_data, attr_data_len );
+ new_temp_offset += attr_data_len ;
+ ntfs_debug("new_temp_offset [%d]",new_temp_offset);
+
+ } /****************************** end of DATA *************/
+
+ { /****************************** start of $END *************/
+ /***  $AT_END              = cpu_to_le32(0xffffffff) */
+ ATTR_REC attr_end ;
+ int attr_end_len= offsetof(ATTR_REC, data) + sizeof(attr_end.data.resident) ;
+ attr_end=(ATTR_REC)
+ {
+ .type = AT_END ,
+ .length = attr_end_len ,
+ .non_resident = 0,
+ .name_length = 0,
+ .name_offset = 0,
+ .flags =  0 ,
+ .instance = (mrec->next_attr_instance) ++ ,
+ .data=
+ {
+ .resident=
+ {
+ .value_length = 0,
+ .value_offset = attr_end_len  ,
+ .flags = 0 ,
+ }
+ },
+ };
+ /** insert END into new_file_record **/
+ memcpy(&(temp_new_record[new_temp_offset]),&attr_end, attr_end_len);
+ new_temp_offset += attr_end_len ;
+ ntfs_debug("new_temp_offset [%d]",new_temp_offset);
+
+ } /****************************** end of $END *************/
+
+
+ /**FIXME : it do not support hard link **/
+ mrec->link_count = cpu_to_le16(1);
+ /** MUST set this **/
+ mrec->bytes_in_use = new_temp_offset;
+
+ flush_dcache_mft_record_page(ni);
+ mark_mft_record_dirty(ni);  /**ntfs_inode_mark_dirty(ni); int ntfs-3g**/
+ unmap_mft_record(ni);
+
+ (VFS_I(ni))->i_op = &ntfs_file_inode_ops;
+ (VFS_I(ni))->i_fop = &ntfs_file_ops;
+
+ if (NInoMstProtected(ni))
+ {
+ (VFS_I(ni))->i_mapping->a_ops = &ntfs_mst_aops;
+ }
+ else
+ {
+ (VFS_I(ni))->i_mapping->a_ops = &ntfs_normal_aops;
+ }
+
+ (VFS_I(ni))->i_blocks = ni->allocated_size >> 9;
+
+
+ ntfs_debug("Done.");
+ return ni;
+err_out:
+ ntfs_debug("Failed.");
+
+ /* TODO : if ni->nr_extents had been set  should been clear here **/
+
+ if(fn)
+ {
+ kfree(fn);
+ fn=NULL;
+ }
+ if(si)
+ {
+ kfree(si);
+ si=NULL;
+ }
+ if(sd)
+ {
+ kfree(sd);
+ sd=NULL;
+ }
+
+ if(mrec)
+ {
+ if (ntfs_mft_record_free(ni->vol, ni,mrec))
+ {
+ ntfs_debug("Failed to free MFT record.  "
+ "Leaving inconsistent metadata. Run chkdsk.\n");
+ }
+ inode_dec_link_count(VFS_I(ni)); //(VFS_I(ni))->i_nlink--;
+ unmap_mft_record(ni);
+ atomic_dec(&(VFS_I(ni))->i_count);
+ mrec=NULL;
+ }
+ return ERR_PTR(err);
+}
+
+/**
+ * Some wrappers around __ntfs_create() ...
+ */
+ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
+ dev_t type)
+{
+ /*TODO : type could be { S_IFREG S_IFDIR  S_IFIFO  S_IFSOCK } */
+ if (type != S_IFREG )
+ {
+ ntfs_error((VFS_I(dir_ni))->i_sb,"Invalid arguments.");
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+ return __ntfs_create(dir_ni, name, name_len, type);
+}
+
+static int ntfs_create_inode(struct inode *dir,
+ struct dentry *dent,
+ umode_t mode,
+ bool pn )
+{
+ ntfschar *uname;
+ int uname_len;
+ ntfs_inode* ni ;
+
+ /* Convert the name of the dentry to Unicode. */
+ uname_len = ntfs_nlstoucs(NTFS_SB(dir->i_sb), dent->d_name.name, dent->d_name.len, &uname);
+ if (uname_len < 0)
+ {
+ if (uname_len != -ENAMETOOLONG)
+ {
+ ntfs_error(dir->i_sb, "Failed to convert name to Unicode.");
+ }
+ return uname_len;
+ }
+
+
+ /* create file and inode */
+ ni = ntfs_create(NTFS_I(dir), uname, uname_len , mode & S_IFMT  );
+ kmem_cache_free(ntfs_name_cache, uname);
+ if(likely(!IS_ERR(ni)))
+ {
+ d_instantiate(dent,VFS_I(ni));
+ /* TODO : modify    dir->i_mtime  to CURRENT_TIME */
+ ntfs_debug("Done.");
+ return 0;
+ }
+ else
+ {
+ ntfs_error(dir->i_sb, "ntfs_create error! dentry->d_name.name[%s]", dent->d_name.name);
+ return  PTR_ERR(ni);
+ }
+
+}
+
+/************************* unlink support **********/
+
+/*
+static int ntfs_index_rm_node(ntfs_index_context *icx)
+{
+ int entry_pos, pindex;
+ VCN vcn;
+ INDEX_BLOCK *ib = NULL;
+ INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry;
+ INDEX_HEADER *ih;
+ u32 new_size;
+ int delta, ret = STATUS_ERROR;
+
+ ntfs_debug("Entering");
+
+ if (!icx->ia_na) {
+ icx->ia_na = ntfs_ia_open(icx, icx->ni);
+ if (!icx->ia_na)
+ return STATUS_ERROR;
+ }
+
+ ib = ntfs_malloc(icx->block_size);
+ if (!ib)
+ return STATUS_ERROR;
+
+ ie_succ = ntfs_ie_get_next(icx->entry);
+ entry_pos = icx->parent_pos[icx->pindex]++;
+ pindex = icx->pindex;
+descend:
+ vcn = ntfs_ie_get_vcn(ie_succ);
+ if (ntfs_ib_read(icx, vcn, ib))
+ goto out;
+
+ ie_succ = ntfs_ie_get_first(&ib->index);
+
+ if (ntfs_icx_parent_inc(icx))
+ goto out;
+
+ icx->parent_vcn[icx->pindex] = vcn;
+ icx->parent_pos[icx->pindex] = 0;
+
+ if ((ib->index.ih_flags & NODE_MASK) == INDEX_NODE)
+ goto descend;
+
+ if (ntfs_ih_zero_entry(&ib->index)) {
+ errno = EIO;
+ ntfs_log_perror("Empty index block");
+ goto out;
+ }
+
+ ie = ntfs_ie_dup(ie_succ);
+ if (!ie)
+ goto out;
+
+ if (ntfs_ie_add_vcn(&ie))
+ goto out2;
+
+ ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry));
+
+ if (icx->is_in_root)
+ ih = &icx->ir->index;
+ else
+ ih = &icx->ib->index;
+
+ delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length);
+ new_size = le32_to_cpu(ih->index_length) + delta;
+ if (delta > 0) {
+ if (icx->is_in_root) {
+ ret = ntfs_ir_make_space(icx, new_size);
+ if (ret != STATUS_OK)
+ goto out2;
+
+ ih = &icx->ir->index;
+ entry = ntfs_ie_get_by_pos(ih, entry_pos);
+
+ } else if (new_size > le32_to_cpu(ih->allocated_size)) {
+ icx->pindex = pindex;
+ ret = ntfs_ib_split(icx, icx->ib);
+ if (ret == STATUS_OK)
+ ret = STATUS_KEEP_SEARCHING;
+ goto out2;
+ }
+ }
+
+ ntfs_ie_delete(ih, entry);
+ ntfs_ie_insert(ih, ie, entry);
+
+ if (icx->is_in_root) {
+ if (ntfs_ir_truncate(icx, new_size))
+ goto out2;
+ } else
+ if (ntfs_icx_ib_write(icx))
+ goto out2;
+
+ ntfs_ie_delete(&ib->index, ie_succ);
+
+ if (ntfs_ih_zero_entry(&ib->index)) {
+ if (ntfs_index_rm_leaf(icx))
+ goto out2;
+ } else
+ if (ntfs_ib_write(icx, ib))
+ goto out2;
+
+ ret = STATUS_OK;
+out2:
+ free(ie);
+out:
+ free(ib);
+ return ret;
+}
+*/
+
+static int ntfs_ie_end(INDEX_ENTRY *ie)
+{
+    return ie->flags & INDEX_ENTRY_END || !ie->length;
+}
+
+static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
+{
+    return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset));
+}
+static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie)
+{
+    return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length));
+}
+
+
+static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie)
+{
+ u32 new_size;
+ ntfs_debug("Entering");
+ new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length);
+ ih->index_length = cpu_to_le32(new_size);
+ memmove(ie, (u8 *)ie + le16_to_cpu(ie->length), new_size - ((u8 *)ie - (u8 *)ih));
+ ntfs_debug("Done");
+}
+
+
+
+static u8 *ntfs_ie_get_end(INDEX_HEADER *ih)
+{
+ /* FIXME: check if it isn't overflowing the index block size */
+ return (u8 *)ih + le32_to_cpu(ih->index_length);
+}
+
+
+static int ntfs_ih_numof_entries(INDEX_HEADER *ih)
+{
+ int n;
+ INDEX_ENTRY *ie;
+ u8 *end;
+
+ ntfs_debug("Entering");
+
+ end = ntfs_ie_get_end(ih);
+ ie = ntfs_ie_get_first(ih);
+ for (n = 0; !ntfs_ie_end(ie) && (u8 *)ie < end; n++)
+ ie = ntfs_ie_get_next(ie);
+ return n;
+}
+
+static int ntfs_ih_one_entry(INDEX_HEADER *ih)
+{
+ return (ntfs_ih_numof_entries(ih) == 1);
+}
+/**
+ * ntfs_index_rm - remove entry from the index
+ * @icx: index context describing entry to delete
+ *
+ * Delete entry described by @icx from the index. 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.
+ */
+static int ntfs_index_rm(ntfs_index_context *icx)
+{
+ INDEX_HEADER *ih;
+ int ret = STATUS_OK;
+
+ ntfs_debug("Entering");
+
+ if (!icx || (!icx->ia && !icx->ir) || ntfs_ie_end(icx->entry))
+ {
+ ntfs_debug("Invalid arguments.");
+ ret = -EINVAL;
+ goto err_out;
+ }
+ if (icx->is_in_root)
+ {
+ ih = &icx->ir->index;
+ }
+ else
+ {
+ ih = &icx->ia->index;
+ }
+
+ if (icx->entry->flags & INDEX_ENTRY_NODE)
+ {
+ /* not support
+ ret = ntfs_index_rm_node(icx);
+ */
+ ret =  -EOPNOTSUPP ;
+ goto err_out;
+ }
+ else if (icx->is_in_root || !ntfs_ih_one_entry(ih))
+ {
+ ntfs_ie_delete(ih, icx->entry);
+
+ if (icx->is_in_root)
+ {
+ ret = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));
+ if (ret != STATUS_OK)
+ {
+ goto err_out;
+ }
+ ntfs_debug("Before flush_dcache_mft_record_page ");
+ flush_dcache_mft_record_page(icx->actx->ntfs_ino);
+
+ ntfs_debug("Before mark_mft_record_dirty ");
+ mark_mft_record_dirty(icx->actx->ntfs_ino);
+ }
+ else
+ {
+ /* shut by Gzged
+ if (ntfs_icx_ib_write(icx))
+ {
+ goto err_out;
+ }
+ */
+ ntfs_debug("Before ntfs_index_entry_flush_dcache_page ");
+ ntfs_index_entry_flush_dcache_page(icx);
+ ntfs_debug("Before ntfs_index_entry_mark_dirty ");
+ ntfs_index_entry_mark_dirty(icx);
+ }
+ }
+ else
+ {
+ ret =  -EOPNOTSUPP ;
+ goto err_out;
+ /** not support yet
+ if (ntfs_index_rm_leaf(icx))
+ {
+ goto err_out;
+ }
+ **/
+ }
+
+
+err_out:
+ ntfs_debug("Done ");
+ return ret;
+}
+/** 20091014 **/
+int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen)
+{
+ int ret = STATUS_ERROR;
+ ntfs_index_context *icx;
+
+ icx = ntfs_index_ctx_get(ni);
+ if (!icx)
+ {
+ return -1;
+ }
+
+ while (1)
+ {
+ /** use my func
+ if (ntfs_index_lookup(key, keylen, icx))
+ */
+ if ( (ret = ntfs_lookup_inode_by_key (key, keylen, icx) ) )
+ {
+ ntfs_debug("ntfs_lookup_inode_by_key faild ...");
+ goto err_out;
+ }
+/*********debug print
+ {
+ struct qstr nls_name;
+ nls_name.name = NULL;
+ nls_name.len = (unsigned)ntfs_ucstonls(ni->vol,
+                ((FILE_NAME_ATTR *)icx->data)->file_name , icx->data_len,
+                (unsigned char**)&nls_name.name, 0);
+ ntfs_debug("icx data name=[%s]",nls_name.name);
+ kfree(nls_name.name);
+ }
+
+ if (((FILE_NAME_ATTR *)icx->data)->file_attributes & FILE_ATTR_REPARSE_POINT)
+ {
+ ntfs_debug("not support faild ");
+ ret = -EOPNOTSUPP;
+ goto err_out;
+ } ********/
+/*********debug print ********/
+
+ ret = ntfs_index_rm(icx);
+ if (ret == STATUS_OK)
+ {
+ ntfs_debug("ntfs_index_rm Done");
+ break;
+ }
+ else
+ {
+ ntfs_debug("ntfs_index_rm faild");
+ goto err_out;
+ }
+ /*
+ flush_dcache_mft_record_page(icx->actx->ntfs_ino);
+ mark_mft_record_dirty(icx->actx->ntfs_ino);
+ */
+ /*FIXME:Gzged change
+ ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
+ ntfs_index_ctx_reinit(icx);
+ ***************/
+        ntfs_index_ctx_put(icx);
+ ntfs_index_ctx_get(ni);
+ }
+
+ /*
+ ntfs_debug("Before flush_dcache_mft_record_page ");
+ flush_dcache_mft_record_page(icx->actx->ntfs_ino);
+ ntfs_debug("Before mark_mft_record_dirty ");
+ mark_mft_record_dirty(icx->actx->ntfs_ino);
+ */
+ /*
+ ntfs_debug("Before ntfs_index_entry_flush_dcache_page ");
+ ntfs_index_entry_flush_dcache_page(icx);
+ ntfs_debug("Before ntfs_index_entry_mark_dirty ");
+ ntfs_index_entry_mark_dirty(icx);
+ */
+
+err_out:
+ ntfs_debug("Delete Done");
+ if(icx)
+ {
+ ntfs_index_ctx_put(icx);
+ }
+ return ret;
+}
+
+static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
+{
+ /** case all attr **/
+    return ntfs_attr_lookup(0, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx);
+}
+
+
+//static const char *es = "  Leaving inconsistent metadata.  Unmount and run chkdsk.";
+typedef bool BOOL;
+#include "lcnalloc.h"
+int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni )
+{
+ ntfs_attr_search_ctx *actx = NULL;
+ MFT_RECORD* mrec;
+ FILE_NAME_ATTR *fn = NULL;
+ ntfs_volume* vol=ni->vol;
+ /*
+ BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
+ BOOL case_sensitive_match = TRUE;
+ */
+ int err = 0;
+
+ ntfs_debug("Entering");
+
+ mrec = map_mft_record(ni);
+ if (IS_ERR(mrec)) {
+ err = PTR_ERR(mrec);
+ mrec = NULL;
+ goto err_out;
+ }
+
+    if ( (mrec->flags & MFT_RECORD_IS_DIRECTORY) )
+ {
+ ntfs_debug("Invalid arguments.");
+ err=  -EINVAL;
+ goto err_out;
+ }
+
+ if (!ni || !dir_ni )
+ {
+ ntfs_debug("Invalid arguments.");
+ err=  -EINVAL;
+ goto err_out;
+ }
+
+ if (ni->nr_extents == -1)
+ ni = ni->ext.base_ntfs_ino;
+ if (dir_ni->nr_extents == -1)
+ dir_ni = dir_ni->ext.base_ntfs_ino;
+
+
+/******************************************* get fn ******************/
+ /*
+ * 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.
+ */
+ actx = ntfs_attr_get_search_ctx(ni, mrec);
+ if (!actx)
+ {
+ goto err_out;
+ }
+ while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE,
+ 0, NULL, 0, actx)) {
+/*debuger need...
+ char *s;
+ **/
+ BOOL case_sensitive = IGNORE_CASE;
+
+ fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
+ le16_to_cpu(actx->attr->data.resident.value_offset));
+/*debuger need...
+ s = ntfs_attr_name_get(fn->file_name, fn->file_name_length);
+ ntfs_debug("name: '%s'  type: %d  dos: %d  win32: %d  "
+       "case: %d\n", s, fn->file_name_type,
+       looking_for_dos_name, looking_for_win32_name,
+       case_sensitive_match);
+ ntfs_attr_name_free(&s);
+ */
+/** all ways use posix name
+ if (looking_for_dos_name) {
+ if (fn->file_name_type == FILE_NAME_DOS)
+ break;
+ else
+ continue;
+ }
+ if (looking_for_win32_name) {
+ if  (fn->file_name_type == FILE_NAME_WIN32)
+ break;
+ else
+ continue;
+ }
+ **/
+
+ /* Ignore hard links from other directories */
+ if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) {
+ ntfs_debug("MFT record numbers don't match "
+       "(%llu != %llu)",
+       (long long unsigned)dir_ni->mft_no,
+       (long long unsigned)MREF_LE(fn->parent_directory));
+ continue;
+ }
+    
+/****all ways use posix case
+ if (fn->file_name_type == FILE_NAME_POSIX || case_sensitive_match)
+ */
+ case_sensitive = CASE_SENSITIVE;
+
+ /** all ways think name is equal
+ if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,
+ name, name_len, case_sensitive,
+ ni->vol->upcase, ni->vol->upcase_len))*/ {
+
+ /**  all ways think it`s posix name...
+ 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;
+ }
+ }
+/******************************************* get fn ******************/
+
+/*********** cut the entry down *****************/
+ if ( (err = ntfs_index_remove(dir_ni, fn, le32_to_cpu(actx->attr->data.resident.value_length)) ) )
+ {
+ ntfs_debug("ntfs_index_remove error.");
+ goto err_out;
+ }
+
+ mrec->link_count = cpu_to_le16(le16_to_cpu( mrec->link_count) - 1);
+/*********** cut the entry down *****************/
+
+
+/********************flush ***************/
+ flush_dcache_mft_record_page(ni);
+ mark_mft_record_dirty(ni);
+/********************flush end ***************/
+
+/********************cut down all run list ***************/
+ ntfs_attr_put_search_ctx(actx);
+ actx = ntfs_attr_get_search_ctx(ni, mrec);
+
+ err=  STATUS_OK ;
+ ntfs_debug("Before while ");
+ while (!ntfs_attrs_walk(actx))
+ {
+ ntfs_debug("new loop ");
+ if (actx->attr->non_resident)
+ {
+ ntfs_debug("Inner case ");
+ /*
+ runlist *rl;
+ rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr,
+ NULL);
+ if (!rl) {
+ err = -EOPNOTSUPP ;
+ ntfs_debug("Failed to decompress runlist.  "
+ "Leaving inconsistent metadata.\n");
+ continue;
+ }
+ if (ntfs_cluster_free_from_rl(ni->vol, rl)) {
+ err = -EOPNOTSUPP ;
+ ntfs_debug("Failed to free clusters.  "
+ "Leaving inconsistent metadata.\n");
+ continue;
+ }
+ free(rl);
+ */
+
+ /* alloc_change < 0 */
+ /* Free the clusters.
+ err = ntfs_cluster_free(ni, 0, -1, actx);*/
+
+ ntfs_debug("before __ntfs_cluster_free ");
+ err = __ntfs_cluster_free(ni, 0, -1, actx, false);
+ if (unlikely(err < 0))
+ {
+ ntfs_error(vol->sb, "Failed to release cluster(s) (error code "
+ "%lli).  Unmount and run chkdsk to recover "
+ "the lost cluster(s).", (long long)err);
+ NVolSetErrors(vol);
+ err = 0;
+ }
+ /* Truncate the runlist.  NO NEED
+ err = ntfs_rl_truncate_nolock(vol, &ni->runlist, 0);
+ if (unlikely(err || IS_ERR(actx->mrec)))
+ {
+ ntfs_error(vol->sb, "Failed to %s (error code %li).%s",
+ IS_ERR(actx->mrec) ?
+ "restore attribute search context" :
+ "truncate attribute runlist",
+ IS_ERR(actx->mrec) ? PTR_ERR(actx->mrec) : err, es);
+ err = -EIO;
+ goto err_out;
+ }*/
+ ntfs_debug("before flush_dcache_mft_record_page actx->ntfs_ino[%p]",actx->ntfs_ino);
+ flush_dcache_mft_record_page(actx->ntfs_ino);
+ ntfs_debug("before mark_mft_record_dirty actx->ntfs_ino[%p]",actx->ntfs_ino);
+ mark_mft_record_dirty(actx->ntfs_ino);
+ }
+ }
+ if (err )
+ {
+ ntfs_debug("Attribute enumeration failed.  "
+ "Probably leaving inconsistent metadata.\n");
+ }
+ /* All extents should be attached after attribute walk. */
+ while (ni->nr_extents)
+ {
+ ntfs_error(vol->sb,"need use ntfs_extent_mft_record_free. not support now ");
+ /**FIXME
+ if ( ( err = ntfs_mft_record_free(ni->vol, *(ni->extent_nis) )))
+ {
+ ntfs_debug("Failed to free extent MFT record.  "
+ "Leaving inconsistent metadata.\n");
+ }
+ **/
+ }
+
+ if (ntfs_mft_record_free(ni->vol, ni,mrec))
+ {
+ err = -EIO;
+ ntfs_debug("Failed to free base MFT record.  "
+ "Leaving inconsistent metadata.\n");
+ }
+ /* FIXME */
+
+ flush_dcache_mft_record_page(ni);
+ mark_mft_record_dirty(ni);
+ /*FIXME:Gzged add */
+ ntfs_debug("before unmap_mft_record.");
+ unmap_mft_record(ni);
+ ni = NULL;
+ mrec=NULL;
+
+
+ /** Gzged shut now
+ ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);
+ */
+err_out:
+ if (actx)
+ ntfs_attr_put_search_ctx(actx);
+ if (mrec)
+ unmap_mft_record(ni);
+ if (err)
+ {
+ ntfs_debug("Could not delete file");
+ return err;
+ }
+ else
+ {
+ ntfs_debug("Done.");
+ return 0;
+ }
+}
+
+static int ntfs_unlink_inode(struct inode *pi,struct dentry *pd)
+{
+ ntfs_inode* ni = NTFS_I(pd->d_inode);
+ int err = -ENOENT;
+
+ ntfs_debug("Entering");
+ BUG_ON(!ni);
+
+ err =   ntfs_delete(ni,NTFS_I(pi));
+ if(err)
+ {
+ ntfs_debug("Faile");
+ return err;
+ }
+ else
+ {
+ (VFS_I(ni))->i_ctime = pi->i_ctime;
+ inode_dec_link_count(VFS_I(ni)); //(VFS_I(ni))->i_nlink--;
+ ntfs_debug("Done");
+ return  err;
+ }
+}
 /**
  * Inode operations for directories.
  */
 const struct inode_operations ntfs_dir_inode_ops = {
  .lookup = ntfs_lookup, /* VFS: Lookup directory. */
+ .create = ntfs_create_inode,
+ .unlink = ntfs_unlink_inode,
 };
 
 /**
--
2.9.3


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linux-NTFS-Dev mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/linux-ntfs-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [PATCH] Patch for NTFS Kernel tree. To add simple create and unlink operation.

Anton Altaparmakov-2
Hi,

I had a very quick experiment applying your patch and testing it.  It failed with errors on the second file create!  And running fsck afterwards showed the volume is corrupt.  Mounting again after repair and deleting the file then unmounting and running fsck again showed corruption.

So I am afraid this patch is totally broken and there is no way that is going into the kernel.  Feel free to fix it and send an updated, fixed patch and I would be happy to have a look.  But please do some basic testing first!  Clearly this patch is totally untested as the only thing it seems to be good for is to cause volume corruption...

Best regards,

        Anton

> On 7 Jul 2017, at 08:34, [hidden email] wrote:
>
> From: Zhigang Gao <gzg1984@icloud .com>
>
> ---
> fs/ntfs/Makefile |   25 +-
> fs/ntfs/aops.h   |    2 +
> fs/ntfs/attrib.c |   26 +-
> fs/ntfs/dir.c    |  602 ++++++++++++++++++++++++
> fs/ntfs/file.c   |    6 +
> fs/ntfs/index.h  |    1 +
> fs/ntfs/mft.c    |   80 ++++
> fs/ntfs/mft.h    |    1 +
> fs/ntfs/namei.c  | 1364 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 9 files changed, 2102 insertions(+), 5 deletions(-)
>
> diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
> index 2ff263e..3edb4e2 100644
> --- a/fs/ntfs/Makefile
> +++ b/fs/ntfs/Makefile
> @@ -1,14 +1,33 @@
> # Rules for making the NTFS driver.
> -
> +ifneq ($(KERNELRELEASE),)
> obj-$(CONFIG_NTFS_FS) += ntfs.o
>
> ntfs-y := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
> -  index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
> -  unistr.o upcase.o
> +  index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
> +  unistr.o upcase.o
>
> ntfs-$(CONFIG_NTFS_RW) += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
>
> ccflags-y := -DNTFS_VERSION=\"2.1.32\"
> ccflags-$(CONFIG_NTFS_DEBUG) += -DDEBUG
> ccflags-$(CONFIG_NTFS_RW) += -DNTFS_RW
> +else
> +
> +KERNEL ?= /lib/modules/`uname -r`/build
> +
> +default:
> + CONFIG_NTFS_FS=m CONFIG_NTFS_RW=y CONFIG_NTFS_DEBUG=y $(MAKE) -C $(KERNEL) M=$$PWD
> +
> +
> +.PHONY : install help clean
> +help:
> + $(MAKE) -C $(KERNEL) M=$$PWD help
> +
> +install : default
> + $(MAKE) -C $(KERNEL) M=$$PWD modules_install
> + depmod -A
> +
> +clean:
> + make -C $(KERNEL) M=`pwd` clean
>
> +endif
> diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
> index 820d6ea..4805986 100644
> --- a/fs/ntfs/aops.h
> +++ b/fs/ntfs/aops.h
> @@ -39,8 +39,10 @@
>  */
> static inline void ntfs_unmap_page(struct page *page)
> {
> + ntfs_debug("Entering .");
> kunmap(page);
> put_page(page);
> + ntfs_debug("done .");
> }
>
> /**
> diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
> index 44a39a0..0092d14 100644
> --- a/fs/ntfs/attrib.c
> +++ b/fs/ntfs/attrib.c
> @@ -599,20 +599,41 @@ static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
> * Iterate over attributes in mft record starting at @ctx->attr, or the
> * attribute following that, if @ctx->is_first is 'true'.
> */
> + ntfs_debug("Entering. type=[0x%x] is_first[%d]", type,ctx->is_first);
> if (ctx->is_first) {
> a = ctx->attr;
> ctx->is_first = false;
> - } else
> + }
> + else
> + {
> a = (ATTR_RECORD*)((u8*)ctx->attr +
> le32_to_cpu(ctx->attr->length));
> + }
> +
> for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
> if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +
> le32_to_cpu(ctx->mrec->bytes_allocated))
> + {
> + ntfs_error(vol->sb, "IN LOOP breaker."
> + "type=[0x%x],a->type[0x%x],a->length[%d],"
> + "a[%p],ctx->mrec[%p],ctx->mrec->bytes_allocated[%d]"
> + ,type,a->type,a->length,
> + a,ctx->mrec,le32_to_cpu(ctx->mrec->bytes_allocated));
> break;
> + }
> ctx->attr = a;
> + if (type != AT_UNUSED)
> + {
> if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
> a->type == AT_END))
> return -ENOENT;
> + }
> + else
> + {
> + if ( a->type == AT_END)
> + return -ENOENT;
> + }
> +
> if (unlikely(!a->length))
> break;
> if (a->type != type)
> @@ -1434,6 +1455,8 @@ int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type)
>  */
> int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
> {
> + BUG_ON(!m);
> + BUG_ON(!a);
> ntfs_debug("Entering for new_size %u.", new_size);
> /* Align to 8 bytes if it is not already done. */
> if (new_size & 7)
> @@ -1455,6 +1478,7 @@ int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
> if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length))
> a->length = cpu_to_le32(new_size);
> }
> + ntfs_debug("Done.");
> return 0;
> }
>
> diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
> index 0ee19ec..caf57c15 100644
> --- a/fs/ntfs/dir.c
> +++ b/fs/ntfs/dir.c
> @@ -77,6 +77,608 @@ ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
>  *       removes them again after the write is complete after which it
>  *       unlocks the page.
>  */
> +#include "index.h"
> +#include "layout.h"
> +#include "types.h"
> +
> +/* Author: Gzged
> + * Caller is in namei.c
> + */
> +int ntfs_lookup_inode_by_key (const void *key, const int key_len, ntfs_index_context *ictx)
> +{
> + ntfs_inode* dir_ni = ictx->idx_ni ;
> + const ntfschar* uname = ((FILE_NAME_ATTR *)key)->file_name ;
> + const int uname_len = ((FILE_NAME_ATTR *)key)->file_name_length;
> +
> + ntfs_volume *vol = dir_ni->vol;
> + struct super_block *sb = vol->sb;
> + MFT_RECORD *m;
> + INDEX_ROOT *ir;
> + INDEX_ENTRY *ie;
> + INDEX_ALLOCATION *ia;
> + u8 *index_end;
> + /*
> + u64 mref;
> + */
> + ntfs_attr_search_ctx *ctx;
> + int err, rc;
> + VCN vcn, old_vcn;
> + struct address_space *ia_mapping;
> + struct page *page;
> + u8 *kaddr;
> +
> + ntfs_debug("Entering.");
> + BUG_ON(!S_ISDIR(VFS_I(dir_ni)->i_mode));
> + BUG_ON(NInoAttr(dir_ni));
> + /* Get hold of the mft record for the directory. */
> + m = map_mft_record(dir_ni);
> + if (IS_ERR(m))
> + {
> + ntfs_error(sb, "map_mft_record() failed with error code %ld.",
> + -PTR_ERR(m));
> + return ERR_MREF(PTR_ERR(m));
> + }
> + ctx = ntfs_attr_get_search_ctx(dir_ni, m);
> + if (unlikely(!ctx)) {
> + err = -ENOMEM;
> + goto err_out;
> + }
> + /* Find the index root attribute in the mft record. */
> + err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
> + 0, ctx);
> + if (unlikely(err)) {
> + if (err == -ENOENT) {
> + ntfs_error(sb, "Index root attribute missing in "
> + "directory inode 0x%lx.",
> + dir_ni->mft_no);
> + err = -EIO;
> + }
> + goto err_out;
> + }
> + /* Get to the index root value (it's been verified in read_inode). */
> + ir = (INDEX_ROOT*)((u8*)ctx->attr +
> + le16_to_cpu(ctx->attr->data.resident.value_offset));
> + index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
> + /* The first index entry. */
> + ie = (INDEX_ENTRY*)((u8*)&ir->index +
> + le32_to_cpu(ir->index.entries_offset));
> + /*
> + * Loop until we exceed valid memory (corruption case) or until we
> + * reach the last entry.
> + */
> + for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
> + /* Bounds checks. */
> + ictx->is_in_root = true;
> + ictx->ir = ir;
> + ictx->entry = ie;
> + ictx->base_ni = dir_ni;
> + ictx->actx = ctx;
> + ictx->ia = NULL;
> + ictx->page = NULL;
> +
> + if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
> + sizeof(INDEX_ENTRY_HEADER) > index_end ||
> + (u8*)ie + le16_to_cpu(ie->key_length) >
> + index_end)
> + goto dir_err_out;
> + /*
> + * The last entry cannot contain a name. It can however contain
> + * a pointer to a child node in the B+tree so we just break out.
> + */
> + if (ie->flags & INDEX_ENTRY_END)
> + break;
> + /*
> + * We perform a case sensitive comparison and if that matches
> + * we are done and return the mft reference of the inode (i.e.
> + * the inode number together with the sequence number for
> + * consistency checking). We convert it to cpu format before
> + * returning.
> + */
> +
> + if (ntfs_are_names_equal(uname, uname_len,
> + (ntfschar*)&ie->key.file_name.file_name,
> + ie->key.file_name.file_name_length,
> + CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
> +found_it:
> + /*
> + * We have a perfect match, so we don't need to care
> + * about having matched imperfectly before, so we can
> + * free name and set *res to NULL.
> + * However, if the perfect match is a short file name,
> + * we need to signal this through *res, so that
> + * ntfs_lookup() can fix dcache aliasing issues.
> + * As an optimization we just reuse an existing
> + * allocation of *res.
> + */
> + /*FIXME:Shut for now and maybe work in future. Author:Gzged
> + if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
> + if (!name) {
> + name = kmalloc(sizeof(ntfs_name),
> + GFP_NOFS);
> + if (!name) {
> + err = -ENOMEM;
> + goto err_out;
> + }
> + }
> + name->mref = le64_to_cpu(
> + ie->data.dir.indexed_file);
> + name->type = FILE_NAME_DOS;
> + name->len = 0;
> + *res = name;
> + } else {
> + kfree(name);
> + *res = NULL;
> + }
> + */
> + /*FIXME: Gzged mod
> + mref = le64_to_cpu(ie->data.dir.indexed_file);
> + ntfs_attr_put_search_ctx(ctx);
> + unmap_mft_record(dir_ni);
> + return mref;
> + */
> +
> +done:
> +            ictx->data = (u8*)ie +
> +                    le16_to_cpu(ie->data.vi.data_offset);
> +            ictx->data_len = le16_to_cpu(ie->data.vi.data_length);
> +            ntfs_debug("Done.");
> +            return err;
> +
> + }
> + /*
> + * For a case insensitive mount, we also perform a case
> + * insensitive comparison (provided the file name is not in the
> + * POSIX namespace). If the comparison matches, and the name is
> + * in the WIN32 namespace, we cache the filename in *res so
> + * that the caller, ntfs_lookup(), can work on it. If the
> + * comparison matches, and the name is in the DOS namespace, we
> + * only cache the mft reference and the file name type (we set
> + * the name length to zero for simplicity).
> + */
> +// if (!NVolCaseSensitive(vol) &&
> +// ie->key.file_name.file_name_type &&
> +// ntfs_are_names_equal(uname, uname_len,
> +// (ntfschar*)&ie->key.file_name.file_name,
> +// ie->key.file_name.file_name_length,
> +// IGNORE_CASE, vol->upcase, vol->upcase_len)) {
> +// int name_size = sizeof(ntfs_name);
> +// u8 type = ie->key.file_name.file_name_type;
> +// u8 len = ie->key.file_name.file_name_length;
> +//
> +// /* Only one case insensitive matching name allowed. */
> +// if (name) {
> +// ntfs_error(sb, "Found already allocated name "
> +// "in phase 1. Please run chkdsk "
> +// "and if that doesn't find any "
> +// "errors please report you saw "
> +// "this message to "
> +// "linux-ntfs-dev@lists."
> +// "sourceforge.net.");
> +// goto dir_err_out;
> +// }
> +//
> +// if (type != FILE_NAME_DOS)
> +// name_size += len * sizeof(ntfschar);
> +// name = kmalloc(name_size, GFP_NOFS);
> +// if (!name) {
> +// err = -ENOMEM;
> +// goto err_out;
> +// }
> +// name->mref = le64_to_cpu(ie->data.dir.indexed_file);
> +// name->type = type;
> +// if (type != FILE_NAME_DOS) {
> +// name->len = len;
> +// memcpy(name->name, ie->key.file_name.file_name,
> +// len * sizeof(ntfschar));
> +// } else
> +// name->len = 0;
> +// *res = name;
> +// }
> + /*
> + * Not a perfect match, need to do full blown collation so we
> + * know which way in the B+tree we have to go.
> + */
> + rc = ntfs_collate_names(uname, uname_len,
> + (ntfschar*)&ie->key.file_name.file_name,
> + ie->key.file_name.file_name_length, 1,
> + IGNORE_CASE, vol->upcase, vol->upcase_len);
> + /*
> + * If uname collates before the name of the current entry, there
> + * is definitely no such name in this index but we might need to
> + * descend into the B+tree so we just break out of the loop.
> + */
> + if (rc == -1)
> + break;
> + /* The names are not equal, continue the search. */
> + if (rc)
> + continue;
> + /*
> + * Names match with case insensitive comparison, now try the
> + * case sensitive comparison, which is required for proper
> + * collation.
> + */
> + rc = ntfs_collate_names(uname, uname_len,
> + (ntfschar*)&ie->key.file_name.file_name,
> + ie->key.file_name.file_name_length, 1,
> + CASE_SENSITIVE, vol->upcase, vol->upcase_len);
> + if (rc == -1)
> + break;
> + if (rc)
> + continue;
> + /*
> + * Perfect match, this will never happen as the
> + * ntfs_are_names_equal() call will have gotten a match but we
> + * still treat it correctly.
> + */
> + goto found_it;
> + }
> + /*
> + * We have finished with this index without success. Check for the
> + * presence of a child node and if not present return -ENOENT, unless
> + * we have got a matching name cached in name in which case return the
> + * mft reference associated with it.
> + */
> + if (!(ie->flags & INDEX_ENTRY_NODE)) {
> + /* FIXME:Gzged shut
> + if (name) {
> + ntfs_attr_put_search_ctx(ctx);
> + unmap_mft_record(dir_ni);
> + return name->mref;
> + }
> + ********/
> + ntfs_debug("Entry not found. ictx->is_in_root[%d]",ictx->is_in_root);
> +
> + /*FIXME:Gzged set
> + ictx->is_in_root = true;
> + ictx->ir = ir;
> + ictx->entry = ie;
> + ictx->base_ni = dir_ni;
> + ictx->actx = ctx;
> + ictx->ia = NULL;
> + ictx->page = NULL;
> + */
> + /*FIXME: Gzged mod ; do not release actx ....and so on
> + goto err_out;
> + */
> + return -ENOENT;
> + } /* Child node present, descend into it. */
> + /* Consistency check: Verify that an index allocation exists. */
> + if (!NInoIndexAllocPresent(dir_ni)) {
> + ntfs_error(sb, "No index allocation attribute but index entry "
> + "requires one. Directory inode 0x%lx is "
> + "corrupt or driver bug.", dir_ni->mft_no);
> + goto err_out;
> + }
> + /* Get the starting vcn of the index_block holding the child node. */
> + vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
> + ia_mapping = VFS_I(dir_ni)->i_mapping;
> + /*
> + * We are done with the index root and the mft record. Release them,
> + * otherwise we deadlock with ntfs_map_page().
> + */
> + ntfs_attr_put_search_ctx(ctx);
> + unmap_mft_record(dir_ni);
> + m = NULL;
> + ctx = NULL;
> +descend_into_child_node:
> + /*
> + * Convert vcn to index into the index allocation attribute in units
> + * of PAGE_SIZE and map the page cache page, reading it from
> + * disk if necessary.
> + */
> + page = ntfs_map_page(ia_mapping, vcn <<
> + dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
> + if (IS_ERR(page)) {
> + ntfs_error(sb, "Failed to map directory index page, error %ld.",
> + -PTR_ERR(page));
> + err = PTR_ERR(page);
> + goto err_out;
> + }
> + lock_page(page);
> + kaddr = (u8*)page_address(page);
> +fast_descend_into_child_node:
> + /* Get to the index allocation block. */
> + ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
> + dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
> + /* Bounds checks. */
> + if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
> + ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
> + "inode 0x%lx or driver bug.", dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + /* Catch multi sector transfer fixup errors. */
> + if (unlikely(!ntfs_is_indx_record(ia->magic))) {
> + ntfs_error(sb, "Directory index record with vcn 0x%llx is "
> + "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
> + (unsigned long long)vcn, dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
> + ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
> + "different from expected VCN (0x%llx). "
> + "Directory inode 0x%lx is corrupt or driver "
> + "bug.", (unsigned long long)
> + sle64_to_cpu(ia->index_block_vcn),
> + (unsigned long long)vcn, dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
> + dir_ni->itype.index.block_size) {
> + ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
> + "0x%lx has a size (%u) differing from the "
> + "directory specified size (%u). Directory "
> + "inode is corrupt or driver bug.",
> + (unsigned long long)vcn, dir_ni->mft_no,
> + le32_to_cpu(ia->index.allocated_size) + 0x18,
> + dir_ni->itype.index.block_size);
> + goto unm_err_out;
> + }
> + index_end = (u8*)ia + dir_ni->itype.index.block_size;
> + if (index_end > kaddr + PAGE_SIZE) {
> + ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
> + "0x%lx crosses page boundary. Impossible! "
> + "Cannot access! This is probably a bug in the "
> + "driver.", (unsigned long long)vcn,
> + dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
> + if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
> + ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
> + "inode 0x%lx exceeds maximum size.",
> + (unsigned long long)vcn, dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + /* The first index entry. */
> + ie = (INDEX_ENTRY*)((u8*)&ia->index +
> + le32_to_cpu(ia->index.entries_offset));
> + /*
> + * Iterate similar to above big loop but applied to index buffer, thus
> + * loop until we exceed valid memory (corruption case) or until we
> + * reach the last entry.
> + */
> + for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
> + /* Bounds check. */
> + if ((u8*)ie < (u8*)ia || (u8*)ie +
> + sizeof(INDEX_ENTRY_HEADER) > index_end ||
> + (u8*)ie + le16_to_cpu(ie->key_length) >
> + index_end) {
> + ntfs_error(sb, "Index entry out of bounds in "
> + "directory inode 0x%lx.",
> + dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + /*FIXME:Gzged set */
> + ictx->is_in_root = false;
> + ictx->ia = ia;
> + ictx->entry = ie;
> + ictx->actx = NULL;
> + ictx->base_ni = NULL;
> + ictx->page = page;
> + /*
> + * The last entry cannot contain a name. It can however contain
> + * a pointer to a child node in the B+tree so we just break out.
> + */
> + if (ie->flags & INDEX_ENTRY_END)
> + break;
> + /*
> + * We perform a case sensitive comparison and if that matches
> + * we are done and return the mft reference of the inode (i.e.
> + * the inode number together with the sequence number for
> + * consistency checking). We convert it to cpu format before
> + * returning.
> + */
> + BUG_ON(!PageLocked(ictx->page));
> +
> + if (ntfs_are_names_equal(uname, uname_len,
> + (ntfschar*)&ie->key.file_name.file_name,
> + ie->key.file_name.file_name_length,
> + CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
> +found_it2:
> + /*
> + * We have a perfect match, so we don't need to care
> + * about having matched imperfectly before, so we can
> + * free name and set *res to NULL.
> + * However, if the perfect match is a short file name,
> + * we need to signal this through *res, so that
> + * ntfs_lookup() can fix dcache aliasing issues.
> + * As an optimization we just reuse an existing
> + * allocation of *res.
> + */
> + /* Gzged shut
> + if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
> + if (!name) {
> + name = kmalloc(sizeof(ntfs_name),
> + GFP_NOFS);
> + if (!name) {
> + err = -ENOMEM;
> + goto unm_err_out;
> + }
> + }
> + name->mref = le64_to_cpu(
> + ie->data.dir.indexed_file);
> + name->type = FILE_NAME_DOS;
> + name->len = 0;
> + *res = name;
> + } else {
> + kfree(name);
> + *res = NULL;
> + }
> + */
> + /*Gzged shut
> + mref = le64_to_cpu(ie->data.dir.indexed_file);
> + unlock_page(page);
> + ntfs_unmap_page(page);
> + * return mref;
> + * */
> +            goto done;
> + }
> + /*
> + * For a case insensitive mount, we also perform a case
> + * insensitive comparison (provided the file name is not in the
> + * POSIX namespace). If the comparison matches, and the name is
> + * in the WIN32 namespace, we cache the filename in *res so
> + * that the caller, ntfs_lookup(), can work on it. If the
> + * comparison matches, and the name is in the DOS namespace, we
> + * only cache the mft reference and the file name type (we set
> + * the name length to zero for simplicity).
> +// */
> +// if (!NVolCaseSensitive(vol) &&
> +// ie->key.file_name.file_name_type &&
> +// ntfs_are_names_equal(uname, uname_len,
> +// (ntfschar*)&ie->key.file_name.file_name,
> +// ie->key.file_name.file_name_length,
> +// IGNORE_CASE, vol->upcase, vol->upcase_len)) {
> +// int name_size = sizeof(ntfs_name);
> +// u8 type = ie->key.file_name.file_name_type;
> +// u8 len = ie->key.file_name.file_name_length;
> +//
> +// /* Only one case insensitive matching name allowed. */
> +// if (name) {
> +// ntfs_error(sb, "Found already allocated name "
> +// "in phase 2. Please run chkdsk "
> +// "and if that doesn't find any "
> +// "errors please report you saw "
> +// "this message to "
> +// "linux-ntfs-dev@lists."
> +// "sourceforge.net.");
> +// unlock_page(page);
> +// ntfs_unmap_page(page);
> +// goto dir_err_out;
> +// }
> +//
> +// if (type != FILE_NAME_DOS)
> +// name_size += len * sizeof(ntfschar);
> +// name = kmalloc(name_size, GFP_NOFS);
> +// if (!name) {
> +// err = -ENOMEM;
> +// goto unm_err_out;
> +// }
> +// name->mref = le64_to_cpu(ie->data.dir.indexed_file);
> +// name->type = type;
> +// if (type != FILE_NAME_DOS) {
> +// name->len = len;
> +// memcpy(name->name, ie->key.file_name.file_name,
> +// len * sizeof(ntfschar));
> +// } else
> +// name->len = 0;
> +// *res = name;
> +// }
> + /*
> + * Not a perfect match, need to do full blown collation so we
> + * know which way in the B+tree we have to go.
> + */
> + rc = ntfs_collate_names(uname, uname_len,
> + (ntfschar*)&ie->key.file_name.file_name,
> + ie->key.file_name.file_name_length, 1,
> + IGNORE_CASE, vol->upcase, vol->upcase_len);
> + /*
> + * If uname collates before the name of the current entry, there
> + * is definitely no such name in this index but we might need to
> + * descend into the B+tree so we just break out of the loop.
> + */
> + if (rc == -1)
> + break;
> + /* The names are not equal, continue the search. */
> + if (rc)
> + continue;
> + /*
> + * Names match with case insensitive comparison, now try the
> + * case sensitive comparison, which is required for proper
> + * collation.
> + */
> + rc = ntfs_collate_names(uname, uname_len,
> + (ntfschar*)&ie->key.file_name.file_name,
> + ie->key.file_name.file_name_length, 1,
> + CASE_SENSITIVE, vol->upcase, vol->upcase_len);
> + if (rc == -1)
> + break;
> + if (rc)
> + continue;
> + /*
> + * Perfect match, this will never happen as the
> + * ntfs_are_names_equal() call will have gotten a match but we
> + * still treat it correctly.
> + */
> + goto found_it2;
> + }
> + /*
> + * We have finished with this index buffer without success. Check for
> + * the presence of a child node.
> + */
> + if (ie->flags & INDEX_ENTRY_NODE) {
> + if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
> + ntfs_error(sb, "Index entry with child node found in "
> + "a leaf node in directory inode 0x%lx.",
> + dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + /* Child node present, descend into it. */
> + old_vcn = vcn;
> + vcn = sle64_to_cpup((sle64*)((u8*)ie +
> + le16_to_cpu(ie->length) - 8));
> + if (vcn >= 0) {
> + /* If vcn is in the same page cache page as old_vcn we
> + * recycle the mapped page. */
> + if (old_vcn << vol->cluster_size_bits >>
> + PAGE_SHIFT == vcn <<
> + vol->cluster_size_bits >>
> + PAGE_SHIFT)
> + goto fast_descend_into_child_node;
> + unlock_page(page);
> + ntfs_unmap_page(page);
> + goto descend_into_child_node;
> + }
> + ntfs_error(sb, "Negative child node vcn in directory inode "
> + "0x%lx.", dir_ni->mft_no);
> + goto unm_err_out;
> + }
> + /*
> + * No child node present, return -ENOENT, unless we have got a matching
> + * name cached in name in which case return the mft reference
> + * associated with it.
> + */
> +/********
> + if (name) {
> + unlock_page(page);
> + ntfs_unmap_page(page);
> + return name->mref;
> + }
> + *******/
> + ntfs_debug("Entry not found.");
> + err = -ENOENT;
> +/*
> + if (!err)
> + err = -EIO;
> + if (ctx)
> + ntfs_attr_put_search_ctx(ctx);
> + if (m)
> + unmap_mft_record(dir_ni);
> + */
> + return ERR_MREF(err);
> +
> +unm_err_out:
> + unlock_page(page);
> + ntfs_unmap_page(page);
> +err_out:
> + if (!err)
> + err = -EIO;
> + if (ctx)
> + ntfs_attr_put_search_ctx(ctx);
> + if (m)
> + unmap_mft_record(dir_ni);
> + /*Gzged shut
> + if (name) {
> + kfree(name);
> + *res = NULL;
> + }
> + */
> + ntfs_debug("done.");
> + return ERR_MREF(err);
> +dir_err_out:
> + ntfs_error(sb, "Corrupt directory.  Aborting lookup.");
> + goto err_out;
> +}
> MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
> const int uname_len, ntfs_name **res)
> {
> diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
> index c4f68c3..1475243 100644
> --- a/fs/ntfs/file.c
> +++ b/fs/ntfs/file.c
> @@ -24,7 +24,13 @@
> #include <linux/gfp.h>
> #include <linux/pagemap.h>
> #include <linux/pagevec.h>
> +#include <linux/sched.h>
> +
> +#include <linux/version.h>
> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
> #include <linux/sched/signal.h>
> +#endif
> +
> #include <linux/swap.h>
> #include <linux/uio.h>
> #include <linux/writeback.h>
> diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
> index 8745469..b7d75ce 100644
> --- a/fs/ntfs/index.h
> +++ b/fs/ntfs/index.h
> @@ -88,6 +88,7 @@ typedef struct {
> extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni);
> extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
>
> +extern int ntfs_lookup_inode_by_key (const void *key, const int key_len, ntfs_index_context *ictx);
> extern int ntfs_index_lookup(const void *key, const int key_len,
> ntfs_index_context *ictx);
>
> diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
> index b6f4021..dbe7f21 100644
> --- a/fs/ntfs/mft.c
> +++ b/fs/ntfs/mft.c
> @@ -2915,4 +2915,84 @@ int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m)
> mark_mft_record_dirty(ni);
> return err;
> }
> +/**
> + * ntfs_mft_record_free - free an mft record on an ntfs volume
> + * @vol: volume on which to free the mft record
> + * @ni: open ntfs inode of the mft record to free
> + *
> + * Free the mft record of the open inode @ni on the mounted ntfs volume @vol.
> + * Note that this function calls ntfs_inode_close() internally and hence you
> + * cannot use the pointer @ni any more after this function returns success.
> + *
> + * On success return 0 and on error return -1 with errno set to the error code.
> + */
> +int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni,MFT_RECORD* mrec)
> +{
> + u64 mft_no;
> + int err;
> + u16 seq_no, old_seq_no;
> +
> + ntfs_debug("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
> +
> + if (!vol || !vol->mftbmp_ino || !ni)
> + {
> + return -EINVAL;
> + }
> +
> + /* Cache the mft reference for later. */
> + mft_no = ni->mft_no;
> +
> + /* Mark the mft record as not in use. */
> + mrec->flags &= ~MFT_RECORD_IN_USE;
> +
> + /* Increment the sequence number, skipping zero, if it is not zero. */
> + old_seq_no = mrec->sequence_number;
> +
> + seq_no = le16_to_cpu(old_seq_no);
> + if (seq_no == 0xffff)
> + seq_no = 1;
> + else if (seq_no)
> + seq_no++;
> + mrec->sequence_number = cpu_to_le16(seq_no);
> +
> + /* Set the inode dirty and write it out. */
> + flush_dcache_mft_record_page(ni);
> + mark_mft_record_dirty(ni);
> +
> + /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
> + ntfs_debug("before down_write...");
> + //down_write(&vol->mftbmp_lock);
> + if ( (err = ntfs_bitmap_clear_bit(vol->mftbmp_ino, mft_no )))
> + //up_write(&vol->mftbmp_lock);
> + {
> + // FIXME: If ntfs_bitmap_clear_run() guarantees rollback on
> + //  error, this could be changed to goto sync_rollback;
> + goto bitmap_rollback;
> + }
> +
> + /* Throw away the now freed inode.
> + if (!ntfs_inode_close(ni)) {
> + vol->free_mft_records++;
> + return 0;
> + }
> + err = errno;*/
> + flush_dcache_mft_record_page(ni);
> + mark_mft_record_dirty(ni);
> + return 0;
> +
> + /* Rollback what we did... */
> +bitmap_rollback:
> + down_write(&vol->mftbmp_lock);
> + if (ntfs_bitmap_set_bit(vol->mftbmp_ino, mft_no))
> + up_write(&vol->mftbmp_lock);
> + {
> + ntfs_debug("Eeek! Rollback failed in ntfs_mft_record_free().  "
> + "Leaving inconsistent metadata!\n");
> + }
> + mrec->flags |= MFT_RECORD_IN_USE;
> + mrec->sequence_number = old_seq_no;
> + flush_dcache_mft_record_page(ni);
> + mark_mft_record_dirty(ni);
> + return err;
> +}
> #endif /* NTFS_RW */
> diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h
> index b52bf87..f6a95ba 100644
> --- a/fs/ntfs/mft.h
> +++ b/fs/ntfs/mft.h
> @@ -118,6 +118,7 @@ extern bool ntfs_may_write_mft_record(ntfs_volume *vol,
> extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
> ntfs_inode *base_ni, MFT_RECORD **mrec);
> extern int ntfs_extent_mft_record_free(ntfs_inode *ni, MFT_RECORD *m);
> +extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni,MFT_RECORD* mrec);
>
> #endif /* NTFS_RW */
>
> diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
> index 4690cd7..a737cf5 100644
> --- a/fs/ntfs/namei.c
> +++ b/fs/ntfs/namei.c
> @@ -159,7 +159,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
> PTR_ERR(dent_inode));
> kfree(name);
> /* Return the error code. */
> - return ERR_CAST(dent_inode);
> + return (struct dentry *)dent_inode;
> }
> /* It is guaranteed that @name is no longer allocated at this point. */
> if (MREF_ERR(mref) == -ENOENT) {
> @@ -273,11 +273,1373 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
>    }
> }
>
> +
> +#include "index.h"
> +
> +#define STATUS_OK               (0)
> +#define STATUS_ERROR                (-1)
> +
> +/**
> + *  Insert @ie index entry at @pos entry. Used @ih values should be ok already.
> + */
> +static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos)
> +{
> + int ie_size = le16_to_cpu(ie->length);
> + ntfs_debug("Entering");
> + ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size);
> + memmove((u8 *)pos + ie_size, pos, le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - ie_size);
> + memcpy(pos, ie, ie_size);
> + ntfs_debug("done");
> +}
> +/**
> + * ntfs_ir_truncate - Truncate index root attribute
> + *
> + * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR.
> + */
> +static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
> +{  
> +/*
> + ntfs_attr *na;
> + */
> + int ret;
> +
> + ntfs_debug("Entering");
> +
> +/**
> + na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len);
> + if (!na) {
> + ntfs_log_perror("Failed to open INDEX_ROOT");
> + return STATUS_ERROR;
> + }
> + */
> + /*
> + *  INDEX_ROOT must be resident and its entries can be moved to
> + *  INDEX_BLOCK, so ENOSPC isn't a real error.
> + */
> + ret = ntfs_resident_attr_value_resize(icx->actx->mrec, icx->actx->attr, data_size + offsetof(INDEX_ROOT, index) );
> + /*Gzged changed
> + ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index));
> + */
> + if (ret == STATUS_OK)
> + {
> + /*
> + icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
> + if (!icx->ir)
> + return STATUS_ERROR;
> + */
> +
> + icx->ir->index.allocated_size = cpu_to_le32(data_size);
> +
> + } else if (ret == -EPERM)
> + {
> + ntfs_debug("Failed to truncate INDEX_ROOT");
> + }
> +
> +/**
> + ntfs_attr_close(na);
> + */
> + return ret;
> +}
> +
> +/**
> + * ntfs_ir_make_space - Make more space for the index root attribute
> + *
> + * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
> + * On error return STATUS_ERROR.
> + */
> +static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size)
> +{  
> + int ret;
> + ntfs_debug("Entering");
> + ret = ntfs_ir_truncate(icx, data_size);
> + /* TODO
> + if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT)
> + {
> + ret = ntfs_ir_reparent(icx);
> + if (ret == STATUS_OK)
> + ret = STATUS_KEEP_SEARCHING;
> + else
> + ntfs_log_perror("Failed to nodify INDEX_ROOT");
> + }
> + */
> + ntfs_debug("Done ");
> + return ret;
> +}
> +
> +
> +static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
> +{
> + INDEX_HEADER *ih;
> + int allocated_size, new_size;
> + int ret = STATUS_ERROR;
> + ntfs_inode *idx_ni = icx->idx_ni;
> + ntfs_debug("Entering. ");
> + while (1)
> + {
> + /* ret = ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx) ; */
> + ntfs_debug("new loop ");
> + ret = ntfs_lookup_inode_by_key(&ie->key, le16_to_cpu(ie->key_length), icx) ;
> + ntfs_debug("ntfs_lookup_inode_by_key ret[%d]",ret);
> + if (!ret)
> + {
> + ntfs_debug("Index already have such entry");
> + goto err_out;
> + }
> + if (ret != -ENOENT)
> + {
> + ntfs_debug("Failed to find place for new entry");
> + goto err_out;
> + }
> + /*
> + ntfs_debug("here icx[%p] icx->is_in_root[%d]",icx,icx->is_in_root);
> + */
> + if (icx->is_in_root)
> + {
> + BUG_ON(!icx->ir);
> + ih = &(icx->ir->index);
> + }
> + else
> + {
> + BUG_ON(!icx->ia);
> + ih = &(icx->ia->index);
> + }
> +
> + allocated_size = le32_to_cpu(ih->allocated_size);
> + new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length);
> +
> + ntfs_debug("index block sizes: allocated: %d  needed: %d", allocated_size, new_size);
> + if (new_size <= allocated_size)
> + {
> + break;
> + }
> + /** else  it will make space for new index entry **/
> +
> + if (icx->is_in_root)
> + {
> + if ( (ret = ntfs_ir_make_space(icx, new_size) ) )
> + {
> + ntfs_debug("ntfs_ir_make_space err ");
> + goto err_out;
> + }
> + else
> + {
> + ntfs_debug("ntfs_ir_make_space done ");
> + }
> + }
> + else
> + {
> + ntfs_debug("should run ntfs_ib_split ");
> + ret = -ENOSPC;
> + goto err_out;
> +
> + /* Gzged shut
> + if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR)
> + {
> + ntfs_debug("ntfs_ib_split err ");
> + ret = -ENOMEM;
> + goto err_out;
> + }
> + **/
> + }
> +
> + /*FIXME: Gzged mod
> + ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
> + ***/
> + /*FIXME: Gzged will fix these in furture */
> + ntfs_debug("Before flush_dcache_mft_record_page ");/*****die here *****/
> + flush_dcache_mft_record_page(icx->actx->ntfs_ino);
> +
> + ntfs_debug("Before mark_mft_record_dirty ");
> + mark_mft_record_dirty(icx->actx->ntfs_ino);
> +
> + /*FIXME: Gzged mod ntfs_index_ctx_reinit(icx); ***/
> + ntfs_index_ctx_put(icx);
> + ntfs_index_ctx_get(idx_ni);
> + }
> +
> + ntfs_ie_insert(ih, ie, icx->entry);
> + ntfs_index_entry_flush_dcache_page(icx);
> + ntfs_index_entry_mark_dirty(icx);
> +
> + ret = STATUS_OK;
> +err_out:
> + ntfs_debug("%s", ret ? "Failed" : "Done");
> + return ret;
> +}
> +/**
> + * 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
> + *
> + * Return 0 on success or -1 on error with errno set to the error code.
> + */
> +ntfs_index_context * ntfs_index_ctx_get_I30(ntfs_inode *idx_ni)
> +{
> +    static ntfschar I30[5] = { cpu_to_le16('$'),
> +            cpu_to_le16('I'),
> +            cpu_to_le16('3'),
> +            cpu_to_le16('0'),
> + 0 };
> +
> +    struct inode * tmp_ino = ntfs_index_iget(VFS_I(idx_ni), I30, 4);
> +    if (IS_ERR(tmp_ino)) {
> +        ntfs_debug("Failed to load $I30 index.");
> +        return NULL;
> +    }
> +
> + return ntfs_index_ctx_get(NTFS_I(tmp_ino));
> +}
> +void ntfs_index_ctx_put_I30(ntfs_index_context *ictx)
> +{
> + ntfs_commit_inode(VFS_I(ictx->idx_ni));
> + iput(VFS_I(ictx->idx_ni));
> + ntfs_index_ctx_put(ictx);
> +}
> +static int ntfs_index_add_filename(ntfs_inode *dir_ni, FILE_NAME_ATTR *fn, MFT_REF mref)
> +{
> + INDEX_ENTRY *ie;
> + ntfs_index_context *icx;
> + int ret = -1;
> +
> + ntfs_debug("Entering");
> +
> + if (!dir_ni || !fn)
> + {
> + ntfs_error((VFS_I(dir_ni))->i_sb,"Invalid arguments.");
> + return -EINVAL;
> + }
> +
> + {/** create and set INDEX_entry **/
> + int fn_size, ie_size;
> + fn_size = (fn->file_name_length * sizeof(ntfschar)) + sizeof(FILE_NAME_ATTR);
> + ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7;
> +
> + ie = kcalloc(1,ie_size,GFP_KERNEL);
> + if (!ie)
> + {
> + return -ENOMEM;
> + }
> +
> + ie->data.dir.indexed_file = cpu_to_le64(mref);
> + ie->length = cpu_to_le16(ie_size);
> + ie->key_length = cpu_to_le16(fn_size);
> + ie->flags = cpu_to_le16(0);
> + memcpy(&(ie->key.file_name), fn, fn_size);
> + }/**  END of create and set INDEX_entry **/
> +
> + icx =  ntfs_index_ctx_get(dir_ni);
> + if (!icx)
> + {
> + ret = PTR_ERR(icx);
> + goto out;
> + }
> +
> + ret = ntfs_ie_add(icx, ie);
> +out:
> + if(icx)
> + {
> + ntfs_index_ctx_put(icx);
> + }
> + if(ie)
> + {
> + kfree(ie);
> + }
> + ntfs_debug("done");
> + return ret;
> +}
> +
> +
> +/**
> + * __ntfs_create - create object 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
> + *
> + * Internal, use ntfs_create{,_device,_symlink} wrappers instead.
> + *
> + * @type can be:
> + * S_IFREG to create regular file
> + *
> + * Return opened ntfs inode that describes created object on success
> + * or ERR_PTR(errno) on error
> + */
> +
> +static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni,
> + ntfschar *name, u8 name_len, dev_t type )
> +{
> + ntfs_inode *ni =NULL;/** this is for new inode **/
> + FILE_NAME_ATTR *fn = NULL;
> + STANDARD_INFORMATION *si = NULL;
> + SECURITY_DESCRIPTOR_ATTR *sd =NULL;
> + int err;
> +
> + /*Author:Gzged */
> + MFT_RECORD* mrec;
> + int new_temp_offset ;
> + char* temp_new_record;
> +
> + ntfs_debug("Entering.");
> +
> + /* Sanity checks. */
> + if (!dir_ni || !name || !name_len)
> + {
> + ntfs_error((VFS_I(dir_ni))->i_sb,"Invalid arguments.");
> + return ERR_PTR(-EINVAL);
> + }
> +
> + /* TODO : not support REPARSE_POINT **/
> +
> + /** alloc new mft record for new file **/
> + ni = ntfs_mft_record_alloc(dir_ni->vol, type,NULL,&mrec);
> + if (IS_ERR(ni))
> + {
> + ntfs_debug("ntfs_mft_record_alloc error [%ld]",PTR_ERR(ni));
> + return ni;
> + }
> + else
> + {
> + new_temp_offset = mrec->attrs_offset ;
> + /** ntfs_mft_record_alloc{} had map ni to mrec */
> + temp_new_record=(char*)mrec;
> + ntfs_debug("mrec->mft_record_number [%d]",mrec->mft_record_number);
> + }
> +
> +
> +/**************** Begin from here , error must goto err_out *****************/
> + { /************************ STANDARD_INFORMATION start ******************/
> + /*
> + * Create STANDARD_INFORMATION attribute. Write STANDARD_INFORMATION
> + * version 1.2, windows will upgrade it to version 3 if needed.
> + */
> + ATTR_REC attr_si;
> + int si_len,attr_si_len;
> +
> + /*** $STANDARD_INFORMATION (0x10)  **/
> + si_len = offsetof(STANDARD_INFORMATION, ver) + sizeof(si->ver.v1.reserved12);
> + si = kcalloc(1,si_len,GFP_KERNEL );
> + if (!si)
> + {
> + err = -ENOMEM;
> + goto err_out;
> + }
> +#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
> + si->creation_time = NTFS_TIME_OFFSET ;
> + si->last_data_change_time = NTFS_TIME_OFFSET ;
> + si->last_mft_change_time = NTFS_TIME_OFFSET ;
> + si->last_access_time = NTFS_TIME_OFFSET ;
> +
> + /** set attr **/
> + attr_si_len = offsetof(ATTR_REC, data) + sizeof(attr_si.data.resident) ;
> + attr_si= (ATTR_REC )
> + {
> + .type = AT_STANDARD_INFORMATION ,
> + .length = attr_si_len +  si_len ,
> + .non_resident = 0,
> + .name_length = 0,
> + .name_offset = 0,
> + .flags =  0 ,
> + .instance = (mrec->next_attr_instance) ++ ,
> + .data=
> + {
> + .resident=
> + {
> + .value_length = si_len,
> + .value_offset = attr_si_len  ,
> + .flags = 0 ,
> + }
> + },
> + };
> + /*
> + attr_si.data.resident.value_length=si_len
> + attr_si.data.resident.flags = 0;
> + */
> +
> + /* Add STANDARD_INFORMATION to inode. */
> + memcpy(&(temp_new_record[new_temp_offset]),&attr_si, attr_si_len  );
> + new_temp_offset += attr_si_len;
> + memcpy(&(temp_new_record[new_temp_offset]),  si,  si_len);
> + new_temp_offset += si_len;
> +
> + ntfs_debug("new_temp_offset [%d]",new_temp_offset);
> +
> + kfree(si);
> + si=NULL;
> + } /****************************** end of STANDARD_INFORMATION *************/
> +
> + /*
> + if (ntfs_sd_add_everyone(ni)) {
> + err = errno;
> + goto err_out;
> + }
> + rollback_sd = 1;
> + */
> +
> +
> +
> + { /****************************** start of FILE_NAME *************/
> +
> + ATTR_REC attr_fna;
> + int fn_len , attr_fna_len;
> + /** create FILE_NAME_ATTR **/
> + fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
> + fn = kcalloc(1,fn_len,GFP_KERNEL);
> + if (!fn)
> + {
> + err = -ENOMEM;
> + goto err_out;
> + }
> + fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, le16_to_cpu(dir_ni->seq_no));
> + fn->file_name_length = name_len;
> + fn->file_name_type = FILE_NAME_POSIX;
> + fn->creation_time = NTFS_TIME_OFFSET;
> + fn->last_data_change_time = NTFS_TIME_OFFSET;
> + fn->last_mft_change_time = NTFS_TIME_OFFSET;
> + fn->last_access_time = NTFS_TIME_OFFSET;
> + fn->data_size = cpu_to_sle64(ni->initialized_size);
> + fn->allocated_size = cpu_to_sle64(ni->allocated_size);
> + memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
> +
> + /* Create FILE_NAME attribute. */
> + attr_fna_len = offsetof(ATTR_REC, data) + sizeof(attr_fna.data.resident) ;
> + attr_fna=(ATTR_REC)
> + {
> + .type = AT_FILE_NAME ,
> + .length = ( attr_fna_len + fn_len + 7 ) & ~7 ,
> + .non_resident = 0,
> + .name_length = 0,
> + .name_offset = 0,
> + .flags =  RESIDENT_ATTR_IS_INDEXED ,
> + .instance = (mrec->next_attr_instance) ++ ,
> + .data=
> + {
> + .resident=
> + {
> + .value_length = fn_len,
> + .value_offset = attr_fna_len  ,
> + .flags = 0 ,
> + }
> + },
> + };
> +
> + /** insert FILE_NAME into new_file_record **/
> + memcpy(&(temp_new_record[new_temp_offset]) , &attr_fna,  attr_fna_len);
> + memcpy(&(temp_new_record[new_temp_offset + attr_fna_len]),fn,fn_len);
> + new_temp_offset += attr_fna.length;
> +
> + ntfs_debug("new_temp_offset [%d]",new_temp_offset);
> +
> +/**********add to index ********************************************/
> + /* Add FILE_NAME attribute to index. */
> + if ((err = ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, le16_to_cpu(ni->seq_no))) ))
> + {
> + ntfs_error((VFS_I(dir_ni))->i_sb,"Failed to add entry to the index");
> + goto err_out;
> + }
> +/*********************************************************/
> +
> + kfree(fn);
> + fn=NULL;
> + } /****************************** end of FILE_NAME *************/
> +
> + { /****************************** start of SECURITY_DESCRIPTOR *************/
> + ACL *acl;
> + ACCESS_ALLOWED_ACE *ace;
> + SID *sid;
> + ATTR_REC attr_sd;
> + int sd_len, attr_sd_len;
> +
> + /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
> + /*
> + * Calculate security descriptor length. We have 2 sub-authorities in
> + * owner and group SIDs, but structure SID contain only one, so add
> + * 4 bytes to every SID.
> + */
> + sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
> + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
> + sd = kcalloc(1,sd_len,GFP_KERNEL);
> + if (!sd)
> + {
> + err = -ENOMEM;
> + goto err_out;
> + }
> +
> + sd->revision = 1;
> + sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
> +
> + sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
> + sid->revision = 1;
> + sid->sub_authority_count = 2;
> + sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
> + sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
> + sid->identifier_authority.value[5] = 5;
> + sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd);
> +
> + sid = (SID *)((u8 *)sid + sizeof(SID) + 4);
> + sid->revision = 1;
> + sid->sub_authority_count = 2;
> + sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
> + sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
> + sid->identifier_authority.value[5] = 5;
> + sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd);
> +
> + acl = (ACL *)((u8 *)sid + sizeof(SID) + 4);
> + acl->revision = 2;
> + acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
> + acl->ace_count = cpu_to_le16(1);
> + sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd);
> +
> + ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL));
> + ace->type = ACCESS_ALLOWED_ACE_TYPE;
> + ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
> + ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
> + ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */
> + ace->sid.revision = 1;
> + ace->sid.sub_authority_count = 1;
> + ace->sid.sub_authority[0] = 0;
> + ace->sid.identifier_authority.value[5] = 1;
> +
> + /* Create the attribute */
> + attr_sd_len = offsetof(ATTR_REC, data) + sizeof(attr_sd.data.resident) ;
> + attr_sd=(ATTR_REC)
> + {
> + .type = AT_SECURITY_DESCRIPTOR  ,
> + .length = ( attr_sd_len + sd_len + 7 ) & ~7 ,
> + .non_resident = 0,
> + .name_length = 0,
> + .name_offset = 0,
> + .flags =  0 ,
> + .instance = (mrec->next_attr_instance) ++ ,
> + .data=
> + {
> + .resident=
> + {
> + .value_length = sd_len,
> + .value_offset = attr_sd_len  ,
> + .flags = 0 ,
> + }
> + },
> + };
> +
> + /** insert FILE_NAME into new_file_record **/
> + memcpy(&(temp_new_record[new_temp_offset]) , &attr_sd,  attr_sd_len);
> + memcpy(&(temp_new_record[new_temp_offset + attr_sd_len]), sd ,sd_len);
> + new_temp_offset += attr_sd.length;
> + ntfs_debug("new_temp_offset [%d]",new_temp_offset);
> +/************************/
> +
> + kfree(sd);
> + sd=NULL;
> + } /****************************** end of SECURITY_DESCRIPTOR *************/
> +
> + { /****************************** start of DATA *************/
> + /***  $DATA (0x80)   **/
> + ATTR_REC attr_data;
> + int attr_data_len= offsetof(ATTR_REC, data) + sizeof(attr_data.data.resident) ;
> + attr_data=(ATTR_REC)
> + {
> + .type = AT_DATA ,
> + .length = attr_data_len,
> + .non_resident = 0,
> + .name_length = 0,
> + .name_offset = 0,
> + .flags =  0 ,
> + .instance = (mrec->next_attr_instance) ++ ,
> + .data=
> + {
> + .resident=
> + {
> + .value_length = 0,
> + .value_offset = attr_data_len  ,
> + .flags = 0 ,
> + }
> + },
> + };
> + /** insert DATA into new_file_record **/
> + memcpy(&(temp_new_record[new_temp_offset]),&attr_data, attr_data_len );
> + new_temp_offset += attr_data_len ;
> + ntfs_debug("new_temp_offset [%d]",new_temp_offset);
> +
> + } /****************************** end of DATA *************/
> +
> + { /****************************** start of $END *************/
> + /***  $AT_END              = cpu_to_le32(0xffffffff) */
> + ATTR_REC attr_end ;
> + int attr_end_len= offsetof(ATTR_REC, data) + sizeof(attr_end.data.resident) ;
> + attr_end=(ATTR_REC)
> + {
> + .type = AT_END ,
> + .length = attr_end_len ,
> + .non_resident = 0,
> + .name_length = 0,
> + .name_offset = 0,
> + .flags =  0 ,
> + .instance = (mrec->next_attr_instance) ++ ,
> + .data=
> + {
> + .resident=
> + {
> + .value_length = 0,
> + .value_offset = attr_end_len  ,
> + .flags = 0 ,
> + }
> + },
> + };
> + /** insert END into new_file_record **/
> + memcpy(&(temp_new_record[new_temp_offset]),&attr_end, attr_end_len);
> + new_temp_offset += attr_end_len ;
> + ntfs_debug("new_temp_offset [%d]",new_temp_offset);
> +
> + } /****************************** end of $END *************/
> +
> +
> + /**FIXME : it do not support hard link **/
> + mrec->link_count = cpu_to_le16(1);
> + /** MUST set this **/
> + mrec->bytes_in_use = new_temp_offset;
> +
> + flush_dcache_mft_record_page(ni);
> + mark_mft_record_dirty(ni);  /**ntfs_inode_mark_dirty(ni); int ntfs-3g**/
> + unmap_mft_record(ni);
> +
> + (VFS_I(ni))->i_op = &ntfs_file_inode_ops;
> + (VFS_I(ni))->i_fop = &ntfs_file_ops;
> +
> + if (NInoMstProtected(ni))
> + {
> + (VFS_I(ni))->i_mapping->a_ops = &ntfs_mst_aops;
> + }
> + else
> + {
> + (VFS_I(ni))->i_mapping->a_ops = &ntfs_normal_aops;
> + }
> +
> + (VFS_I(ni))->i_blocks = ni->allocated_size >> 9;
> +
> +
> + ntfs_debug("Done.");
> + return ni;
> +err_out:
> + ntfs_debug("Failed.");
> +
> + /* TODO : if ni->nr_extents had been set  should been clear here **/
> +
> + if(fn)
> + {
> + kfree(fn);
> + fn=NULL;
> + }
> + if(si)
> + {
> + kfree(si);
> + si=NULL;
> + }
> + if(sd)
> + {
> + kfree(sd);
> + sd=NULL;
> + }
> +
> + if(mrec)
> + {
> + if (ntfs_mft_record_free(ni->vol, ni,mrec))
> + {
> + ntfs_debug("Failed to free MFT record.  "
> + "Leaving inconsistent metadata. Run chkdsk.\n");
> + }
> + inode_dec_link_count(VFS_I(ni)); //(VFS_I(ni))->i_nlink--;
> + unmap_mft_record(ni);
> + atomic_dec(&(VFS_I(ni))->i_count);
> + mrec=NULL;
> + }
> + return ERR_PTR(err);
> +}
> +
> +/**
> + * Some wrappers around __ntfs_create() ...
> + */
> +ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
> + dev_t type)
> +{
> + /*TODO : type could be { S_IFREG S_IFDIR  S_IFIFO  S_IFSOCK } */
> + if (type != S_IFREG )
> + {
> + ntfs_error((VFS_I(dir_ni))->i_sb,"Invalid arguments.");
> + return ERR_PTR(-EOPNOTSUPP);
> + }
> + return __ntfs_create(dir_ni, name, name_len, type);
> +}
> +
> +static int ntfs_create_inode(struct inode *dir,
> + struct dentry *dent,
> + umode_t mode,
> + bool pn )
> +{
> + ntfschar *uname;
> + int uname_len;
> + ntfs_inode* ni ;
> +
> + /* Convert the name of the dentry to Unicode. */
> + uname_len = ntfs_nlstoucs(NTFS_SB(dir->i_sb), dent->d_name.name, dent->d_name.len, &uname);
> + if (uname_len < 0)
> + {
> + if (uname_len != -ENAMETOOLONG)
> + {
> + ntfs_error(dir->i_sb, "Failed to convert name to Unicode.");
> + }
> + return uname_len;
> + }
> +
> +
> + /* create file and inode */
> + ni = ntfs_create(NTFS_I(dir), uname, uname_len , mode & S_IFMT  );
> + kmem_cache_free(ntfs_name_cache, uname);
> + if(likely(!IS_ERR(ni)))
> + {
> + d_instantiate(dent,VFS_I(ni));
> + /* TODO : modify    dir->i_mtime  to CURRENT_TIME */
> + ntfs_debug("Done.");
> + return 0;
> + }
> + else
> + {
> + ntfs_error(dir->i_sb, "ntfs_create error! dentry->d_name.name[%s]", dent->d_name.name);
> + return  PTR_ERR(ni);
> + }
> +
> +}
> +
> +/************************* unlink support **********/
> +
> +/*
> +static int ntfs_index_rm_node(ntfs_index_context *icx)
> +{
> + int entry_pos, pindex;
> + VCN vcn;
> + INDEX_BLOCK *ib = NULL;
> + INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry;
> + INDEX_HEADER *ih;
> + u32 new_size;
> + int delta, ret = STATUS_ERROR;
> +
> + ntfs_debug("Entering");
> +
> + if (!icx->ia_na) {
> + icx->ia_na = ntfs_ia_open(icx, icx->ni);
> + if (!icx->ia_na)
> + return STATUS_ERROR;
> + }
> +
> + ib = ntfs_malloc(icx->block_size);
> + if (!ib)
> + return STATUS_ERROR;
> +
> + ie_succ = ntfs_ie_get_next(icx->entry);
> + entry_pos = icx->parent_pos[icx->pindex]++;
> + pindex = icx->pindex;
> +descend:
> + vcn = ntfs_ie_get_vcn(ie_succ);
> + if (ntfs_ib_read(icx, vcn, ib))
> + goto out;
> +
> + ie_succ = ntfs_ie_get_first(&ib->index);
> +
> + if (ntfs_icx_parent_inc(icx))
> + goto out;
> +
> + icx->parent_vcn[icx->pindex] = vcn;
> + icx->parent_pos[icx->pindex] = 0;
> +
> + if ((ib->index.ih_flags & NODE_MASK) == INDEX_NODE)
> + goto descend;
> +
> + if (ntfs_ih_zero_entry(&ib->index)) {
> + errno = EIO;
> + ntfs_log_perror("Empty index block");
> + goto out;
> + }
> +
> + ie = ntfs_ie_dup(ie_succ);
> + if (!ie)
> + goto out;
> +
> + if (ntfs_ie_add_vcn(&ie))
> + goto out2;
> +
> + ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry));
> +
> + if (icx->is_in_root)
> + ih = &icx->ir->index;
> + else
> + ih = &icx->ib->index;
> +
> + delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length);
> + new_size = le32_to_cpu(ih->index_length) + delta;
> + if (delta > 0) {
> + if (icx->is_in_root) {
> + ret = ntfs_ir_make_space(icx, new_size);
> + if (ret != STATUS_OK)
> + goto out2;
> +
> + ih = &icx->ir->index;
> + entry = ntfs_ie_get_by_pos(ih, entry_pos);
> +
> + } else if (new_size > le32_to_cpu(ih->allocated_size)) {
> + icx->pindex = pindex;
> + ret = ntfs_ib_split(icx, icx->ib);
> + if (ret == STATUS_OK)
> + ret = STATUS_KEEP_SEARCHING;
> + goto out2;
> + }
> + }
> +
> + ntfs_ie_delete(ih, entry);
> + ntfs_ie_insert(ih, ie, entry);
> +
> + if (icx->is_in_root) {
> + if (ntfs_ir_truncate(icx, new_size))
> + goto out2;
> + } else
> + if (ntfs_icx_ib_write(icx))
> + goto out2;
> +
> + ntfs_ie_delete(&ib->index, ie_succ);
> +
> + if (ntfs_ih_zero_entry(&ib->index)) {
> + if (ntfs_index_rm_leaf(icx))
> + goto out2;
> + } else
> + if (ntfs_ib_write(icx, ib))
> + goto out2;
> +
> + ret = STATUS_OK;
> +out2:
> + free(ie);
> +out:
> + free(ib);
> + return ret;
> +}
> +*/
> +
> +static int ntfs_ie_end(INDEX_ENTRY *ie)
> +{
> +    return ie->flags & INDEX_ENTRY_END || !ie->length;
> +}
> +
> +static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
> +{
> +    return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset));
> +}
> +static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie)
> +{
> +    return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length));
> +}
> +
> +
> +static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie)
> +{
> + u32 new_size;
> + ntfs_debug("Entering");
> + new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length);
> + ih->index_length = cpu_to_le32(new_size);
> + memmove(ie, (u8 *)ie + le16_to_cpu(ie->length), new_size - ((u8 *)ie - (u8 *)ih));
> + ntfs_debug("Done");
> +}
> +
> +
> +
> +static u8 *ntfs_ie_get_end(INDEX_HEADER *ih)
> +{
> + /* FIXME: check if it isn't overflowing the index block size */
> + return (u8 *)ih + le32_to_cpu(ih->index_length);
> +}
> +
> +
> +static int ntfs_ih_numof_entries(INDEX_HEADER *ih)
> +{
> + int n;
> + INDEX_ENTRY *ie;
> + u8 *end;
> +
> + ntfs_debug("Entering");
> +
> + end = ntfs_ie_get_end(ih);
> + ie = ntfs_ie_get_first(ih);
> + for (n = 0; !ntfs_ie_end(ie) && (u8 *)ie < end; n++)
> + ie = ntfs_ie_get_next(ie);
> + return n;
> +}
> +
> +static int ntfs_ih_one_entry(INDEX_HEADER *ih)
> +{
> + return (ntfs_ih_numof_entries(ih) == 1);
> +}
> +/**
> + * ntfs_index_rm - remove entry from the index
> + * @icx: index context describing entry to delete
> + *
> + * Delete entry described by @icx from the index. 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.
> + */
> +static int ntfs_index_rm(ntfs_index_context *icx)
> +{
> + INDEX_HEADER *ih;
> + int ret = STATUS_OK;
> +
> + ntfs_debug("Entering");
> +
> + if (!icx || (!icx->ia && !icx->ir) || ntfs_ie_end(icx->entry))
> + {
> + ntfs_debug("Invalid arguments.");
> + ret = -EINVAL;
> + goto err_out;
> + }
> + if (icx->is_in_root)
> + {
> + ih = &icx->ir->index;
> + }
> + else
> + {
> + ih = &icx->ia->index;
> + }
> +
> + if (icx->entry->flags & INDEX_ENTRY_NODE)
> + {
> + /* not support
> + ret = ntfs_index_rm_node(icx);
> + */
> + ret =  -EOPNOTSUPP ;
> + goto err_out;
> + }
> + else if (icx->is_in_root || !ntfs_ih_one_entry(ih))
> + {
> + ntfs_ie_delete(ih, icx->entry);
> +
> + if (icx->is_in_root)
> + {
> + ret = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));
> + if (ret != STATUS_OK)
> + {
> + goto err_out;
> + }
> + ntfs_debug("Before flush_dcache_mft_record_page ");
> + flush_dcache_mft_record_page(icx->actx->ntfs_ino);
> +
> + ntfs_debug("Before mark_mft_record_dirty ");
> + mark_mft_record_dirty(icx->actx->ntfs_ino);
> + }
> + else
> + {
> + /* shut by Gzged
> + if (ntfs_icx_ib_write(icx))
> + {
> + goto err_out;
> + }
> + */
> + ntfs_debug("Before ntfs_index_entry_flush_dcache_page ");
> + ntfs_index_entry_flush_dcache_page(icx);
> + ntfs_debug("Before ntfs_index_entry_mark_dirty ");
> + ntfs_index_entry_mark_dirty(icx);
> + }
> + }
> + else
> + {
> + ret =  -EOPNOTSUPP ;
> + goto err_out;
> + /** not support yet
> + if (ntfs_index_rm_leaf(icx))
> + {
> + goto err_out;
> + }
> + **/
> + }
> +
> +
> +err_out:
> + ntfs_debug("Done ");
> + return ret;
> +}
> +/** 20091014 **/
> +int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen)
> +{
> + int ret = STATUS_ERROR;
> + ntfs_index_context *icx;
> +
> + icx = ntfs_index_ctx_get(ni);
> + if (!icx)
> + {
> + return -1;
> + }
> +
> + while (1)
> + {
> + /** use my func
> + if (ntfs_index_lookup(key, keylen, icx))
> + */
> + if ( (ret = ntfs_lookup_inode_by_key (key, keylen, icx) ) )
> + {
> + ntfs_debug("ntfs_lookup_inode_by_key faild ...");
> + goto err_out;
> + }
> +/*********debug print
> + {
> + struct qstr nls_name;
> + nls_name.name = NULL;
> + nls_name.len = (unsigned)ntfs_ucstonls(ni->vol,
> +                ((FILE_NAME_ATTR *)icx->data)->file_name , icx->data_len,
> +                (unsigned char**)&nls_name.name, 0);
> + ntfs_debug("icx data name=[%s]",nls_name.name);
> + kfree(nls_name.name);
> + }
> +
> + if (((FILE_NAME_ATTR *)icx->data)->file_attributes & FILE_ATTR_REPARSE_POINT)
> + {
> + ntfs_debug("not support faild ");
> + ret = -EOPNOTSUPP;
> + goto err_out;
> + } ********/
> +/*********debug print ********/
> +
> + ret = ntfs_index_rm(icx);
> + if (ret == STATUS_OK)
> + {
> + ntfs_debug("ntfs_index_rm Done");
> + break;
> + }
> + else
> + {
> + ntfs_debug("ntfs_index_rm faild");
> + goto err_out;
> + }
> + /*
> + flush_dcache_mft_record_page(icx->actx->ntfs_ino);
> + mark_mft_record_dirty(icx->actx->ntfs_ino);
> + */
> + /*FIXME:Gzged change
> + ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
> + ntfs_index_ctx_reinit(icx);
> + ***************/
> +        ntfs_index_ctx_put(icx);
> + ntfs_index_ctx_get(ni);
> + }
> +
> + /*
> + ntfs_debug("Before flush_dcache_mft_record_page ");
> + flush_dcache_mft_record_page(icx->actx->ntfs_ino);
> + ntfs_debug("Before mark_mft_record_dirty ");
> + mark_mft_record_dirty(icx->actx->ntfs_ino);
> + */
> + /*
> + ntfs_debug("Before ntfs_index_entry_flush_dcache_page ");
> + ntfs_index_entry_flush_dcache_page(icx);
> + ntfs_debug("Before ntfs_index_entry_mark_dirty ");
> + ntfs_index_entry_mark_dirty(icx);
> + */
> +
> +err_out:
> + ntfs_debug("Delete Done");
> + if(icx)
> + {
> + ntfs_index_ctx_put(icx);
> + }
> + return ret;
> +}
> +
> +static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
> +{
> + /** case all attr **/
> +    return ntfs_attr_lookup(0, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx);
> +}
> +
> +
> +//static const char *es = "  Leaving inconsistent metadata.  Unmount and run chkdsk.";
> +typedef bool BOOL;
> +#include "lcnalloc.h"
> +int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni )
> +{
> + ntfs_attr_search_ctx *actx = NULL;
> + MFT_RECORD* mrec;
> + FILE_NAME_ATTR *fn = NULL;
> + ntfs_volume* vol=ni->vol;
> + /*
> + BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE;
> + BOOL case_sensitive_match = TRUE;
> + */
> + int err = 0;
> +
> + ntfs_debug("Entering");
> +
> + mrec = map_mft_record(ni);
> + if (IS_ERR(mrec)) {
> + err = PTR_ERR(mrec);
> + mrec = NULL;
> + goto err_out;
> + }
> +
> +    if ( (mrec->flags & MFT_RECORD_IS_DIRECTORY) )
> + {
> + ntfs_debug("Invalid arguments.");
> + err=  -EINVAL;
> + goto err_out;
> + }
> +
> + if (!ni || !dir_ni )
> + {
> + ntfs_debug("Invalid arguments.");
> + err=  -EINVAL;
> + goto err_out;
> + }
> +
> + if (ni->nr_extents == -1)
> + ni = ni->ext.base_ntfs_ino;
> + if (dir_ni->nr_extents == -1)
> + dir_ni = dir_ni->ext.base_ntfs_ino;
> +
> +
> +/******************************************* get fn ******************/
> + /*
> + * 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.
> + */
> + actx = ntfs_attr_get_search_ctx(ni, mrec);
> + if (!actx)
> + {
> + goto err_out;
> + }
> + while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE,
> + 0, NULL, 0, actx)) {
> +/*debuger need...
> + char *s;
> + **/
> + BOOL case_sensitive = IGNORE_CASE;
> +
> + fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
> + le16_to_cpu(actx->attr->data.resident.value_offset));
> +/*debuger need...
> + s = ntfs_attr_name_get(fn->file_name, fn->file_name_length);
> + ntfs_debug("name: '%s'  type: %d  dos: %d  win32: %d  "
> +       "case: %d\n", s, fn->file_name_type,
> +       looking_for_dos_name, looking_for_win32_name,
> +       case_sensitive_match);
> + ntfs_attr_name_free(&s);
> + */
> +/** all ways use posix name
> + if (looking_for_dos_name) {
> + if (fn->file_name_type == FILE_NAME_DOS)
> + break;
> + else
> + continue;
> + }
> + if (looking_for_win32_name) {
> + if  (fn->file_name_type == FILE_NAME_WIN32)
> + break;
> + else
> + continue;
> + }
> + **/
> +
> + /* Ignore hard links from other directories */
> + if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) {
> + ntfs_debug("MFT record numbers don't match "
> +       "(%llu != %llu)",
> +       (long long unsigned)dir_ni->mft_no,
> +       (long long unsigned)MREF_LE(fn->parent_directory));
> + continue;
> + }
> +    
> +/****all ways use posix case
> + if (fn->file_name_type == FILE_NAME_POSIX || case_sensitive_match)
> + */
> + case_sensitive = CASE_SENSITIVE;
> +
> + /** all ways think name is equal
> + if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,
> + name, name_len, case_sensitive,
> + ni->vol->upcase, ni->vol->upcase_len))*/ {
> +
> + /**  all ways think it`s posix name...
> + 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;
> + }
> + }
> +/******************************************* get fn ******************/
> +
> +/*********** cut the entry down *****************/
> + if ( (err = ntfs_index_remove(dir_ni, fn, le32_to_cpu(actx->attr->data.resident.value_length)) ) )
> + {
> + ntfs_debug("ntfs_index_remove error.");
> + goto err_out;
> + }
> +
> + mrec->link_count = cpu_to_le16(le16_to_cpu( mrec->link_count) - 1);
> +/*********** cut the entry down *****************/
> +
> +
> +/********************flush ***************/
> + flush_dcache_mft_record_page(ni);
> + mark_mft_record_dirty(ni);
> +/********************flush end ***************/
> +
> +/********************cut down all run list ***************/
> + ntfs_attr_put_search_ctx(actx);
> + actx = ntfs_attr_get_search_ctx(ni, mrec);
> +
> + err=  STATUS_OK ;
> + ntfs_debug("Before while ");
> + while (!ntfs_attrs_walk(actx))
> + {
> + ntfs_debug("new loop ");
> + if (actx->attr->non_resident)
> + {
> + ntfs_debug("Inner case ");
> + /*
> + runlist *rl;
> + rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr,
> + NULL);
> + if (!rl) {
> + err = -EOPNOTSUPP ;
> + ntfs_debug("Failed to decompress runlist.  "
> + "Leaving inconsistent metadata.\n");
> + continue;
> + }
> + if (ntfs_cluster_free_from_rl(ni->vol, rl)) {
> + err = -EOPNOTSUPP ;
> + ntfs_debug("Failed to free clusters.  "
> + "Leaving inconsistent metadata.\n");
> + continue;
> + }
> + free(rl);
> + */
> +
> + /* alloc_change < 0 */
> + /* Free the clusters.
> + err = ntfs_cluster_free(ni, 0, -1, actx);*/
> +
> + ntfs_debug("before __ntfs_cluster_free ");
> + err = __ntfs_cluster_free(ni, 0, -1, actx, false);
> + if (unlikely(err < 0))
> + {
> + ntfs_error(vol->sb, "Failed to release cluster(s) (error code "
> + "%lli).  Unmount and run chkdsk to recover "
> + "the lost cluster(s).", (long long)err);
> + NVolSetErrors(vol);
> + err = 0;
> + }
> + /* Truncate the runlist.  NO NEED
> + err = ntfs_rl_truncate_nolock(vol, &ni->runlist, 0);
> + if (unlikely(err || IS_ERR(actx->mrec)))
> + {
> + ntfs_error(vol->sb, "Failed to %s (error code %li).%s",
> + IS_ERR(actx->mrec) ?
> + "restore attribute search context" :
> + "truncate attribute runlist",
> + IS_ERR(actx->mrec) ? PTR_ERR(actx->mrec) : err, es);
> + err = -EIO;
> + goto err_out;
> + }*/
> + ntfs_debug("before flush_dcache_mft_record_page actx->ntfs_ino[%p]",actx->ntfs_ino);
> + flush_dcache_mft_record_page(actx->ntfs_ino);
> + ntfs_debug("before mark_mft_record_dirty actx->ntfs_ino[%p]",actx->ntfs_ino);
> + mark_mft_record_dirty(actx->ntfs_ino);
> + }
> + }
> + if (err )
> + {
> + ntfs_debug("Attribute enumeration failed.  "
> + "Probably leaving inconsistent metadata.\n");
> + }
> + /* All extents should be attached after attribute walk. */
> + while (ni->nr_extents)
> + {
> + ntfs_error(vol->sb,"need use ntfs_extent_mft_record_free. not support now ");
> + /**FIXME
> + if ( ( err = ntfs_mft_record_free(ni->vol, *(ni->extent_nis) )))
> + {
> + ntfs_debug("Failed to free extent MFT record.  "
> + "Leaving inconsistent metadata.\n");
> + }
> + **/
> + }
> +
> + if (ntfs_mft_record_free(ni->vol, ni,mrec))
> + {
> + err = -EIO;
> + ntfs_debug("Failed to free base MFT record.  "
> + "Leaving inconsistent metadata.\n");
> + }
> + /* FIXME */
> +
> + flush_dcache_mft_record_page(ni);
> + mark_mft_record_dirty(ni);
> + /*FIXME:Gzged add */
> + ntfs_debug("before unmap_mft_record.");
> + unmap_mft_record(ni);
> + ni = NULL;
> + mrec=NULL;
> +
> +
> + /** Gzged shut now
> + ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);
> + */
> +err_out:
> + if (actx)
> + ntfs_attr_put_search_ctx(actx);
> + if (mrec)
> + unmap_mft_record(ni);
> + if (err)
> + {
> + ntfs_debug("Could not delete file");
> + return err;
> + }
> + else
> + {
> + ntfs_debug("Done.");
> + return 0;
> + }
> +}
> +
> +static int ntfs_unlink_inode(struct inode *pi,struct dentry *pd)
> +{
> + ntfs_inode* ni = NTFS_I(pd->d_inode);
> + int err = -ENOENT;
> +
> + ntfs_debug("Entering");
> + BUG_ON(!ni);
> +
> + err =   ntfs_delete(ni,NTFS_I(pi));
> + if(err)
> + {
> + ntfs_debug("Faile");
> + return err;
> + }
> + else
> + {
> + (VFS_I(ni))->i_ctime = pi->i_ctime;
> + inode_dec_link_count(VFS_I(ni)); //(VFS_I(ni))->i_nlink--;
> + ntfs_debug("Done");
> + return  err;
> + }
> +}
> /**
>  * Inode operations for directories.
>  */
> const struct inode_operations ntfs_dir_inode_ops = {
> .lookup = ntfs_lookup, /* VFS: Lookup directory. */
> + .create = ntfs_create_inode,
> + .unlink = ntfs_unlink_inode,
> };
>
> /**
> --
> 2.9.3
>

--
Anton Altaparmakov <anton at tuxera.com> (replace at with @)
Lead in File System Development, Tuxera Inc., http://www.tuxera.com/
Linux NTFS maintainer


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linux-NTFS-Dev mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/linux-ntfs-dev
Loading...