Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv19578/libntfs
Modified Files:
attrib.c bootsect.c volume.c
Log Message:
More fixes and updates.
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -U2 -r1.39 -r1.40
--- attrib.c 1 Jun 2002 00:41:45 -0000 1.39
+++ attrib.c 2 Jun 2002 23:02:20 -0000 1.40
@@ -82,5 +82,5 @@
}
/* Set the volume flags. */
- c->flags = cpu_to_le16(flags);
+ v->flags = c->flags = cpu_to_le16(flags);
ntfs_put_attr_search_ctx(ctx);
/* Success! */
Index: bootsect.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/bootsect.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -U2 -r1.9 -r1.10
--- bootsect.c 24 Apr 2002 01:37:37 -0000 1.9
+++ bootsect.c 2 Jun 2002 23:02:20 -0000 1.10
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
-#include "types.h"
#include "bootsect.h"
#include "debug.h"
@@ -165,4 +166,102 @@
}
return FALSE;
+}
+
+/**
+ * parse_ntfs_boot_sector - setup an ntfs volume from an ntfs boot sector
+ * @vol: ntfs_volume to setup
+ * @bs: buffer containing ntfs boot sector to parse
+ *
+ * Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the
+ * obtained values.
+ *
+ * Return 0 on success or -1 on error with errno set to the error code EINVAL.
+ */
+int parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
+{
+ __u8 sectors_per_cluster;
+ __s8 c;
+
+ /* We return -1 with errno = EINVAL on error. */
+ errno = EINVAL;
+
+ /*
+ * 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;
+ Dprintf("NumberOfSectors = %Li\n", sle64_to_cpu(bs->number_of_sectors));
+ Dprintf("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
+ if (sectors_per_cluster & (sectors_per_cluster - 1)) {
+ Dprintf("Error: %s is not a valid NTFS partition! "
+ "sectors_per_cluster is not a power of 2.\n",
+ vol->dev_name);
+ return -1;
+ }
+ vol->nr_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);
+ Dprintf("MFT LCN = 0x%Lx\n", vol->mft_lcn);
+ Dprintf("MFTMirr LCN = 0x%Lx\n", vol->mftmirr_lcn);
+ if (vol->mft_lcn > vol->nr_clusters ||
+ vol->mftmirr_lcn > vol->nr_clusters) {
+ Dprintf("Error: %s is not a valid NTFS partition! ($Mft LCN "
+ "or\n$MftMirr LCN is greater than the number "
+ "of clusters!\n", vol->dev_name);
+ return -1;
+ }
+ vol->cluster_size = sectors_per_cluster *
+ le16_to_cpu(bs->bpb.bytes_per_sector);
+ if (vol->cluster_size & (vol->cluster_size - 1)) {
+ Dprintf("Error: %s is not a valid NTFS partition! "
+ "cluster_size is not a power of 2.\n",
+ vol->dev_name);
+ return -1;
+ }
+ 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;
+ Dprintf("ClusterSize = 0x%x\n", vol->cluster_size);
+ Dprintf("ClusterSizeBits = %u\n", vol->cluster_size_bits);
+ Dprintf("ClustersPerMftRecord = 0x%x\n", c);
+ /*
+ * 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)) {
+ Dprintf("Error: %s is not a valid NTFS partition! "
+ "mft_record_size is not a power of 2.\n",
+ vol->dev_name);
+ return -1;
+ }
+ vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
+ Dprintf("MftRecordSize = 0x%x\n", vol->mft_record_size);
+ Dprintf("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
+ /*
+ * Work out the size of the MFT mirror in number of mft records. If the
+ * cluster size is less than or equal to the size taken by four mft
+ * records, the mft mirror stores the first four mft records. If the
+ * cluster size is bigger than the size taken by four mft records, the
+ * mft mirror contains as many mft records as will fit into one
+ * cluster.
+ */
+ if (vol->cluster_size <= 4 * vol->mft_record_size)
+ vol->mftmirr_size = 4;
+ else
+ vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
+ return 0;
}
Index: volume.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/volume.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -U2 -r1.42 -r1.43
--- volume.c 2 Jun 2002 13:57:59 -0000 1.42
+++ volume.c 2 Jun 2002 23:02:20 -0000 1.43
@@ -84,225 +84,54 @@
extern ntfs_inode *allocate_ntfs_inode(ntfs_volume *);
-/**
- * ntfs_mount - open ntfs volume
- * @name: name of device/file to open
- * @rwflag: optional mount flags
- *
- * This function mounts an ntfs volume. @name should contain the name of the
- * device/file to mount as the ntfs volume.
- *
- * @rwflags is an optional second parameter. The same flags are used as for
- * the mount system call (man 2 mount). Currently only the following flag
- * is implemented:
- * MS_RDONLY - mount volume read-only
- *
- * The function opens the device or file @name and verifies that it contains a
- * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
- * some of the values inside the structure from the information stored in the
- * bootsector. It proceeds to load the necessary system files and completes
- * setting up the structure.
+/*
+ * Internal function:
*
- * ntfs_mount() returns a pointer to the allocated ntfs_volume structure.
- * On error, the return value is NULL and errno is set appropriately.
+ * ntfs_load_mft - load the $MFT and setup the ntfs volume with it
+ * @vol: ntfs volume whose $MFT to load
*
- * Note, that a copy is made of @name, and hence it can be discarded as
- * soon as the function returns.
+ * Load $MFT from @vol and setup @vol with it. After calling this function the
+ * volume @vol is ready for use by all read access functions provided by the
+ * ntfs library.
*
- * FIXME: Should document all error codes that can be returned and what each
- * means.
+ * Return 0 on success and -1 on error with errno set to the error code.
*/
-ntfs_volume *ntfs_mount(const char *name, unsigned long rwflag)
+static int ntfs_load_mft(ntfs_volume *vol)
{
VCN next_vcn, last_vcn, highest_vcn;
__s64 l;
- const char *OK = "OK";
- const char *FAILED = "FAILED";
- ntfs_volume *vol = NULL;
- NTFS_BOOT_SECTOR *bs = NULL;
MFT_RECORD *mb = NULL;
- __u8 *m = NULL, *m2 = NULL;
ntfs_attr_search_ctx *ctx = NULL;
- run_list_element *rl;
- ntfs_inode *ni;
- ntfs_attr *na;
ATTR_RECORD *a;
- VOLUME_INFORMATION *vinf;
- uchar_t *vname;
- int i, j;
- __u32 u;
- ssize_t br;
- __u8 sectors_per_cluster;
- __s8 c;
- int eo, ro = rwflag & MS_RDONLY;
-#ifdef DEBUG
- BOOL debug = 1;
-#else
- BOOL debug = 0;
-#endif
-
- if (!name) {
- errno = EINVAL;
- return NULL;
- }
- /* Allocate the volume structure. */
- vol = __allocate_ntfs_volume();
- if (!vol)
- goto error_exit;
- /* Make a copy of the partition name. */
- if (!(vol->dev_name = strdup(name)))
- goto error_exit;
- /* Allocate the boot sector structure. */
- if (!(bs = (NTFS_BOOT_SECTOR *)malloc(sizeof(NTFS_BOOT_SECTOR))))
- goto error_exit;
- Dprintf("Reading bootsector... ");
- if ((vol->fd = open(name, ro ? O_RDONLY: O_RDWR)) == -1) {
- Dputs(FAILED);
- Dperror("Error opening partition file");
- goto error_exit;
- }
- /* Now read the bootsector. */
- br = ntfs_pread(vol->fd, 0, sizeof(NTFS_BOOT_SECTOR), bs);
- if (br != sizeof(NTFS_BOOT_SECTOR)) {
- Dputs(FAILED);
- if (br != -1)
- errno = EINVAL;
- if (!br)
- Dputs("Error: partition is smaller than bootsector "
- "size. Weird!");
- else
- Dperror("Error reading bootsector");
- goto error_exit;
- }
- Dputs(OK);
- if (!is_boot_sector_ntfs(bs, !debug)) {
- // FIXME: Try the bootsector backup or leave to ntfsck? (AIA)
- Dprintf("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;
- Dprintf("NumberOfSectors = %Li\n", sle64_to_cpu(bs->number_of_sectors));
- Dprintf("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
- if (sectors_per_cluster & (sectors_per_cluster - 1)) {
- Dprintf("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->nr_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);
- Dprintf("MFT LCN = %Li\n", vol->mft_lcn);
- Dprintf("MFTMirr LCN = 0x%Li\n", vol->mftmirr_lcn);
- if (vol->mft_lcn > vol->nr_clusters ||
- vol->mftmirr_lcn > vol->nr_clusters) {
- Dprintf("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)) {
- Dprintf("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;
- Dprintf("ClusterSize = 0x%x\n", vol->cluster_size);
- Dprintf("ClusterSizeBits = %u\n", vol->cluster_size_bits);
- Dprintf("ClustersPerMftRecord = 0x%x\n", c);
- /*
- * 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)) {
- Dprintf("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;
- Dprintf("MftRecordSize = 0x%x\n", vol->mft_record_size);
- Dprintf("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
- /*
- * Work out the size of the MFT mirror in number of mft records. If the
- * cluster size is less than or equal to the size taken by four mft
- * records, the mft mirror stores the first four mft records. If the
- * cluster size is bigger than the size taken by four mft records, the
- * mft mirror contains as many mft records as will fit into one
- * cluster.
- */
- if (vol->cluster_size <= 4 * vol->mft_record_size)
- vol->mftmirr_size = 4;
- else
- vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
+ int eo;
- /* Start with $Mft. */
- Dprintf("Loading $Mft... ");
/* Manually setup an ntfs_inode. */
vol->mft_ni = allocate_ntfs_inode(vol);
- if (!vol->mft_ni) {
- Dputs(FAILED);
- Dperror("Error allocating memory for $Mft");
+ mb = (MFT_RECORD*)malloc(vol->mft_record_size);
+ if (!vol->mft_ni || !mb) {
+ Dperror("Error allocating memory for $MFT");
goto error_exit;
}
vol->mft_ni->mft_no = 0;
- if (!(mb = (MFT_RECORD*)malloc(vol->mft_record_size))) {
- Dputs(FAILED);
- Dperror("Error allocating memory for $Mft");
- goto error_exit;
- }
vol->mft_ni->mrec = mb;
/* Can't use any of the higher level functions yet! */
- br = ntfs_mst_pread(vol->fd, vol->mft_lcn << vol->cluster_size_bits, 1,
+ l = ntfs_mst_pread(vol->fd, vol->mft_lcn << vol->cluster_size_bits, 1,
vol->mft_record_size, mb);
- if (br != 1) {
- Dputs(FAILED);
- if (br == -1)
- Dperror("Error reading $Mft");
- else
- Dputs("Error reading $Mft.");
- errno = EIO;
+ if (l != 1) {
+ if (l != -1)
+ errno = EIO;
+ Dperror("Error reading $MFT");
goto error_exit;
}
if (is_baad_record(mb->magic)) {
- Dputs(FAILED);
Dputs("Error: Incomplete multi sector transfer detected in "
- "$Mft.");
- errno = EIO;
- goto error_exit;
+ "$MFT.");
+ goto io_error_exit;
}
if (!is_mft_record(mb->magic)) {
- Dputs(FAILED);
- Dputs("Error: Invalid mft record for $Mft.");
- errno = EIO;
- goto error_exit;
+ Dputs("Error: $MFT has invalid magic.");
+ goto io_error_exit;
}
ctx = ntfs_get_attr_search_ctx(vol->mft_ni, mb);
if (!ctx) {
- Dputs(FAILED);
Dperror("Failed to allocate attribute search context");
goto error_exit;
@@ -310,6 +139,5 @@
if (p2n(ctx->attr) < p2n(mb) ||
(char*)ctx->attr > (char*)mb + vol->mft_record_size) {
- Dputs(FAILED);
- Dputs("Error: corrupt mft record for $Mft.");
+ Dputs("Error: $MFT is corrupt.");
goto io_error_exit;
}
@@ -317,7 +145,5 @@
if (ntfs_lookup_attr(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx)) {
if (errno != ENOENT) {
- Dputs(FAILED);
- Dputs("Error: corrupt attribute list in mft record "
- "for $Mft.");
+ Dputs("Error: $MFT has corrupt attribute list.");
goto io_error_exit;
}
@@ -326,14 +152,6 @@
NInoSetAttrList(vol->mft_ni);
l = get_attribute_value_length(ctx->attr);
- if (l <= 0) {
- Dputs(FAILED);
- Dputs("Error: attribute list in mft record for $Mft has zero "
- "length.");
- goto io_error_exit;
- }
- if (l > 0x40000) {
- Dputs(FAILED);
- Dputs("Error: attribute list in mft record for $Mft exceeds "
- "maximum length.");
+ if (l <= 0 || l > 0x40000) {
+ Dputs("Error: $MFT/$ATTRIBUTE_LIST has invalid length.");
goto io_error_exit;
}
@@ -341,5 +159,4 @@
vol->mft_ni->attr_list = malloc(l);
if (!vol->mft_ni->attr_list) {
- Dputs(FAILED);
Dputs("Error: failed to allocate buffer for attribute list.");
goto error_exit;
@@ -348,12 +165,10 @@
vol->mft_ni->attr_list);
if (!l) {
- Dputs(FAILED);
- Dputs("Error: failed to get attribute list.");
+ Dputs("Error: failed to get value of $MFT/$ATTRIBUTE_LIST.");
goto io_error_exit;
}
if (l != vol->mft_ni->attr_list_size) {
- Dputs(FAILED);
- Dputs("Error: bytes gotten != expected when getting "
- "attribute list.");
+ Dputs("Error: got unexepected amount of data when reading "
+ "$MFT/$ATTRIBUTE_LIST.");
goto io_error_exit;
}
@@ -364,7 +179,6 @@
ctx->attr, NULL);
if (!vol->mft_ni->attr_list_rl) {
- Dputs(FAILED);
- Dputs("Error: failed to get run list for attribute "
- "list.");
+ Dperror("Error: failed to get run list for "
+ "$MFT/$ATTRIBUTE_LIST");
goto error_exit;
}
@@ -376,5 +190,4 @@
vol->mft_na = ntfs_attr_open(vol->mft_ni, AT_DATA, NULL, 0);
if (!vol->mft_na) {
- Dputs(FAILED);
Dperror("Failed to open ntfs attribute");
goto error_exit;
@@ -391,9 +204,7 @@
run_list_element *nrl;
- /* Cache the current attribute. */
a = ctx->attr;
/* $MFT must be non-resident. */
if (!a->non_resident) {
- Dputs(FAILED);
Dputs("$MFT must be non-resident but a resident "
"extent was found. $MFT is corrupt. "
@@ -404,5 +215,4 @@
if (a->flags & ATTR_COMPRESSION_MASK ||
a->flags & ATTR_IS_ENCRYPTED) {
- Dputs(FAILED);
Dputs("$MFT must be uncompressed and unencrypted but "
"a compressed/encrypted extent was "
@@ -418,5 +228,4 @@
nrl = ntfs_decompress_mapping_pairs(vol, a, vol->mft_na->rl);
if (!nrl) {
- Dputs(FAILED);
Dperror("decompress_mapping_pairs() failed");
goto error_exit;
@@ -434,5 +243,4 @@
/* Avoid endless loops due to corruption. */
if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {
- Dputs(FAILED);
Dputs("$MFT has corrupt attribute list attribute. "
"Run chkdsk.");
@@ -441,5 +249,4 @@
}
if (!a) {
- Dputs(FAILED);
Dputs("$MFT/$DATA attribute not found. $MFT is corrupt. "
"Run chkdsk.");
@@ -447,5 +254,4 @@
}
if (highest_vcn && highest_vcn != last_vcn - 1) {
- Dputs(FAILED);
Dputs("Failed to load the complete run list for $MFT/$DATA. "
"Bug or corrupt $MFT. Run chkdsk.");
@@ -458,5 +264,4 @@
ntfs_put_attr_search_ctx(ctx);
ctx = NULL;
- mb = NULL;
/*
* The volume is now setup so we can use all read access functions.
@@ -464,41 +269,67 @@
vol->mftbmp_na = ntfs_attr_open(vol->mft_ni, AT_BITMAP, NULL, 0);
if (!vol->mftbmp_na) {
- Dputs(FAILED);
- Dperror("Failed to open ntfs attribute");
+ Dperror("Failed to open $MFT/$BITMAP");
goto error_exit;
}
- Dputs(OK);
+ return 0;
+io_error_exit:
+ errno = EIO;
+error_exit:
+ eo = errno;
+ if (ctx)
+ ntfs_put_attr_search_ctx(ctx);
+ if (vol->mft_na) {
+ ntfs_attr_close(vol->mft_na);
+ vol->mft_na = NULL;
+ }
+ if (vol->mft_ni) {
+ ntfs_close_inode(vol->mft_ni);
+ vol->mft_ni = NULL;
+ }
+ errno = eo;
+ return -1;
+}
+
+/*
+ * Internal function:
+ *
+ * ntfs_load_mftmirr - load the $MFTMirr and setup the ntfs volume with it
+ * @vol: ntfs volume whose $MFTMirr to load
+ *
+ * Load $MFTMirr from @vol and setup @vol with it. After calling this function
+ * the volume @vol is ready for use by all write access functions provided by
+ * the ntfs library (assuming ntfs_load_mft() has been called successfully
+ * beforehand).
+ *
+ * Return 0 on success and -1 on error with errno set to the error code.
+ */
+static int ntfs_load_mftmirr(ntfs_volume *vol)
+{
+ int i;
+ run_list_element rl[2];
- /* Need to setup the mft mirror so we can use write functions, too. */
- Dprintf("Loading $MFTMirr... ");
vol->mftmirr_ni = ntfs_open_inode(vol, FILE_MFTMirr);
if (!vol->mftmirr_ni) {
- Dputs(FAILED);
- Dperror("Failed to open inode");
- goto error_exit;
+ Dperror("Failed to open inode $MFTMirr");
+ return -1;
}
/* Get an ntfs attribute for $MFTMirr/$DATA, too. */
vol->mftmirr_na = ntfs_attr_open(vol->mftmirr_ni, AT_DATA, NULL, 0);
if (!vol->mftmirr_na) {
- Dputs(FAILED);
- Dperror("Failed to open ntfs attribute");
+ Dperror("Failed to open $MFTMirr/$DATA");
goto error_exit;
}
if (ntfs_attr_map_run_list(vol->mftmirr_na, 0) < 0) {
- Dputs(FAILED);
- Dperror("Failed to map run list");
- goto error_exit;
- }
- rl = (run_list_element*)malloc(sizeof(run_list_element) * 2);
- if (!rl) {
- Dperror("Failed to allocate run list for mft mirror");
+ Dperror("Failed to map run list of $MFTMirr/$DATA");
goto error_exit;
}
/* Construct the mft mirror run list. */
- rl[0].vcn = rl[1].length = 0;
+ rl[0].vcn = 0;
rl[0].lcn = vol->mftmirr_lcn;
- rl[1].vcn = rl[0].length = (vol->mftmirr_size * vol->mft_record_size +
+ rl[0].length = (vol->mftmirr_size * vol->mft_record_size +
vol->cluster_size - 1) / vol->cluster_size;
+ rl[1].vcn = rl[0].length;
rl[1].lcn = LCN_ENOENT;
+ rl[1].length = 0;
/* Compare the two run lists. They must be identical. */
i = 0;
@@ -507,13 +338,171 @@
rl[i].lcn != vol->mftmirr_na->rl[i].lcn ||
rl[i].length != vol->mftmirr_na->rl[i].length) {
- Dputs(FAILED);
- Dputs("$MFTMirr location mismatch! Run chkdsk.");
- goto io_error_exit;
+ Dputs("Error: $MFTMirr location mismatch! Run chkdsk.");
+ errno = EIO;
+ goto error_exit;
}
} while (rl[i++].length);
- free(rl);
+ return 0;
+error_exit:
+ i = errno;
+ if (vol->mftmirr_na) {
+ ntfs_attr_close(vol->mftmirr_na);
+ vol->mftmirr_na = NULL;
+ }
+ ntfs_close_inode(vol->mftmirr_ni);
+ vol->mftmirr_ni = NULL;
+ errno = i;
+ return -1;
+}
+
+/**
+ * ntfs_startup_volume - allocate and setup an ntfs volume
+ * @name: name of device/file to open
+ * @rwflag: optional mount flags
+ *
+ * Load, verify and parse bootsector; load and setup $MFT and $MFTMirr. After
+ * calling this function, the volume is setup sufficiently to call all read
+ * and write access functions provided by the library.
+ *
+ * Return the allocated volume structure on success and NULL on error with
+ * errno set to the error code.
+ */
+ntfs_volume *ntfs_startup_volume(const char *name, unsigned long rwflag)
+{
+ __s64 br;
+ const char *OK = "OK";
+ const char *FAILED = "FAILED";
+ ntfs_volume *vol;
+ NTFS_BOOT_SECTOR *bs = NULL;
+ int eo, ro = rwflag & MS_RDONLY;
+#ifdef DEBUG
+ BOOL debug = 1;
+#else
+ BOOL debug = 0;
+#endif
+
+ /* Allocate the volume structure. */
+ vol = __allocate_ntfs_volume();
+ if (!vol)
+ return NULL;
+ /* Make a copy of the partition name. */
+ if (!(vol->dev_name = strdup(name)))
+ goto error_exit;
+ /* Allocate the boot sector structure. */
+ if (!(bs = (NTFS_BOOT_SECTOR *)malloc(sizeof(NTFS_BOOT_SECTOR))))
+ goto error_exit;
+ Dprintf("Reading bootsector... ");
+ if ((vol->fd = open(name, ro ? O_RDONLY: O_RDWR)) == -1) {
+ Dputs(FAILED);
+ Dperror("Error opening partition file");
+ goto error_exit;
+ }
+ /* Now read the bootsector. */
+ br = ntfs_pread(vol->fd, 0, sizeof(NTFS_BOOT_SECTOR), bs);
+ if (br != sizeof(NTFS_BOOT_SECTOR)) {
+ Dputs(FAILED);
+ if (br != -1)
+ errno = EINVAL;
+ if (!br)
+ Dputs("Error: partition is smaller than bootsector "
+ "size. Weird!");
+ else
+ Dperror("Error reading bootsector");
+ goto error_exit;
+ }
Dputs(OK);
+ if (!is_boot_sector_ntfs(bs, !debug)) {
+ Dprintf("Error: %s is not a valid NTFS partition!\n", name);
+ errno = EINVAL;
+ goto error_exit;
+ }
+ if (parse_ntfs_boot_sector(vol, bs) < 0) {
+ Dperror("Failed to parse ntfs bootsector");
+ goto error_exit;
+ }
+ free(bs);
+ bs = NULL;
+
+ /* Need to setup $MFT so we can use the library read functions. */
+ Dprintf("Loading $MFT... ");
+ if (ntfs_load_mft(vol) < 0) {
+ Dputs(FAILED);
+ Dperror("Failed to load $MFT");
+ goto error_exit;
+ }
+ Dputs(OK);
+
+ /* Need to setup $MFTMirr so we can use the write functions, too. */
+ Dprintf("Loading $MFTMirr... ");
+ if (ntfs_load_mftmirr(vol) < 0) {
+ Dputs(FAILED);
+ Dperror("Failed to load $MFTMirr");
+ goto error_exit;
+ }
+ Dputs(OK);
+ return vol;
+error_exit:
+ eo = errno;
+ if (bs)
+ free(bs);
+ if (vol)
+ __release_ntfs_volume(vol);
+ errno = eo;
+ return NULL;
+}
+
+/**
+ * ntfs_mount - open ntfs volume
+ * @name: name of device/file to open
+ * @rwflag: optional mount flags
+ *
+ * This function mounts an ntfs volume. @name should contain the name of the
+ * device/file to mount as the ntfs volume.
+ *
+ * @rwflags is an optional second parameter. The same flags are used as for
+ * the mount system call (man 2 mount). Currently only the following flag
+ * is implemented:
+ * MS_RDONLY - mount volume read-only
+ *
+ * The function opens the device or file @name and verifies that it contains a
+ * valid bootsector. Then, it allocates an ntfs_volume structure and initializes
+ * some of the values inside the structure from the information stored in the
+ * bootsector. It proceeds to load the necessary system files and completes
+ * setting up the structure.
+ *
+ * Return the allocated volume structure on success and NULL on error with
+ * errno set to the error code.
+ *
+ * Note, that a copy is made of @name, and hence it can be discarded as
+ * soon as the function returns.
+ */
+ntfs_volume *ntfs_mount(const char *name, unsigned long rwflag)
+{
+ __s64 l;
+ const char *OK = "OK";
+ const char *FAILED = "FAILED";
+ ntfs_volume *vol;
+ __u8 *m = NULL, *m2 = NULL;
+ ntfs_attr_search_ctx *ctx = NULL;
+ ntfs_inode *ni;
+ ntfs_attr *na;
+ ATTR_RECORD *a;
+ VOLUME_INFORMATION *vinf;
+ uchar_t *vname;
+ int i, j, eo;
+ __u32 u;
+
+ if (!name) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ vol = ntfs_startup_volume(name, rwflag);
+ if (!vol) {
+ Dperror("Failed to startup volume");
+ return NULL;
+ }
- /* Load $MFT and $MFTMirr and compare the contents. */
+ /* Load data from $MFT and $MFTMirr and compare the contents. */
m = (__u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
m2 = (__u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
@@ -545,5 +534,5 @@
goto error_exit;
}
- Dprintf("Verifying $MFTMirr and beginning of $MFT... ");
+ Dprintf("Comparing $MFTMirr to $MFT... ");
for (i = 0; i < vol->mftmirr_size; ++i) {
const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
@@ -582,8 +571,4 @@
goto io_error_exit;
}
- }
- Dputs(OK);
- Dprintf("Comparing $MFTMirr to $MFT... ");
- for (i = 0; i < vol->mftmirr_size; ++i) {
if (memcmp((__u8*)m + i * vol->mft_record_size, (__u8*)m2 +
i * vol->mft_record_size,
@@ -591,6 +576,5 @@
(__u8*)m + i * vol->mft_record_size)))) {
Dputs(FAILED);
- Dputs("The $MFT mirror does not match the $MFT. "
- "You need to run chkdsk.");
+ Dputs("$MFTMirr does not match $MFT. Run chkdsk.");
goto io_error_exit;
}
@@ -772,15 +756,10 @@
return vol;
-
io_error_exit:
errno = EIO;
error_exit:
eo = errno;
- if (bs)
- free(bs);
if (ctx)
ntfs_put_attr_search_ctx(ctx);
- if (mb)
- free(mb);
if (m)
free(m);
|