update libntfs-3g to 1.616
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21586 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -92,7 +92,7 @@ fs_identify_partition(int fd, partition_data *partition, void **_cookie)
|
||||
if(strlen(ntVolume->vol_name)>0)
|
||||
strcpy(cookie->label,ntVolume->vol_name);
|
||||
|
||||
ntfs_device_umount( ntVolume, true );
|
||||
ntfs_umount( ntVolume, true );
|
||||
|
||||
*_cookie = cookie;
|
||||
|
||||
@@ -230,7 +230,7 @@ fs_unmount(void *_ns)
|
||||
|
||||
ERRPRINT("fs_unmount - ENTER\n");
|
||||
|
||||
ntfs_device_umount( ns->ntvol, true );
|
||||
ntfs_umount( ns->ntvol, true );
|
||||
|
||||
#ifdef __HAIKU__
|
||||
recursive_lock_destroy(&(ns->vlock));
|
||||
|
||||
@@ -544,8 +544,9 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na)
|
||||
if (!next_vcn) {
|
||||
if (a->lowest_vcn) {
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Attribute first extent has "
|
||||
"non-zero lowest_vcn");
|
||||
ntfs_log_perror("First extent of inode %llu "
|
||||
"attribute has non-zero lowest_vcn",
|
||||
(unsigned long long)na->ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
/* Get the last vcn in the attribute. */
|
||||
@@ -566,7 +567,8 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na)
|
||||
/* Avoid endless loops due to corruption. */
|
||||
if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Inode has corrupt attribute list");
|
||||
ntfs_log_perror("Inode %llu has corrupt attribute list",
|
||||
(unsigned long long)na->ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
@@ -576,8 +578,9 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na)
|
||||
}
|
||||
if (highest_vcn && highest_vcn != last_vcn - 1) {
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Couldn't load full runlist: "
|
||||
"highest_vcn = 0x%llx, last_vcn = 0x%llx",
|
||||
ntfs_log_perror("Failed to load full runlist: inode: %llu "
|
||||
"highest_vcn: 0x%llx last_vcn: 0x%llx",
|
||||
(unsigned long long)na->ni->mft_no,
|
||||
(long long)highest_vcn, (long long)last_vcn);
|
||||
goto err_out;
|
||||
}
|
||||
@@ -988,10 +991,8 @@ static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs,
|
||||
((*ofs + to_write - 1) >> vol->cluster_size_bits)
|
||||
+ 1 + (*rl)->vcn - from_vcn,
|
||||
lcn_seek_from, DATA_ZONE);
|
||||
if (!rlc) {
|
||||
ntfs_log_perror("Hole filling cluster allocation failed");
|
||||
if (!rlc)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
*rl = ntfs_runlists_merge(na->rl, rlc);
|
||||
if (!*rl) {
|
||||
|
||||
@@ -466,11 +466,14 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
q++;
|
||||
}
|
||||
|
||||
len = ntfs_mbstoucs(p, &unicode, NTFS_MAX_NAME_LEN);
|
||||
len = ntfs_mbstoucs(p, &unicode, MAX_PATH);
|
||||
if (len < 0) {
|
||||
ntfs_log_debug("Couldn't convert name to Unicode: %s.\n", p);
|
||||
err = errno;
|
||||
goto close;
|
||||
} else if (len > NTFS_MAX_NAME_LEN) {
|
||||
err = ENAMETOOLONG;
|
||||
goto close;
|
||||
}
|
||||
|
||||
inum = ntfs_inode_lookup_by_name(ni, unicode, len);
|
||||
@@ -482,7 +485,10 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
}
|
||||
|
||||
if (ni != parent)
|
||||
ntfs_inode_close(ni);
|
||||
if (ntfs_inode_close(ni)) {
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
inum = MREF(inum);
|
||||
ni = ntfs_inode_open(vol, inum);
|
||||
@@ -502,7 +508,9 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
ni = NULL;
|
||||
close:
|
||||
if (ni && (ni != parent))
|
||||
ntfs_inode_close(ni);
|
||||
if (ntfs_inode_close(ni) && !err)
|
||||
err = errno;
|
||||
out:
|
||||
free(ascii);
|
||||
free(unicode);
|
||||
if (err)
|
||||
@@ -1045,12 +1053,15 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni,
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
/* Allocate MFT record for new file. */
|
||||
ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
|
||||
if (!ni) {
|
||||
ntfs_log_perror("Could not allocate new MFT record");
|
||||
|
||||
if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
|
||||
errno = EOPNOTSUPP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
|
||||
if (!ni)
|
||||
return NULL;
|
||||
/*
|
||||
* Create STANDARD_INFORMATION attribute. Write STANDARD_INFORMATION
|
||||
* version 1.2, windows will upgrade it to version 3 if needed.
|
||||
@@ -1299,7 +1310,7 @@ int ntfs_check_empty_dir(ntfs_inode *ni)
|
||||
}
|
||||
|
||||
/* Non-empty directory? */
|
||||
if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))) {
|
||||
if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){
|
||||
/* Both ENOTEMPTY and EEXIST are ok. We use the more common. */
|
||||
errno = EEXIST;
|
||||
ntfs_log_debug("Directory is not empty\n");
|
||||
@@ -1416,7 +1427,7 @@ search:
|
||||
|
||||
if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,
|
||||
name, name_len, case_sensitive,
|
||||
ni->vol->upcase, ni->vol->upcase_len)) {
|
||||
ni->vol->upcase, ni->vol->upcase_len)){
|
||||
|
||||
if (fn->file_name_type == FILE_NAME_WIN32) {
|
||||
looking_for_dos_name = TRUE;
|
||||
@@ -1525,8 +1536,8 @@ out:
|
||||
ntfs_attr_put_search_ctx(actx);
|
||||
if (ictx)
|
||||
ntfs_index_ctx_put(ictx);
|
||||
if (ni)
|
||||
ntfs_inode_close(ni);
|
||||
if (ni && ntfs_inode_close(ni) && !err)
|
||||
err = errno;
|
||||
if (err) {
|
||||
errno = err;
|
||||
ntfs_log_debug("Could not delete file: %s\n", strerror(errno));
|
||||
@@ -1567,6 +1578,12 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len)
|
||||
ntfs_log_perror("ntfs_link wrong arguments");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
|
||||
err = EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Create FILE_NAME attribute. */
|
||||
fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
|
||||
fn = ntfs_calloc(fn_len);
|
||||
@@ -1628,7 +1645,6 @@ rollback_failed:
|
||||
err_out:
|
||||
free(fn);
|
||||
errno = err;
|
||||
ntfs_log_perror("Hard link failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#define S_IFSOCK 0140000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We do not have these under DJGPP, so define our version that do not conflict
|
||||
* with other S_IFs defined under DJGPP.
|
||||
|
||||
@@ -1417,6 +1417,7 @@ static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
|
||||
|
||||
fn = ntfs_ie_filename_get(ie);
|
||||
ntfs_log_trace("file: '%s'\n", fn);
|
||||
ntfs_attr_name_free(&fn);
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -1461,7 +1462,6 @@ static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
|
||||
|
||||
ret = STATUS_OK;
|
||||
err_out:
|
||||
ntfs_attr_name_free(&fn);
|
||||
ntfs_log_trace("%s\n", ret ? "Failed" : "Done");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -107,15 +107,16 @@ ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol)
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int __ntfs_inode_release(ntfs_inode *ni)
|
||||
static void __ntfs_inode_release(ntfs_inode *ni)
|
||||
{
|
||||
if (NInoDirty(ni))
|
||||
ntfs_log_debug("Eeek. Discarding dirty inode!\n");
|
||||
ntfs_log_error("Releasing dirty inode %lld!\n",
|
||||
(long long)ni->mft_no);
|
||||
if (NInoAttrList(ni) && ni->attr_list)
|
||||
free(ni->attr_list);
|
||||
free(ni->mrec);
|
||||
free(ni);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,7 +272,7 @@ int ntfs_inode_close(ntfs_inode *ni)
|
||||
if (!ni)
|
||||
return 0;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
|
||||
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long)ni->mft_no);
|
||||
|
||||
/* If we have dirty metadata, write it out. */
|
||||
if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
|
||||
@@ -330,11 +331,18 @@ int ntfs_inode_close(ntfs_inode *ni)
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We could successfully sync, so only log this error
|
||||
* and try to sync other inode extents too.
|
||||
*/
|
||||
if (i != -1)
|
||||
ntfs_log_debug("Extent inode was not attached to base inode! "
|
||||
"Weird! Continuing regardless.\n");
|
||||
ntfs_log_error("Extent inode %lld was not found\n",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
return __ntfs_inode_release(ni);
|
||||
|
||||
__ntfs_inode_release(ni);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -425,9 +433,7 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
|
||||
base_ni->extent_nis[base_ni->nr_extents++] = ni;
|
||||
return ni;
|
||||
err_out:
|
||||
i = errno;
|
||||
__ntfs_inode_release(ni);
|
||||
errno = i;
|
||||
ntfs_log_perror("Failed to open extent inode");
|
||||
return NULL;
|
||||
}
|
||||
@@ -536,12 +542,11 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
|
||||
FILE_NAME_ATTR *fn;
|
||||
int err = 0;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
|
||||
ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no);
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to get attribute search context.\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Walk through all FILE_NAME attributes and update them. */
|
||||
@@ -550,27 +555,29 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
|
||||
le16_to_cpu(ctx->attr->value_offset));
|
||||
if (MREF_LE(fn->parent_directory) == ni->mft_no) {
|
||||
/*
|
||||
* WARNING: We cheater here and obtain 2 attribute
|
||||
* WARNING: We cheat here and obtain 2 attribute
|
||||
* search contexts for one inode (first we obtained
|
||||
* above, second will be obtained inside
|
||||
* ntfs_index_lookup), it's acceptable for library,
|
||||
* but will lock kernel.
|
||||
* but will deadlock in the kernel.
|
||||
*/
|
||||
index_ni = ni;
|
||||
} else
|
||||
index_ni = ntfs_inode_open(ni->vol,
|
||||
le64_to_cpu(fn->parent_directory));
|
||||
index_ni = ntfs_inode_open(ni->vol,
|
||||
le64_to_cpu(fn->parent_directory));
|
||||
if (!index_ni) {
|
||||
if (!err)
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to open inode with index.\n");
|
||||
ntfs_log_perror("Failed to open inode %lld with index",
|
||||
le64_to_cpu(fn->parent_directory));
|
||||
continue;
|
||||
}
|
||||
ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4);
|
||||
if (!ictx) {
|
||||
if (!err)
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to get index context.\n");
|
||||
ntfs_log_perror("Failed to get index ctx, inode %lld",
|
||||
(long long)index_ni->mft_no);
|
||||
ntfs_inode_close(index_ni);
|
||||
continue;
|
||||
}
|
||||
@@ -581,7 +588,8 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
|
||||
else
|
||||
err = errno;
|
||||
}
|
||||
ntfs_log_trace("Index lookup failed.\n");
|
||||
ntfs_log_perror("Index lookup failed, inode %lld",
|
||||
(long long)index_ni->mft_no);
|
||||
ntfs_index_ctx_put(ictx);
|
||||
ntfs_inode_close(index_ni);
|
||||
continue;
|
||||
@@ -599,13 +607,14 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
|
||||
fn->last_access_time = utc2ntfs(ni->last_access_time);
|
||||
ntfs_index_entry_mark_dirty(ictx);
|
||||
ntfs_index_ctx_put(ictx);
|
||||
if (ni != index_ni)
|
||||
ntfs_inode_close(index_ni);
|
||||
if ((ni != index_ni) && ntfs_inode_close(index_ni) && !err)
|
||||
err = errno;
|
||||
}
|
||||
/* Check for real error occurred. */
|
||||
if (errno != ENOENT) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
ntfs_log_perror("Attribute lookup failed, inode %lld",
|
||||
(long long)ni->mft_no);
|
||||
goto err_out;
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
@@ -646,10 +655,11 @@ int ntfs_inode_sync(ntfs_inode *ni)
|
||||
|
||||
if (!ni) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_error("Failed to sync NULL inode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
|
||||
ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no);
|
||||
|
||||
/* Update STANDARD_INFORMATION. */
|
||||
if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
|
||||
@@ -659,7 +669,8 @@ int ntfs_inode_sync(ntfs_inode *ni)
|
||||
if (err != EIO)
|
||||
err = EBUSY;
|
||||
}
|
||||
ntfs_log_trace("Failed to sync standard information.\n");
|
||||
ntfs_log_perror("Failed to sync standard info (inode %lld)",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
|
||||
/* Update FILE_NAME's in the index. */
|
||||
@@ -671,7 +682,8 @@ int ntfs_inode_sync(ntfs_inode *ni)
|
||||
if (err != EIO)
|
||||
err = EBUSY;
|
||||
}
|
||||
ntfs_log_trace("Failed to sync FILE_NAME attributes.\n");
|
||||
ntfs_log_perror("Failed to sync FILE_NAME (inode %lld)",
|
||||
(long long)ni->mft_no);
|
||||
NInoFileNameSetDirty(ni);
|
||||
}
|
||||
|
||||
@@ -686,33 +698,37 @@ int ntfs_inode_sync(ntfs_inode *ni)
|
||||
err = errno;
|
||||
if (err != EIO)
|
||||
err = EBUSY;
|
||||
ntfs_log_trace("Attribute list sync failed (open "
|
||||
"failed).\n");
|
||||
ntfs_log_perror("Attribute list sync failed "
|
||||
"(open, inode %lld)",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
NInoAttrListSetDirty(ni);
|
||||
} else {
|
||||
if (na->data_size == ni->attr_list_size) {
|
||||
if (ntfs_attr_pwrite(na, 0, ni->attr_list_size,
|
||||
ni->attr_list) !=
|
||||
ni->attr_list_size) {
|
||||
if (!err || errno == EIO) {
|
||||
err = errno;
|
||||
if (err != EIO)
|
||||
err = EBUSY;
|
||||
ntfs_log_trace("Attribute list sync "
|
||||
"failed (write failed).\n");
|
||||
}
|
||||
NInoAttrListSetDirty(ni);
|
||||
goto sync_inode;
|
||||
}
|
||||
|
||||
if (na->data_size == ni->attr_list_size) {
|
||||
if (ntfs_attr_pwrite(na, 0, ni->attr_list_size,
|
||||
ni->attr_list) != ni->attr_list_size) {
|
||||
if (!err || errno == EIO) {
|
||||
err = errno;
|
||||
if (err != EIO)
|
||||
err = EBUSY;
|
||||
ntfs_log_perror("Attribute list sync "
|
||||
"failed (write, inode %lld)",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
} else {
|
||||
err = EIO;
|
||||
ntfs_log_trace("Attribute list sync failed (invalid size).\n");
|
||||
NInoAttrListSetDirty(ni);
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else {
|
||||
err = EIO;
|
||||
ntfs_log_error("Attribute list sync failed (bad size, "
|
||||
"inode %lld)\n", (long long)ni->mft_no);
|
||||
NInoAttrListSetDirty(ni);
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
|
||||
|
||||
sync_inode:
|
||||
/* Write this inode out to the $MFT (and $MFTMirr if applicable). */
|
||||
if (NInoTestAndClearDirty(ni)) {
|
||||
if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) {
|
||||
@@ -722,7 +738,8 @@ int ntfs_inode_sync(ntfs_inode *ni)
|
||||
err = EBUSY;
|
||||
}
|
||||
NInoSetDirty(ni);
|
||||
ntfs_log_trace("Base MFT record sync failed.\n");
|
||||
ntfs_log_perror("MFT record sync failed, inode %lld",
|
||||
(long long)ni->mft_no);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,18 +751,21 @@ int ntfs_inode_sync(ntfs_inode *ni)
|
||||
ntfs_inode *eni;
|
||||
|
||||
eni = ni->extent_nis[i];
|
||||
if (NInoTestAndClearDirty(eni)) {
|
||||
if (ntfs_mft_record_write(eni->vol, eni->mft_no,
|
||||
eni->mrec)) {
|
||||
if (!err || errno == EIO) {
|
||||
err = errno;
|
||||
if (err != EIO)
|
||||
err = EBUSY;
|
||||
}
|
||||
NInoSetDirty(eni);
|
||||
ntfs_log_trace("Extent MFT record sync "
|
||||
"failed.\n");
|
||||
if (!NInoTestAndClearDirty(eni))
|
||||
continue;
|
||||
|
||||
if (ntfs_mft_record_write(eni->vol, eni->mft_no,
|
||||
eni->mrec)) {
|
||||
if (!err || errno == EIO) {
|
||||
err = errno;
|
||||
if (err != EIO)
|
||||
err = EBUSY;
|
||||
}
|
||||
NInoSetDirty(eni);
|
||||
ntfs_log_perror("Extent MFT record sync failed,"
|
||||
" inode %lld/%lld",
|
||||
(long long)ni->mft_no,
|
||||
(long long)eni->mft_no);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* lcnalloc.c - Cluster (de)allocation code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2007 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
* Copyright (c) 2004-2007 Szabolcs Szakacsits
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -45,56 +45,91 @@
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define NTFS_LCNALLOC_BSIZE 512
|
||||
/*
|
||||
* Plenty possibilities for big optimizations all over in the cluster
|
||||
* allocation, however at the moment the dominant bottleneck (~ 90%) is
|
||||
* the update of the mapping pairs which converges to the cubic Faulhaber's
|
||||
* formula as the function of the number of extents (fragments, runs).
|
||||
*/
|
||||
#define NTFS_LCNALLOC_BSIZE 1024
|
||||
#define NTFS_LCNALLOC_SKIP NTFS_LCNALLOC_BSIZE
|
||||
|
||||
#define NTFS_LCNALLOC_SKIP 4096
|
||||
|
||||
static void ntfs_cluster_set_zone_pos(LCN zone_start, LCN zone_end,
|
||||
LCN *zone_pos, LCN tc, LCN bmp_initial_pos)
|
||||
static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc)
|
||||
{
|
||||
ntfs_log_trace("Before: zone_pos: %lld\n", (long long)*zone_pos);
|
||||
ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, tc);
|
||||
|
||||
if (tc >= zone_end) {
|
||||
*zone_pos = zone_start;
|
||||
// FIXME: seems to be bogus and only MFT zone used it
|
||||
if (!zone_end)
|
||||
*zone_pos = 0;
|
||||
} else if ((bmp_initial_pos >= *zone_pos || tc > *zone_pos) &&
|
||||
tc >= zone_start)
|
||||
*zone_pos = tc;
|
||||
|
||||
ntfs_log_trace("After: zone_pos: %lld\n", (long long)*zone_pos);
|
||||
if (tc >= end)
|
||||
*pos = start;
|
||||
else if (tc >= start)
|
||||
*pos = tc;
|
||||
}
|
||||
|
||||
static int ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc,
|
||||
LCN bmp_initial_pos)
|
||||
static void ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc)
|
||||
{
|
||||
ntfs_log_trace("tc = %lld, zone = %d\n", (long long)tc, zone);
|
||||
|
||||
switch (zone) {
|
||||
case 1:
|
||||
ntfs_cluster_set_zone_pos(vol->mft_lcn,
|
||||
vol->mft_zone_end,
|
||||
&vol->mft_zone_pos,
|
||||
tc, bmp_initial_pos);
|
||||
break;
|
||||
case 2:
|
||||
ntfs_cluster_set_zone_pos(vol->mft_zone_end,
|
||||
vol->nr_clusters,
|
||||
&vol->data1_zone_pos,
|
||||
tc, bmp_initial_pos);
|
||||
break;
|
||||
case 4:
|
||||
ntfs_cluster_set_zone_pos(0,
|
||||
vol->mft_zone_start,
|
||||
&vol->data2_zone_pos,
|
||||
tc, bmp_initial_pos);
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Invalid zone: %d\n", zone);
|
||||
return -1;
|
||||
if (zone == 1)
|
||||
ntfs_cluster_set_zone_pos(vol->mft_lcn, vol->mft_zone_end,
|
||||
&vol->mft_zone_pos, tc);
|
||||
else if (zone == 2)
|
||||
ntfs_cluster_set_zone_pos(vol->mft_zone_end, vol->nr_clusters,
|
||||
&vol->data1_zone_pos, tc);
|
||||
else /* zone == 4 */
|
||||
ntfs_cluster_set_zone_pos(0, vol->mft_zone_start,
|
||||
&vol->data2_zone_pos, tc);
|
||||
}
|
||||
|
||||
static s64 max_empty_bit_range(unsigned char *buf, int size)
|
||||
{
|
||||
int i, j, run = 0;
|
||||
int max_range = 0;
|
||||
s64 start_pos = -1;
|
||||
|
||||
ntfs_log_trace("Entering");
|
||||
|
||||
for (i = 0; i < size; i++, buf++) {
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
|
||||
int bit = *buf & (1 << j);
|
||||
|
||||
if (bit) {
|
||||
if (run > max_range) {
|
||||
max_range = run;
|
||||
start_pos = i * 8 + j - run;
|
||||
}
|
||||
run = 0;
|
||||
} else
|
||||
run++;
|
||||
}
|
||||
}
|
||||
|
||||
if (run > max_range)
|
||||
start_pos = i * 8 - run;
|
||||
|
||||
return start_pos;
|
||||
}
|
||||
|
||||
static int bitmap_writeback(ntfs_volume *vol, s64 pos, s64 size, void *b,
|
||||
u8 *writeback)
|
||||
{
|
||||
s64 written;
|
||||
|
||||
ntfs_log_trace("Entering");
|
||||
|
||||
if (!*writeback)
|
||||
return 0;
|
||||
|
||||
*writeback = 0;
|
||||
|
||||
written = ntfs_attr_pwrite(vol->lcnbmp_na, pos, size, b);
|
||||
if (written != size) {
|
||||
if (!written)
|
||||
errno = EIO;
|
||||
ntfs_log_perror("Bitmap write error (%lld, %lld)", pos, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -126,45 +161,33 @@ static int ntfs_cluster_update_zone_pos(ntfs_volume *vol, u8 zone, LCN tc,
|
||||
* expanded to cover the start of the volume in order to reserve space for the
|
||||
* mft bitmap attribute.
|
||||
*
|
||||
* This is not the prettiest function but the complexity stems from the need of
|
||||
* implementing the mft vs data zoned approach and from the fact that we have
|
||||
* access to the lcn bitmap via up to NTFS_LCNALLOC_BSIZE bytes at a time, so we
|
||||
* need to cope with crossing over boundaries of two buffers. Further, the fact
|
||||
* that the allocator allows for caller supplied hints as to the location of
|
||||
* where allocation should begin and the fact that the allocator keeps track of
|
||||
* where in the data zones the next natural allocation should occur, contribute
|
||||
* to the complexity of the function. But it should all be worthwhile, because
|
||||
* this allocator should: 1) be a full implementation of the MFT zone approach
|
||||
* used by Windows, 2) cause reduction in fragmentation as much as possible,
|
||||
* and 3) be speedy in allocations (the code is not optimized for speed, but
|
||||
* the algorithm is, so further speed improvements are probably possible).
|
||||
*
|
||||
* FIXME: We should be monitoring cluster allocation and increment the MFT zone
|
||||
* size dynamically but this is something for the future. We will just cause
|
||||
* heavier fragmentation by not doing it and I am not even sure Windows would
|
||||
* grow the MFT zone dynamically, so it might even be correct not to do this.
|
||||
* The overhead in doing dynamic MFT zone expansion would be very large and
|
||||
* unlikely worth the effort. (AIA)
|
||||
*
|
||||
* TODO: I have added in double the required zone position pointer wrap around
|
||||
* logic which can be optimized to having only one of the two logic sets.
|
||||
* However, having the double logic will work fine, but if we have only one of
|
||||
* the sets and we get it wrong somewhere, then we get into trouble, so
|
||||
* removing the duplicate logic requires _very_ careful consideration of _all_
|
||||
* possible code paths. So at least for now, I am leaving the double logic -
|
||||
* better safe than sorry... (AIA)
|
||||
* The complexity stems from the need of implementing the mft vs data zoned
|
||||
* approach and from the fact that we have access to the lcn bitmap via up to
|
||||
* NTFS_LCNALLOC_BSIZE bytes at a time, so we need to cope with crossing over
|
||||
* boundaries of two buffers. Further, the fact that the allocator allows for
|
||||
* caller supplied hints as to the location of where allocation should begin
|
||||
* and the fact that the allocator keeps track of where in the data zones the
|
||||
* next natural allocation should occur, contribute to the complexity of the
|
||||
* function. But it should all be worthwhile, because this allocator:
|
||||
* 1) implements MFT zone reservation
|
||||
* 2) causes reduction in fragmentation.
|
||||
* The code is not optimized for speed.
|
||||
*/
|
||||
runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone)
|
||||
{
|
||||
LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
|
||||
LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
|
||||
LCN zone_start, zone_end; /* current search range */
|
||||
LCN last_read_pos, lcn;
|
||||
LCN bmp_pos; /* current bit position inside the bitmap */
|
||||
LCN prev_lcn = 0, prev_run_len = 0;
|
||||
s64 clusters, br;
|
||||
runlist *rl = NULL, *trl;
|
||||
u8 *buf, *byte;
|
||||
u8 *buf, *byte, bit, writeback;
|
||||
u8 pass = 1; /* 1: inside zone; 2: start of zone */
|
||||
u8 search_zone; /* 4: data2 (start) 1: mft (middle) 2: data1 (end) */
|
||||
u8 done_zones = 0;
|
||||
u8 has_guess, used_zone_pos;
|
||||
int err = 0, rlpos, rlsize, buf_size;
|
||||
u8 pass, done_zones, search_zone, need_writeback, bit;
|
||||
u8 first_try = 1;
|
||||
|
||||
ntfs_log_trace("Entering with count = 0x%llx, start_lcn = 0x%llx, "
|
||||
"zone = %s_ZONE.\n", (long long)count, (long long)
|
||||
@@ -181,490 +204,280 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
/* Return empty runlist if @count == 0 */
|
||||
if (!count) {
|
||||
rl = ntfs_malloc(0x1000);
|
||||
if (!rl)
|
||||
return NULL;
|
||||
rl[0].vcn = start_vcn;
|
||||
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[0].length = 0;
|
||||
if (rl) {
|
||||
rl[0].vcn = start_vcn;
|
||||
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[0].length = 0;
|
||||
}
|
||||
return rl;
|
||||
}
|
||||
|
||||
/* Allocate memory. */
|
||||
buf = ntfs_malloc(NTFS_LCNALLOC_BSIZE);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
/*
|
||||
* If no specific @start_lcn was requested, use the current data zone
|
||||
* position, otherwise use the requested @start_lcn but make sure it
|
||||
* lies outside the mft zone. Also set done_zones to 0 (no zones done)
|
||||
* and pass depending on whether we are starting inside a zone (1) or
|
||||
* at the beginning of a zone (2). If requesting from the MFT_ZONE,
|
||||
* we either start at the current position within the mft zone or at
|
||||
* the specified position. If the latter is out of bounds then we start
|
||||
* at the beginning of the MFT_ZONE.
|
||||
*/
|
||||
done_zones = 0;
|
||||
pass = 1;
|
||||
/*
|
||||
* zone_start and zone_end are the current search range. search_zone
|
||||
* is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of
|
||||
* volume) and 4 for data zone 2 (start of volume till start of mft
|
||||
* zone).
|
||||
* If no @start_lcn was requested, use the current zone
|
||||
* position otherwise use the requested @start_lcn.
|
||||
*/
|
||||
has_guess = 1;
|
||||
zone_start = start_lcn;
|
||||
|
||||
if (zone_start < 0) {
|
||||
if (zone == DATA_ZONE)
|
||||
zone_start = vol->data1_zone_pos;
|
||||
else
|
||||
zone_start = vol->mft_zone_pos;
|
||||
if (!zone_start) {
|
||||
/*
|
||||
* Zone starts at beginning of volume which means a
|
||||
* single pass is sufficient.
|
||||
*/
|
||||
pass = 2;
|
||||
}
|
||||
} else if (zone == DATA_ZONE && zone_start >= vol->mft_zone_start &&
|
||||
zone_start < vol->mft_zone_end) {
|
||||
zone_start = vol->mft_zone_end;
|
||||
/*
|
||||
* Starting at beginning of data1_zone which means a single
|
||||
* pass in this zone is sufficient.
|
||||
*/
|
||||
pass = 2;
|
||||
} else if (zone == MFT_ZONE && (zone_start < vol->mft_zone_start ||
|
||||
zone_start >= vol->mft_zone_end)) {
|
||||
zone_start = vol->mft_lcn;
|
||||
if (!vol->mft_zone_end)
|
||||
zone_start = 0;
|
||||
/*
|
||||
* Starting at beginning of volume which means a single pass
|
||||
* is sufficient.
|
||||
*/
|
||||
pass = 2;
|
||||
has_guess = 0;
|
||||
}
|
||||
if (zone == MFT_ZONE) {
|
||||
|
||||
used_zone_pos = has_guess ? 0 : 1;
|
||||
|
||||
if (!zone_start || zone_start == vol->mft_zone_start ||
|
||||
zone_start == vol->mft_zone_end)
|
||||
pass = 2;
|
||||
|
||||
if (zone_start < vol->mft_zone_start) {
|
||||
zone_end = vol->mft_zone_start;
|
||||
search_zone = 4;
|
||||
} else if (zone_start < vol->mft_zone_end) {
|
||||
zone_end = vol->mft_zone_end;
|
||||
search_zone = 1;
|
||||
} else /* if (zone == DATA_ZONE) */ {
|
||||
/* Skip searching the mft zone. */
|
||||
done_zones |= 1;
|
||||
if (zone_start >= vol->mft_zone_end) {
|
||||
zone_end = vol->nr_clusters;
|
||||
search_zone = 2;
|
||||
} else {
|
||||
zone_end = vol->mft_zone_start;
|
||||
search_zone = 4;
|
||||
}
|
||||
} else {
|
||||
zone_end = vol->nr_clusters;
|
||||
search_zone = 2;
|
||||
}
|
||||
/*
|
||||
* bmp_pos is the current bit position inside the bitmap. We use
|
||||
* bmp_initial_pos to determine whether or not to do a zone switch.
|
||||
*/
|
||||
bmp_pos = bmp_initial_pos = zone_start;
|
||||
|
||||
bmp_pos = zone_start;
|
||||
|
||||
/* Loop until all clusters are allocated, i.e. clusters == 0. */
|
||||
/* Loop until all clusters are allocated. */
|
||||
clusters = count;
|
||||
rlpos = rlsize = 0;
|
||||
while (1) {
|
||||
ntfs_log_trace("Start of outer while loop: done_zones = 0x%x, "
|
||||
"search_zone = %i, pass = %i, zone_start = "
|
||||
"0x%llx, zone_end = 0x%llx, bmp_initial_pos = "
|
||||
"0x%llx, bmp_pos = 0x%llx, rlpos = %i, rlsize = "
|
||||
"%i.\n", done_zones, search_zone, pass,
|
||||
(long long)zone_start, (long long)zone_end,
|
||||
(long long)bmp_initial_pos, (long long)bmp_pos,
|
||||
rlpos, rlsize);
|
||||
/* Loop until we run out of free clusters. */
|
||||
last_read_pos = bmp_pos >> 3;
|
||||
ntfs_log_trace("last_read_pos = 0x%llx.\n", (long long)last_read_pos);
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos, NTFS_LCNALLOC_BSIZE, buf);
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos,
|
||||
NTFS_LCNALLOC_BSIZE, buf);
|
||||
if (br <= 0) {
|
||||
if (!br) {
|
||||
/* Reached end of attribute. */
|
||||
ntfs_log_trace("End of attribute reached. Skipping "
|
||||
"to zone_pass_done.\n");
|
||||
if (!br)
|
||||
goto zone_pass_done;
|
||||
}
|
||||
err = errno;
|
||||
ntfs_log_perror("ntfs_attr_pread() failed");
|
||||
ntfs_log_perror("Reading $BITMAP failed");
|
||||
goto err_ret;
|
||||
}
|
||||
/*
|
||||
* We might have read less than NTFS_LCNALLOC_BSIZE bytes if we are close to
|
||||
* the end of the attribute.
|
||||
* We might have read less than NTFS_LCNALLOC_BSIZE bytes
|
||||
* if we are close to the end of the attribute.
|
||||
*/
|
||||
buf_size = (int)br << 3;
|
||||
lcn = bmp_pos & 7;
|
||||
bmp_pos &= ~7;
|
||||
need_writeback = 0;
|
||||
ntfs_log_trace("Before inner while loop: buf_size = %i, lcn = "
|
||||
"0x%llx, bmp_pos = 0x%llx, need_writeback = %i.\n",
|
||||
buf_size, (long long)lcn, (long long)bmp_pos,
|
||||
need_writeback);
|
||||
while (lcn < buf_size && lcn + bmp_pos < zone_end) {
|
||||
writeback = 0;
|
||||
|
||||
while (1) {
|
||||
byte = buf + (lcn >> 3);
|
||||
ntfs_log_trace("In inner while loop: buf_size = %i, lcn = "
|
||||
"0x%llx, bmp_pos = 0x%llx, "
|
||||
"need_writeback = %i, byte ofs = 0x%x, "
|
||||
"*byte = 0x%x.\n", buf_size,
|
||||
(long long)lcn, (long long)bmp_pos,
|
||||
need_writeback, (unsigned int)(lcn >> 3),
|
||||
(unsigned int)*byte);
|
||||
/* Skip full bytes. */
|
||||
if (*byte == 0xff) {
|
||||
lcn = (lcn + 8) & ~7;
|
||||
ntfs_log_trace("continuing while loop 1.\n");
|
||||
if (first_try) {
|
||||
first_try = 0;
|
||||
lcn += NTFS_LCNALLOC_SKIP;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
bit = 1 << (lcn & 7);
|
||||
ntfs_log_trace("bit = %i.\n", bit);
|
||||
/* If the bit is already set, go onto the next one. */
|
||||
if (*byte & bit) {
|
||||
lcn++;
|
||||
ntfs_log_trace("continuing while loop 2.\n");
|
||||
if (first_try) {
|
||||
first_try = 0;
|
||||
lcn += NTFS_LCNALLOC_SKIP;
|
||||
if (has_guess) {
|
||||
if (*byte & bit) {
|
||||
has_guess = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
lcn = max_empty_bit_range(buf, br);
|
||||
if (lcn < 0)
|
||||
break;
|
||||
has_guess = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First free bit is at lcn + bmp_pos. */
|
||||
|
||||
/* Reallocate memory if necessary. */
|
||||
if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
|
||||
ntfs_log_trace("Reallocating space.\n");
|
||||
if (!rl)
|
||||
ntfs_log_trace("First free bit is at LCN = "
|
||||
"0x%llx.\n", (long long)(lcn + bmp_pos));
|
||||
rlsize += 4096;
|
||||
trl = (runlist*)realloc(rl, rlsize);
|
||||
trl = realloc(rl, rlsize);
|
||||
if (!trl) {
|
||||
err = ENOMEM;
|
||||
ntfs_log_perror("Failed to allocate memory");
|
||||
ntfs_log_perror("realloc() failed");
|
||||
goto wb_err_ret;
|
||||
}
|
||||
rl = trl;
|
||||
ntfs_log_trace("Reallocated memory, rlsize = "
|
||||
"0x%x.\n", rlsize);
|
||||
}
|
||||
|
||||
/* Allocate the bitmap bit. */
|
||||
*byte |= bit;
|
||||
/* We need to write this bitmap buffer back to disk! */
|
||||
need_writeback = 1;
|
||||
ntfs_log_trace("*byte = 0x%x, need_writeback is set.\n",
|
||||
(unsigned int)*byte);
|
||||
writeback = 1;
|
||||
|
||||
/*
|
||||
* Coalesce with previous run if adjacent LCNs.
|
||||
* Otherwise, append a new run.
|
||||
*/
|
||||
ntfs_log_trace("Adding run (lcn 0x%llx, len 0x%llx), "
|
||||
"prev_lcn = 0x%llx, lcn = 0x%llx, "
|
||||
"bmp_pos = 0x%llx, prev_run_len = "
|
||||
"0x%llx, rlpos = %i.\n",
|
||||
(long long)(lcn + bmp_pos), 1LL,
|
||||
(long long)prev_lcn, (long long)lcn,
|
||||
(long long)bmp_pos,
|
||||
(long long)prev_run_len, rlpos);
|
||||
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
|
||||
ntfs_log_trace("Coalescing to run (lcn 0x%llx, len "
|
||||
"0x%llx).\n",
|
||||
(long long)rl[rlpos - 1].lcn,
|
||||
(long long) rl[rlpos - 1].length);
|
||||
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos)
|
||||
rl[rlpos - 1].length = ++prev_run_len;
|
||||
ntfs_log_trace("Run now (lcn 0x%llx, len 0x%llx), "
|
||||
"prev_run_len = 0x%llx.\n",
|
||||
(long long)rl[rlpos - 1].lcn,
|
||||
(long long)rl[rlpos - 1].length,
|
||||
(long long)prev_run_len);
|
||||
} else {
|
||||
if (rlpos) {
|
||||
ntfs_log_trace("Adding new run, (previous "
|
||||
"run lcn 0x%llx, len 0x%llx).\n",
|
||||
(long long) rl[rlpos - 1].lcn,
|
||||
(long long) rl[rlpos - 1].length);
|
||||
else {
|
||||
if (rlpos)
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
||||
prev_run_len;
|
||||
} else {
|
||||
ntfs_log_trace("Adding new run, is first run.\n");
|
||||
else
|
||||
rl[rlpos].vcn = start_vcn;
|
||||
}
|
||||
|
||||
rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
|
||||
rl[rlpos].length = prev_run_len = 1;
|
||||
rlpos++;
|
||||
}
|
||||
|
||||
/* Done? */
|
||||
if (!--clusters) {
|
||||
if (ntfs_cluster_update_zone_pos(vol,
|
||||
search_zone, lcn + bmp_pos + 1
|
||||
+ NTFS_LCNALLOC_SKIP,
|
||||
bmp_initial_pos)) {
|
||||
free(rl);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
if (used_zone_pos)
|
||||
ntfs_cluster_update_zone_pos(vol,
|
||||
search_zone, lcn + bmp_pos + 1 +
|
||||
NTFS_LCNALLOC_SKIP);
|
||||
goto done_ret;
|
||||
}
|
||||
|
||||
lcn++;
|
||||
}
|
||||
bmp_pos += buf_size;
|
||||
ntfs_log_trace("After inner while loop: buf_size = 0x%x, lcn = "
|
||||
"0x%llx, bmp_pos = 0x%llx, need_writeback = %i.\n",
|
||||
buf_size, (long long)lcn,
|
||||
(long long)bmp_pos, need_writeback);
|
||||
if (need_writeback) {
|
||||
s64 bw;
|
||||
ntfs_log_trace("Writing back.\n");
|
||||
need_writeback = 0;
|
||||
bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos,
|
||||
br, buf);
|
||||
if (bw != br) {
|
||||
if (bw == -1)
|
||||
err = errno;
|
||||
else
|
||||
err = EIO;
|
||||
ntfs_log_perror("Bitmap writeback failed in "
|
||||
"read next buffer code path");
|
||||
goto err_ret;
|
||||
}
|
||||
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||
err = errno;
|
||||
goto err_ret;
|
||||
}
|
||||
if (bmp_pos < zone_end) {
|
||||
ntfs_log_trace("Continuing outer while loop, bmp_pos = "
|
||||
"0x%llx, zone_end = 0x%llx.\n",
|
||||
(long long)bmp_pos,
|
||||
(long long)zone_end);
|
||||
|
||||
if (!used_zone_pos) {
|
||||
|
||||
used_zone_pos = 1;
|
||||
|
||||
if (search_zone == 1)
|
||||
zone_start = vol->mft_zone_pos;
|
||||
else if (search_zone == 2)
|
||||
zone_start = vol->data1_zone_pos;
|
||||
else
|
||||
zone_start = vol->data2_zone_pos;
|
||||
|
||||
if (!zone_start || zone_start == vol->mft_zone_start ||
|
||||
zone_start == vol->mft_zone_end)
|
||||
pass = 2;
|
||||
bmp_pos = zone_start;
|
||||
} else
|
||||
bmp_pos += buf_size;
|
||||
|
||||
if (bmp_pos < zone_end)
|
||||
continue;
|
||||
}
|
||||
zone_pass_done: /* Finished with the current zone pass. */
|
||||
ntfs_log_trace("At zone_pass_done, pass = %i.\n", pass);
|
||||
|
||||
zone_pass_done:
|
||||
ntfs_log_trace("Finished current zone pass(%i).\n", pass);
|
||||
if (pass == 1) {
|
||||
/*
|
||||
* Now do pass 2, scanning the first part of the zone
|
||||
* we omitted in pass 1.
|
||||
*/
|
||||
|
||||
pass = 2;
|
||||
zone_end = zone_start;
|
||||
switch (search_zone) {
|
||||
case 1: /* mft_zone */
|
||||
|
||||
if (search_zone == 1)
|
||||
zone_start = vol->mft_zone_start;
|
||||
break;
|
||||
case 2: /* data1_zone */
|
||||
else if (search_zone == 2)
|
||||
zone_start = vol->mft_zone_end;
|
||||
break;
|
||||
case 4: /* data2_zone */
|
||||
else
|
||||
zone_start = 0;
|
||||
break;
|
||||
default:
|
||||
NTFS_BUG("switch (search_zone) 2");
|
||||
}
|
||||
|
||||
/* Sanity check. */
|
||||
if (zone_end < zone_start)
|
||||
zone_end = zone_start;
|
||||
|
||||
bmp_pos = zone_start;
|
||||
ntfs_log_trace("Continuing outer while loop, pass = 2, "
|
||||
"zone_start = 0x%llx, zone_end = "
|
||||
"0x%llx, bmp_pos = 0x%llx.\n",
|
||||
zone_start, zone_end, bmp_pos);
|
||||
|
||||
continue;
|
||||
} /* pass == 2 */
|
||||
}
|
||||
/* pass == 2 */
|
||||
done_zones_check:
|
||||
ntfs_log_trace("At done_zones_check, search_zone = %i, done_zones "
|
||||
"before = 0x%x, done_zones after = 0x%x.\n",
|
||||
search_zone, done_zones, done_zones | search_zone);
|
||||
done_zones |= search_zone;
|
||||
if (done_zones < 7) {
|
||||
ntfs_log_trace("Switching zone.\n");
|
||||
/* Now switch to the next zone we haven't done yet. */
|
||||
pass = 1;
|
||||
if (rlpos) {
|
||||
LCN tc;
|
||||
|
||||
tc = rl[rlpos - 1].lcn + rl[rlpos - 1].length
|
||||
+ NTFS_LCNALLOC_SKIP;
|
||||
LCN tc = tc = rl[rlpos - 1].lcn +
|
||||
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
|
||||
|
||||
if (ntfs_cluster_update_zone_pos(vol,
|
||||
search_zone, tc, bmp_initial_pos))
|
||||
return NULL;
|
||||
if (used_zone_pos)
|
||||
ntfs_cluster_update_zone_pos(vol,
|
||||
search_zone, tc);
|
||||
}
|
||||
|
||||
switch (search_zone) {
|
||||
case 1:
|
||||
ntfs_log_trace("Zone switch: mft -> data1\n");
|
||||
switch_to_data1_zone: search_zone = 2;
|
||||
zone_start = bmp_initial_pos =
|
||||
vol->data1_zone_pos;
|
||||
zone_start = vol->data1_zone_pos;
|
||||
zone_end = vol->nr_clusters;
|
||||
if (zone_start == vol->mft_zone_end)
|
||||
pass = 2;
|
||||
if (zone_start >= zone_end) {
|
||||
vol->data1_zone_pos = zone_start =
|
||||
vol->mft_zone_end;
|
||||
pass = 2;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
ntfs_log_trace("Zone switch: data1 -> data2\n");
|
||||
search_zone = 4;
|
||||
zone_start = bmp_initial_pos =
|
||||
vol->data2_zone_pos;
|
||||
zone_start = vol->data2_zone_pos;
|
||||
zone_end = vol->mft_zone_start;
|
||||
if (!zone_start)
|
||||
pass = 2;
|
||||
if (zone_start >= zone_end) {
|
||||
vol->data2_zone_pos = zone_start =
|
||||
bmp_initial_pos = 0;
|
||||
pass = 2;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
ntfs_log_trace("Zone switch: data2 -> data1\n");
|
||||
goto switch_to_data1_zone; /* See above. */
|
||||
default:
|
||||
NTFS_BUG("switch (search_zone) 3");
|
||||
if (!(done_zones & 2)) {
|
||||
ntfs_log_trace("data2 -> data1\n");
|
||||
goto switch_to_data1_zone;
|
||||
}
|
||||
ntfs_log_trace("Zone switch: data2 -> mft\n");
|
||||
search_zone = 1;
|
||||
zone_start = vol->mft_zone_pos;
|
||||
zone_end = vol->mft_zone_end;
|
||||
if (!zone_start == vol->mft_zone_start)
|
||||
pass = 2;
|
||||
break;
|
||||
}
|
||||
ntfs_log_trace("After zone switch, search_zone = %i, pass = "
|
||||
"%i, bmp_initial_pos = 0x%llx, "
|
||||
"zone_start = 0x%llx, zone_end = "
|
||||
"0x%llx.\n", search_zone, pass,
|
||||
(long long)bmp_initial_pos,
|
||||
(long long)zone_start,
|
||||
(long long)zone_end);
|
||||
|
||||
bmp_pos = zone_start;
|
||||
|
||||
if (zone_start == zone_end) {
|
||||
ntfs_log_trace("Empty zone, going to "
|
||||
"done_zones_check.\n");
|
||||
/* Empty zone. Don't bother searching it. */
|
||||
ntfs_log_trace("Empty zone, skipped.\n");
|
||||
goto done_zones_check;
|
||||
}
|
||||
ntfs_log_trace("Continuing outer while loop.\n");
|
||||
|
||||
continue;
|
||||
} /* done_zones == 7 */
|
||||
ntfs_log_trace("All zones are finished.\n");
|
||||
/*
|
||||
* All zones are finished! If DATA_ZONE, shrink mft zone. If
|
||||
* MFT_ZONE, we have really run out of space.
|
||||
*/
|
||||
mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;
|
||||
ntfs_log_trace("vol->mft_zone_start = 0x%llx, vol->mft_zone_end = "
|
||||
"0x%llx, mft_zone_size = 0x%llx.\n",
|
||||
(long long)vol->mft_zone_start,
|
||||
(long long)vol->mft_zone_end,
|
||||
(long long)mft_zone_size);
|
||||
if (zone == MFT_ZONE || mft_zone_size <= 0) {
|
||||
ntfs_log_trace("No free clusters left, going to err_ret.\n");
|
||||
/* Really no more space left on device. */
|
||||
err = ENOSPC;
|
||||
goto err_ret;
|
||||
} /* zone == DATA_ZONE && mft_zone_size > 0 */
|
||||
ntfs_log_trace("Shrinking mft zone.\n");
|
||||
zone_end = vol->mft_zone_end;
|
||||
mft_zone_size >>= 1;
|
||||
if (mft_zone_size > 0)
|
||||
vol->mft_zone_end = vol->mft_zone_start + mft_zone_size;
|
||||
else /* mft zone and data2 zone no longer exist. */
|
||||
vol->data2_zone_pos = vol->mft_zone_start =
|
||||
vol->mft_zone_end = 0;
|
||||
if (vol->mft_zone_pos >= vol->mft_zone_end) {
|
||||
vol->mft_zone_pos = vol->mft_lcn;
|
||||
if (!vol->mft_zone_end)
|
||||
vol->mft_zone_pos = 0;
|
||||
}
|
||||
bmp_pos = zone_start = bmp_initial_pos =
|
||||
vol->data1_zone_pos = vol->mft_zone_end;
|
||||
search_zone = 2;
|
||||
pass = 2;
|
||||
done_zones &= ~2;
|
||||
ntfs_log_trace("After shrinking mft zone, mft_zone_size = 0x%llx, "
|
||||
"vol->mft_zone_start = 0x%llx, "
|
||||
"vol->mft_zone_end = 0x%llx, vol->mft_zone_pos "
|
||||
"= 0x%llx, search_zone = 2, pass = 2, "
|
||||
"dones_zones = 0x%x, zone_start = 0x%llx, "
|
||||
"zone_end = 0x%llx, vol->data1_zone_pos = "
|
||||
"0x%llx, continuing outer while loop.\n",
|
||||
(long long)mft_zone_size,
|
||||
(long long)vol->mft_zone_start,
|
||||
(long long)vol->mft_zone_end,
|
||||
(long long)vol->mft_zone_pos,
|
||||
done_zones,
|
||||
(long long)zone_start,
|
||||
(long long)zone_end,
|
||||
(long long)vol->data1_zone_pos);
|
||||
|
||||
ntfs_log_trace("All zones are finished, no space on device.\n");
|
||||
err = ENOSPC;
|
||||
goto err_ret;
|
||||
}
|
||||
ntfs_log_debug("After outer while loop.\n");
|
||||
done_ret:
|
||||
ntfs_log_debug("At done_ret.\n");
|
||||
/* Add runlist terminator element. */
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[rlpos].length = 0;
|
||||
if (need_writeback) {
|
||||
s64 bw;
|
||||
ntfs_log_trace("Writing back.\n");
|
||||
need_writeback = 0;
|
||||
bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf);
|
||||
if (bw != br) {
|
||||
if (bw < 0)
|
||||
err = errno;
|
||||
else
|
||||
err = EIO;
|
||||
ntfs_log_perror("Bitmap writeback failed");
|
||||
goto err_ret;
|
||||
}
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback)) {
|
||||
err = errno;
|
||||
goto err_ret;
|
||||
}
|
||||
done_err_ret:
|
||||
ntfs_log_debug("At done_err_ret (follows done_ret).\n");
|
||||
free(buf);
|
||||
/* Done! */
|
||||
if (!err)
|
||||
return rl;
|
||||
ntfs_log_perror("Failed to allocate clusters");
|
||||
ntfs_log_trace("Failed to allocate clusters (%d)", errno);
|
||||
errno = err;
|
||||
return NULL;
|
||||
|
||||
wb_err_ret:
|
||||
ntfs_log_trace("At wb_err_ret.\n");
|
||||
if (need_writeback) {
|
||||
s64 bw;
|
||||
ntfs_log_trace("Writing back.\n");
|
||||
need_writeback = 0;
|
||||
bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf);
|
||||
if (bw != br) {
|
||||
if (bw < 0)
|
||||
err = errno;
|
||||
else
|
||||
err = EIO;
|
||||
ntfs_log_trace("Bitmap writeback failed in error code path "
|
||||
"with error code %i.\n", err);
|
||||
}
|
||||
}
|
||||
if (bitmap_writeback(vol, last_read_pos, br, buf, &writeback))
|
||||
err = errno;
|
||||
err_ret:
|
||||
ntfs_log_trace("At err_ret.\n");
|
||||
if (rl) {
|
||||
if (err == ENOSPC) {
|
||||
ntfs_log_trace("err = ENOSPC, first free lcn = 0x%llx, could "
|
||||
"allocate up to = 0x%llx clusters.\n",
|
||||
(long long)rl[0].lcn,
|
||||
(long long)count - clusters);
|
||||
}
|
||||
/* Add runlist terminator element. */
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[rlpos].length = 0;
|
||||
/* Deallocate all allocated clusters. */
|
||||
ntfs_log_trace("Deallocating allocated clusters.\n");
|
||||
ntfs_cluster_free_from_rl(vol, rl);
|
||||
/* Free the runlist. */
|
||||
free(rl);
|
||||
rl = NULL;
|
||||
} else {
|
||||
if (err == ENOSPC) {
|
||||
ntfs_log_trace("No space left at all, err = ENOSPC, first "
|
||||
"free lcn = 0x%llx.\n",
|
||||
(long long)vol->data1_zone_pos);
|
||||
}
|
||||
}
|
||||
ntfs_log_trace("rl = NULL, going to done_err_ret.\n");
|
||||
goto done_err_ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -699,55 +699,31 @@ BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
||||
*/
|
||||
int ntfs_empty_logfile(ntfs_attr *na)
|
||||
{
|
||||
s64 len, pos, count;
|
||||
s64 pos, count;
|
||||
char buf[NTFS_BUF_SIZE];
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
if (NVolLogFileEmpty(na->ni->vol))
|
||||
return 0;
|
||||
|
||||
/* The $DATA attribute of the $LogFile has to be non-resident. */
|
||||
if (!NAttrNonResident(na)) {
|
||||
errno = EIO;
|
||||
ntfs_log_perror("$LogFile $DATA attribute is resident!?!\n");
|
||||
ntfs_log_perror("Resident $LogFile $DATA attribute");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get length of $LogFile contents. */
|
||||
len = na->data_size;
|
||||
if (!len) {
|
||||
ntfs_log_debug("$LogFile has zero length, no disk write "
|
||||
"needed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read $LogFile until its end. We do this as a check for correct
|
||||
length thus making sure we are decompressing the mapping pairs
|
||||
array correctly and hence writing below is safe as well. */
|
||||
pos = 0;
|
||||
while ((count = ntfs_attr_pread(na, pos, NTFS_BUF_SIZE, buf)) > 0)
|
||||
pos += count;
|
||||
|
||||
if (count == -1 || pos != len) {
|
||||
ntfs_log_error("Amount of $LogFile data read does not "
|
||||
"correspond to expected length!\n");
|
||||
if (count != -1)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill the buffer with 0xff's. */
|
||||
memset(buf, -1, NTFS_BUF_SIZE);
|
||||
|
||||
/* Set the $DATA attribute. */
|
||||
pos = 0;
|
||||
while ((count = len - pos) > 0) {
|
||||
while ((count = na->data_size - pos) > 0) {
|
||||
|
||||
if (count > NTFS_BUF_SIZE)
|
||||
count = NTFS_BUF_SIZE;
|
||||
|
||||
if ((count = ntfs_attr_pwrite(na, pos, count, buf)) <= 0) {
|
||||
ntfs_log_perror("Failed to set the $LogFile attribute "
|
||||
"value.\n");
|
||||
count = ntfs_attr_pwrite(na, pos, count, buf);
|
||||
if (count <= 0) {
|
||||
ntfs_log_perror("Failed to reset $LogFile");
|
||||
if (count != -1)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
@@ -755,7 +731,7 @@ int ntfs_empty_logfile(ntfs_attr *na)
|
||||
pos += count;
|
||||
}
|
||||
|
||||
/* Set the flag so we do not have to do it again on remount. */
|
||||
NVolSetLogFileEmpty(na->ni->vol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ static FILE * ntfs_log_get_stream(u32 level)
|
||||
}
|
||||
|
||||
return stream;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,43 +348,33 @@ int ntfs_log_redirect(const char *function, const char *file,
|
||||
* num Number of output characters
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
|
||||
#define LOG_LINE_LEN 512
|
||||
|
||||
int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
const char *file, __attribute__((unused)) int line,
|
||||
u32 level __attribute__((unused)), void *data __attribute__((unused)),
|
||||
const char *format, va_list args)
|
||||
const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), u32 level,
|
||||
void *data __attribute__((unused)),
|
||||
const char *format, va_list args)
|
||||
{
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
char log[LOG_LINE_LEN];
|
||||
int ret, olderr = errno;
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
file = strrchr(file, PATH_SEP) + 1;
|
||||
#if 0 /* FIXME: Implement this all. */
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */
|
||||
ret += fprintf(stream, "%s", ntfs_log_get_prefix(level));
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) /* Source filename */
|
||||
ret += fprintf(stream, "%s ", file);
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_LINE) /* Source line number */
|
||||
ret += fprintf(stream, "(%d) ", line);
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
|
||||
(level & NTFS_LOG_LEVEL_TRACE))
|
||||
ret += fprintf(stream, "%s(): ", function);
|
||||
|
||||
ret += vfprintf(stream, format, args);
|
||||
|
||||
if (level & NTFS_LOG_LEVEL_PERROR) {
|
||||
if (reason)
|
||||
ret += fprintf(stream, ": %s\n", reason);
|
||||
else
|
||||
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
ret = vsnprintf(log, LOG_LINE_LEN, format, args);
|
||||
if (ret < 0) {
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
ret = 1; /* FIXME: caclulate how many bytes had been written. */
|
||||
|
||||
if ((LOG_LINE_LEN > ret + 3) && (level & NTFS_LOG_LEVEL_PERROR)) {
|
||||
strncat(log, ": ", LOG_LINE_LEN - ret - 1);
|
||||
strncat(log, strerror(olderr), LOG_LINE_LEN - (ret + 3));
|
||||
ret = strlen(log);
|
||||
}
|
||||
|
||||
syslog(LOG_NOTICE, "%s", log);
|
||||
|
||||
errno = olderr;
|
||||
return ret;
|
||||
@@ -543,7 +533,7 @@ int ntfs_log_handler_stdout(const char *function, const char *file,
|
||||
data = stdout;
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -612,7 +602,7 @@ int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||
data = stderr;
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1007,8 +1007,7 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
|
||||
// this extent is not required to find the mft record in
|
||||
// question.
|
||||
errno = EOPNOTSUPP;
|
||||
ntfs_log_perror("Not enough space to extended mft data "
|
||||
"attribute.\n");
|
||||
ntfs_log_perror("Not enough space to extended mft data");
|
||||
goto undo_alloc;
|
||||
}
|
||||
mp_rebuilt = TRUE;
|
||||
@@ -1098,6 +1097,115 @@ undo_alloc:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
|
||||
{
|
||||
int ret = -1;
|
||||
ntfs_attr *mft_na, *mftbmp_na;
|
||||
s64 old_data_initialized, old_data_size;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */
|
||||
|
||||
mft_na = vol->mft_na;
|
||||
mftbmp_na = vol->mftbmp_na;
|
||||
|
||||
/*
|
||||
* The mft record is outside the initialized data. Extend the mft data
|
||||
* attribute until it covers the allocated record. The loop is only
|
||||
* actually traversed more than once when a freshly formatted volume
|
||||
* is first written to so it optimizes away nicely in the common case.
|
||||
*/
|
||||
ntfs_log_debug("Status of mft data before extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
while (size > mft_na->allocated_size) {
|
||||
if (ntfs_mft_data_extend_allocation(vol))
|
||||
goto out;
|
||||
ntfs_log_debug("Status of mft data after allocation extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
}
|
||||
|
||||
old_data_initialized = mft_na->initialized_size;
|
||||
old_data_size = mft_na->data_size;
|
||||
|
||||
/*
|
||||
* Extend mft data initialized size (and data size of course) to reach
|
||||
* the allocated mft record, formatting the mft records along the way.
|
||||
* Note: We only modify the ntfs_attr structure as that is all that is
|
||||
* needed by ntfs_mft_record_format(). We will update the attribute
|
||||
* record itself in one fell swoop later on.
|
||||
*/
|
||||
while (size > mft_na->initialized_size) {
|
||||
s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||
mft_na->initialized_size += vol->mft_record_size;
|
||||
if (mft_na->initialized_size > mft_na->data_size)
|
||||
mft_na->data_size = mft_na->initialized_size;
|
||||
ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2);
|
||||
if (ntfs_mft_record_format(vol, ll2) < 0) {
|
||||
ntfs_log_error("Failed to format mft record.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the mft data attribute record to reflect the new sizes. */
|
||||
ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get search context.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||
0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("Failed to find first attribute extent of "
|
||||
"mft data attribute.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto undo_data_init;
|
||||
}
|
||||
ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size);
|
||||
ctx->attr->data_size = cpu_to_sle64(mft_na->data_size);
|
||||
|
||||
/* Ensure the changes make it to disk. */
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ntfs_log_debug("Status of mft data after mft record initialization: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
|
||||
/* Sanity checks. */
|
||||
if (mft_na->data_size > mft_na->allocated_size ||
|
||||
mft_na->initialized_size > mft_na->data_size)
|
||||
NTFS_BUG("mft_na sanity checks failed");
|
||||
// BUG_ON(mft_na->initialized_size > mft_na->data_size);
|
||||
// BUG_ON(mft_na->data_size > mft_na->allocated_size);
|
||||
|
||||
/* Sync MFT to minimize data loss if there won't be clean unmount. */
|
||||
if (ntfs_inode_sync(mft_na->ni)) {
|
||||
ntfs_log_error("Failed to sync $MFT.");
|
||||
goto undo_data_init;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
|
||||
undo_data_init:
|
||||
mft_na->initialized_size = old_data_initialized;
|
||||
mft_na->data_size = old_data_size;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_alloc - allocate an mft record on an ntfs volume
|
||||
* @vol: volume on which to allocate the mft record
|
||||
@@ -1183,11 +1291,9 @@ undo_alloc:
|
||||
*/
|
||||
ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
{
|
||||
s64 ll, bit, old_data_initialized, old_data_size;
|
||||
s64 ll, bit;
|
||||
ntfs_attr *mft_na, *mftbmp_na;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
MFT_RECORD *m;
|
||||
ATTR_RECORD *a;
|
||||
ntfs_inode *ni;
|
||||
int err;
|
||||
u16 seq_no, usn;
|
||||
@@ -1202,8 +1308,10 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mft_na = vol->mft_na;
|
||||
mftbmp_na = vol->mftbmp_na;
|
||||
retry:
|
||||
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
|
||||
if (bit >= 0) {
|
||||
ntfs_log_debug("Found free record (#1), bit 0x%llx.\n",
|
||||
@@ -1269,99 +1377,18 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
||||
ntfs_log_debug("Found free record (#3), bit 0x%llx.\n", (long long)bit);
|
||||
found_free_rec:
|
||||
/* @bit is the found free mft record, allocate it in the mft bitmap. */
|
||||
ntfs_log_debug("At found_free_rec.\n");
|
||||
if (ntfs_bitmap_set_bit(mftbmp_na, bit)) {
|
||||
ntfs_log_error("Failed to allocate bit in mft bitmap.\n");
|
||||
goto err_out;
|
||||
}
|
||||
ntfs_log_debug("Set bit 0x%llx in mft bitmap.\n", (long long)bit);
|
||||
|
||||
/* The mft bitmap is now uptodate. Deal with mft data attribute now. */
|
||||
ll = (bit + 1) << vol->mft_record_size_bits;
|
||||
if (ll <= mft_na->initialized_size) {
|
||||
ntfs_log_debug("Allocated mft record already initialized.\n");
|
||||
goto mft_rec_already_initialized;
|
||||
}
|
||||
ntfs_log_debug("Initializing allocated mft record.\n");
|
||||
/*
|
||||
* The mft record is outside the initialized data. Extend the mft data
|
||||
* attribute until it covers the allocated record. The loop is only
|
||||
* actually traversed more than once when a freshly formatted volume is
|
||||
* first written to so it optimizes away nicely in the common case.
|
||||
*/
|
||||
ntfs_log_debug("Status of mft data before extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
while (ll > mft_na->allocated_size) {
|
||||
if (ntfs_mft_data_extend_allocation(vol))
|
||||
if (ll > mft_na->initialized_size)
|
||||
if (ntfs_mft_record_init(vol, ll) < 0)
|
||||
goto undo_mftbmp_alloc;
|
||||
ntfs_log_debug("Status of mft data after allocation extension: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
}
|
||||
old_data_initialized = mft_na->initialized_size;
|
||||
old_data_size = mft_na->data_size;
|
||||
/*
|
||||
* Extend mft data initialized size (and data size of course) to reach
|
||||
* the allocated mft record, formatting the mft records along the way.
|
||||
* Note: We only modify the ntfs_attr structure as that is all that is
|
||||
* needed by ntfs_mft_record_format(). We will update the attribute
|
||||
* record itself in one fell swoop later on.
|
||||
*/
|
||||
while (ll > mft_na->initialized_size) {
|
||||
s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||
mft_na->initialized_size += vol->mft_record_size;
|
||||
if (mft_na->initialized_size > mft_na->data_size)
|
||||
mft_na->data_size = mft_na->initialized_size;
|
||||
ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2);
|
||||
err = ntfs_mft_record_format(vol, ll2);
|
||||
if (err) {
|
||||
ntfs_log_error("Failed to format mft record.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
}
|
||||
/* Update the mft data attribute record to reflect the new sizes. */
|
||||
ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Failed to get search context.\n");
|
||||
goto undo_data_init;
|
||||
}
|
||||
if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0,
|
||||
0, NULL, 0, ctx)) {
|
||||
ntfs_log_error("Failed to find first attribute extent of "
|
||||
"mft data attribute.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto undo_data_init;
|
||||
}
|
||||
a = ctx->attr;
|
||||
a->initialized_size = cpu_to_sle64(mft_na->initialized_size);
|
||||
a->data_size = cpu_to_sle64(mft_na->data_size);
|
||||
/* Ensure the changes make it to disk. */
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ntfs_log_debug("Status of mft data after mft record initialization: "
|
||||
"allocated_size 0x%llx, data_size 0x%llx, "
|
||||
"initialized_size 0x%llx.\n",
|
||||
(long long)mft_na->allocated_size,
|
||||
(long long)mft_na->data_size,
|
||||
(long long)mft_na->initialized_size);
|
||||
/* Sanity checks. */
|
||||
if (mft_na->data_size > mft_na->allocated_size ||
|
||||
mft_na->initialized_size > mft_na->data_size)
|
||||
NTFS_BUG("mft_na sanity checks failed");
|
||||
// BUG_ON(mft_na->initialized_size > mft_na->data_size);
|
||||
// BUG_ON(mft_na->data_size > mft_na->allocated_size);
|
||||
/* Sync MFT to minimize data loss if there won't be clean unmount. */
|
||||
if (ntfs_inode_sync(mft_na->ni)) {
|
||||
ntfs_log_error("Failed to sync $MFT.");
|
||||
goto undo_data_init;
|
||||
}
|
||||
mft_rec_already_initialized:
|
||||
|
||||
/*
|
||||
* We now have allocated and initialized the mft record. Need to read
|
||||
* it from disk and re-format it, preserving the sequence number if it
|
||||
@@ -1373,29 +1400,22 @@ mft_rec_already_initialized:
|
||||
goto undo_mftbmp_alloc;
|
||||
|
||||
if (ntfs_mft_record_read(vol, bit, m)) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to read mft record.\n");
|
||||
ntfs_log_perror("Error reading mft %lld", (long long)bit);
|
||||
free(m);
|
||||
errno = err;
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
/* Sanity check that the mft record is really not in use. */
|
||||
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
|
||||
ntfs_log_error("Mft record 0x%llx was marked unused in "
|
||||
"mft bitmap but is marked used itself. "
|
||||
"Corrupt filesystem or library bug! "
|
||||
"Run chkdsk immediately!\n", (long long)bit);
|
||||
ntfs_log_error("Inode %lld is used but it wasn't marked in "
|
||||
"$MFT bitmap. Fixed.\n", (long long)bit);
|
||||
free(m);
|
||||
errno = EIO;
|
||||
goto undo_mftbmp_alloc;
|
||||
goto retry;
|
||||
}
|
||||
seq_no = m->sequence_number;
|
||||
usn = *(u16*)((u8*)m + le16_to_cpu(m->usa_ofs));
|
||||
if (ntfs_mft_record_layout(vol, bit, m)) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to re-format mft record.\n");
|
||||
free(m);
|
||||
errno = err;
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
if (le16_to_cpu(seq_no))
|
||||
@@ -1408,10 +1428,8 @@ mft_rec_already_initialized:
|
||||
/* Now need to open an ntfs inode for the mft record. */
|
||||
ni = ntfs_inode_allocate(vol);
|
||||
if (!ni) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to allocate buffer for inode.\n");
|
||||
free(m);
|
||||
errno = err;
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
ni->mft_no = bit;
|
||||
@@ -1465,9 +1483,7 @@ mft_rec_already_initialized:
|
||||
ntfs_log_debug("Returning opened, allocated %sinode 0x%llx.\n",
|
||||
base_ni ? "extent " : "", (long long)bit);
|
||||
return ni;
|
||||
undo_data_init:
|
||||
mft_na->initialized_size = old_data_initialized;
|
||||
mft_na->data_size = old_data_size;
|
||||
|
||||
undo_mftbmp_alloc:
|
||||
err = errno;
|
||||
if (ntfs_bitmap_clear_bit(mftbmp_na, bit))
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
@@ -39,16 +35,17 @@ void *ntfs_malloc(size_t size)
|
||||
}
|
||||
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
#include <stdio.h>
|
||||
int ntfs_snprintf(char *buff, size_t size, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
char buffer[BUFSIZ];
|
||||
char buffer[BUF_SIZE];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
memset(buffer,0,BUFSIZ);
|
||||
memset(buffer,0,BUF_SIZE);
|
||||
ret = sprintf(buffer, format, args);
|
||||
va_end(args);
|
||||
strncpy(buff,buffer,size);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,9 @@ void *ntfs_calloc(size_t size);
|
||||
void *ntfs_malloc(size_t size);
|
||||
|
||||
#if defined(__BEOS__) || defined(__HAIKU__)
|
||||
#define BUF_SIZE 16384
|
||||
int ntfs_snprintf(char *buff, size_t size, const char *format, ...);
|
||||
#define snprintf ntfs_snprintf
|
||||
#endif /* defined(__BEOS__) || defined(__HAIKU__) */
|
||||
#endif /* _NTFS_MISC_H_ */
|
||||
#endif
|
||||
|
||||
#endif /* _NTFS_MISC_H_ */
|
||||
|
||||
@@ -113,7 +113,7 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
|
||||
NDevSetReadOnly(dev);
|
||||
|
||||
/* locking not implemented in BeOS */
|
||||
#if !defined(__BEOS__) && !defined(__HAIKU__)
|
||||
#if !defined(__BEOS__) && !defined(__HAIKU__)
|
||||
memset(&flk, 0, sizeof(flk));
|
||||
if (NDevReadOnly(dev))
|
||||
flk.l_type = F_RDLCK;
|
||||
@@ -153,25 +153,27 @@ static int ntfs_device_unix_io_close(struct ntfs_device *dev)
|
||||
|
||||
if (!NDevOpen(dev)) {
|
||||
errno = EBADF;
|
||||
ntfs_log_perror("Device %s is not open", dev->d_name);
|
||||
return -1;
|
||||
}
|
||||
if (NDevDirty(dev))
|
||||
fsync(DEV_FD(dev));
|
||||
|
||||
if (fsync(DEV_FD(dev))) {
|
||||
ntfs_log_perror("Failed to fsync device %s", dev->d_name);
|
||||
return -1;
|
||||
}
|
||||
/* locking not implemented in BeOS */
|
||||
#if !defined(__BEOS__) && !defined(__HAIKU__)
|
||||
/* Release exclusive (mandatory) lock on the whole device. */
|
||||
#if !defined(__BEOS__) && !defined(__HAIKU__)
|
||||
memset(&flk, 0, sizeof(flk));
|
||||
flk.l_type = F_UNLCK;
|
||||
flk.l_whence = SEEK_SET;
|
||||
flk.l_start = flk.l_len = 0LL;
|
||||
if (fcntl(DEV_FD(dev), F_SETLK, &flk))
|
||||
ntfs_log_perror("ntfs_device_unix_io_close: Warning: Could not "
|
||||
"unlock %s", dev->d_name);
|
||||
#endif
|
||||
/* Close the file descriptor and clear our open flag. */
|
||||
if (close(DEV_FD(dev)))
|
||||
ntfs_log_perror("Could not unlock %s", dev->d_name);
|
||||
#endif
|
||||
if (close(DEV_FD(dev))) {
|
||||
ntfs_log_perror("Failed to close device %s", dev->d_name);
|
||||
return -1;
|
||||
}
|
||||
NDevClearOpen(dev);
|
||||
free(dev->d_private);
|
||||
dev->d_private = NULL;
|
||||
@@ -288,13 +290,16 @@ static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
|
||||
*/
|
||||
static int ntfs_device_unix_io_sync(struct ntfs_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (!NDevReadOnly(dev)) {
|
||||
int res = fsync(DEV_FD(dev));
|
||||
if (!res)
|
||||
res = fsync(DEV_FD(dev));
|
||||
if (res)
|
||||
ntfs_log_perror("Failed to sync device %s", dev->d_name);
|
||||
else
|
||||
NDevClearDirty(dev);
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -79,6 +79,35 @@ ntfs_volume *ntfs_volume_alloc(void)
|
||||
return calloc(1, sizeof(ntfs_volume));
|
||||
}
|
||||
|
||||
|
||||
static void ntfs_attr_free(ntfs_attr **na)
|
||||
{
|
||||
if (na && *na) {
|
||||
ntfs_attr_close(*na);
|
||||
*na = NULL;
|
||||
} else
|
||||
ntfs_log_error("Tried to free NULL attribute pointer (%p)\n", na);
|
||||
}
|
||||
|
||||
static int ntfs_inode_free(ntfs_inode **ni)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (ni && *ni) {
|
||||
ret = ntfs_inode_close(*ni);
|
||||
*ni = NULL;
|
||||
} else
|
||||
ntfs_log_error("Tried to free NULL inode pointer (%p)\n", ni);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ntfs_error_set(int *err)
|
||||
{
|
||||
if (!*err)
|
||||
*err = errno;
|
||||
}
|
||||
|
||||
/**
|
||||
* __ntfs_volume_release - Destroy an NTFS volume object
|
||||
* @v:
|
||||
@@ -87,41 +116,51 @@ ntfs_volume *ntfs_volume_alloc(void)
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static void __ntfs_volume_release(ntfs_volume *v)
|
||||
static int __ntfs_volume_release(ntfs_volume *v)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (ntfs_inode_free(&v->vol_ni))
|
||||
ntfs_error_set(&err);
|
||||
/*
|
||||
* FIXME: Inodes must be synced before closing
|
||||
* attributes, otherwise unmount could fail.
|
||||
*/
|
||||
if (v->lcnbmp_ni && NInoDirty(v->lcnbmp_ni))
|
||||
ntfs_inode_sync(v->lcnbmp_ni);
|
||||
if (v->vol_ni)
|
||||
ntfs_inode_close(v->vol_ni);
|
||||
if (v->lcnbmp_na)
|
||||
ntfs_attr_close(v->lcnbmp_na);
|
||||
if (v->lcnbmp_ni)
|
||||
ntfs_inode_close(v->lcnbmp_ni);
|
||||
ntfs_attr_free(&v->lcnbmp_na);
|
||||
if (ntfs_inode_free(&v->lcnbmp_ni))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
if (v->mft_ni && NInoDirty(v->mft_ni))
|
||||
ntfs_inode_sync(v->mft_ni);
|
||||
if (v->mftbmp_na)
|
||||
ntfs_attr_close(v->mftbmp_na);
|
||||
if (v->mft_na)
|
||||
ntfs_attr_close(v->mft_na);
|
||||
if (v->mft_ni)
|
||||
ntfs_inode_close(v->mft_ni);
|
||||
ntfs_attr_free(&v->mftbmp_na);
|
||||
ntfs_attr_free(&v->mft_na);
|
||||
if (ntfs_inode_free(&v->mft_ni))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
if (v->mftmirr_ni && NInoDirty(v->mftmirr_ni))
|
||||
ntfs_inode_sync(v->mftmirr_ni);
|
||||
if (v->mftmirr_na)
|
||||
ntfs_attr_close(v->mftmirr_na);
|
||||
if (v->mftmirr_ni)
|
||||
ntfs_inode_close(v->mftmirr_ni);
|
||||
ntfs_attr_free(&v->mftmirr_na);
|
||||
if (ntfs_inode_free(&v->mftmirr_ni))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
if (v->dev) {
|
||||
struct ntfs_device *dev = v->dev;
|
||||
|
||||
dev->d_ops->sync(dev);
|
||||
if (dev->d_ops->sync(dev))
|
||||
ntfs_error_set(&err);
|
||||
if (dev->d_ops->close(dev))
|
||||
ntfs_log_perror("Failed to close the device");
|
||||
ntfs_error_set(&err);
|
||||
}
|
||||
|
||||
free(v->vol_name);
|
||||
free(v->upcase);
|
||||
free(v->attrdef);
|
||||
free(v);
|
||||
|
||||
errno = err;
|
||||
return errno ? -1 : 0;
|
||||
}
|
||||
|
||||
static void ntfs_attr_setup_flag(ntfs_inode *ni)
|
||||
@@ -457,32 +496,11 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
|
||||
"sector size. This may affect performance "
|
||||
"but should be harmless otherwise. Error: "
|
||||
"%s\n", strerror(errno));
|
||||
/*
|
||||
* We now initialize the cluster allocator.
|
||||
*
|
||||
* FIXME: Move this to its own function? (AIA)
|
||||
*/
|
||||
|
||||
/* We now initialize the cluster allocator. */
|
||||
|
||||
// TODO: Make this tunable at mount time. (AIA)
|
||||
vol->mft_zone_multiplier = 1;
|
||||
|
||||
/* Determine the size of the MFT zone. */
|
||||
mft_zone_size = vol->nr_clusters;
|
||||
switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */
|
||||
case 4:
|
||||
mft_zone_size >>= 1; /* 50% */
|
||||
break;
|
||||
case 3:
|
||||
mft_zone_size = mft_zone_size * 3 >> 3; /* 37.5% */
|
||||
break;
|
||||
case 2:
|
||||
mft_zone_size >>= 2; /* 25% */
|
||||
break;
|
||||
/* case 1: */
|
||||
default:
|
||||
mft_zone_size >>= 3; /* 12.5% */
|
||||
break;
|
||||
}
|
||||
mft_zone_size = min(vol->nr_clusters >> 3, /* 12.5% */
|
||||
200 * 1000 * 1024 >> vol->cluster_size_bits);
|
||||
|
||||
/* Setup the mft zone. */
|
||||
vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
|
||||
@@ -573,23 +591,27 @@ static int ntfs_volume_check_logfile(ntfs_volume *vol)
|
||||
RESTART_PAGE_HEADER *rp = NULL;
|
||||
int err = 0;
|
||||
|
||||
if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) {
|
||||
ni = ntfs_inode_open(vol, FILE_LogFile);
|
||||
if (!ni) {
|
||||
ntfs_log_perror("Failed to open inode FILE_LogFile");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
|
||||
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
|
||||
err = EIO;
|
||||
goto exit;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
|
||||
err = EOPNOTSUPP;
|
||||
free(rp);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
ntfs_inode_close(ni);
|
||||
ntfs_attr_close(na);
|
||||
out:
|
||||
if (ntfs_inode_close(ni))
|
||||
ntfs_error_set(&err);
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
@@ -643,7 +665,10 @@ static ntfs_inode *ntfs_hiberfile_open(ntfs_volume *vol)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
ntfs_inode_close(ni_root);
|
||||
if (ntfs_inode_close(ni_root)) {
|
||||
ntfs_inode_close(ni_hibr);
|
||||
ni_hibr = NULL;
|
||||
}
|
||||
free(unicode);
|
||||
return ni_hibr;
|
||||
}
|
||||
@@ -663,7 +688,7 @@ static int ntfs_volume_check_hiberfile(ntfs_volume *vol)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
ntfs_attr *na = NULL;
|
||||
int i, bytes_read, ret = -1;
|
||||
int i, bytes_read, err;
|
||||
char *buf = NULL;
|
||||
|
||||
ni = ntfs_hiberfile_open(vol);
|
||||
@@ -707,13 +732,16 @@ static int ntfs_volume_check_hiberfile(ntfs_volume *vol)
|
||||
}
|
||||
}
|
||||
/* All right, all header bytes are zero */
|
||||
ret = 0;
|
||||
errno = 0;
|
||||
out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(buf);
|
||||
ntfs_inode_close(ni);
|
||||
return ret;
|
||||
err = errno;
|
||||
if (ntfs_inode_close(ni))
|
||||
ntfs_error_set(&err);
|
||||
errno = err;
|
||||
return errno ? -1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -785,20 +813,11 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
|
||||
vol->mft_record_size, m2);
|
||||
if (l != vol->mftmirr_size) {
|
||||
if (l == 4)
|
||||
vol->mftmirr_size = 4;
|
||||
else {
|
||||
if (l == -1)
|
||||
ntfs_log_perror("Failed to read $MFTMirr");
|
||||
else {
|
||||
ntfs_log_error("Failed to read $MFTMirr "
|
||||
"unexpected length (%d != %lld)."
|
||||
"\n", vol->mftmirr_size,
|
||||
(long long)l);
|
||||
errno = EIO;
|
||||
}
|
||||
if (l == -1) {
|
||||
ntfs_log_perror("Failed to read $MFTMirr");
|
||||
goto error_exit;
|
||||
}
|
||||
vol->mftmirr_size = l;
|
||||
}
|
||||
ntfs_log_debug("Comparing $MFTMirr to $MFT... ");
|
||||
for (i = 0; i < vol->mftmirr_size; ++i) {
|
||||
@@ -929,8 +948,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
/* Done with the $UpCase mft record. */
|
||||
ntfs_log_debug(OK);
|
||||
ntfs_attr_close(na);
|
||||
if (ntfs_inode_close(ni))
|
||||
ntfs_log_perror("Failed to close inode, leaking memory");
|
||||
if (ntfs_inode_close(ni)) {
|
||||
ntfs_log_perror("Failed to close $UpCase");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now load $Volume and set the version information and flags in the
|
||||
@@ -1089,17 +1110,24 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
||||
/* Done with the $AttrDef mft record. */
|
||||
ntfs_log_debug(OK);
|
||||
ntfs_attr_close(na);
|
||||
if (ntfs_inode_close(ni))
|
||||
ntfs_log_perror("Failed to close inode, leaking memory");
|
||||
if (ntfs_inode_close(ni)) {
|
||||
ntfs_log_perror("Failed to close $AttrDef");
|
||||
goto error_exit;
|
||||
}
|
||||
/*
|
||||
* Check for dirty logfile and hibernated Windows.
|
||||
* We care only about read-write mounts.
|
||||
*/
|
||||
if (!(flags & MS_RDONLY)) {
|
||||
if (ntfs_volume_check_logfile(vol) < 0)
|
||||
goto error_exit;
|
||||
if (ntfs_volume_check_hiberfile(vol) < 0)
|
||||
goto error_exit;
|
||||
if (ntfs_volume_check_logfile(vol) < 0) {
|
||||
if (!(flags & MS_FORCE))
|
||||
goto error_exit;
|
||||
ntfs_log_info("WARNING: Forced mount, reset $LogFile.\n");
|
||||
if (ntfs_logfile_reset(vol))
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
return vol;
|
||||
@@ -1172,42 +1200,6 @@ ntfs_volume *ntfs_mount(const char *name __attribute__((unused)),
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_umount - close ntfs volume
|
||||
* @vol: address of ntfs_volume structure of volume to close
|
||||
* @force: if true force close the volume even if it is busy
|
||||
*
|
||||
* Deallocate all structures (including @vol itself) associated with the ntfs
|
||||
* volume @vol.
|
||||
*
|
||||
* Note it is up to the caller to destroy the device associated with the volume
|
||||
* being unmounted after this function returns.
|
||||
*
|
||||
* Return 0 on success. On error return -1 with errno set appropriately
|
||||
* (most likely to one of EAGAIN, EBUSY or EINVAL). The EAGAIN error means that
|
||||
* an operation is in progress and if you try the close later the operation
|
||||
* might be completed and the close succeed.
|
||||
*
|
||||
* If @force is true (i.e. not zero) this function will close the volume even
|
||||
* if this means that data might be lost.
|
||||
*
|
||||
* @vol must have previously been returned by a call to ntfs_device_mount().
|
||||
*
|
||||
* @vol itself is deallocated and should no longer be dereferenced after this
|
||||
* function returns success. If it returns an error then nothing has been done
|
||||
* so it is safe to continue using @vol.
|
||||
*/
|
||||
int ntfs_device_umount(ntfs_volume *vol,
|
||||
const BOOL force __attribute__((unused)))
|
||||
{
|
||||
if (!vol) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
__ntfs_volume_release(vol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_umount - close ntfs volume
|
||||
* @vol: address of ntfs_volume structure of volume to close
|
||||
@@ -1230,19 +1222,19 @@ int ntfs_device_umount(ntfs_volume *vol,
|
||||
* function returns success. If it returns an error then nothing has been done
|
||||
* so it is safe to continue using @vol.
|
||||
*/
|
||||
int ntfs_umount(ntfs_volume *vol,
|
||||
const BOOL force __attribute__((unused)))
|
||||
int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused)))
|
||||
{
|
||||
struct ntfs_device *dev;
|
||||
int ret;
|
||||
|
||||
if (!vol) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
dev = vol->dev;
|
||||
__ntfs_volume_release(vol);
|
||||
ret = __ntfs_volume_release(vol);
|
||||
ntfs_device_free(dev);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MNTENT_H
|
||||
@@ -1420,12 +1412,14 @@ int ntfs_logfile_reset(ntfs_volume *vol)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ni = ntfs_inode_open(vol, FILE_LogFile)) == NULL) {
|
||||
ntfs_log_perror("Failed to open inode FILE_LogFile.");
|
||||
ni = ntfs_inode_open(vol, FILE_LogFile);
|
||||
if (!ni) {
|
||||
ntfs_log_perror("Failed to open inode FILE_LogFile");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0)) == NULL) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
eo = errno;
|
||||
ntfs_log_perror("Failed to open $FILE_LogFile/$DATA");
|
||||
goto error_exit;
|
||||
@@ -1433,10 +1427,10 @@ int ntfs_logfile_reset(ntfs_volume *vol)
|
||||
|
||||
if (ntfs_empty_logfile(na)) {
|
||||
eo = errno;
|
||||
ntfs_log_perror("Failed to empty $FILE_LogFile/$DATA");
|
||||
ntfs_attr_close(na);
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
ntfs_attr_close(na);
|
||||
return ntfs_inode_close(ni);
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@
|
||||
|
||||
#define MS_EXCLUSIVE 0x08000000
|
||||
|
||||
#ifndef MS_FORCE
|
||||
#define MS_FORCE 0x10000000
|
||||
#endif
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_volume ntfs_volume;
|
||||
|
||||
@@ -221,7 +225,6 @@ extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
|
||||
extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
extern int ntfs_device_umount(ntfs_volume *vol, const BOOL force);
|
||||
|
||||
extern ntfs_volume *ntfs_mount(const char *name, unsigned long flags);
|
||||
extern int ntfs_umount(ntfs_volume *vol, const BOOL force);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Sample settings file for the ntfs plugin
|
||||
# Sample settings file for the ntfs addon
|
||||
#
|
||||
# This file should be moved to the directory
|
||||
# /boot/home/config/settings/kernel/drivers/
|
||||
|
||||
Reference in New Issue
Block a user