Changes by: cha0smaster
Update of /cvsroot/linux-ntfs/ntfsprogs/libntfs
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26027/libntfs
Modified Files:
attrib.c dir.c inode.c
Log Message:
Fix resident attribute adding: Add @val to ntfs_attr_add and @val and @size to ntfs_resident_attr_record_add.
Still need to fix attribute lis entry adding. :-(
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/attrib.c,v
retrieving revision 1.173
retrieving revision 1.174
diff -u -p -r1.173 -r1.174
--- attrib.c 14 Aug 2005 15:44:47 -0000 1.173
+++ attrib.c 16 Sep 2005 14:28:18 -0000 1.174
@@ -2496,6 +2496,8 @@ int ntfs_make_room_for_attr(MFT_RECORD *
* @type: type of the new attribute
* @name: name of the new attribute
* @name_len: name length of the new attribute
+ * @val: value of the new attribute
+ * @size: size of new attribute (length of @val, if @val != NULL)
* @flags: flags of the new attribute
*
* Return offset to attribute from the beginning of the mft record on success
@@ -2506,7 +2508,8 @@ int ntfs_make_room_for_attr(MFT_RECORD *
* EIO - I/O error occurred or damaged filesystem.
*/
int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, ATTR_FLAGS flags)
+ ntfschar *name, u8 name_len, u8 *val, u32 size,
+ ATTR_FLAGS flags)
{
ntfs_attr_search_ctx *ctx;
u32 length;
@@ -2541,7 +2544,7 @@ int ntfs_resident_attr_record_add(ntfs_i
if (!ctx)
return -1;
if (!ntfs_attr_lookup(type, name, name_len,
- CASE_SENSITIVE, 0, NULL, 0, ctx)) {
+ CASE_SENSITIVE, 0, val, size, ctx)) {
err = EEXIST;
Dprintf("%s(): Attribute already present.\n", __FUNCTION__);
goto put_err_out;
@@ -2554,7 +2557,9 @@ int ntfs_resident_attr_record_add(ntfs_i
m = ctx->mrec;
/* Make room for attribute. */
- length = (0x18 + sizeof(ntfschar) * name_len + 7) & ~7;
+ length = offsetof(ATTR_RECORD, resident_end) +
+ ((name_len * sizeof(ntfschar) + 7) & ~7) +
+ ((size + 7) & ~7);
if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) {
err = errno;
Dprintf("%s(): Failed to make room for attribute.\n",
@@ -2568,11 +2573,15 @@ int ntfs_resident_attr_record_add(ntfs_i
a->length = cpu_to_le32(length);
a->non_resident = 0;
a->name_length = name_len;
- a->name_offset = cpu_to_le16(0x18);
+ a->name_offset = cpu_to_le16(offsetof(ATTR_RECORD, resident_end));
a->flags = flags;
a->instance = m->next_attr_instance;
- a->value_length = 0;
- a->value_offset = cpu_to_le16(length);
+ a->value_length = cpu_to_le32(size);
+ a->value_offset = cpu_to_le16(length - ((size + 7) & ~7));
+ if (val)
+ memcpy((u8*)a + le16_to_cpu(a->value_offset), val, size);
+ else
+ memset((u8*)a + le16_to_cpu(a->value_offset), 0, size);
if (type == AT_FILE_NAME)
a->resident_flags = RESIDENT_ATTR_IS_INDEXED;
else
@@ -2893,7 +2902,14 @@ int ntfs_attr_record_rm(ntfs_attr_search
* @type: type of the new attribute
* @name: name in unicode of the new attribute
* @name_len: name length in unicode characters of the new attribute
- * @size: size of the new attribute
+ * @val: value of new attribute
+ * @size: size of the new attribute / length of @val (if specified)
+ *
+ * @val should always be specified for always resident attributes (eg. FILE_NAME
+ * attribute), for attributes that can become non-resident @val can be NULL
+ * (eg. DATA attribute). @size can be specified even if @val is NULL, in this
+ * case data size will be equal to @size and initialized size will be equal
+ * to 0.
*
* If inode haven't got enough space to add attribute, add attribute to one of
* it extents, if no extents present or no one of them have enough space, than
@@ -2904,21 +2920,21 @@ int ntfs_attr_record_rm(ntfs_attr_search
* @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call
* ntfs_inode_add_attrlist instead.
*
- * On success return opened new ntfs attribute. On error return NULL with errno
- * set to the error code.
+ * On success return 0. On error return -1 with errno set to the error code.
*/
-ntfs_attr *ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
- ntfschar *name, u8 name_len, s64 size)
+int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
+ ntfschar *name, u8 name_len, u8 *val, s64 size)
{
u32 attr_rec_size;
int err, i, offset;
+ BOOL is_resident;
ntfs_inode *attr_ni;
ntfs_attr *na;
if (!ni || size < 0 || type == AT_ATTRIBUTE_LIST) {
Dprintf("%s(): Invalid arguments passed.\n", __FUNCTION__);
errno = EINVAL;
- return NULL;
+ return -1;
}
Dprintf("%s(): Entering for inode 0x%llx, attr %x, size %lld.\n",
@@ -2927,19 +2943,40 @@ ntfs_attr *ntfs_attr_add(ntfs_inode *ni,
if (ni->nr_extents == -1)
ni = ni->base_ni;
- /* Validate attribute type. */
- if (!ntfs_attr_find_in_attrdef(ni->vol, type)) {
- if (errno == ENOENT) {
- Dprintf("%s(): Invalid attribute type.\n",
- __FUNCTION__);
- errno = EINVAL;
- return NULL;
- } else {
+ /* Check the attribute type and the size. */
+ if (ntfs_attr_size_bounds_check(ni->vol, type, size)) {
+ err = errno;
+ if (err == ERANGE) {
+ Dprintf("%s(): Size bounds check failed. "
+ "Aborting...\n", __FUNCTION__);
+ } else if (err == ENOENT) {
+ Dprintf("%s(): Invalid attribute type. "
+ "Aborting...\n", __FUNCTION__);
+ err = EIO;
+ }
+ errno = err;
+ return -1;
+ }
+
+ /* Sanity checks for always resident attributes. */
+ if (ntfs_attr_can_be_non_resident(ni->vol, type)) {
+ if (errno != EPERM) {
err = errno;
- Dprintf("%s(): ntfs_attr_find_in_attrdef failed.\n",
+ Dprintf("%s(): ntfs_attr_can_be_non_resident failed.\n",
__FUNCTION__);
- errno = err;
- return NULL;
+ goto err_out;
+ }
+ /* @val is mandatory. */
+ if (!val) {
+ Dprintf("%s(): @val is mandatory for always resident "
+ "atributes.\n", __FUNCTION__);
+ errno = EINVAL;
+ return -1;
+ }
+ if (size > ni->vol->mft_record_size) {
+ Dprintf("%s(): Attribute is too big.\n", __FUNCTION__);
+ errno = ERANGE;
+ return -1;
}
}
@@ -2947,28 +2984,38 @@ ntfs_attr *ntfs_attr_add(ntfs_inode *ni,
* Determine resident or not will be new attribute. We add 8 to size in
* non resident case for mapping pairs.
*/
- if (ntfs_attr_can_be_resident(ni->vol, type)) {
+ if (!ntfs_attr_can_be_resident(ni->vol, type)) {
+ /* Attribute can be resident. */
+ is_resident = TRUE;
+ /* Check if it is better to make attribute non resident. */
+ if (!ntfs_attr_can_be_non_resident(ni->vol, type) &&
+ offsetof(ATTR_RECORD, resident_end) + size >=
+ offsetof(ATTR_RECORD, non_resident_end) + 8)
+ /* Make it non resident. */
+ is_resident = FALSE;
+ } else {
if (errno != EPERM) {
err = errno;
- Dprintf("%s(): ntfs_attr_can_be resident failed.\n",
+ Dprintf("%s(): ntfs_attr_can_be_resident failed.\n",
__FUNCTION__);
goto err_out;
}
/* Attribute can't be resident. */
+ is_resident = FALSE;
+ }
+ /* Calculate atribute record size. */
+ if (is_resident)
+ attr_rec_size = offsetof(ATTR_RECORD, resident_end) +
+ ((name_len * sizeof(ntfschar) + 7) & ~7) +
+ ((size + 7) & ~7);
+ else
attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) +
((name_len * sizeof(ntfschar) + 7) & ~7) + 8;
- } else {
- /* Attribute can be resident. */
- attr_rec_size = offsetof(ATTR_RECORD, resident_end) +
- ((name_len * sizeof(ntfschar) + 7) & ~7);
- /* Check whether attribute will fit into the MFT record. */
- if (size + attr_rec_size >= ni->vol->mft_record_size)
- /* Will not fit, make it non resident. */
- attr_rec_size = offsetof(ATTR_RECORD,
- non_resident_end) + ((name_len *
- sizeof(ntfschar) + 7) & ~7) + 8;
- }
+ /*
+ * If we have enough free space for the new attribute in the base MFT
+ * record, then add attribute to it.
+ */
if (le32_to_cpu(ni->mrec->bytes_allocated) -
le32_to_cpu(ni->mrec->bytes_in_use) >= attr_rec_size) {
attr_ni = ni;
@@ -2999,7 +3046,7 @@ ntfs_attr *ntfs_attr_add(ntfs_inode *ni,
__FUNCTION__);
goto err_out;
}
- return ntfs_attr_add(ni, type, name, name_len, size);
+ return ntfs_attr_add(ni, type, name, name_len, val, size);
}
/* Allocate new extent. */
attr_ni = ntfs_mft_record_alloc(ni->vol, ni);
@@ -3011,29 +3058,33 @@ ntfs_attr *ntfs_attr_add(ntfs_inode *ni,
}
add_attr_record:
- if (attr_rec_size == offsetof(ATTR_RECORD, resident_end) +
- ((name_len * sizeof(ntfschar) + 7) & ~7)) {
+ if (is_resident) {
/* Add resident attribute. */
offset = ntfs_resident_attr_record_add(attr_ni, type, name,
- name_len, 0);
+ name_len, val, size, 0);
if (offset < 0) {
err = errno;
Dprintf("%s(): Failed to add resident attribute.\n",
__FUNCTION__);
goto free_err_out;
}
- } else {
- /* Add non resident attribute. */
- offset = ntfs_non_resident_attr_record_add(attr_ni, type, name,
+ return 0;
+ }
+
+ /* Add non resident attribute. */
+ offset = ntfs_non_resident_attr_record_add(attr_ni, type, name,
name_len, 0, 8, 0);
- if (offset < 0) {
- err = errno;
- Dprintf("%s(): Failed to add non resident attribute.\n",
- __FUNCTION__);
- goto free_err_out;
- }
+ if (offset < 0) {
+ err = errno;
+ Dprintf("%s(): Failed to add non resident attribute.\n",
+ __FUNCTION__);
+ goto free_err_out;
}
+ /* If @size == 0, we are done. */
+ if (!size)
+ return 0;
+
/* Open new attribute and resize it. */
na = ntfs_attr_open(ni, type, name, name_len);
if (!na) {
@@ -3042,21 +3093,23 @@ add_attr_record:
__FUNCTION__);
goto rm_attr_err_out;
}
- if (!size)
- return na;
- if (ntfs_attr_truncate(na, size)) {
+ /* Resize and set attribute value. */
+ if (ntfs_attr_truncate(na, size) ||
+ (val && (ntfs_attr_pwrite(na, 0, size, val) != size))) {
err = errno;
- Dprintf("%s(): Failed to resize just added attribute.\n",
+ Dprintf("%s(): Failed to initialize just added attribute.\n",
__FUNCTION__);
if (ntfs_attr_rm(na)) {
Dprintf("%s(): Failed to remove just added attribute. "
"Probably leaving inconstant metadata.\n",
__FUNCTION__);
+ ntfs_attr_close(na);
}
goto err_out;
}
+ ntfs_attr_close(na);
/* Done !*/
- return na;
+ return 0;
rm_attr_err_out:
/* Remove just added attribute. */
@@ -3076,7 +3129,7 @@ free_err_out:
}
err_out:
errno = err;
- return NULL;
+ return -1;
}
/**
Index: dir.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/dir.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -p -r1.22 -r1.23
--- dir.c 22 Aug 2005 21:33:07 -0000 1.22
+++ dir.c 16 Sep 2005 14:28:18 -0000 1.23
@@ -1076,7 +1076,6 @@ ntfs_inode *ntfs_create(ntfs_inode *dir_
const unsigned type)
{
ntfs_inode *ni;
- ntfs_attr *na;
FILE_NAME_ATTR *fn = NULL;
STANDARD_INFORMATION *si = NULL;
int err, fn_len, si_len;
@@ -1110,20 +1109,12 @@ ntfs_inode *ntfs_create(ntfs_inode *dir_
si->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
si->last_access_time = utc2ntfs(ni->last_access_time);
/* Add STANDARD_INFORMATION to inode. */
- na = ntfs_attr_add(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, si_len);
- if (!na) {
+ if (ntfs_attr_add(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0,
+ (u8*)si, si_len)) {
err = errno;
ntfs_error(, "Failed to add STANDARD_INFORMATION attribute.");
goto err_out;
}
- if (ntfs_attr_pwrite(na, 0, si_len, si) != si_len) {
- err = errno;
- ntfs_attr_close(na);
- ntfs_error(, "Failed to initialize STANDARD_INFORMATION "
- "attribute.");
- goto err_out;
- }
- ntfs_attr_close(na);
if (type == NTFS_DT_DIR) {
INDEX_ROOT *ir = NULL;
INDEX_ENTRY *ie;
@@ -1156,30 +1147,19 @@ ntfs_inode *ntfs_create(ntfs_inode *dir_
ie->key_length = 0;
ie->flags = INDEX_ENTRY_END;
/* Add INDEX_ROOT attribute to inode. */
- na = ntfs_attr_add(ni, AT_INDEX_ROOT, I30, 4, ir_len);
- if (!na) {
+ if (ntfs_attr_add(ni, AT_INDEX_ROOT, I30, 4, (u8*)ir, ir_len)) {
err = errno;
free(ir);
ntfs_error(, "Failed to add INDEX_ROOT attribute.");
goto err_out;
}
- if (ntfs_attr_pwrite(na, 0, ir_len, ir) != ir_len) {
- err = errno;
- free(ir);
- ntfs_attr_close(na);
- ntfs_error(, "Failed to initialize INDEX_ROOT.");
- goto err_out;
- }
- ntfs_attr_close(na);
} else {
/* Add DATA attribute to inode. */
- na = ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, 0);
- if (!na) {
+ if (ntfs_attr_add(ni, AT_DATA, AT_UNNAMED, 0, NULL, 0)) {
err = errno;
ntfs_error(, "Failed to add DATA attribute.");
goto err_out;
}
- ntfs_attr_close(na);
}
/* Create FILE_NAME attribute. */
fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar);
@@ -1201,19 +1181,11 @@ ntfs_inode *ntfs_create(ntfs_inode *dir_
fn->last_access_time = utc2ntfs(ni->last_access_time);
memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
/* Add FILE_NAME attribute to inode. */
- na = ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, fn_len);
- if (!na) {
+ if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) {
err = errno;
ntfs_error(, "Failed to add FILE_NAME attribute.");
goto err_out;
}
- if (ntfs_attr_pwrite(na, 0, fn_len, fn) != fn_len) {
- err = errno;
- ntfs_attr_close(na);
- ntfs_error(, "Failed to initialize FILE_NAME attribute.");
- goto err_out;
- }
- ntfs_attr_close(na);
/* Add FILE_NAME attribute to index. */
if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,
le16_to_cpu(ni->mrec->sequence_number)))) {
Index: inode.c
===================================================================
RCS file: /cvsroot/linux-ntfs/ntfsprogs/libntfs/inode.c,v
retrieving revision 1.65
retrieving revision 1.66
diff -u -p -r1.65 -r1.66
--- inode.c 14 Aug 2005 15:44:47 -0000 1.65
+++ inode.c 16 Sep 2005 14:28:18 -0000 1.66
@@ -866,7 +866,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *
/* Add $ATTRIBUTE_LIST to mft record. */
if (ntfs_resident_attr_record_add(ni,
- AT_ATTRIBUTE_LIST, NULL, 0, 0) < 0) {
+ AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
err = errno;
Dprintf("%s(): Couldn't add $ATTRIBUTE_LIST to MFT record.\n",
__FUNCTION__);
|