mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 18:14:24 +08:00
Make libntfs keep track number of free clusters and MFT records.
Thanks for idea to David Fox and Szabolcs Szakacsits.
This commit is contained in:
parent
f5b9888eb6
commit
e248e6b986
@ -208,10 +208,8 @@ struct _ntfs_volume {
|
||||
s32 attrdef_len; /* Size of the attribute definition table in
|
||||
bytes. */
|
||||
|
||||
/* Temp: for directory handling */
|
||||
void *private_data; /* ntfs_dir for . */
|
||||
void *private_bmp1; /* ntfs_bmp for $MFT/$BITMAP */
|
||||
void *private_bmp2; /* ntfs_bmp for $Bitmap */
|
||||
long nr_free_clusters; /* This two are self explaining. */
|
||||
long nr_free_mft_records;
|
||||
};
|
||||
|
||||
extern ntfs_volume *ntfs_volume_alloc(void);
|
||||
|
@ -58,7 +58,8 @@
|
||||
static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
s64 count, int value)
|
||||
{
|
||||
s64 bufsize, br;
|
||||
ntfs_volume *vol = na->ni->vol;
|
||||
s64 bufsize, br, left = count;
|
||||
u8 *buf, *lastbyte_buf;
|
||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, err;
|
||||
|
||||
@ -95,7 +96,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
return -1;
|
||||
}
|
||||
/* and set or clear the appropriate bits in it. */
|
||||
while ((bit & 7) && count--) {
|
||||
while ((bit & 7) && left--) {
|
||||
if (value)
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
@ -105,14 +106,14 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
start_bit = (start_bit + 7) & ~7;
|
||||
}
|
||||
|
||||
/* Loop until @count reaches zero. */
|
||||
/* Loop until @left reaches zero. */
|
||||
lastbyte = 0;
|
||||
lastbyte_buf = NULL;
|
||||
bit = count & 7;
|
||||
bit = left & 7;
|
||||
do {
|
||||
/* If there is a last partial byte... */
|
||||
if (count > 0 && bit) {
|
||||
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||
if (left > 0 && bit) {
|
||||
lastbyte_pos = ((left + 7) >> 3) + firstbyte;
|
||||
if (!lastbyte_pos) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("lastbyte is zero. Leaving "
|
||||
@ -125,7 +126,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||
|
||||
/* read the byte in... */
|
||||
br = ntfs_attr_pread(na, (start_bit + count) >>
|
||||
br = ntfs_attr_pread(na, (start_bit + left) >>
|
||||
3, 1, lastbyte_buf);
|
||||
if (br != 1) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
@ -137,7 +138,7 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set/clear the appropriate bits in it. */
|
||||
while (bit && count--) {
|
||||
while (bit && left--) {
|
||||
if (value)
|
||||
*lastbyte_buf |= 1 << --bit;
|
||||
else
|
||||
@ -172,19 +173,33 @@ static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
*buf = value ? 0xff : 0;
|
||||
}
|
||||
start_bit += tmp;
|
||||
count -= tmp;
|
||||
if (bufsize > (tmp = (count + 7) >> 3))
|
||||
left -= tmp;
|
||||
if (bufsize > (tmp = (left + 7) >> 3))
|
||||
bufsize = tmp;
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
if (lastbyte && left != 0) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("Last buffer but count is not zero (= "
|
||||
"%lli). Leaving inconsistent metadata."
|
||||
"\n", (long long)count);
|
||||
"\n", (long long)left);
|
||||
err = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
} while (left > 0);
|
||||
|
||||
/* Update free clusters and MFT records. */
|
||||
if (na == vol->mftbmp_na) {
|
||||
if (value)
|
||||
vol->nr_free_mft_records -= count;
|
||||
else
|
||||
vol->nr_free_mft_records += count;
|
||||
}
|
||||
if (na == vol->lcnbmp_na) {
|
||||
if (value)
|
||||
vol->nr_free_clusters -= count;
|
||||
else
|
||||
vol->nr_free_clusters += count;
|
||||
}
|
||||
|
||||
/* Done! */
|
||||
free(buf);
|
||||
|
@ -287,6 +287,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
}
|
||||
/* Allocate the bitmap bit. */
|
||||
*byte |= bit;
|
||||
vol->nr_free_clusters--;
|
||||
/* We need to write this bitmap buffer back to disk! */
|
||||
need_writeback = 1;
|
||||
ntfs_log_trace("*byte = 0x%x, need_writeback is set.\n",
|
||||
|
@ -609,6 +609,7 @@ static int ntfs_mft_bitmap_extend_allocation(ntfs_volume *vol)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
vol->nr_free_clusters--;
|
||||
/* Update the mft bitmap runlist. */
|
||||
rl->length++;
|
||||
rl[1].vcn++;
|
||||
@ -833,6 +834,7 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
|
||||
ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n");
|
||||
return 0;
|
||||
}
|
||||
vol->nr_free_mft_records += 64; /* 8 bytes x 8 bits each. */
|
||||
ntfs_log_error("Failed to write to mft bitmap.\n");
|
||||
err = errno;
|
||||
if (ll >= 0)
|
||||
|
@ -744,6 +744,88 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_volume_get_nr_free_mft_records - calculate number of free MFT records
|
||||
* vol: ntfs volume for which perform calculations.
|
||||
*
|
||||
* This function initializes @vol->nr_free_mft_records. @vol->mftbmp_na should
|
||||
* be already opened upon call to this function.
|
||||
*
|
||||
* Return 0 on success. On error return -1 with errno set appropriately and
|
||||
* @vol->nr_free_mft_records is not touched in this case.
|
||||
*/
|
||||
static int ntfs_volume_get_nr_free_mft_records(ntfs_volume *vol)
|
||||
{
|
||||
long nr_free = vol->mft_na->data_size >> vol->mft_record_size_bits;
|
||||
s64 br, total = 0;
|
||||
u8 *buf;
|
||||
|
||||
buf = ntfs_malloc(vol->cluster_size);
|
||||
if (!buf)
|
||||
return -1;
|
||||
while (1) {
|
||||
int i, j;
|
||||
|
||||
br = ntfs_attr_pread(vol->mftbmp_na, total,
|
||||
vol->cluster_size, buf);
|
||||
if (br <= 0)
|
||||
break;
|
||||
total += br;
|
||||
for (i = 0; i < br; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((buf[i] >> j) & 1)
|
||||
nr_free--;
|
||||
}
|
||||
free(buf);
|
||||
if (!total || br < 0) {
|
||||
ntfs_log_error("pread: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
vol->nr_free_mft_records = nr_free;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_volume_get_nr_free_clusters - calculate number of free clusters
|
||||
* vol: ntfs volume for which perform calculations.
|
||||
*
|
||||
* This function initializes @vol->nr_free_clusters. @vol->lcnbmp_na should be
|
||||
* already opened upon call to this function.
|
||||
*
|
||||
* Return 0 on success. On error return -1 with errno set appropriately and
|
||||
* @vol->nr_free_clusters is not touched in this case.
|
||||
*/
|
||||
static long ntfs_volume_get_nr_free_clusters(ntfs_volume *vol)
|
||||
{
|
||||
long nr_free = vol->nr_clusters;
|
||||
s64 br, total = 0;
|
||||
u8 *buf;
|
||||
|
||||
buf = ntfs_malloc(vol->cluster_size);
|
||||
if (!buf)
|
||||
return -1;
|
||||
while (1) {
|
||||
int i, j;
|
||||
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, total,
|
||||
vol->cluster_size, buf);
|
||||
if (br <= 0)
|
||||
break;
|
||||
total += br;
|
||||
for (i = 0; i < br; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((buf[i] >> j) & 1)
|
||||
nr_free--;
|
||||
}
|
||||
free(buf);
|
||||
if (!total || br < 0) {
|
||||
ntfs_log_error("pread: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
vol->nr_free_clusters = nr_free;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_mount - open ntfs volume
|
||||
* @dev: device to open
|
||||
@ -1127,6 +1209,15 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
||||
ntfs_attr_close(na);
|
||||
if (ntfs_inode_close(ni))
|
||||
ntfs_log_perror("Failed to close inode, leaking memory");
|
||||
/* Initialize number of free clusters and MFT records. */
|
||||
if (ntfs_volume_get_nr_free_mft_records(vol)) {
|
||||
ntfs_log_perror("Failed to calculate number of free MFTs");
|
||||
goto error_exit;
|
||||
}
|
||||
if (ntfs_volume_get_nr_free_clusters(vol)) {
|
||||
ntfs_log_perror("Failed to calculate number of free clusters");
|
||||
goto error_exit;
|
||||
}
|
||||
/*
|
||||
* Check for dirty logfile and hibernated Windows.
|
||||
* We care only about read-write mounts.
|
||||
|
@ -97,9 +97,6 @@ typedef struct {
|
||||
char *mnt_point;
|
||||
char *device;
|
||||
char *locale;
|
||||
int state;
|
||||
long free_clusters;
|
||||
long free_mft;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int fmask;
|
||||
@ -119,13 +116,6 @@ typedef struct {
|
||||
BOOL blkdev;
|
||||
} ntfs_fuse_context_t;
|
||||
|
||||
typedef enum {
|
||||
NF_FreeClustersOutdate = (1 << 0), /* Information about amount of
|
||||
free clusters is outdated. */
|
||||
NF_FreeMFTOutdate = (1 << 1), /* Information about amount of
|
||||
free MFT records is outdated. */
|
||||
} ntfs_fuse_state_bits;
|
||||
|
||||
#define NTFS_FUSE_OPT(t, p) { t, offsetof(ntfs_fuse_context_t, p), TRUE }
|
||||
#define NTFS_FUSE_OPT_NEG(t, p) { t, offsetof(ntfs_fuse_context_t, p), FALSE }
|
||||
#define NTFS_FUSE_OPT_VAL(t, p, v) { t, offsetof(ntfs_fuse_context_t, p), v }
|
||||
@ -187,15 +177,6 @@ static char ntfs_fuse_default_options[] =
|
||||
"default_permissions,allow_other,use_ino,kernel_cache,nonempty";
|
||||
static ntfs_fuse_context_t *ctx;
|
||||
|
||||
/**
|
||||
* ntfs_fuse_mark_free_space_outdated - forces free space recalculation
|
||||
*/
|
||||
static __inline__ void ntfs_fuse_mark_free_space_outdated(void)
|
||||
{
|
||||
/* Mark information about free MFT record and clusters outdated. */
|
||||
ctx->state |= (NF_FreeClustersOutdate | NF_FreeMFTOutdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_fuse_is_named_data_stream - check path to be to named data stream
|
||||
* @path: path to check
|
||||
@ -221,73 +202,6 @@ static __inline__ void ntfs_fuse_update_times(ntfs_inode *ni,
|
||||
ntfs_inode_update_times(ni, mask);
|
||||
}
|
||||
|
||||
static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol, long nr_free)
|
||||
{
|
||||
u8 *buf;
|
||||
s64 br, total = 0;
|
||||
|
||||
if (!(ctx->state & NF_FreeMFTOutdate))
|
||||
return ctx->free_mft;
|
||||
buf = ntfs_malloc(vol->cluster_size);
|
||||
if (!buf)
|
||||
return -errno;
|
||||
while (1) {
|
||||
int i, j;
|
||||
|
||||
br = ntfs_attr_pread(vol->mftbmp_na, total,
|
||||
vol->cluster_size, buf);
|
||||
if (br <= 0)
|
||||
break;
|
||||
total += br;
|
||||
for (i = 0; i < br; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((buf[i] >> j) & 1)
|
||||
nr_free--;
|
||||
}
|
||||
free(buf);
|
||||
if (!total || br < 0) {
|
||||
ntfs_log_error("pread: %s\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
ctx->free_mft = nr_free;
|
||||
ctx->state &= ~(NF_FreeMFTOutdate);
|
||||
return nr_free;
|
||||
}
|
||||
|
||||
static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol)
|
||||
{
|
||||
u8 *buf;
|
||||
long nr_free = vol->nr_clusters;
|
||||
s64 br, total = 0;
|
||||
|
||||
if (!(ctx->state & NF_FreeClustersOutdate))
|
||||
return ctx->free_clusters;
|
||||
buf = ntfs_malloc(vol->cluster_size);
|
||||
if (!buf)
|
||||
return -errno;
|
||||
while (1) {
|
||||
int i, j;
|
||||
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, total,
|
||||
vol->cluster_size, buf);
|
||||
if (br <= 0)
|
||||
break;
|
||||
total += br;
|
||||
for (i = 0; i < br; i++)
|
||||
for (j = 0; j < 8; j++)
|
||||
if ((buf[i] >> j) & 1)
|
||||
nr_free--;
|
||||
}
|
||||
free(buf);
|
||||
if (!total || br < 0) {
|
||||
ntfs_log_error("pread: %s\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
ctx->free_clusters = nr_free;
|
||||
ctx->state &= ~(NF_FreeClustersOutdate);
|
||||
return nr_free;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_fuse_statfs - return information about mounted NTFS volume
|
||||
* @path: ignored (but fuse requires it)
|
||||
@ -308,8 +222,6 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol)
|
||||
static int ntfs_fuse_statfs(const char *path __attribute__((unused)),
|
||||
struct statvfs *sfs)
|
||||
{
|
||||
long size;
|
||||
|
||||
/* Optimal transfer block size. */
|
||||
sfs->f_bsize = ctx->vol->cluster_size;
|
||||
sfs->f_frsize = ctx->vol->cluster_size;
|
||||
@ -319,20 +231,16 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)),
|
||||
* the total clusters.
|
||||
*/
|
||||
sfs->f_blocks = ctx->vol->nr_clusters;
|
||||
/* Free data blocks in file system in units of f_bsize. */
|
||||
size = ntfs_fuse_get_nr_free_clusters(ctx->vol);
|
||||
if (size < 0)
|
||||
size = 0;
|
||||
/* Free blocks avail to non-superuser, same as above on NTFS. */
|
||||
sfs->f_bavail = sfs->f_bfree = size;
|
||||
/*
|
||||
* Free data blocks and free data block available to non-superuser in
|
||||
* file system in units of f_bsize.
|
||||
*/
|
||||
sfs->f_bavail = sfs->f_bfree = ctx->vol->nr_free_clusters;
|
||||
/* Number of inodes in file system (at this point in time). */
|
||||
size = ctx->vol->mft_na->data_size >> ctx->vol->mft_record_size_bits;
|
||||
sfs->f_files = size;
|
||||
sfs->f_files = ctx->vol->mft_na->data_size >>
|
||||
ctx->vol->mft_record_size_bits;
|
||||
/* Free inodes in fs (based on current total count). */
|
||||
size = ntfs_fuse_get_nr_free_mft_records(ctx->vol, size);
|
||||
if (size < 0)
|
||||
size = 0;
|
||||
sfs->f_ffree = size;
|
||||
sfs->f_ffree = ctx->vol->nr_free_mft_records;
|
||||
/* Maximum length of filenames. */
|
||||
sfs->f_namemax = NTFS_MAX_NAME_LEN;
|
||||
return 0;
|
||||
@ -746,7 +654,6 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size,
|
||||
}
|
||||
res = total;
|
||||
exit:
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
if (res > 0)
|
||||
ntfs_fuse_update_times(ni, NTFS_UPDATE_MTIME |
|
||||
NTFS_UPDATE_CTIME);
|
||||
@ -793,7 +700,6 @@ static int ntfs_fuse_truncate(const char *org_path, off_t size)
|
||||
NTFS_UPDATE_CTIME);
|
||||
res = 0;
|
||||
}
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
ntfs_attr_close(na);
|
||||
exit:
|
||||
if (ni && ntfs_inode_close(ni))
|
||||
@ -938,7 +844,6 @@ static int ntfs_fuse_mknod(const char *org_path, mode_t mode, dev_t dev)
|
||||
else
|
||||
res = ntfs_fuse_create_stream(path, stream_name,
|
||||
stream_name_len);
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
exit:
|
||||
free(path);
|
||||
if (stream_name_len)
|
||||
@ -950,7 +855,6 @@ static int ntfs_fuse_symlink(const char *to, const char *from)
|
||||
{
|
||||
if (ntfs_fuse_is_named_data_stream(from))
|
||||
return -EINVAL; /* n/a for named data streams. */
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
return ntfs_fuse_create(from, S_IFLNK, 0, to);
|
||||
}
|
||||
|
||||
@ -992,7 +896,6 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path)
|
||||
res = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
/* Create hard link. */
|
||||
if (ntfs_link(ni, dir_ni, uname, uname_len))
|
||||
res = -errno;
|
||||
@ -1101,7 +1004,6 @@ static int ntfs_fuse_unlink(const char *org_path)
|
||||
res = ntfs_fuse_rm(path);
|
||||
else
|
||||
res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len);
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
free(path);
|
||||
if (stream_name_len)
|
||||
free(stream_name);
|
||||
@ -1153,7 +1055,6 @@ static int ntfs_fuse_mkdir(const char *path,
|
||||
{
|
||||
if (ntfs_fuse_is_named_data_stream(path))
|
||||
return -EINVAL; /* n/a for named data streams. */
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
return ntfs_fuse_create(path, S_IFDIR, 0, NULL);
|
||||
}
|
||||
|
||||
@ -1161,7 +1062,6 @@ static int ntfs_fuse_rmdir(const char *path)
|
||||
{
|
||||
if (ntfs_fuse_is_named_data_stream(path))
|
||||
return -EINVAL; /* n/a for named data streams. */
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
return ntfs_fuse_rm(path);
|
||||
}
|
||||
|
||||
@ -1389,7 +1289,6 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
||||
res = -EEXIST;
|
||||
goto exit;
|
||||
}
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
if (!na) {
|
||||
if (flags == XATTR_REPLACE) {
|
||||
res = -ENODATA;
|
||||
@ -1444,7 +1343,6 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
|
||||
res = -ENODATA;
|
||||
goto exit;
|
||||
}
|
||||
ntfs_fuse_mark_free_space_outdated();
|
||||
if (ntfs_attr_rm(na))
|
||||
res = -errno;
|
||||
na = NULL;
|
||||
@ -1543,7 +1441,6 @@ static int ntfs_fuse_init(void)
|
||||
return -1;
|
||||
|
||||
*ctx = (ntfs_fuse_context_t) {
|
||||
.state = NF_FreeClustersOutdate | NF_FreeMFTOutdate,
|
||||
.uid = getuid(),
|
||||
.gid = getgid(),
|
||||
.fmask = 0111,
|
||||
|
Loading…
Reference in New Issue
Block a user