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
cantab.net!aia21 2002-12-26 00:44:57 +00:00
parent 6b5c3e9079
commit 9fd51dde62
9 changed files with 225 additions and 46 deletions

View File

@ -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

View File

@ -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)
/**

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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. */

View File

@ -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;