New API functions (mostly still WIP):
attrib.[hc]: ntfs_resident_attr_value_resize(), ntfs_attr_truncate() inode.[hc]: ntfs_inode_mark_dirty(), ntfs_inode_sync() lcnalloc.[hc]: ntfs_cluster_{alloc,free}() Renamed ntfs_clusters_{read,write}() to ntfs_cluster_{read,write}(). (Logical change 1.55)edge.strict_endians
parent
6b5c3e9079
commit
9fd51dde62
13
ChangeLog
13
ChangeLog
|
@ -13,7 +13,7 @@
|
|||
- Rewrite disk_io.[ch] and mft.[ch] defining new access API:
|
||||
disk_io.[ch] provide: ntfs_p{read,write}(),
|
||||
ntfs_mst_p{read,write}(), and
|
||||
ntfs_clusters_{read,write}().
|
||||
ntfs_cluster_{read,write}().
|
||||
mft.[ch] provide: ntfs_mft_record_{read,write}(),
|
||||
ntfs_mft_records_{read,write}(), and
|
||||
ntfs_mft_record_get_data_size().
|
||||
|
@ -100,7 +100,7 @@
|
|||
and writes and deal with end of file properly. Affected functions:
|
||||
ntfs_p{read,write}(),
|
||||
ntfs_mst_p{read,write}(), and
|
||||
ntfs_clusters_{read,write}().
|
||||
ntfs_cluster_{read,write}().
|
||||
- Change ntfsfix to take into account the automatic mft mirror updates.
|
||||
- Add new API provided by new files dir.[ch]:
|
||||
ntfs_inode_lookup_by_name(), and
|
||||
|
@ -167,6 +167,15 @@
|
|||
Thanks to Szakacsits Szabolcs for pointing this problem out.
|
||||
- New API function provided by unistr.[hc] and use it in mkntfs:
|
||||
ntfs_ucsnlen().
|
||||
- New API function provided by attrib.[hc] and use it in mkntfs:
|
||||
ntfs_resident_attr_value_resize(),
|
||||
ntfs_attr_truncate(). -- WIP
|
||||
- New API functions provided by inode.[hc]:
|
||||
ntfs_inode_mark_dirty(),
|
||||
ntfs_inode_sync(). -- WIP
|
||||
- Change ntfs_inode_close() to write out dirty inodes and inode extents.
|
||||
- New API functions provided by lcnalloc.[hc]:
|
||||
ntfs_cluster_{alloc,free}().
|
||||
|
||||
12/03/2002 - 1.6.0 - More mkntfs options and cleanups.
|
||||
Fix typo in usage information of mkntfs. Thanks to Richard Russon for
|
||||
|
|
|
@ -261,6 +261,10 @@ extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
|||
extern int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max,
|
||||
const s64 n);
|
||||
|
||||
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 newsize);
|
||||
|
||||
extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
|
||||
|
||||
// FIXME / TODO: Above here the file is cleaned up. (AIA)
|
||||
/**
|
||||
|
|
|
@ -32,9 +32,9 @@ extern s64 ntfs_mst_pread(const int fd, const s64 pos, s64 count,
|
|||
extern s64 ntfs_mst_pwrite(const int fd, const s64 pos, s64 count,
|
||||
const u32 bksize, const void *b);
|
||||
|
||||
extern s64 ntfs_clusters_read(const ntfs_volume *vol, const s64 lcn,
|
||||
extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b);
|
||||
extern s64 ntfs_clusters_write(const ntfs_volume *vol, const s64 lcn,
|
||||
extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b);
|
||||
|
||||
#endif /* defined _NTFS_DISK_IO_H */
|
||||
|
|
|
@ -85,6 +85,7 @@ struct _ntfs_inode {
|
|||
u32 attr_list_size; /* Length of attribute list value in bytes. */
|
||||
u8 *attr_list; /* Attribute list value itself. */
|
||||
runlist *attr_list_rl; /* Run list for the attribute list value. */
|
||||
/* Below fields are always valid. */
|
||||
s32 nr_extents; /* For a base mft record, the number of
|
||||
attached extent inodes (0 if none), for
|
||||
extent records this is -1. */
|
||||
|
@ -105,5 +106,23 @@ extern int ntfs_inode_close(ntfs_inode *ni);
|
|||
extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
|
||||
const MFT_REF mref);
|
||||
|
||||
/**
|
||||
* ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty
|
||||
* @ni: ntfs inode to set dirty
|
||||
*
|
||||
* Set the inode @ni dirty so it is written out later (at the latest at
|
||||
* ntfs_inode_close() time). If @ni is an extent inode, set the base inode
|
||||
* dirty, too.
|
||||
*
|
||||
* This function cannot fail.
|
||||
*/
|
||||
static __inline__ void ntfs_inode_mark_dirty(ntfs_inode *ni) {
|
||||
NInoSetDirty(ni);
|
||||
if (ni->nr_extents == -1)
|
||||
NInoSetDirty(ni->base_ni);
|
||||
}
|
||||
|
||||
extern int ntfs_inode_sync(ntfs_inode *ni);
|
||||
|
||||
#endif /* defined _NTFS_INODE_H */
|
||||
|
||||
|
|
153
libntfs/attrib.c
153
libntfs/attrib.c
|
@ -2037,3 +2037,156 @@ err_out:
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute
|
||||
* @na: non-resident ntfs attribute to shrink
|
||||
* @newsize: new size (in bytes) to which to shrink the attribute
|
||||
*
|
||||
* Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
* The following error codes are defined:
|
||||
* ENOTSUP - The desired resize is not implemented yet.
|
||||
*/
|
||||
static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_resident_attr_value_resize - resize the value of a resident attribute
|
||||
* @m: mft record containing attribute record
|
||||
* @a: attribute record whose value to resize
|
||||
* @newsize: new size in bytes to which to resize the attribute value of @a
|
||||
*
|
||||
* Resize the value of the attribute @a in the mft record @m to @newsize bytes.
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code.
|
||||
* The following error codes are defined:
|
||||
* ENOSPC - Not enough space in mft record to perform the resize.
|
||||
* Note that on error no modifications have been performed whatsoever.
|
||||
*/
|
||||
int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 newsize)
|
||||
{
|
||||
u32 new_alen, new_muse;
|
||||
|
||||
/* Calculate the new attribute length and mft record bytes used. */
|
||||
new_alen = (le32_to_cpu(a->length) - le32_to_cpu(a->value_length) +
|
||||
newsize + 7) & ~7;
|
||||
new_muse = le32_to_cpu(m->bytes_in_use) - le32_to_cpu(a->length) +
|
||||
new_alen;
|
||||
/* Not enough space in this mft record. */
|
||||
if (new_muse > le32_to_cpu(m->bytes_allocated)) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
/* Move attributes following @a to their new location. */
|
||||
memmove((u8*)a + new_alen, (u8*)a + le32_to_cpu(a->length),
|
||||
le32_to_cpu(m->bytes_in_use) - ((u8*)a - (u8*)m) -
|
||||
le32_to_cpu(a->length));
|
||||
/* Adjust @a to reflect the new value size. */
|
||||
a->length = cpu_to_le32(new_alen);
|
||||
a->value_length = cpu_to_le32(newsize);
|
||||
/* Adjust @m to reflect the change in used space. */
|
||||
m->bytes_in_use = cpu_to_le32(new_muse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_resident_attr_shrink - shrink a resident, open ntfs attribute
|
||||
* @na: resident ntfs attribute to shrink
|
||||
* @newsize: new size (in bytes) to which to shrink the attribute
|
||||
*
|
||||
* Reduce the size of a resident, open ntfs attribute @na to @newsize bytes.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
* The following error codes are defined:
|
||||
* ENOTSUP - The desired resize is not implemented yet.
|
||||
*/
|
||||
static int ntfs_resident_attr_shrink(ntfs_attr *na, const u32 newsize) {
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
int err;
|
||||
|
||||
Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x.\n", __FUNCTION__,
|
||||
(unsigned long long)na->ni->mft_no, na->type);
|
||||
/* Get the attribute record that needs modification. */
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx)
|
||||
return -1;
|
||||
if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0,
|
||||
ctx)) {
|
||||
err = errno;
|
||||
goto put_err_out;
|
||||
}
|
||||
|
||||
// TODO: Check the attribute type and the corresponding minimum size
|
||||
// against @newsize and fail if @newsize is too small! (AIA)
|
||||
|
||||
/* Perform the resize of the attribute record. */
|
||||
if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, newsize)) {
|
||||
err = errno;
|
||||
goto put_err_out;
|
||||
}
|
||||
/* Update the ntfs attribute structure, too. */
|
||||
na->allocated_size = na->data_size = na->initialized_size = newsize;
|
||||
if (NAttrCompressed(na) || NAttrSparse(na))
|
||||
na->compressed_size = newsize;
|
||||
|
||||
/*
|
||||
* Set the inode (and its base inode if it exists) dirty so it is
|
||||
* written out later.
|
||||
*/
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
return 0;
|
||||
put_err_out:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_attr_truncate - resize an ntfs attribute
|
||||
* @na: open ntfs attribute to resize
|
||||
* @newsize: new size (in bytes) to which to resize the attribute
|
||||
*
|
||||
* Change the size of an open ntfs attribute @na to @newsize bytes.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
* The following error codes are defined:
|
||||
* EINVAL - Invalid arguments were passed to the function.
|
||||
* ENOTSUP - The desired resize is not implemented yet.
|
||||
*
|
||||
* NOTE: At present attributes can only be made smaller using this function,
|
||||
* never bigger.
|
||||
*/
|
||||
int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
|
||||
{
|
||||
if (!na || newsize < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Encrypted attributes are not supported. We return access denied,
|
||||
* which is what Windows NT4 does, too.
|
||||
*/
|
||||
if (NAttrEncrypted(na)) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* TODO: Implement making attributes bigger/filling in of uninitialized
|
||||
* holes as well as handling of compressed attributes. (AIA)
|
||||
*/
|
||||
if (newsize > na->initialized_size || NAttrCompressed(na)) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NAttrNonResident(na))
|
||||
return ntfs_non_resident_attr_shrink(na, newsize);
|
||||
return ntfs_resident_attr_shrink(na, newsize);
|
||||
}
|
||||
|
||||
|
|
|
@ -264,7 +264,7 @@ s64 ntfs_mst_pwrite(const int fd, const s64 pos, s64 count,
|
|||
}
|
||||
|
||||
/**
|
||||
* ntfs_clusters_read - read ntfs clusters
|
||||
* ntfs_cluster_read - read ntfs clusters
|
||||
* @vol: volume to read from
|
||||
* @lcn: starting logical cluster number
|
||||
* @count: number of clusters to read
|
||||
|
@ -274,7 +274,7 @@ s64 ntfs_mst_pwrite(const int fd, const s64 pos, s64 count,
|
|||
* volume @vol into buffer @b. Return number of clusters read or -1 on error,
|
||||
* with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_clusters_read(const ntfs_volume *vol, const s64 lcn,
|
||||
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b)
|
||||
{
|
||||
s64 br;
|
||||
|
@ -297,7 +297,7 @@ s64 ntfs_clusters_read(const ntfs_volume *vol, const s64 lcn,
|
|||
}
|
||||
|
||||
/**
|
||||
* ntfs_clusters_write - write ntfs clusters
|
||||
* ntfs_cluster_write - write ntfs clusters
|
||||
* @vol: volume to write to
|
||||
* @lcn: starting logical cluster number
|
||||
* @count: number of clusters to write
|
||||
|
@ -307,7 +307,7 @@ s64 ntfs_clusters_read(const ntfs_volume *vol, const s64 lcn,
|
|||
* buffer @b to volume @vol. Return the number of clusters written or -1 on
|
||||
* error, with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_clusters_write(const ntfs_volume *vol, const s64 lcn,
|
||||
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b)
|
||||
{
|
||||
s64 bw;
|
||||
|
|
|
@ -193,22 +193,25 @@ err_out:
|
|||
* error, @ni has not been freed. The user should attempt to handle the error
|
||||
* and call ntfs_inode_close() again. The following error codes are defined:
|
||||
*
|
||||
* EBUSY @ni is dirty and/or the attribute list runlist is dirty.
|
||||
* EBUSY @ni and/or its attribute list runlist is/are dirty and the
|
||||
* attempt to write it/them to disk failed.
|
||||
* EINVAL @ni is invalid (probably it is an extent inode!)
|
||||
*/
|
||||
int ntfs_inode_close(ntfs_inode *ni)
|
||||
{
|
||||
/* If the inode is an extent inode, comply rudely! */
|
||||
/* If the inode is an extent inode, complain rudely! */
|
||||
if (ni->nr_extents == -1) {
|
||||
Dprintf("%s(): BUG: Tried to close extent inode!\n",
|
||||
__FUNCTION__);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
// TODO: This needs to be replaced with a flush to disk attempt. (AIA)
|
||||
/* If we have dirty metadata, write it out. */
|
||||
if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
if (ntfs_inode_sync(ni)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Is this a base inode with mapped extent inodes? */
|
||||
if (ni->nr_extents > 0) {
|
||||
|
@ -318,3 +321,23 @@ err_out:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_inode_sync - write the inode (and its dirty extents) to disk
|
||||
* @ni: ntfs inode to write
|
||||
*
|
||||
* Write the inode @ni to disk as well as its dirty extent inodes if such
|
||||
* exist.
|
||||
*
|
||||
* Return 0 on success or -1 on error with errno set to the error code.
|
||||
*/
|
||||
int ntfs_inode_sync(ntfs_inode *ni)
|
||||
{
|
||||
if (!ni) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -860,35 +860,6 @@ int make_room_for_attribute(MFT_RECORD *m, char *pos, const u32 size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Return 0 on success and -errno on error. */
|
||||
int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 new_vsize)
|
||||
{
|
||||
int new_alen, new_muse;
|
||||
|
||||
/* New attribute length and mft record bytes used. */
|
||||
new_alen = (le32_to_cpu(a->length) - le32_to_cpu(a->value_length) +
|
||||
new_vsize + 7) & ~7;
|
||||
new_muse = le32_to_cpu(m->bytes_in_use) - le32_to_cpu(a->length) +
|
||||
new_alen;
|
||||
/* Check for sufficient space. */
|
||||
if (new_muse > le32_to_cpu(m->bytes_allocated) ) {
|
||||
// Aarrgghh! Need to make space. Probably want generic function
|
||||
// for this as we need to call it from other places, too.
|
||||
return -ENOTSUP;
|
||||
}
|
||||
/* Move attributes behind @a to their new location. */
|
||||
memmove((char*)a + new_alen, (char*)a + le32_to_cpu(a->length),
|
||||
le32_to_cpu(m->bytes_in_use) - ((char*)a - (char*)m) -
|
||||
le32_to_cpu(a->length));
|
||||
/* Adjust @m to reflect change in used space. */
|
||||
m->bytes_in_use = cpu_to_le32(new_muse);
|
||||
/* Adjust @a to reflect new value size. */
|
||||
a->length = cpu_to_le32(new_alen);
|
||||
a->value_length = cpu_to_le32(new_vsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void deallocate_scattered_clusters(const runlist *rl)
|
||||
{
|
||||
LCN j;
|
||||
|
@ -1976,12 +1947,12 @@ int upgrade_to_large_index(MFT_RECORD *m, const char *name,
|
|||
+ le16_to_cpu(re->length));
|
||||
r->index.allocated_size = r->index.index_length;
|
||||
/* Resize index root attribute. */
|
||||
err = resize_resident_attribute_value(m, a, sizeof(INDEX_ROOT) -
|
||||
if (ntfs_resident_attr_value_resize(m, a, sizeof(INDEX_ROOT) -
|
||||
sizeof(INDEX_HEADER) +
|
||||
le32_to_cpu(r->index.allocated_size));
|
||||
if (err) {
|
||||
le32_to_cpu(r->index.allocated_size))) {
|
||||
// TODO: Remove the added bitmap!
|
||||
// Revert index root from index allocation.
|
||||
err = -errno;
|
||||
goto err_out;
|
||||
}
|
||||
/* Set VCN pointer to 0LL. */
|
||||
|
|
|
@ -1823,7 +1823,7 @@ int undelete_file (ntfs_volume *vol, long long inode)
|
|||
goto free;
|
||||
}
|
||||
} else {
|
||||
if (ntfs_clusters_read(vol, j, 1, buffer) < 1) {
|
||||
if (ntfs_cluster_read(vol, j, 1, buffer) < 1) {
|
||||
Eprintf ("Read failed: %s\n", strerror (errno));
|
||||
close (fd);
|
||||
goto free;
|
||||
|
|
Loading…
Reference in New Issue