1 /** 2 * attrlist.c - Attribute list attribute handling code. Originated from the Linux-NTFS 3 * project. 4 * 5 * Copyright (c) 2004-2005 Anton Altaparmakov 6 * Copyright (c) 2004-2005 Yura Pakhuchiy 7 * Copyright (c) 2006 Szabolcs Szakacsits 8 * 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. 13 * 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. 18 * 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 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 #include "config.h" 27 #endif 28 29 #ifdef HAVE_STRING_H 30 #include <string.h> 31 #endif 32 #ifdef HAVE_STDLIB_H 33 #include <stdlib.h> 34 #endif 35 #ifdef HAVE_ERRNO_H 36 #include <errno.h> 37 #endif 38 39 #include "types.h" 40 #include "layout.h" 41 #include "attrib.h" 42 #include "attrlist.h" 43 #include "debug.h" 44 #include "unistr.h" 45 #include "logging.h" 46 #include "misc.h" 47 48 /** 49 * ntfs_attrlist_need - check whether inode need attribute list 50 * @ni: opened ntfs inode for which perform check 51 * 52 * Check whether all are attributes belong to one MFT record, in that case 53 * attribute list is not needed. 54 * 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 57 * codes are defined: 58 * EINVAL - Invalid arguments passed to function or attribute haven't got 59 * attribute list. 60 */ 61 int ntfs_attrlist_need(ntfs_inode *ni) 62 { 63 ATTR_LIST_ENTRY *ale; 64 65 if (!ni) { 66 ntfs_log_trace("Invalid arguments.\n"); 67 errno = EINVAL; 68 return -1; 69 } 70 71 ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); 72 73 if (!NInoAttrList(ni)) { 74 ntfs_log_trace("Inode haven't got attribute list.\n"); 75 errno = EINVAL; 76 return -1; 77 } 78 79 if (!ni->attr_list) { 80 ntfs_log_trace("Corrupt in-memory struct.\n"); 81 errno = EINVAL; 82 return -1; 83 } 84 85 errno = 0; 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) 89 return 1; 90 ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length)); 91 } 92 return 0; 93 } 94 95 /** 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 99 * 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. 106 */ 107 int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr) 108 { 109 ATTR_LIST_ENTRY *ale; 110 leMFT_REF mref; 111 ntfs_attr *na = NULL; 112 ntfs_attr_search_ctx *ctx; 113 u8 *new_al; 114 int entry_len, entry_offset, err; 115 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)); 119 120 if (!ni || !attr) { 121 ntfs_log_trace("Invalid arguments.\n"); 122 errno = EINVAL; 123 return -1; 124 } 125 126 mref = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)); 127 128 if (ni->nr_extents == -1) 129 ni = ni->base_ni; 130 131 if (!NInoAttrList(ni)) { 132 ntfs_log_trace("Attribute list isn't present.\n"); 133 errno = ENOENT; 134 return -1; 135 } 136 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); 141 if (!new_al) 142 return -1; 143 144 /* Find place for the new entry. */ 145 ctx = ntfs_attr_get_search_ctx(ni, NULL); 146 if (!ctx) { 147 err = errno; 148 goto err_out; 149 } 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) ? sle64_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) { 159 err = EEXIST; 160 ntfs_log_trace("Such attribute already present in the " 161 "attribute list.\n"); 162 ntfs_attr_put_search_ctx(ctx); 163 goto err_out; 164 } 165 /* Add new entry after this extent. */ 166 ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry + 167 le16_to_cpu(ctx->al_entry->length)); 168 } else { 169 /* Check for real errors. */ 170 if (errno != ENOENT) { 171 err = errno; 172 ntfs_log_trace("Attribute lookup failed.\n"); 173 ntfs_attr_put_search_ctx(ctx); 174 goto err_out; 175 } 176 /* No previous extents found. */ 177 ale = ctx->al_entry; 178 } 179 /* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */ 180 ntfs_attr_put_search_ctx(ctx); 181 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; 195 else 196 ale->lowest_vcn = const_cpu_to_sle64(0); 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)); 201 202 /* Resize $ATTRIBUTE_LIST to new length. */ 203 na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); 204 if (!na) { 205 err = errno; 206 ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n"); 207 goto err_out; 208 } 209 if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) { 210 err = errno; 211 ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n"); 212 goto err_out; 213 } 214 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); 219 220 /* Set new runlist. */ 221 free(ni->attr_list); 222 ni->attr_list = new_al; 223 ni->attr_list_size = ni->attr_list_size + entry_len; 224 NInoAttrListSetDirty(ni); 225 /* Done! */ 226 ntfs_attr_close(na); 227 return 0; 228 err_out: 229 if (na) 230 ntfs_attr_close(na); 231 free(new_al); 232 errno = err; 233 return -1; 234 } 235 236 /** 237 * ntfs_attrlist_entry_rm - remove an attribute list attribute entry 238 * @ctx: attribute search context describing the attribute list entry 239 * 240 * Remove the attribute list entry @ctx->al_entry from the attribute list. 241 * 242 * Return 0 on success and -1 on error with errno set to the error code. 243 */ 244 int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx) 245 { 246 u8 *new_al; 247 int new_al_len; 248 ntfs_inode *base_ni; 249 ntfs_attr *na; 250 ATTR_LIST_ENTRY *ale; 251 int err; 252 253 if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) { 254 ntfs_log_trace("Invalid arguments.\n"); 255 errno = EINVAL; 256 return -1; 257 } 258 259 if (ctx->base_ntfs_ino) 260 base_ni = ctx->base_ntfs_ino; 261 else 262 base_ni = ctx->ntfs_ino; 263 ale = ctx->al_entry; 264 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) sle64_to_cpu(ctx->al_entry->lowest_vcn)); 269 270 if (!NInoAttrList(base_ni)) { 271 ntfs_log_trace("Attribute list isn't present.\n"); 272 errno = ENOENT; 273 return -1; 274 } 275 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); 279 if (!new_al) 280 return -1; 281 282 /* Reisze $ATTRIBUTE_LIST to new length. */ 283 na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); 284 if (!na) { 285 err = errno; 286 ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n"); 287 goto err_out; 288 } 289 if (ntfs_attr_truncate(na, new_al_len)) { 290 err = errno; 291 ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n"); 292 goto err_out; 293 } 294 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)); 299 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); 305 /* Done! */ 306 ntfs_attr_close(na); 307 return 0; 308 err_out: 309 if (na) 310 ntfs_attr_close(na); 311 free(new_al); 312 errno = err; 313 return -1; 314 } 315