2 * attrlist.c - Attribute list attribute handling code. Originated from the Linux-NTFS
5 * Copyright (c) 2004-2005 Anton Altaparmakov
6 * Copyright (c) 2004-2005 Yura Pakhuchiy
7 * Copyright (c) 2006 Szabolcs Szakacsits
9 * This program/include file is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program/include file is distributed in the hope that it will be
15 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (in the main directory of the NTFS-3G
21 * distribution in the file COPYING); if not, write to the Free Software
22 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
49 * ntfs_attrlist_need - check whether inode need attribute list
50 * @ni: opened ntfs inode for which perform check
52 * Check whether all are attributes belong to one MFT record, in that case
53 * attribute list is not needed.
55 * Return 1 if inode need attribute list, 0 if not, -1 on error with errno set
56 * to the error code. If function succeed errno set to 0. The following error
58 * EINVAL - Invalid arguments passed to function or attribute haven't got
61 int ntfs_attrlist_need(ntfs_inode
*ni
)
66 ntfs_log_trace("Invalid arguments.\n");
71 ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni
->mft_no
);
73 if (!NInoAttrList(ni
)) {
74 ntfs_log_trace("Inode haven't got attribute list.\n");
80 ntfs_log_trace("Corrupt in-memory struct.\n");
86 ale
= (ATTR_LIST_ENTRY
*)ni
->attr_list
;
87 while ((u8
*)ale
< ni
->attr_list
+ ni
->attr_list_size
) {
88 if (MREF_LE(ale
->mft_reference
) != ni
->mft_no
)
90 ale
= (ATTR_LIST_ENTRY
*)((u8
*)ale
+ le16_to_cpu(ale
->length
));
96 * ntfs_attrlist_entry_add - add an attribute list attribute entry
97 * @ni: opened ntfs inode, which contains that attribute
98 * @attr: attribute record to add to attribute list
100 * Return 0 on success and -1 on error with errno set to the error code. The
101 * following error codes are defined:
102 * EINVAL - Invalid arguments passed to function.
103 * ENOMEM - Not enough memory to allocate necessary buffers.
104 * EIO - I/O error occurred or damaged filesystem.
105 * EEXIST - Such attribute already present in attribute list.
107 int ntfs_attrlist_entry_add(ntfs_inode
*ni
, ATTR_RECORD
*attr
)
109 ATTR_LIST_ENTRY
*ale
;
111 ntfs_attr
*na
= NULL
;
112 ntfs_attr_search_ctx
*ctx
;
114 int entry_len
, entry_offset
, err
;
116 ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
117 (long long) ni
->mft_no
,
118 (unsigned) le32_to_cpu(attr
->type
));
121 ntfs_log_trace("Invalid arguments.\n");
126 mref
= MK_LE_MREF(ni
->mft_no
, le16_to_cpu(ni
->mrec
->sequence_number
));
128 if (ni
->nr_extents
== -1)
131 if (!NInoAttrList(ni
)) {
132 ntfs_log_trace("Attribute list isn't present.\n");
137 /* Determine size and allocate memory for new attribute list. */
138 entry_len
= (sizeof(ATTR_LIST_ENTRY
) + sizeof(ntfschar
) *
139 attr
->name_length
+ 7) & ~7;
140 new_al
= ntfs_calloc(ni
->attr_list_size
+ entry_len
);
144 /* Find place for the new entry. */
145 ctx
= ntfs_attr_get_search_ctx(ni
, NULL
);
150 if (!ntfs_attr_lookup(attr
->type
, (attr
->name_length
) ? (ntfschar
*)
151 ((u8
*)attr
+ le16_to_cpu(attr
->name_offset
)) :
152 AT_UNNAMED
, attr
->name_length
, CASE_SENSITIVE
,
153 (attr
->non_resident
) ? le64_to_cpu(attr
->lowest_vcn
) :
154 0, (attr
->non_resident
) ? NULL
: ((u8
*)attr
+
155 le16_to_cpu(attr
->value_offset
)), (attr
->non_resident
) ?
156 0 : le32_to_cpu(attr
->value_length
), ctx
)) {
157 /* Found some extent, check it to be before new extent. */
158 if (ctx
->al_entry
->lowest_vcn
== attr
->lowest_vcn
) {
160 ntfs_log_trace("Such attribute already present in the "
161 "attribute list.\n");
162 ntfs_attr_put_search_ctx(ctx
);
165 /* Add new entry after this extent. */
166 ale
= (ATTR_LIST_ENTRY
*)((u8
*)ctx
->al_entry
+
167 le16_to_cpu(ctx
->al_entry
->length
));
169 /* Check for real errors. */
170 if (errno
!= ENOENT
) {
172 ntfs_log_trace("Attribute lookup failed.\n");
173 ntfs_attr_put_search_ctx(ctx
);
176 /* No previous extents found. */
179 /* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
180 ntfs_attr_put_search_ctx(ctx
);
182 /* Determine new entry offset. */
183 entry_offset
= ((u8
*)ale
- ni
->attr_list
);
184 /* Set pointer to new entry. */
185 ale
= (ATTR_LIST_ENTRY
*)(new_al
+ entry_offset
);
186 /* Zero it to fix valgrind warning. */
187 memset(ale
, 0, entry_len
);
188 /* Form new entry. */
189 ale
->type
= attr
->type
;
190 ale
->length
= cpu_to_le16(entry_len
);
191 ale
->name_length
= attr
->name_length
;
192 ale
->name_offset
= offsetof(ATTR_LIST_ENTRY
, name
);
193 if (attr
->non_resident
)
194 ale
->lowest_vcn
= attr
->lowest_vcn
;
197 ale
->mft_reference
= mref
;
198 ale
->instance
= attr
->instance
;
199 memcpy(ale
->name
, (u8
*)attr
+ le16_to_cpu(attr
->name_offset
),
200 attr
->name_length
* sizeof(ntfschar
));
202 /* Resize $ATTRIBUTE_LIST to new length. */
203 na
= ntfs_attr_open(ni
, AT_ATTRIBUTE_LIST
, AT_UNNAMED
, 0);
206 ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
209 if (ntfs_attr_truncate(na
, ni
->attr_list_size
+ entry_len
)) {
211 ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
215 /* Copy entries from old attribute list to new. */
216 memcpy(new_al
, ni
->attr_list
, entry_offset
);
217 memcpy(new_al
+ entry_offset
+ entry_len
, ni
->attr_list
+
218 entry_offset
, ni
->attr_list_size
- entry_offset
);
220 /* Set new runlist. */
222 ni
->attr_list
= new_al
;
223 ni
->attr_list_size
= ni
->attr_list_size
+ entry_len
;
224 NInoAttrListSetDirty(ni
);
237 * ntfs_attrlist_entry_rm - remove an attribute list attribute entry
238 * @ctx: attribute search context describing the attribute list entry
240 * Remove the attribute list entry @ctx->al_entry from the attribute list.
242 * Return 0 on success and -1 on error with errno set to the error code.
244 int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx
*ctx
)
250 ATTR_LIST_ENTRY
*ale
;
253 if (!ctx
|| !ctx
->ntfs_ino
|| !ctx
->al_entry
) {
254 ntfs_log_trace("Invalid arguments.\n");
259 if (ctx
->base_ntfs_ino
)
260 base_ni
= ctx
->base_ntfs_ino
;
262 base_ni
= ctx
->ntfs_ino
;
265 ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
266 (long long) ctx
->ntfs_ino
->mft_no
,
267 (unsigned) le32_to_cpu(ctx
->al_entry
->type
),
268 (long long) le64_to_cpu(ctx
->al_entry
->lowest_vcn
));
270 if (!NInoAttrList(base_ni
)) {
271 ntfs_log_trace("Attribute list isn't present.\n");
276 /* Allocate memory for new attribute list. */
277 new_al_len
= base_ni
->attr_list_size
- le16_to_cpu(ale
->length
);
278 new_al
= ntfs_calloc(new_al_len
);
282 /* Reisze $ATTRIBUTE_LIST to new length. */
283 na
= ntfs_attr_open(base_ni
, AT_ATTRIBUTE_LIST
, AT_UNNAMED
, 0);
286 ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
289 if (ntfs_attr_truncate(na
, new_al_len
)) {
291 ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
295 /* Copy entries from old attribute list to new. */
296 memcpy(new_al
, base_ni
->attr_list
, (u8
*)ale
- base_ni
->attr_list
);
297 memcpy(new_al
+ ((u8
*)ale
- base_ni
->attr_list
), (u8
*)ale
+ le16_to_cpu(
298 ale
->length
), new_al_len
- ((u8
*)ale
- base_ni
->attr_list
));
300 /* Set new runlist. */
301 free(base_ni
->attr_list
);
302 base_ni
->attr_list
= new_al
;
303 base_ni
->attr_list_size
= new_al_len
;
304 NInoAttrListSetDirty(base_ni
);