Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv13537/libntfs
Modified Files:
Makefile.am Makefile.in attrib.c bitmap.c bootsect.c disk_io.c
mft.c ntfs_rec.c ntfsd.c unistr.c volume.c
Log Message:
It has been a long time since last commit. At moment have done a lot of work
on mkntfs but also at the moment ntfsfix and ntfsdump_logfile and libntfs are
broken. Basically only mkntfs works and that is not complete either.
Index: Makefile.am
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/Makefile.am,v
retrieving revision 1.5
retrieving revision 1.6
diff -U2 -r1.5 -r1.6
--- Makefile.am 2001/04/07 00:53:37 1.5
+++ Makefile.am 2001/06/01 02:07:25 1.6
@@ -9,4 +9,11 @@
LTVERSION = 1:0:0
+# Need this to enable 64-bit (device) file access functions and parameters.
+if DEBUG
+AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -g -DDEBUG
+else
+AM_CFLAGS = -D_FILE_OFFSET_BITS=64
+endif
+
linux_ntfsincludedir = -I$(top_srcdir)/include
lib_LTLIBRARIES = libntfs.la
@@ -24,3 +31,6 @@
INCLUDES = $(linux_ntfsincludedir) $(all_includes)
+
+EXTRA_DIST = \
+ attrib_RE.c
Index: Makefile.in
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/Makefile.in,v
retrieving revision 1.4
retrieving revision 1.5
diff -U2 -r1.4 -r1.5
--- Makefile.in 2001/04/07 00:53:37 1.4
+++ Makefile.in 2001/06/01 02:07:25 1.5
@@ -1,3 +1,3 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
+# Makefile.in generated automatically by automake 1.4-p1 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
@@ -79,12 +79,17 @@
CXX = @CXX@
DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
LDFLAGS = @LDFLAGS@
LIBTOOL = @LIBTOOL@
+LIBTOOL_DEPS = @LIBTOOL_DEPS@
LN_S = @LN_S@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
+STRIP = @STRIP@
VERSION = @VERSION@
all_includes = @all_includes@
@@ -92,4 +97,6 @@
LTVERSION = 1:0:0
+@DEBUG_TRUE@AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -g -DDEBUG
+@DEBUG_FALSE@AM_CFLAGS = -D_FILE_OFFSET_BITS=64
linux_ntfsincludedir = -I$(top_srcdir)/include
@@ -100,4 +107,7 @@
INCLUDES = $(linux_ntfsincludedir) $(all_includes)
+
+EXTRA_DIST = attrib_RE.c
+
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
@@ -130,5 +140,5 @@
all: all-redirect
.SUFFIXES:
-.SUFFIXES: .S .c .lo .o .s
+.SUFFIXES: .S .c .lo .o .obj .s
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu libntfs/Makefile
@@ -164,4 +174,9 @@
done
+# FIXME: We should only use cygpath when building on Windows,
+# and only if it is available.
+.c.obj:
+ $(COMPILE) -c `cygpath -w $<`
+
.s.o:
$(COMPILE) -c $<
@@ -172,4 +187,5 @@
mostlyclean-compile:
-rm -f *.o core *.core
+ -rm -f *.$(OBJEXT)
clean-compile:
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -U2 -r1.13 -r1.14
--- attrib.c 2001/04/12 22:37:21 1.13
+++ attrib.c 2001/06/01 02:07:25 1.14
@@ -24,23 +24,116 @@
#include <stddef.h>
#include <stdio.h>
-#include <linux/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
-#include "attrib.h"
-#include "layout.h"
#include "types.h"
+#include "attrib.h"
#include "unistr.h"
#include "endians.h"
#include "disk_io.h"
#include "support.h"
+#include "mft.h"
+
+int write_non_resident_attr(attr *a)
+{
+ return -ENOTSUP;
+}
+
+int ntfs_flush_attr(attr *a)
+{
+ int err = 0;
+
+ if (!AttrDirty(a) || !AttrMapped(a))
+ return 0;
+ if (!AttrNonResident(a)) {
+ /* Resident, just flush the mft entry. */
+ if (err = ntfs_flush_mft_entry(a->a_m_entry))
+ return err;
+ ClearAttrDirty(a);
+ } else /* Non-resident, write out to disk. */
+ err = write_non_resident_attr(a);
+ ntfs_flush();
+ return err;
+}
+
+BOOL __set_attr_dirty(attr *a)
+{
+ ntfs_volume *v;
+
+ /* If resident just mark mft entry as dirty. */
+ if (!AttrNonResident(a)) {
+ ntfs_set_mft_entry_dirty(a->a_m_entry);
+ return;
+ }
+ /* It is non-resident so add to dirty list. */
+ v = a->a_vol;
+ list_add_tail(&a->a_dirty_list, &v->dirty_attrs);
+ v->nr_dirty_attrs++;
+ return TRUE;
+}
+
+__inline__ attr *__allocate_attr(void)
+{
+ attr *a = (attr *)malloc(sizeof(attr));
+ if (!a)
+ return NULL;
+ memset(a, 0, sizeof(attr));
+ INIT_LIST_HEAD(&a->a_dirty_list);
+ return a;
+}
+
+__inline__ int __free_attr(attr *a)
+{
+ if (a->a_count || AttrDirty(a) || AttrMapped(a))
+ return -EBUSY;
+ if (a->a_run_list)
+ free(a->a_run_list);
+ free(a);
+ return 0;
+}
+
+int __map_attr_value(attr *a)
+{
+ if (!AttrNonResident(a)) {
+ }
+ return -ENOTSUP;
+}
-int __map_attribute_value(attr *a)
+int __unmap_attr_value(attr *a)
{
+ if (!AttrMapped(a))
+ return 0;
return -ENOTSUP;
}
+
+int insert_attr(mft_entry *me, attr **a, ATTR_RECORD *arec, attr_val *aval,
+ const BOOL dirty, const BOOL nonresident, run_list *arl,
+ const BOOL inattrlist, ATTR_LIST_ENTRY *alist,
+ ATTR_LIST_ENTRY *alistentry, const BOOL inextrecord)
+{
+ attr *aent;
+
+ if (!*a && !(*a = __allocate_attr()))
+ return -errno;
+ aent = *a;
+ aent->a_rec = arec;
+ if (aval) {
+ if (nonresident) {
+ aent->a_run_list = arl;
+ SetAttrNonResident(aent);
+ }
+ aent->a_val = aval;
+
+ } else {
+ if (__map_attr_value(aent)) {
+ // error
+ }
+ }
+
+ return -ENOTSUP;
+}
-int __unmap_attribute_value(attr *a)
+int remove_attr(attr *a)
{
return -ENOTSUP;
@@ -49,9 +142,10 @@
/**
* find_attr - find (next) attribute in mft record
- * @vol: volume on which @a resides (used to find the upcase table)
* @type: attribute type to find
* @name: attribute name to find (optional, i.e. NULL means don't care)
* @name_len: attribute name length (only needed if @name present)
* @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
+ * @upcase: unicode upcase table
+ * @ucpase_len: length of upcase table in unicode characters
* @val: attribute value to find (optional, resident attributes only)
* @val_len: attribute value length
@@ -72,7 +166,6 @@
* @name_len is the @name length in Unicode characters.
*
- * If @name is not present (NULL), no attribute name checking is performed at
- * all. Thus, to find an unnamed attribute specifically, specify a @name
- * pointing to a zero length string.
+ * If @name is not present (NULL), we assume that the unnamed attribute is
+ * being searched for.
*
* Finally, the resident attribute value @val is looked for, if present. If @val
@@ -84,13 +177,15 @@
* lookup_attr() instead (see below). This also means that you cannot use
* find_attr() to search for extent records of non-resident attributes, as
- * extents with lowest_vcn != 0 are invariably described by the attribute list
- * attribute only.
+ * extents with lowest_vcn != 0 are usually described by the attribute list
+ * attribute only. - Note that it is possible that the first extent is only in
+ * the attribute list while the last extent is in the base mft record, so don't
+ * rely on being able to find the first extent in the base mft record.
*
* Warning: Never use @val when looking for attribute types which can be
* non-resident as this most likely will result in a crash!
*/
-BOOL find_attr(const ntfs_volume *vol, const ATTR_TYPES type,
- const wchar_t *name, const __u32 name_len,
- const IGNORE_CASE_BOOL ic, const __u8 *val, const __u32 val_len,
+BOOL find_attr(const ATTR_TYPES type, const uchar_t *name, const __u32 name_len,
+ const IGNORE_CASE_BOOL ic, const uchar_t *upcase,
+ const __u32 upcase_len, const __u8 *val, const __u32 val_len,
attr_search_context *ctx)
{
@@ -98,6 +193,6 @@
#ifdef DEBUG
- if (!vol || !ctx || !ctx->mrec || !ctx->attr) {
- printf(stderr, "find_attr() received NULL pointer!\n");
+ if (!ctx || !ctx->mrec || !ctx->attr) {
+ fprintf(stderr, "find_attr() received NULL pointer!\n");
return FALSE;
}
@@ -113,9 +208,7 @@
a = (ATTR_RECORD*)((char*)ctx->attr +
le32_to_cpu(ctx->attr->length));
- for (; p2n(a) >= p2n(ctx->mrec) &&
- (char*)a <= (char*)ctx->mrec + vol->mft_record_size;
- a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
- if (p2n(a) < p2n(ctx->mrec) ||
- (char*)a > (char*)ctx->mrec + vol->mft_record_size)
+ for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
+ if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec +
+ le32_to_cpu(ctx->mrec->bytes_allocated))
break;
ctx->attr = a;
@@ -127,12 +220,19 @@
if (a->type != type)
continue;
- /* If @name is present, compare the two names. */
- if (name && !ntfs_are_names_equal(name, name_len,
- (wchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
- a->name_length, ic, vol->upcase, vol->upcase_len)) {
+ /*
+ * If @name is present, compare the two names. If @name is
+ * missing, assume we want an unnamed attribute.
+ */
+ if (!name) {
+ /* The search failed if the found attribute is named. */
+ if (a->name_length)
+ return FALSE;
+ } else if (!ntfs_are_names_equal(name, name_len,
+ (uchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
+ a->name_length, ic, upcase, upcase_len)) {
register int rc;
- rc = ntfs_collate_names(vol->upcase, vol->upcase_len,
- name, name_len, (wchar_t*)((char*)a +
+ rc = ntfs_collate_names(upcase, upcase_len,
+ name, name_len, (uchar_t*)((char*)a +
le16_to_cpu(a->name_offset)),
a->name_length, IGNORE_CASE, 1);
@@ -146,6 +246,6 @@
if (rc)
continue;
- rc = ntfs_collate_names(vol->upcase, vol->upcase_len,
- name, name_len, (wchar_t*)((char*)a +
+ rc = ntfs_collate_names(upcase, upcase_len,
+ name, name_len, (uchar_t*)((char*)a +
le16_to_cpu(a->name_offset)),
a->name_length, CASE_SENSITIVE, 1);
@@ -156,6 +256,7 @@
}
/*
- * The names match or @name not present. If no @val specified,
- * we have found the attribute and are done.
+ * The names match or @name not present and attribute is
+ * unnamed. If no @val specified, we have found the attribute
+ * and are done.
*/
if (!val)
@@ -183,5 +284,5 @@
}
#ifdef DEBUG
- printf(stderr, "find_attr(): File is corrupt. Run chkdsk.\n");
+ fprintf(stderr, "find_attr(): File is corrupt. Run chkdsk.\n");
#endif
return FALSE;
@@ -190,9 +291,10 @@
/**
* find_first_attr - find first attribute in mft record
- * @vol: volume on which @a resides (used to find the upcase table)
* @type: attribute type to find
* @name: attribute name to find (optional, i.e. NULL means don't care)
* @name_len: attribute name length (only needed if @name present)
* @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
+ * @upcase: unicode upcase table
+ * @ucpase_len: length of upcase table in unicode characters
* @val: attribute value to find (optional, resident attributes only)
* @val_len: attribute value length
@@ -202,8 +304,8 @@
* see description of find_attr() above.
*/
-__inline__ BOOL find_first_attr(const ntfs_volume *vol, const ATTR_TYPES type,
- const wchar_t *name, const __u32 name_len,
- const IGNORE_CASE_BOOL ic, const __u8 *val, const __u32 val_len,
- attr_search_context *ctx)
+__inline__ BOOL find_first_attr(const ATTR_TYPES type, const uchar_t *name,
+ const __u32 name_len, const IGNORE_CASE_BOOL ic,
+ const uchar_t *upcase, const __u32 upcase_len,
+ const __u8 *val, const __u32 val_len, attr_search_context *ctx)
{
MFT_RECORD *m;
@@ -211,21 +313,22 @@
#ifdef DEBUG
- if (!vol || !ctx || !ctx->mrec) {
- printf(stderr, "find_first_attr() received NULL pointer!\n");
+ if (!ctx || !ctx->mrec) {
+ fprintf(stderr, "find_first_attr() received NULL pointer!\n");
return FALSE;
}
if (ctx->attr)
- printf(stderr, "find_first_attr(): received non-NULL attribute "
- "pointer.\nThis will be overwritten resulting "
- "in possible memory leakage.\n");
+ fprintf(stderr, "find_first_attr(): received non-NULL "
+ "attribute pointer.\nThis will be overwritten "
+ "resulting in possible memory leakage.\n");
#endif
m = ctx->mrec;
ctx->is_first = TRUE;
ctx->attr = a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
- if (p2n(a) >= p2n(m) && (char*)a <= (char*)m + vol->mft_record_size)
- return find_attr(vol, type, name, name_len, ic, val, val_len,
- ctx);
+ if (p2n(a) >= p2n(m) && (char*)a <= (char*)m +
+ le32_to_cpu(m->bytes_allocated))
+ return find_attr(type, name, name_len, ic, upcase, upcase_len,
+ val, val_len, ctx);
#ifdef DEBUG
- printf(stderr, "find_first_attr(): file is corrupt.");
+ fprintf(stderr, "find_first_attr(): file is corrupt.");
#endif
return FALSE;
@@ -246,5 +349,5 @@
memset(&ctx, 0, sizeof(attr_search_context));
ctx.mrec = b;
- if (!find_first_attr(v, $VOLUME_INFORMATION, NULL, 0, 0, NULL, 0,
+ if (!find_first_attr($VOLUME_INFORMATION, NULL, 0, 0, NULL, 0, NULL, 0,
&ctx)) {
fprintf(stderr, "Error: Attribute $VOLUME_INFORMATION was " \
@@ -317,5 +420,5 @@
return (__s64)le32_to_cpu(a->value_length);
} else { /* Attribute is not resident. */
- run_list rl;
+ run_list *rl;
__s64 total;
int r, i;
@@ -365,4 +468,5 @@
perror("Couldn't allocate memory for "
"internal buffer.\n");
+ free(rl);
errno = eo;
return 0;
@@ -399,4 +503,5 @@
}
#undef ESTR
+ free(rl);
return 0;
}
@@ -478,5 +583,5 @@
return 1;
} else { /* Attribute is not resident. */
- run_list rl;
+ run_list *rl;
__s64 total;
int w, i;
@@ -540,11 +645,11 @@
}
-run_list decompress_run_list(const ATTR_RECORD *attr)
+run_list *decompress_run_list(const ATTR_RECORD *attr)
{
VCN vcn; /* Current vcn. */
LCN lcn; /* Current lcn. */
__s64 deltaxcn; /* Change in [vl]cn. */
- run_list rl = NULL; /* The output run_list. */
- run_list rl2; /* Temporary run_list. */
+ run_list *rl = NULL; /* The output run_list. */
+ run_list *rl2; /* Temporary run_list. */
__u8* buf; /* Current position in mapping pairs array. */
int rlsize; /* Size of run_list buffer. */
@@ -597,6 +702,15 @@
* length as a signed value so that's how it is...
*/
- for (b = *buf & 0xf, deltaxcn = (__s8)buf[b--]; b; b--) {
- deltaxcn = (deltaxcn << 8) + buf[b];
+ b = *buf & 0xf;
+ if (b) {
+ for (deltaxcn = (__s8)buf[b--]; b; b--)
+ deltaxcn = (deltaxcn << 8) + buf[b];
+ } else { /* The length entry is compulsory. */
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG Linux-NTFS: No length entry in "
+ "mapping pairs array.\n"
+ "decompress_run_list() failed.\n");
+#endif
+ deltaxcn = (__s64)-1;
}
/* Assume a negative length to indicate data corruption and
@@ -612,15 +726,30 @@
vcn += deltaxcn;
/* There might be no lcn change at all, as is the case for
- sparse clusters, in which case we set the lcn to -1. */
+ * sparse clusters on NTFS 3.0+, in which case we set the lcn
+ * to -1. */
if (!(*buf & 0xf0))
(rl + rlpos)->lcn = -1;
else {
/* Get the lcn change which really can be negative. */
- for (b = (*buf & 0xf) + ((*buf >> 4) & 0xf),
- deltaxcn = (__s8)buf[b--]; b > (*buf & 0xf); b--) {
+ for (b = (*buf & 0xf) + ((*buf >> 4) & 0xf), deltaxcn =
+ (__s8)buf[b--]; b > (*buf & 0xf); b--)
deltaxcn = (deltaxcn << 8) + buf[b];
- }
/* Change the current lcn to it's new value. */
lcn += deltaxcn;
+#ifdef DEBUG
+ /*
+ * On NTFS 1.2-, apparently can have lcn == -1 to
+ * indicate a hole. But we haven't verified ourselves
+ * whether it is really the lcn or the deltaxcn that is
+ * -1. So if either is found give us a message so we
+ * can investigate it further! (AIA)
+ */
+ if (deltaxcn == -1)
+ fprintf(stderr, "DEBUG Linux-NTFS: lcn delta "
+ "== -1\n");
+ else if (lcn == -1)
+ fprintf(stderr, "DEBUG Linux-NTFS: lcn "
+ "== -1\n");
+#endif
/* Enter the current lcn into the run_list_element. */
(rl + rlpos)->lcn = lcn;
@@ -670,7 +799,14 @@
puts("VCN LCN Run length");
for (i = 0; ; i++) {
- printf("%-16Lx %-16Lx %-16Lx\n", (rl + i)->vcn,
- (rl + i)->lcn,
- (rl + i)->length);
+ if ((rl + i)->lcn == -1)
+ printf("%-16Lx %-16i %-16Lx (%s)\n",
+ (rl + i)->vcn, -1, (rl + i)->length,
+ (rl + i)->length ? "sparse run" :
+ "run list end");
+ else
+ printf("%-16Lx %-16Lx %-16Lx%s\n",
+ (rl + i)->vcn, (rl + i)->lcn,
+ (rl + i)->length, (rl + i)->length ?
+ "" : " (run list end)");
if (!(rl + i)->length)
break;
@@ -682,5 +818,5 @@
}
-LCN vcn_to_lcn(const run_list rl, const VCN vcn)
+LCN vcn_to_lcn(const run_list *rl, const VCN vcn)
{
int i = 0;
Index: bitmap.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/bitmap.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -U2 -r1.4 -r1.5
--- bitmap.c 2001/04/08 03:02:55 1.4
+++ bitmap.c 2001/06/01 02:07:25 1.5
@@ -22,4 +22,5 @@
*/
+#include "types.h"
#include "bitmap.h"
@@ -37,4 +38,5 @@
const __u8 new_value)
{
+// printf("bitmap %p, bit 0x%Lx, new_value %i\n", bitmap, bit, new_value);
if (!bitmap || new_value > 1)
return;
@@ -52,20 +54,23 @@
}
+__inline__ void ntfs_change_bit(__u8 *bitmap, const __u64 bit)
+{
+ if (!bitmap)
+ return;
+ bitmap[bit >> 3] ^= 1 << (bit & 7);
+}
+
__inline__ char ntfs_get_and_set_bit(__u8 *bitmap, const __u64 bit,
const __u8 new_value)
{
- __u8 b, old_value;
+ register __u8 old_bit, shift;
if (!bitmap || new_value > 1)
return -1;
- b = bitmap[bit >> 3];
- old_value = (b >> (bit & 7)) & 1;
- if (new_value != old_value) {
- if (!new_value)
- bitmap[bit >> 3] = b & ~(1 << (bit & 7));
- else
- bitmap[bit >> 3] = b | (1 << (bit & 7));
- }
- return old_value;
+ shift = bit & 7;
+ old_bit = (bitmap[bit >> 3] >> shift) & 1;
+ if (new_value != old_bit)
+ bitmap[bit >> 3] ^= 1 << shift;
+ return old_bit;
}
Index: bootsect.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/bootsect.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -U2 -r1.4 -r1.5
--- bootsect.c 2001/04/08 03:02:55 1.4
+++ bootsect.c 2001/06/01 02:07:26 1.5
@@ -24,6 +24,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <linux/types.h>
+#include "types.h"
#include "bootsect.h"
#include "endians.h"
@@ -86,5 +86,5 @@
puts("OK");
- /* Check the sector size is not above 65536 bytes. */
+ /* Check the cluster size is not above 65536 bytes. */
if (!silent)
printf("Checking cluster size... ");
Index: disk_io.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/disk_io.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -U2 -r1.13 -r1.14
--- disk_io.c 2001/04/11 15:29:39 1.13
+++ disk_io.c 2001/06/01 02:07:26 1.14
@@ -24,16 +24,14 @@
#include <unistd.h>
#include <stdlib.h>
-#include <linux/types.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
-#include "layout.h"
#include "types.h"
#include "disk_io.h"
-__u64 ntfs_pwrite(int fd, const void *b, __u64 count, const __u64 pos)
+__s64 ntfs_pwrite(int fd, const void *b, __s64 count, const __s64 pos)
{
- __u64 written, total;
+ __s64 written, total;
char retry;
@@ -75,7 +73,7 @@
* mst read on the written data. This way cache coherency is achieved.
*/
-__u64 mst_pwrite(int fd, const void *b, __u64 count, const __u64 pos)
+__s64 mst_pwrite(int fd, const void *b, __s64 count, const __s64 pos)
{
- __u64 written, total, error;
+ __s64 written, total, error;
char retry;
@@ -124,8 +122,8 @@
}
-__u64 ntfs_pread(const int fd, void *b, const __u32 bksize, __u64 count,
- const __u64 pos)
+__s64 ntfs_pread(const int fd, void *b, const __u32 bksize, __s64 count,
+ const __s64 pos)
{
- __u64 br, btr, total;
+ __s64 br, btr, total;
char bksize_bits;
@@ -183,8 +181,8 @@
}
-__u64 mst_pread(const int fd, void *b, const __u32 bksize, __u64 count,
- const __u64 pos)
+__s64 mst_pread(const int fd, void *b, const __u32 bksize, __s64 count,
+ const __s64 pos)
{
- __u64 br, i;
+ __s64 br, i;
char bksize_bits;
@@ -209,5 +207,5 @@
const int count)
{
- __u64 br;
+ __s64 br;
if (!vol || !buf || count < 0 || lcn < 0)
@@ -238,5 +236,5 @@
int put_clusters(ntfs_volume *vol, const __u8 *buf, const __s64 lcn, int count)
{
- __u64 bw;
+ __s64 bw;
if (!vol || !buf || count < 0 || lcn < 0)
@@ -265,5 +263,5 @@
/**
- * get_mft_records - read records from the mft
+ * get_mft_records - read records from the mft from disk
* @vol: volume to read from
* @mrec: output data buffer
@@ -281,5 +279,5 @@
const MFT_REF *mref, const int count)
{
- __u64 br, ofs;
+ __s64 br, ofs;
LCN lcn;
VCN m;
@@ -294,24 +292,11 @@
if (!ntfs_get_bit(vol->mft_bitmap, m))
return -ENOENT;
- /* Size of mft record != size of cluster thus need to work with
- offsets into clusters. */
- if (vol->mft_records_per_cluster) {
- lcn = vcn_to_lcn(vol->mft_runlist,
- m / vol->mft_records_per_cluster);
- /* FIXME: Change "/" above and "%" below to ">>" and "&"
- respectively! */
- ofs = m % vol->mft_records_per_cluster;
- ofs <<= vol->mft_record_size_bits;
- } else {
- lcn = vcn_to_lcn(vol->mft_runlist,
- m * vol->clusters_per_mft_record);
- /* FIXME: Change "*" above to "<<"! */
- ofs = 0;
+ lcn = vcn_to_lcn(vol->mft_runlist, m << vol->mft_record_size_bits >>
+ vol->cluster_size_bits);
+ if (lcn == -1) {
+ perror("Error sparse $Mft records are not supported");
+ return -ENOTSUP;
}
- if (lcn < 0) {
- int eo = errno;
- perror("Error determining on disk location of $Mft record");
- return -eo;
- }
+ ofs = m << vol->mft_record_size_bits & vol->cluster_size - 1;
br = mst_pread(vol->fd, (__u8*)mrec, vol->mft_record_size, count,
(lcn << vol->cluster_size_bits) + ofs);
@@ -354,5 +339,5 @@
/**
- * read_file_record - read a FILE record from the mft
+ * __read_file_record - read a FILE record from the mft from disk
* @vol: volume to read from
* @mref: mft reference specifying mft record to read
@@ -360,8 +345,9 @@
* @attr: address of pointer in which to return the first attribute
*
- * Read a FILE record from the mft of @vol. @mref specifies the mft record
- * to read, including the sequence number. When the function returns, @mrec and
- * @attr will contain pointers to the read mft record and to the first attribute
- * within the mft record, respectively. @attr is optional (can be NULL).
+ * Read a FILE record from the mft of @vol from the storage medium. @mref
+ * specifies the mft record to read, including the sequence number. When the
+ * function returns, @mrec and @attr will contain pointers to the read mft
+ * record and to the first attribute within the mft record, respectively.
+ * @attr is optional (can be NULL).
*
* The read mft record is checked for having the magic FILE, for being in use,
@@ -373,6 +359,6 @@
* Note: Caller has to free *@mrec when finished.
*/
-int read_file_record(const ntfs_volume *vol, const MFT_REF *mref,
- MFT_RECORD **mrec, ATTR_RECORD **attr)
+int __read_file_record(const ntfs_volume *vol, const MFT_REF *mref,
+ MFT_RECORD **mrec, ATTR_RECORD **attr)
{
MFT_RECORD *m;
@@ -413,7 +399,37 @@
}
+/**
+ * read_file_record - read a FILE record from the mft from @vol
+ * @vol: volume to read from
+ * @mref: mft reference specifying mft record to read
+ * @mrec: address of pointer in which to return the mft record
+ * @attr: address of pointer in which to return the first attribute
+ *
+ * Return the FILE record @mref from the mft of @vol. @mref, the mft record to
+ * return, includes the sequence number, which can be 0 if no sequence number
+ * checking is to be performed. If the mft record is already loaded in the
+ * volume's mft cache this is returned straight away. Otherwise a new mft entry
+ * is allocated and inserted into the cache and the mft record is within the
+ * entry is returned. When the function returns, @mrec and @attr will contain
+ * pointers to the mft record and to the first attribute within the mft record,
+ * respectively. @attr is optional (can be NULL).
+ *
+ * The mft record is checked for having the magic FILE, for being in use,
+ * and for having a matching sequence number (if MSEQNO(*@mref) != 0).
+ * If either of these fails, return -EIO.
+ *
+ * Return 0 on success, or -ERRNO on error, where ERRNO is the error code.
+ *
+ * Note: Caller has to free *@mrec when finished.
+ */
+int read_file_record(const ntfs_volume *vol, const MFT_REF *mref,
+ MFT_RECORD **mrec, ATTR_RECORD **attr)
+{
+ return -ENOTSUP;
+}
+
int put_mft_record(ntfs_volume *vol, const __u8 *buf, const MFT_REF *mref)
{
- __u64 bw, m;
+ __s64 bw, m;
__s64 lcn, ofs;
@@ -427,20 +443,12 @@
if (!ntfs_get_bit(vol->mft_bitmap, m))
return -ENOENT;
- /* Size of mft record != size of cluster thus need to work with offsets
- into clusters. */
- if (vol->mft_records_per_cluster) {
- lcn = vcn_to_lcn(vol->mft_runlist,
- m / vol->mft_records_per_cluster);
- /* FIXME: Change "/" above and "%" below to ">>" and "&"
- respectively! */
- ofs = m % vol->mft_records_per_cluster;
- ofs <<= vol->mft_record_size_bits;
- } else {
- lcn = vcn_to_lcn(vol->mft_runlist,
- m * vol->clusters_per_mft_record);
- /* FIXME: Change "*" above to "<<"! */
- ofs = 0;
+ lcn = vcn_to_lcn(vol->mft_runlist, m << vol->mft_record_size_bits >>
+ vol->cluster_size_bits);
+ if (lcn == -1) {
+ perror("Error sparse $Mft records are not supported");
+ return -ENOTSUP;
}
- if (lcn < 0) {
+ ofs = m << vol->mft_record_size_bits & vol->cluster_size - 1;
+ if (lcn == -1) {
int eo = errno;
perror("Error determining on disk location of $Mft record");
Index: mft.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/mft.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -U2 -r1.9 -r1.10
--- mft.c 2001/04/11 14:29:12 1.9
+++ mft.c 2001/06/01 02:07:26 1.10
@@ -25,14 +25,12 @@
#include <stdio.h>
#include <errno.h>
-#include <linux/types.h>
-#include <linux/bitops.h>
+#include "types.h"
#include "list.h"
#include "mft.h"
-#include "layout.h"
-#include "types.h"
#include "endians.h"
[...1283 lines suppressed...]
ntfs_volume *v;
- if (f->f_count > 0 && --f->f_count)
- return 0;
- f->f_count = 0;
- list_del(&f->f_list);
- v = f->f_vol;
- v->nr_open_files--;
- list_add(&f->f_list, &v->closed_files);
- v->nr_closed_files++;
- return 0;
+
+ if (--f->f_count > 1)
+ return 0;
+ /* Remove all mft_refs/_entries from @f and, if no errors, remove @f
+ * from its volume and kill the file. */
+ if (!__remove_all_mft_entries_from_file(f))
+ return __free_ntfs_file(f);
+ return -1;
}
Index: ntfs_rec.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/ntfs_rec.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -U2 -r1.8 -r1.9
--- ntfs_rec.c 2001/04/11 15:48:41 1.8
+++ ntfs_rec.c 2001/06/01 02:07:26 1.9
@@ -23,9 +23,8 @@
#include <stdio.h>
-#include <linux/types.h>
+#include "types.h"
#include "volume.h"
#include "ntfs_rec.h"
-#include "layout.h"
#include "endians.h"
@@ -63,5 +62,6 @@
/* Setup the variables. */
usa_ofs = le16_to_cpu(b->usa_ofs);
- usa_count = le16_to_cpu(b->usa_count);
+ /* Decrement usa_count to get number of fixups. */
+ usa_count = le16_to_cpu(b->usa_count) - 1;
/* Size and alignement checks. */
if ( size & (NTFS_SECTOR_SIZE - 1) ||
@@ -70,6 +70,4 @@
(size >> NTFS_SECTOR_SIZE_BITS) != usa_count)
return 1;
- /* Decrement usa_count to get number of fixups. */
- --usa_count;
/* Position of usn in update sequence array. */
usa_pos = (__u16*)b + usa_ofs/sizeof(__u16);
@@ -127,13 +125,12 @@
/* Setup the variables. */
usa_ofs = le16_to_cpu(b->usa_ofs);
- usa_count = le16_to_cpu(b->usa_count);
+ /* Decrement usa_count to get number of fixups. */
+ usa_count = le16_to_cpu(b->usa_count) - 1;
/* Size and alignement checks. */
if ( size & (NTFS_SECTOR_SIZE - 1) ||
- usa_ofs & 1 ||
+ usa_ofs & 1 ||
usa_ofs + (usa_count * 2) > size ||
(size >> NTFS_SECTOR_SIZE_BITS) != usa_count)
return 0;
- /* Decrement usa_count to get number of fixups. */
- --usa_count;
/* Position of usn in update sequence array. */
usa_pos = (__u16*)((__u8*)b + usa_ofs);
Index: ntfsd.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/ntfsd.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -U2 -r1.5 -r1.6
--- ntfsd.c 2001/04/11 15:29:39 1.5
+++ ntfsd.c 2001/06/01 02:07:26 1.6
@@ -37,10 +37,34 @@
*/
LIST_HEAD(ntfs_mounted_volumes);
-int nr_ntfs_mounted_volumes = 0;
-BOOL ntfs_need_sync = FALSE;
+atomic_t ntfs_nr_mounted_volumes = ATOMIC_INIT(0);
/*
- * Keep track of how many times the timer has been starter.
+ * Private global flags for NTFS.
+ *
+ * NF_need_sync bit is set by ntfsd every 5 seconds and cleared by ntfs_flush(),
+ * when it is called.
+ *
+ * NF_ntfsd_running is set by ntfs_flush() when it initiates the sync to disk
+ * and cleared when it finishes. This prevents reentry and loops where
+ * ntfs_flush() will call a function which will have an ntfs_flush() call in
+ * its code path.
*/
+static unsigned long ntfs_flags = 0;
+
+#define NF_need_sync 0
+#define NF_ntfsd_running 1
+ /* bits 2-31 reserved for future use */
+
+#define NtfsNeedSync(n) test_bit(NF_need_sync, &(n))
+#define SetNtfsNeedSync(n) set_bit(NF_need_sync, &(n))
+#define ClearNtfsNeedSync(n) clear_bit(NF_need_sync, &(n))
+
+#define NtfsdRunning(n) test_bit(NF_ntfsd_running, &(n))
+#define SetNtfsdRunning(n) set_bit(NF_ntfsd_running, &(n))
+#define ClearNtfsdRunning(n) clear_bit(NF_ntfsd_running, &(n))
+
+/*
+ * Keep track of how many times the timer has been started.
+ */
static atomic_t ntfsd_times_started = ATOMIC_INIT(0);
@@ -53,39 +77,38 @@
/* Convenience strings. */
static const char *ntfsd_internal_error = "Internal error.";
-static const char *ntfsd_sigalrm_not_supported = "The system does not support "
+static const char *ntfsd_sigalrm_not_supported = "This system does not support "
"the SIGALRM signal.";
-int ntfs_sync_volumes(void)
+static void ntfs_flush_all_volumes(void)
{
- int i = 0;
struct list_head *tmp;
ntfs_volume *vol;
- ntfs_need_sync = FALSE;
- if (!nr_ntfs_mounted_volumes)
- return 0;
+ if (!atomic_read(&ntfs_nr_mounted_volumes))
+ return;
list_for_each(tmp, &ntfs_mounted_volumes) {
vol = list_entry(tmp, ntfs_volume, v_list);
- i = 0;
-repeat_sync:
- if (!ntfs_sync_volume(vol)) {
- switch (errno) {
- case EINTR:
- case EAGAIN:
- if (i++ < 3)
- goto repeat_sync;
- break;
- }
- fprintf(stderr, "Linux-NTFS: sync_volume() "
+ if (ntfs_sync_volume(vol) < 0) {
+#ifdef DEBUG
+ fprintf(stderr, "DEBUG Linux-NTFS: ntfs_sync_volume() "
"failed for volume %s (%s): %s",
vol->vol_name, vol->dev_name,
strerror(errno));
+#endif
}
+ }
+}
+
+__inline__ void ntfs_flush(void)
+{
+ if (test_and_clear_bit(NF_need_sync, &ntfs_flags) &&
+ !test_and_set_bit(NF_ntfsd_running, &ntfs_flags)) {
+ ntfs_flush_all_volumes();
+ ClearNtfsdRunning(ntfs_flags);
}
- return;
}
/*
- * The signal handler which sets the ntfs_need_sync to true every time it is
+ * The signal handler which sets ntfs_need_sync to true every time it is
* called. (Every 5 seconds. Only if it is started and there are some mounted
* volumes.)
@@ -93,6 +116,7 @@
static void ntfsd_thread(int i)
{
- if (atomic_read(&ntfsd_times_started) && nr_ntfs_mounted_volumes)
- ntfs_need_sync = TRUE;
+ if (atomic_read(&ntfsd_times_started) &&
+ atomic_read(&ntfs_nr_mounted_volumes))
+ SetNtfsNeedSync(ntfs_flags);
}
Index: unistr.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/unistr.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -U2 -r1.4 -r1.5
--- unistr.c 2001/04/08 03:02:55 1.4
+++ unistr.c 2001/06/01 02:07:26 1.5
@@ -22,4 +22,7 @@
*/
+#include <stdio.h>
+
+#include "types.h"
#include "unistr.h"
@@ -56,8 +59,8 @@
* the @upcase table is used to performa a case insensitive comparison.
*/
-BOOL ntfs_are_names_equal(const wchar_t *s1, size_t s1_len,
- const wchar_t *s2, size_t s2_len,
+BOOL ntfs_are_names_equal(const uchar_t *s1, size_t s1_len,
+ const uchar_t *s2, size_t s2_len,
const IGNORE_CASE_BOOL ic,
- const wchar_t *upcase, const __u32 upcase_size)
+ const uchar_t *upcase, const __u32 upcase_size)
{
if (s1_len != s2_len)
@@ -87,15 +90,15 @@
* The following characters are considered invalid: '"', '*', '<', '>' and '?'.
*/
-int ntfs_collate_names(const wchar_t *upcase, const __u32 upcase_len,
- const wchar_t *name1, const __u32 name1_len,
- const wchar_t *name2, const __u32 name2_len,
+int ntfs_collate_names(const uchar_t *upcase, const __u32 upcase_len,
+ const uchar_t *name1, const __u32 name1_len,
+ const uchar_t *name2, const __u32 name2_len,
const IGNORE_CASE_BOOL ic, const int err_val)
{
__u32 cnt;
- wchar_t c1, c2;
+ uchar_t c1, c2;
#ifdef DEBUG
if (!name1 || !name2 || ic && !upcase && upcase_len) {
- printf(stderr, "ntfs_wcsncmp() received NULL pointer!\n");
+ fprintf(stderr, "ntfs_wcsncmp() received NULL pointer!\n");
exit(1);
}
@@ -145,12 +148,12 @@
* to be less than, to match, or be greater than @s2.
*/
-int ntfs_wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n)
+int ntfs_wcsncmp(const uchar_t *s1, const uchar_t *s2, size_t n)
{
- wchar_t c1, c2;
+ uchar_t c1, c2;
size_t i;
#ifdef DEBUG
if (!s1 || !s2) {
- printf(stderr, "ntfs_wcsncmp() received NULL pointer!\n");
+ fprintf(stderr, "ntfs_wcsncmp() received NULL pointer!\n");
exit(1);
}
@@ -187,13 +190,13 @@
* to be less than, to match, or be greater than @s2.
*/
-int ntfs_wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n,
- const wchar_t *upcase, const __u32 upcase_size)
+int ntfs_wcsncasecmp(const uchar_t *s1, const uchar_t *s2, size_t n,
+ const uchar_t *upcase, const __u32 upcase_size)
{
- wchar_t c1, c2;
+ uchar_t c1, c2;
size_t i;
#ifdef DEBUG
if (!s1 || !s2 || !upcase) {
- printf(stderr, "ntfs_wcsncasecmp() received NULL pointer!\n");
+ fprintf(stderr, "ntfs_wcsncasecmp() received NULL pointer!\n");
exit(1);
}
Index: volume.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/volume.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -U2 -r1.15 -r1.16
--- volume.c 2001/04/11 14:29:12 1.15
+++ volume.c 2001/06/01 02:07:26 1.16
@@ -28,10 +28,8 @@
#include <fcntl.h>
#include <unistd.h>
-#include <linux/types.h>
+#include "types.h"
#include "list.h"
-#include "layout.h"
#include "volume.h"
-#include "types.h"
#include "support.h"
#include "bootsect.h"
@@ -41,30 +39,104 @@
#include "mft.h"
-BOOL ntfs_sync_volume(ntfs_volume *vol)
+/**
+ * ntfs_sync_volume - sync a mounted ntfs volume to physical storage
+ * @vol: ntfs volume to sync
+ *
+ * Sync a mounted ntfs volumes to physical storage.
+ *
+ * Return zero on success and -1 if one or more mft records and/or
+ * non-resident attributes were busy, and could not be committed to disk.
+ */
+int ntfs_sync_volume(ntfs_volume *vol)
{
struct list_head *tmp;
- int i, nr_err;
+ int s = 0;
- i = nr_err = 0;
- list_for_each(tmp, &vol->dirty_mft_entries)
- if (flush_mft_entry(list_entry(tmp, mft_entry, m_dirty_list)))
- nr_err++;
- if (!nr_err)
- return TRUE;
- errno = EBUSY;
- return FALSE;
+ list_for_each(tmp, &vol->dirty_attrs) {
+ if (!ntfs_flush_attr(list_entry(tmp, attr, a_dirty_list)) || s)
+ continue;
+ s = -1;
+ }
+ list_for_each(tmp, &vol->dirty_mft_entries) {
+ if (!ntfs_flush_mft_entry(list_entry(tmp, mft_entry,
+ m_dirty_list)) || s)
+ continue;
+ s = -1;
+ }
+ return s;
+}
+
+static __inline__ ntfs_volume *__allocate_ntfs_volume()
+{
+ ntfs_volume *v = (ntfs_volume *)malloc(sizeof(ntfs_volume));
+ if (!v)
+ return NULL;
+ memset(v, 0, sizeof(ntfs_volume));
+ INIT_LIST_HEAD(&v->open_files);
+ INIT_LIST_HEAD(&v->mft_entries);
+ INIT_LIST_HEAD(&v->dirty_mft_entries);
+ INIT_LIST_HEAD(&v->dirty_attrs);
+ return v;
+}
+
+static __inline__ int __free_ntfs_volume(ntfs_volume *v)
+{
+ if (v->nr_open_files || v->nr_mft_entries || v->nr_dirty_attrs)
+ return -1;
+ if (v->dev_name)
+ free(v->dev_name);
+ if (v->vol_name)
+ free(v->vol_name);
+ if (v->lcn_bitmap)
+ free(v->lcn_bitmap);
+ if (v->mft_bitmap)
+ free(v->mft_bitmap);
+ if (v->mft_runlist)
+ free(v->mft_runlist);
+ if (v->upcase)
+ free(v->upcase);
+ free(v);
+ return 0;
+}
+
+/**
+ * __init_ntfs_volume - initialize an ntfs_volume
+ * @v: ntfs_volume to initialize
+ *
+ * Before we can use any of the libntfs higher level functions to open files,
+ * load mft records and such like, we need to load the system files but these
+ * are files. Catch 22!
+ *
+ * So we have to cheat, i.e. we setup a minumum set of fields in @v to more or
+ * less faked values, just to allow us to use the library functions to open the
+ * system files. Perhaps not the most beautiful solution but IMO the most
+ * elegant one. Otherwise we would have to keep around special functions to work
+ * without all the information required or we would need to do everything
+ * manually (as it used to be in the early days of Linux-NTFS).
+ *
+ * Using a fake-it approach means we still use the same code for everything,
+ * even for meta data, which is way cool. It does mean we have some uglyness in
+ * the mount code path but hey, it's just the mount... All the real fun comes
+ * after mounting anyway.
+ *
+ * Once we have opened the system files we do the proper initialisation of @v,
+ * disposing off the faked info as we go along.
+ */
+int __init_ntfs_volume(ntfs_volume *v)
+{
+ return 0;
}
ntfs_volume *ntfs_mount(const char *name)
{
- const char *OK = "OK";
- const char *FAILED = "FAILED";
+ const char *OK = "OK";
+ const char *FAILED = "FAILED";
ntfs_volume *vol = NULL;
- NTFS_BOOT_SECTOR *bs = NULL;
+ NTFS_BOOT_SECTOR *bs = NULL;
MFT_RECORD *mb = NULL;
ATTR_RECORD *a;
VOLUME_INFORMATION *vinf;
__u32 u;
- __u64 l;
+ __s64 l;
ssize_t br;
__u8 sectors_per_cluster, bits;
@@ -73,5 +145,5 @@
MFT_REF mref;
int err;
-
+
if (!name) {
errno = EINVAL;
@@ -79,11 +151,10 @@
}
/* Allocate the volume structure. */
- if (!(vol = (ntfs_volume *)malloc(sizeof(ntfs_volume)))) {
+ vol = __allocate_ntfs_volume();
+ if (!vol) {
perror("Error allocating memory for ntfs volume structure");
errno = ENOMEM;
goto error_exit;
}
- /* Zero the volume structure. */
- memset(vol, 0, sizeof(ntfs_volume));
/* Make a copy of the partition name. */
if (!(vol->dev_name = strdup(name))) {
@@ -93,131 +164,129 @@
}
/* Allocate the boot sector structure. */
- if (!(bs = (NTFS_BOOT_SECTOR *)malloc(sizeof(NTFS_BOOT_SECTOR)))) {
- puts(FAILED);
- perror("Error allocating memory for bootsector");
+ if (!(bs = (NTFS_BOOT_SECTOR *)malloc(sizeof(NTFS_BOOT_SECTOR)))) {
+ puts(FAILED);
+ perror("Error allocating memory for bootsector");
errno = ENOMEM;
goto error_exit;
- }
- printf("Reading bootsector... ");
- if ((vol->fd = open(name, O_RDWR)) == -1) {
+ }
+ printf("Reading bootsector... ");
+ if ((vol->fd = open(name, O_RDWR)) == -1) {
int eo = errno;
- puts(FAILED);
- perror("Error opening partition file");
+ puts(FAILED);
+ perror("Error opening partition file");
errno = eo;
goto error_exit;
- }
- /* Now read the bootsector. */
- br = ntfs_pread(vol->fd, bs, sizeof(NTFS_BOOT_SECTOR), 1, 0);
- if (br != 1) {
+ }
+ /* Now read the bootsector. */
+ br = ntfs_pread(vol->fd, bs, sizeof(NTFS_BOOT_SECTOR), 1, 0);
+ if (br != 1) {
int eo = errno;
- puts(FAILED);
+ puts(FAILED);
#define ESTR "Error reading bootsector"
- if (br == -1) {
- perror(ESTR);
+ if (br == -1) {
+ perror(ESTR);
errno = eo;
} else if (!br) {
- fprintf(stderr, "Error: partition is smaller than " \
- "bootsector size. Weird!\n");
+ fprintf(stderr, "Error: partition is smaller than " \
+ "bootsector size. Weird!\n");
errno = EINVAL;
} else {
- fprintf(stderr, ESTR ": unknown error\n");
+ fprintf(stderr, ESTR ": unknown error\n");
errno = EINVAL;
}
#undef ESTR
- goto error_exit;
- }
- puts(OK);
- if (!is_boot_sector_ntfs(bs, 0)) {
- fprintf(stderr, "Error: %s is not a valid NTFS partition!\n",
- name);
+ goto error_exit;
+ }
+ puts(OK);
+ if (!is_boot_sector_ntfs(bs, 0)) {
+ fprintf(stderr, "Error: %s is not a valid NTFS partition!\n",
+ name);
errno = EINVAL;
- goto error_exit;
- }
- /* The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
- below or equal the number_of_clusters) really belong in the
- is_boot_sector_ntfs but in this way we can just do this once. */
- sectors_per_cluster = bs->bpb.sectors_per_cluster;
+ goto error_exit;
+ }
+ /* The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
+ * below or equal the number_of_clusters) really belong in the
+ * is_boot_sector_ntfs but in this way we can just do this once. */
+ sectors_per_cluster = bs->bpb.sectors_per_cluster;
#ifdef DEBUG
printf("NumberOfSectors = %Li\n", sle64_to_cpu(bs->number_of_sectors));
- printf("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
+ printf("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
#endif
- for (bits = 0; sectors_per_cluster > 1; sectors_per_cluster >>= 1)
- bits++;
- sectors_per_cluster = bs->bpb.sectors_per_cluster;
-
- vol->number_of_clusters = sle64_to_cpu(bs->number_of_sectors) >> bits;
-
- vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
- vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
-
- if ((vol->mft_lcn > vol->number_of_clusters) ||
- (vol->mftmirr_lcn > vol->number_of_clusters)) {
- fprintf(stderr, "Error: %s is not a valid NTFS partition! " \
- "($Mft LCN or\n$MftMirr LCN is greater than " \
- "the number of clusters!\n", name);
+ if (sectors_per_cluster & sectors_per_cluster - 1) {
+ fprintf(stderr, "Error: %s is not a valid NTFS partition! "
+ "sectors_per_cluster is not a power of 2.\n",
+ name);
errno = EINVAL;
- goto error_exit;
- }
- vol->cluster_size = sectors_per_cluster *
- le16_to_cpu(bs->bpb.bytes_per_sector);
- u = vol->cluster_size;
- for (bits = 0; u > 1; u >>= 1)
- bits++;
- vol->cluster_size_bits = bits;
-
- /* Need to get the clusters per mft record and handle it if it is
- negative. Then calculate the mft_record_size and replace the
- cluster_size with the mft_record_size where applicable below!
- A value of 0x80 is illegal, thus signed char is actually ok! */
- c = bs->clusters_per_mft_record;
+ goto error_exit;
+ }
+ vol->number_of_clusters = sle64_to_cpu(bs->number_of_sectors) >>
+ ffs(sectors_per_cluster) - 1;
+
+ vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
+ vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
#ifdef DEBUG
- printf("ClusterSize = 0x%x\n", vol->cluster_size);
+ printf("MFT LCN = %Li\n", vol->mft_lcn);
+ printf("MFTMirr LCN = 0x%Li\n", vol->mftmirr_lcn);
+#endif
+ if ((vol->mft_lcn > vol->number_of_clusters) ||
+ (vol->mftmirr_lcn > vol->number_of_clusters)) {
+ fprintf(stderr, "Error: %s is not a valid NTFS partition! "
+ "($Mft LCN or\n$MftMirr LCN is greater than "
+ "the number of clusters!\n", name);
+ errno = EINVAL;
+ goto error_exit;
+ }
+ vol->cluster_size = sectors_per_cluster *
+ le16_to_cpu(bs->bpb.bytes_per_sector);
+ if (vol->cluster_size & vol->cluster_size - 1) {
+ fprintf(stderr, "Error: %s is not a valid NTFS partition! "
+ "cluster_size is not a power of 2.\n", name);
+ errno = EINVAL;
+ goto error_exit;
+ }
+ vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
+ /*
+ * Need to get the clusters per mft record and handle it if it is
+ * negative. Then calculate the mft_record_size. A value of 0x80 is
+ * illegal, thus signed char is actually ok!
+ */
+ c = bs->clusters_per_mft_record;
+#ifdef DEBUG
+ printf("ClusterSize = 0x%x\n", vol->cluster_size);
printf("ClusterSizeBits = %u\n", vol->cluster_size_bits);
- printf("ClustersPerMftRecord = 0x%x\n", c);
+ printf("ClustersPerMftRecord = 0x%x\n", c);
#endif
- /* When clusters_per_mft_record is negative, it means that it is to
- be taken to be the negative base 2 logarithm of the mft_record_size
- in bytes. Then:
- mft_record_size = 2^(-clusters_per_mft_record) bytes. */
- if (c < 0)
- vol->mft_record_size = 1 << -c;
- else
- vol->mft_record_size = vol->cluster_size * c;
- u = vol->mft_record_size;
- for (bits = 0; u > 1; u >>= 1)
- bits++;
- vol->mft_record_size_bits = bits;
- if (vol->cluster_size > vol->mft_record_size) {
- vol->mft_records_per_cluster = vol->cluster_size /
- vol->mft_record_size;
- vol->clusters_per_mft_record = 0;
- } else {
- vol->mft_records_per_cluster = 0;
- vol->clusters_per_mft_record = vol->mft_record_size /
- vol->cluster_size;
+ /*
+ * When clusters_per_mft_record is negative, it means that it is to
+ * be taken to be the negative base 2 logarithm of the mft_record_size
+ * min bytes. Then:
+ * mft_record_size = 2^(-clusters_per_mft_record) bytes.
+ */
+ if (c < 0)
+ vol->mft_record_size = 1 << -c;
+ else
+ vol->mft_record_size = vol->cluster_size * c;
+ if (vol->mft_record_size & vol->mft_record_size - 1) {
+ fprintf(stderr, "Error: %s is not a valid NTFS partition! "
+ "mft_record_size is not a power of 2.\n", name);
+ errno = EINVAL;
+ goto error_exit;
}
+ vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
+ vol->max_open_files = 10000;
#ifdef DEBUG
- printf("MftRecordSize = 0x%x\n", vol->mft_record_size);
+ printf("MftRecordSize = 0x%x\n", vol->mft_record_size);
printf("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
- printf("There are %i mft records in each cluster.\n",
- vol->mft_records_per_cluster);
- printf("There are %i clusters in each mft record.\n",
- vol->clusters_per_mft_record);
+ printf("max_open_files set to %u\n", vol->max_open_files);
#endif
- /* Initialize files and mft records lists and associated variables. */
- INIT_LIST_HEAD(&vol->open_files);
- INIT_LIST_HEAD(&vol->closed_files);
- vol->max_files = 1000;
- INIT_LIST_HEAD(&vol->mft_entries);
- INIT_LIST_HEAD(&vol->dirty_mft_entries);
/* Start with $Mft. */
printf("Loading $Mft... ");
if (!(mb = (MFT_RECORD *)malloc(vol->mft_record_size))) {
- puts(FAILED);
- perror("Error allocating memory for $Mft");
+ puts(FAILED);
+ perror("Error allocating memory for $Mft");
errno = ENOMEM;
goto error_exit;
- }
- /* Can't use get_mft_records yet!!! */
+ }
+ /* Can't use any of the higher level functions yet! */
br = mst_pread(vol->fd, (char *)mb, vol->mft_record_size, 1,
vol->mft_lcn << vol->cluster_size_bits);
@@ -238,5 +307,5 @@
if (is_baad_record(mb)) {
puts(FAILED);
- fprintf(stderr, "Error: Incomplete multi sector "
+ fprintf(stderr, "Error: Incomplete multi sector "
"transfer detected in $Mft.\nCannot "
"handle this yet. )-:\n");
@@ -244,11 +313,11 @@
goto error_exit;
}
- if (!is_mft_recordp(mb)) {
- puts(FAILED);
- fprintf(stderr, "Error: Invalid mft record for $Mft.\n"
- "Cannot handle this yet. )-:\n");
+ if (!is_mft_recordp(mb)) {
+ puts(FAILED);
+ fprintf(stderr, "Error: Invalid mft record for $Mft.\n"
+ "Cannot handle this yet. )-:\n");
errno = EIO;
goto error_exit;
- }
+ }
/* Find the bitmap attribute. */
memset(&ctx, 0, sizeof(attr_search_context));
@@ -257,12 +326,12 @@
if (p2n(ctx.attr) < p2n(mb) ||
(char*)ctx.attr > (char*)mb + vol->mft_record_size) {
- puts(FAILED);
- fprintf(stderr, "Error: corrupt mft record for $Mft.\n"
- "Cannot handle this yet. )-:\n");
+ puts(FAILED);
+ fprintf(stderr, "Error: corrupt mft record for $Mft.\n"
+ "Cannot handle this yet. )-:\n");
errno = EIO;
goto error_exit;
}
ctx.is_first = TRUE;
- if (!find_attr(vol, $BITMAP, NULL, 0, 0, NULL, 0, &ctx)) {
+ if (!find_attr($BITMAP, NULL, 0, 0, NULL, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "$bitmap attribute not found in $Mft?!?\n");
@@ -279,4 +348,5 @@
goto error_exit;
}
+ printf("$MFT $DATA attribute value length = %Li\n", l);
vol->mft_bitmap = (__u8*)malloc(l);
if (!vol->mft_bitmap) {
@@ -294,4 +364,13 @@
goto error_exit;
}
+#ifdef DEBUG
+ { int _i_;
+ printf("$MFT $BITMAP =\n");
+ for (_i_ = 0; _i_ < l; _i_++)
+ printf("0x%s%x%s", vol->mft_bitmap[_i_] < 0x10 ? "0" : "",
+ vol->mft_bitmap[_i_], _i_ % 8 ? ", " : "\n");
+ printf("\n");
+ }
+#endif
/* Find the $DATA attribute in $Mft. */
memset(&ctx, 0, sizeof(attr_search_context));
@@ -299,5 +378,5 @@
ctx.attr = (ATTR_RECORD*)((char*)mb + le16_to_cpu(mb->attrs_offset));
ctx.is_first = TRUE;
- if (!find_attr(vol, $DATA, NULL, 0, 0, NULL, 0, &ctx)) {
+ if (!find_attr($DATA, NULL, 0, 0, NULL, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "$DATA attribute not found in $Mft?!?\n");
@@ -330,8 +409,8 @@
/* Now load the bitmap from $Bitmap. */
printf("Loading $Bitmap... ");
- mref = (MFT_REF)FILE_$BitMap;
+ mref = (MFT_REF)FILE_$Bitmap;
if (err = read_file_record(vol, &mref, &mb, NULL)) {
puts(FAILED);
- errno = err;
+ errno = -err;
goto error_exit;
}
@@ -339,5 +418,5 @@
ctx.mrec = mb;
/* Find the bitmap (it is in the $DATA attribute). */
- if (!find_first_attr(vol, $DATA, NULL, 0, 0, NULL, 0, &ctx)) {
+ if (!find_first_attr($DATA, NULL, 0, 0, NULL, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "bitmap attribute not found in $Bitmap?!?\n");
@@ -378,5 +457,5 @@
if (err = read_file_record(vol, &mref, &mb, NULL)) {
puts(FAILED);
- errno = err;
+ errno = -err;
goto error_exit;
}
@@ -384,5 +463,5 @@
ctx.mrec = mb;
/* Find the bitmap (it is in the $DATA attribute). */
- if (!find_first_attr(vol, $DATA, NULL, 0, 0, NULL, 0, &ctx)) {
+ if (!find_first_attr($DATA, NULL, 0, 0, NULL, 0, NULL, 0, &ctx)) {
puts(FAILED);
fprintf(stderr, "$DATA attribute not found in $UpCase?!?\n");
@@ -410,5 +489,5 @@
}
vol->upcase_len = l >> 1;
- vol->upcase = (wchar_t*)malloc(l);
+ vol->upcase = (uchar_t*)malloc(l);
if (!vol->upcase) {
puts(FAILED);
@@ -435,5 +514,5 @@
if (err = read_file_record(vol, &mref, &mb, NULL)) {
puts(FAILED);
- errno = err;
+ errno = -err;
goto error_exit;
}
@@ -441,5 +520,5 @@
ctx.mrec = mb;
/* Find the $VOLUME_INFORMATION attribute. */
- if (!find_first_attr(vol, $VOLUME_INFORMATION, NULL, 0, 0, NULL, 0,
+ if (!find_first_attr($VOLUME_INFORMATION, NULL, 0, 0, NULL, 0, NULL, 0,
&ctx)) {
puts(FAILED);
@@ -450,11 +529,11 @@
}
a = ctx.attr;
- /* Has to be resident. */
- if (a->non_resident) {
- fprintf(stderr, "Error: Attribute $VOLUME_INFORMATION must " \
- "be resident (and it isn't)!\n");
- errno = EIO;
+ /* Has to be resident. */
+ if (a->non_resident) {
+ fprintf(stderr, "Error: Attribute $VOLUME_INFORMATION must " \
+ "be resident (and it isn't)!\n");
+ errno = EIO;
goto error_exit;
- }
+ }
/* Get a pointer to the value of the attribute. */
vinf = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
@@ -471,5 +550,5 @@
}
/* Setup vol from the volume information attribute value. */
- vol->major_ver = vinf->major_ver;
+ vol->major_ver = vinf->major_ver;
vol->minor_ver = vinf->minor_ver;
/* Do not use le16_to_cpu() macro here as our VOLUME_FLAGS are
@@ -483,5 +562,5 @@
free(mb);
mb = NULL;
-
+
/* FIXME: Need to deal with FILE_$AttrDef. */
|