Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1 | /** |
| 2 | * attrib.c - Attribute handling code. Originated from the Linux-NTFS project. |
| 3 | * |
| 4 | * Copyright (c) 2000-2010 Anton Altaparmakov |
| 5 | * Copyright (c) 2002-2005 Richard Russon |
| 6 | * Copyright (c) 2002-2008 Szabolcs Szakacsits |
| 7 | * Copyright (c) 2004-2007 Yura Pakhuchiy |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 8 | * Copyright (c) 2007-2015 Jean-Pierre Andre |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 9 | * Copyright (c) 2010 Erik Larsson |
| 10 | * |
| 11 | * This program/include file is free software; you can redistribute it and/or |
| 12 | * modify it under the terms of the GNU General Public License as published |
| 13 | * by the Free Software Foundation; either version 2 of the License, or |
| 14 | * (at your option) any later version. |
| 15 | * |
| 16 | * This program/include file is distributed in the hope that it will be |
| 17 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
| 18 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | * GNU General Public License for more details. |
| 20 | * |
| 21 | * You should have received a copy of the GNU General Public License |
| 22 | * along with this program (in the main directory of the NTFS-3G |
| 23 | * distribution in the file COPYING); if not, write to the Free Software |
| 24 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 25 | */ |
| 26 | |
| 27 | #ifdef HAVE_CONFIG_H |
| 28 | #include "config.h" |
| 29 | #endif |
| 30 | |
| 31 | #ifdef HAVE_STDIO_H |
| 32 | #include <stdio.h> |
| 33 | #endif |
| 34 | #ifdef HAVE_STRING_H |
| 35 | #include <string.h> |
| 36 | #endif |
| 37 | #ifdef HAVE_STDLIB_H |
| 38 | #include <stdlib.h> |
| 39 | #endif |
| 40 | #ifdef HAVE_ERRNO_H |
| 41 | #include <errno.h> |
| 42 | #endif |
| 43 | #ifdef HAVE_LIMITS_H |
| 44 | #include <limits.h> |
| 45 | #endif |
| 46 | |
| 47 | #include "param.h" |
| 48 | #include "compat.h" |
| 49 | #include "attrib.h" |
| 50 | #include "attrlist.h" |
| 51 | #include "device.h" |
| 52 | #include "mft.h" |
| 53 | #include "debug.h" |
| 54 | #include "mst.h" |
| 55 | #include "volume.h" |
| 56 | #include "types.h" |
| 57 | #include "layout.h" |
| 58 | #include "inode.h" |
| 59 | #include "runlist.h" |
| 60 | #include "lcnalloc.h" |
| 61 | #include "dir.h" |
| 62 | #include "compress.h" |
| 63 | #include "bitmap.h" |
| 64 | #include "logging.h" |
| 65 | #include "misc.h" |
| 66 | #include "efs.h" |
| 67 | |
| 68 | ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') }; |
| 69 | ntfschar STREAM_SDS[] = { const_cpu_to_le16('$'), |
| 70 | const_cpu_to_le16('S'), |
| 71 | const_cpu_to_le16('D'), |
| 72 | const_cpu_to_le16('S'), |
| 73 | const_cpu_to_le16('\0') }; |
| 74 | |
| 75 | ntfschar TXF_DATA[] = { const_cpu_to_le16('$'), |
| 76 | const_cpu_to_le16('T'), |
| 77 | const_cpu_to_le16('X'), |
| 78 | const_cpu_to_le16('F'), |
| 79 | const_cpu_to_le16('_'), |
| 80 | const_cpu_to_le16('D'), |
| 81 | const_cpu_to_le16('A'), |
| 82 | const_cpu_to_le16('T'), |
| 83 | const_cpu_to_le16('A'), |
| 84 | const_cpu_to_le16('\0') }; |
| 85 | |
| 86 | static int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) |
| 87 | { |
| 88 | if (na->type == AT_DATA && na->name == AT_UNNAMED) |
| 89 | return (na->ni->flags & flag); |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | static void NAttrSetFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) |
| 94 | { |
| 95 | if (na->type == AT_DATA && na->name == AT_UNNAMED) |
| 96 | na->ni->flags |= flag; |
| 97 | else |
| 98 | ntfs_log_trace("Denied setting flag %d for not unnamed data " |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 99 | "attribute\n", le32_to_cpu(flag)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | static void NAttrClearFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) |
| 103 | { |
| 104 | if (na->type == AT_DATA && na->name == AT_UNNAMED) |
| 105 | na->ni->flags &= ~flag; |
| 106 | } |
| 107 | |
| 108 | #define GenNAttrIno(func_name, flag) \ |
| 109 | int NAttr##func_name(ntfs_attr *na) { return NAttrFlag (na, flag); } \ |
| 110 | void NAttrSet##func_name(ntfs_attr *na) { NAttrSetFlag (na, flag); } \ |
| 111 | void NAttrClear##func_name(ntfs_attr *na){ NAttrClearFlag(na, flag); } |
| 112 | |
| 113 | GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED) |
| 114 | GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED) |
| 115 | GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE) |
| 116 | |
| 117 | /** |
| 118 | * ntfs_get_attribute_value_length - Find the length of an attribute |
| 119 | * @a: |
| 120 | * |
| 121 | * Description... |
| 122 | * |
| 123 | * Returns: |
| 124 | */ |
| 125 | s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a) |
| 126 | { |
| 127 | if (!a) { |
| 128 | errno = EINVAL; |
| 129 | return 0; |
| 130 | } |
| 131 | errno = 0; |
| 132 | if (a->non_resident) |
| 133 | return sle64_to_cpu(a->data_size); |
| 134 | |
| 135 | return (s64)le32_to_cpu(a->value_length); |
| 136 | } |
| 137 | |
| 138 | /** |
| 139 | * ntfs_get_attribute_value - Get a copy of an attribute |
| 140 | * @vol: |
| 141 | * @a: |
| 142 | * @b: |
| 143 | * |
| 144 | * Description... |
| 145 | * |
| 146 | * Returns: |
| 147 | */ |
| 148 | s64 ntfs_get_attribute_value(const ntfs_volume *vol, |
| 149 | const ATTR_RECORD *a, u8 *b) |
| 150 | { |
| 151 | runlist *rl; |
| 152 | s64 total, r; |
| 153 | int i; |
| 154 | |
| 155 | /* Sanity checks. */ |
| 156 | if (!vol || !a || !b) { |
| 157 | errno = EINVAL; |
| 158 | return 0; |
| 159 | } |
| 160 | /* Complex attribute? */ |
| 161 | /* |
| 162 | * Ignore the flags in case they are not zero for an attribute list |
| 163 | * attribute. Windows does not complain about invalid flags and chkdsk |
| 164 | * does not detect or fix them so we need to cope with it, too. |
| 165 | */ |
| 166 | if (a->type != AT_ATTRIBUTE_LIST && a->flags) { |
| 167 | ntfs_log_error("Non-zero (%04x) attribute flags. Cannot handle " |
| 168 | "this yet.\n", le16_to_cpu(a->flags)); |
| 169 | errno = EOPNOTSUPP; |
| 170 | return 0; |
| 171 | } |
| 172 | if (!a->non_resident) { |
| 173 | /* Attribute is resident. */ |
| 174 | |
| 175 | /* Sanity check. */ |
| 176 | if (le32_to_cpu(a->value_length) + le16_to_cpu(a->value_offset) |
| 177 | > le32_to_cpu(a->length)) { |
| 178 | return 0; |
| 179 | } |
| 180 | |
| 181 | memcpy(b, (const char*)a + le16_to_cpu(a->value_offset), |
| 182 | le32_to_cpu(a->value_length)); |
| 183 | errno = 0; |
| 184 | return (s64)le32_to_cpu(a->value_length); |
| 185 | } |
| 186 | |
| 187 | /* Attribute is not resident. */ |
| 188 | |
| 189 | /* If no data, return 0. */ |
| 190 | if (!(a->data_size)) { |
| 191 | errno = 0; |
| 192 | return 0; |
| 193 | } |
| 194 | /* |
| 195 | * FIXME: What about attribute lists?!? (AIA) |
| 196 | */ |
| 197 | /* Decompress the mapping pairs array into a runlist. */ |
| 198 | rl = ntfs_mapping_pairs_decompress(vol, a, NULL); |
| 199 | if (!rl) { |
| 200 | errno = EINVAL; |
| 201 | return 0; |
| 202 | } |
| 203 | /* |
| 204 | * FIXED: We were overflowing here in a nasty fashion when we |
| 205 | * reach the last cluster in the runlist as the buffer will |
| 206 | * only be big enough to hold data_size bytes while we are |
| 207 | * reading in allocated_size bytes which is usually larger |
| 208 | * than data_size, since the actual data is unlikely to have a |
| 209 | * size equal to a multiple of the cluster size! |
| 210 | * FIXED2: We were also overflowing here in the same fashion |
| 211 | * when the data_size was more than one run smaller than the |
| 212 | * allocated size which happens with Windows XP sometimes. |
| 213 | */ |
| 214 | /* Now load all clusters in the runlist into b. */ |
| 215 | for (i = 0, total = 0; rl[i].length; i++) { |
| 216 | if (total + (rl[i].length << vol->cluster_size_bits) >= |
| 217 | sle64_to_cpu(a->data_size)) { |
| 218 | unsigned char *intbuf = NULL; |
| 219 | /* |
| 220 | * We have reached the last run so we were going to |
| 221 | * overflow when executing the ntfs_pread() which is |
| 222 | * BAAAAAAAD! |
| 223 | * Temporary fix: |
| 224 | * Allocate a new buffer with size: |
| 225 | * rl[i].length << vol->cluster_size_bits, do the |
| 226 | * read into our buffer, then memcpy the correct |
| 227 | * amount of data into the caller supplied buffer, |
| 228 | * free our buffer, and continue. |
| 229 | * We have reached the end of data size so we were |
| 230 | * going to overflow in the same fashion. |
| 231 | * Temporary fix: same as above. |
| 232 | */ |
| 233 | intbuf = ntfs_malloc(rl[i].length << vol->cluster_size_bits); |
| 234 | if (!intbuf) { |
| 235 | free(rl); |
| 236 | return 0; |
| 237 | } |
| 238 | /* |
| 239 | * FIXME: If compressed file: Only read if lcn != -1. |
| 240 | * Otherwise, we are dealing with a sparse run and we |
| 241 | * just memset the user buffer to 0 for the length of |
| 242 | * the run, which should be 16 (= compression unit |
| 243 | * size). |
| 244 | * FIXME: Really only when file is compressed, or can |
| 245 | * we have sparse runs in uncompressed files as well? |
| 246 | * - Yes we can, in sparse files! But not necessarily |
| 247 | * size of 16, just run length. |
| 248 | */ |
| 249 | r = ntfs_pread(vol->dev, rl[i].lcn << |
| 250 | vol->cluster_size_bits, rl[i].length << |
| 251 | vol->cluster_size_bits, intbuf); |
| 252 | if (r != rl[i].length << vol->cluster_size_bits) { |
| 253 | #define ESTR "Error reading attribute value" |
| 254 | if (r == -1) |
| 255 | ntfs_log_perror(ESTR); |
| 256 | else if (r < rl[i].length << |
| 257 | vol->cluster_size_bits) { |
| 258 | ntfs_log_debug(ESTR ": Ran out of input data.\n"); |
| 259 | errno = EIO; |
| 260 | } else { |
| 261 | ntfs_log_debug(ESTR ": unknown error\n"); |
| 262 | errno = EIO; |
| 263 | } |
| 264 | #undef ESTR |
| 265 | free(rl); |
| 266 | free(intbuf); |
| 267 | return 0; |
| 268 | } |
| 269 | memcpy(b + total, intbuf, sle64_to_cpu(a->data_size) - |
| 270 | total); |
| 271 | free(intbuf); |
| 272 | total = sle64_to_cpu(a->data_size); |
| 273 | break; |
| 274 | } |
| 275 | /* |
| 276 | * FIXME: If compressed file: Only read if lcn != -1. |
| 277 | * Otherwise, we are dealing with a sparse run and we just |
| 278 | * memset the user buffer to 0 for the length of the run, which |
| 279 | * should be 16 (= compression unit size). |
| 280 | * FIXME: Really only when file is compressed, or can |
| 281 | * we have sparse runs in uncompressed files as well? |
| 282 | * - Yes we can, in sparse files! But not necessarily size of |
| 283 | * 16, just run length. |
| 284 | */ |
| 285 | r = ntfs_pread(vol->dev, rl[i].lcn << vol->cluster_size_bits, |
| 286 | rl[i].length << vol->cluster_size_bits, |
| 287 | b + total); |
| 288 | if (r != rl[i].length << vol->cluster_size_bits) { |
| 289 | #define ESTR "Error reading attribute value" |
| 290 | if (r == -1) |
| 291 | ntfs_log_perror(ESTR); |
| 292 | else if (r < rl[i].length << vol->cluster_size_bits) { |
| 293 | ntfs_log_debug(ESTR ": Ran out of input data.\n"); |
| 294 | errno = EIO; |
| 295 | } else { |
| 296 | ntfs_log_debug(ESTR ": unknown error\n"); |
| 297 | errno = EIO; |
| 298 | } |
| 299 | #undef ESTR |
| 300 | free(rl); |
| 301 | return 0; |
| 302 | } |
| 303 | total += r; |
| 304 | } |
| 305 | free(rl); |
| 306 | return total; |
| 307 | } |
| 308 | |
| 309 | /* Already cleaned up code below, but still look for FIXME:... */ |
| 310 | |
| 311 | /** |
| 312 | * __ntfs_attr_init - primary initialization of an ntfs attribute structure |
| 313 | * @na: ntfs attribute to initialize |
| 314 | * @ni: ntfs inode with which to initialize the ntfs attribute |
| 315 | * @type: attribute type |
| 316 | * @name: attribute name in little endian Unicode or NULL |
| 317 | * @name_len: length of attribute @name in Unicode characters (if @name given) |
| 318 | * |
| 319 | * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len. |
| 320 | */ |
| 321 | static void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni, |
| 322 | const ATTR_TYPES type, ntfschar *name, const u32 name_len) |
| 323 | { |
| 324 | na->rl = NULL; |
| 325 | na->ni = ni; |
| 326 | na->type = type; |
| 327 | na->name = name; |
| 328 | if (name) |
| 329 | na->name_len = name_len; |
| 330 | else |
| 331 | na->name_len = 0; |
| 332 | } |
| 333 | |
| 334 | /** |
| 335 | * ntfs_attr_init - initialize an ntfs_attr with data sizes and status |
| 336 | * @na: |
| 337 | * @non_resident: |
| 338 | * @compressed: |
| 339 | * @encrypted: |
| 340 | * @sparse: |
| 341 | * @allocated_size: |
| 342 | * @data_size: |
| 343 | * @initialized_size: |
| 344 | * @compressed_size: |
| 345 | * @compression_unit: |
| 346 | * |
| 347 | * Final initialization for an ntfs attribute. |
| 348 | */ |
| 349 | void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident, |
| 350 | const ATTR_FLAGS data_flags, |
| 351 | const BOOL encrypted, const BOOL sparse, |
| 352 | const s64 allocated_size, const s64 data_size, |
| 353 | const s64 initialized_size, const s64 compressed_size, |
| 354 | const u8 compression_unit) |
| 355 | { |
| 356 | if (!NAttrInitialized(na)) { |
| 357 | na->data_flags = data_flags; |
| 358 | if (non_resident) |
| 359 | NAttrSetNonResident(na); |
| 360 | if (data_flags & ATTR_COMPRESSION_MASK) |
| 361 | NAttrSetCompressed(na); |
| 362 | if (encrypted) |
| 363 | NAttrSetEncrypted(na); |
| 364 | if (sparse) |
| 365 | NAttrSetSparse(na); |
| 366 | na->allocated_size = allocated_size; |
| 367 | na->data_size = data_size; |
| 368 | na->initialized_size = initialized_size; |
| 369 | if ((data_flags & ATTR_COMPRESSION_MASK) || sparse) { |
| 370 | ntfs_volume *vol = na->ni->vol; |
| 371 | |
| 372 | na->compressed_size = compressed_size; |
| 373 | na->compression_block_clusters = 1 << compression_unit; |
| 374 | na->compression_block_size = 1 << (compression_unit + |
| 375 | vol->cluster_size_bits); |
| 376 | na->compression_block_size_bits = ffs( |
| 377 | na->compression_block_size) - 1; |
| 378 | } |
| 379 | NAttrSetInitialized(na); |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | /** |
| 384 | * ntfs_attr_open - open an ntfs attribute for access |
| 385 | * @ni: open ntfs inode in which the ntfs attribute resides |
| 386 | * @type: attribute type |
| 387 | * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL |
| 388 | * @name_len: length of attribute @name in Unicode characters (if @name given) |
| 389 | * |
| 390 | * Allocate a new ntfs attribute structure, initialize it with @ni, @type, |
| 391 | * @name, and @name_len, then return it. Return NULL on error with |
| 392 | * errno set to the error code. |
| 393 | * |
| 394 | * If @name is AT_UNNAMED look specifically for an unnamed attribute. If you |
| 395 | * do not care whether the attribute is named or not set @name to NULL. In |
| 396 | * both those cases @name_len is not used at all. |
| 397 | */ |
| 398 | ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, |
| 399 | ntfschar *name, u32 name_len) |
| 400 | { |
| 401 | ntfs_attr_search_ctx *ctx; |
| 402 | ntfs_attr *na = NULL; |
| 403 | ntfschar *newname = NULL; |
| 404 | ATTR_RECORD *a; |
| 405 | le16 cs; |
| 406 | |
| 407 | ntfs_log_enter("Entering for inode %lld, attr 0x%x.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 408 | (unsigned long long)ni->mft_no, le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 409 | |
| 410 | if (!ni || !ni->vol || !ni->mrec) { |
| 411 | errno = EINVAL; |
| 412 | goto out; |
| 413 | } |
| 414 | na = ntfs_calloc(sizeof(ntfs_attr)); |
| 415 | if (!na) |
| 416 | goto out; |
| 417 | if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) { |
| 418 | name = ntfs_ucsndup(name, name_len); |
| 419 | if (!name) |
| 420 | goto err_out; |
| 421 | newname = name; |
| 422 | } |
| 423 | |
| 424 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 425 | if (!ctx) |
| 426 | goto err_out; |
| 427 | |
| 428 | if (ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx)) |
| 429 | goto put_err_out; |
| 430 | |
| 431 | a = ctx->attr; |
| 432 | |
| 433 | if (!name) { |
| 434 | if (a->name_length) { |
| 435 | name = ntfs_ucsndup((ntfschar*)((u8*)a + le16_to_cpu( |
| 436 | a->name_offset)), a->name_length); |
| 437 | if (!name) |
| 438 | goto put_err_out; |
| 439 | newname = name; |
| 440 | name_len = a->name_length; |
| 441 | } else { |
| 442 | name = AT_UNNAMED; |
| 443 | name_len = 0; |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | __ntfs_attr_init(na, ni, type, name, name_len); |
| 448 | |
| 449 | /* |
| 450 | * Wipe the flags in case they are not zero for an attribute list |
| 451 | * attribute. Windows does not complain about invalid flags and chkdsk |
| 452 | * does not detect or fix them so we need to cope with it, too. |
| 453 | */ |
| 454 | if (type == AT_ATTRIBUTE_LIST) |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 455 | a->flags = const_cpu_to_le16(0); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 456 | |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 457 | if ((type == AT_DATA) |
| 458 | && (a->non_resident ? !a->initialized_size : !a->value_length)) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 459 | /* |
| 460 | * Define/redefine the compression state if stream is |
| 461 | * empty, based on the compression mark on parent |
| 462 | * directory (for unnamed data streams) or on current |
| 463 | * inode (for named data streams). The compression mark |
| 464 | * may change any time, the compression state can only |
| 465 | * change when stream is wiped out. |
| 466 | * |
| 467 | * Also prevent compression on NTFS version < 3.0 |
| 468 | * or cluster size > 4K or compression is disabled |
| 469 | */ |
| 470 | a->flags &= ~ATTR_COMPRESSION_MASK; |
| 471 | if ((ni->flags & FILE_ATTR_COMPRESSED) |
| 472 | && (ni->vol->major_ver >= 3) |
| 473 | && NVolCompression(ni->vol) |
| 474 | && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)) |
| 475 | a->flags |= ATTR_IS_COMPRESSED; |
| 476 | } |
| 477 | |
| 478 | cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); |
| 479 | |
| 480 | /* a file may be sparse though its unnamed data is not (cf $UsnJrnl) */ |
| 481 | if (na->type == AT_DATA && na->name == AT_UNNAMED && |
| 482 | (((a->flags & ATTR_IS_SPARSE) && !NAttrSparse(na)) || |
| 483 | (!(a->flags & ATTR_IS_ENCRYPTED) != !NAttrEncrypted(na)))) { |
| 484 | errno = EIO; |
| 485 | ntfs_log_perror("Inode %lld has corrupt attribute flags " |
| 486 | "(0x%x <> 0x%x)",(unsigned long long)ni->mft_no, |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 487 | le16_to_cpu(a->flags), le32_to_cpu(na->ni->flags)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 488 | goto put_err_out; |
| 489 | } |
| 490 | |
| 491 | if (a->non_resident) { |
| 492 | if ((a->flags & ATTR_COMPRESSION_MASK) |
| 493 | && !a->compression_unit) { |
| 494 | errno = EIO; |
| 495 | ntfs_log_perror("Compressed inode %lld attr 0x%x has " |
| 496 | "no compression unit", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 497 | (unsigned long long)ni->mft_no, le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 498 | goto put_err_out; |
| 499 | } |
| 500 | ntfs_attr_init(na, TRUE, a->flags, |
| 501 | a->flags & ATTR_IS_ENCRYPTED, |
| 502 | a->flags & ATTR_IS_SPARSE, |
| 503 | sle64_to_cpu(a->allocated_size), |
| 504 | sle64_to_cpu(a->data_size), |
| 505 | sle64_to_cpu(a->initialized_size), |
| 506 | cs ? sle64_to_cpu(a->compressed_size) : 0, |
| 507 | cs ? a->compression_unit : 0); |
| 508 | } else { |
| 509 | s64 l = le32_to_cpu(a->value_length); |
| 510 | ntfs_attr_init(na, FALSE, a->flags, |
| 511 | a->flags & ATTR_IS_ENCRYPTED, |
| 512 | a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, |
| 513 | cs ? (l + 7) & ~7 : 0, 0); |
| 514 | } |
| 515 | ntfs_attr_put_search_ctx(ctx); |
| 516 | out: |
| 517 | ntfs_log_leave("\n"); |
| 518 | return na; |
| 519 | |
| 520 | put_err_out: |
| 521 | ntfs_attr_put_search_ctx(ctx); |
| 522 | err_out: |
| 523 | free(newname); |
| 524 | free(na); |
| 525 | na = NULL; |
| 526 | goto out; |
| 527 | } |
| 528 | |
| 529 | /** |
| 530 | * ntfs_attr_close - free an ntfs attribute structure |
| 531 | * @na: ntfs attribute structure to free |
| 532 | * |
| 533 | * Release all memory associated with the ntfs attribute @na and then release |
| 534 | * @na itself. |
| 535 | */ |
| 536 | void ntfs_attr_close(ntfs_attr *na) |
| 537 | { |
| 538 | if (!na) |
| 539 | return; |
| 540 | if (NAttrNonResident(na) && na->rl) |
| 541 | free(na->rl); |
| 542 | /* Don't release if using an internal constant. */ |
| 543 | if (na->name != AT_UNNAMED && na->name != NTFS_INDEX_I30 |
| 544 | && na->name != STREAM_SDS) |
| 545 | free(na->name); |
| 546 | free(na); |
| 547 | } |
| 548 | |
| 549 | /** |
| 550 | * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute |
| 551 | * @na: ntfs attribute for which to map (part of) a runlist |
| 552 | * @vcn: map runlist part containing this vcn |
| 553 | * |
| 554 | * Map the part of a runlist containing the @vcn of the ntfs attribute @na. |
| 555 | * |
| 556 | * Return 0 on success and -1 on error with errno set to the error code. |
| 557 | */ |
| 558 | int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn) |
| 559 | { |
| 560 | LCN lcn; |
| 561 | ntfs_attr_search_ctx *ctx; |
| 562 | |
| 563 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 564 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), (long long)vcn); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 565 | |
| 566 | lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn); |
| 567 | if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT) |
| 568 | return 0; |
| 569 | |
| 570 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 571 | if (!ctx) |
| 572 | return -1; |
| 573 | |
| 574 | /* Find the attribute in the mft record. */ |
| 575 | if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
| 576 | vcn, NULL, 0, ctx)) { |
| 577 | runlist_element *rl; |
| 578 | |
| 579 | /* Decode the runlist. */ |
| 580 | rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr, |
| 581 | na->rl); |
| 582 | if (rl) { |
| 583 | na->rl = rl; |
| 584 | ntfs_attr_put_search_ctx(ctx); |
| 585 | return 0; |
| 586 | } |
| 587 | } |
| 588 | |
| 589 | ntfs_attr_put_search_ctx(ctx); |
| 590 | return -1; |
| 591 | } |
| 592 | |
| 593 | #if PARTIAL_RUNLIST_UPDATING |
| 594 | |
| 595 | /* |
| 596 | * Map the runlist of an attribute from some point to the end |
| 597 | * |
| 598 | * Returns 0 if success, |
| 599 | * -1 if it failed (errno telling why) |
| 600 | */ |
| 601 | |
| 602 | static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn) |
| 603 | { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 604 | VCN last_vcn; |
| 605 | VCN highest_vcn; |
| 606 | VCN needed; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 607 | runlist_element *rl; |
| 608 | ATTR_RECORD *a; |
| 609 | BOOL startseen; |
| 610 | ntfs_attr_search_ctx *ctx; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 611 | BOOL done; |
| 612 | BOOL newrunlist; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 613 | |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 614 | if (NAttrFullyMapped(na)) |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 615 | return 0; |
| 616 | |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 617 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 618 | if (!ctx) |
| 619 | return -1; |
| 620 | |
| 621 | /* Get the last vcn in the attribute. */ |
| 622 | last_vcn = na->allocated_size >> na->ni->vol->cluster_size_bits; |
| 623 | |
| 624 | needed = vcn; |
| 625 | highest_vcn = 0; |
| 626 | startseen = FALSE; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 627 | done = FALSE; |
| 628 | rl = (runlist_element*)NULL; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 629 | do { |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 630 | newrunlist = FALSE; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 631 | /* Find the attribute in the mft record. */ |
| 632 | if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
| 633 | needed, NULL, 0, ctx)) { |
| 634 | |
| 635 | a = ctx->attr; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 636 | /* Decode and merge the runlist. */ |
| 637 | if (ntfs_rl_vcn_to_lcn(na->rl, needed) |
| 638 | == LCN_RL_NOT_MAPPED) { |
| 639 | rl = ntfs_mapping_pairs_decompress(na->ni->vol, |
| 640 | a, na->rl); |
| 641 | newrunlist = TRUE; |
| 642 | } else |
| 643 | rl = na->rl; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 644 | if (rl) { |
| 645 | na->rl = rl; |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 646 | highest_vcn = sle64_to_cpu(a->highest_vcn); |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 647 | if (highest_vcn < needed) { |
| 648 | /* corruption detection on unchanged runlists */ |
| 649 | if (newrunlist |
| 650 | && ((highest_vcn + 1) < last_vcn)) { |
| 651 | ntfs_log_error("Corrupt attribute list\n"); |
| 652 | rl = (runlist_element*)NULL; |
| 653 | errno = EIO; |
| 654 | } |
| 655 | done = TRUE; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 656 | } |
| 657 | needed = highest_vcn + 1; |
| 658 | if (!a->lowest_vcn) |
| 659 | startseen = TRUE; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 660 | } |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 661 | } else { |
| 662 | done = TRUE; |
| 663 | } |
| 664 | } while (rl && !done && (needed < last_vcn)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 665 | ntfs_attr_put_search_ctx(ctx); |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 666 | /* |
| 667 | * Make sure we reached the end, unless the last |
| 668 | * runlist was modified earlier (using HOLES_DELAY |
| 669 | * leads to have a visibility over attributes which |
| 670 | * have not yet been fully updated) |
| 671 | */ |
| 672 | if (done && newrunlist && (needed < last_vcn)) { |
| 673 | ntfs_log_error("End of runlist not reached\n"); |
| 674 | rl = (runlist_element*)NULL; |
| 675 | errno = EIO; |
| 676 | } |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 677 | /* mark fully mapped if we did so */ |
| 678 | if (rl && startseen) |
| 679 | NAttrSetFullyMapped(na); |
| 680 | return (rl ? 0 : -1); |
| 681 | } |
| 682 | |
| 683 | #endif |
| 684 | |
| 685 | /** |
| 686 | * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute |
| 687 | * @na: ntfs attribute for which to map the runlist |
| 688 | * |
| 689 | * Map the whole runlist of the ntfs attribute @na. For an attribute made up |
| 690 | * of only one attribute extent this is the same as calling |
| 691 | * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this |
| 692 | * will map the runlist fragments from each of the extents thus giving access |
| 693 | * to the entirety of the disk allocation of an attribute. |
| 694 | * |
| 695 | * Return 0 on success and -1 on error with errno set to the error code. |
| 696 | */ |
| 697 | int ntfs_attr_map_whole_runlist(ntfs_attr *na) |
| 698 | { |
| 699 | VCN next_vcn, last_vcn, highest_vcn; |
| 700 | ntfs_attr_search_ctx *ctx; |
| 701 | ntfs_volume *vol = na->ni->vol; |
| 702 | ATTR_RECORD *a; |
| 703 | int ret = -1; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 704 | int not_mapped; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 705 | |
| 706 | ntfs_log_enter("Entering for inode %llu, attr 0x%x.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 707 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 708 | |
| 709 | /* avoid multiple full runlist mappings */ |
| 710 | if (NAttrFullyMapped(na)) { |
| 711 | ret = 0; |
| 712 | goto out; |
| 713 | } |
| 714 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 715 | if (!ctx) |
| 716 | goto out; |
| 717 | |
| 718 | /* Map all attribute extents one by one. */ |
| 719 | next_vcn = last_vcn = highest_vcn = 0; |
| 720 | a = NULL; |
| 721 | while (1) { |
| 722 | runlist_element *rl; |
| 723 | |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 724 | not_mapped = 0; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 725 | if (ntfs_rl_vcn_to_lcn(na->rl, next_vcn) == LCN_RL_NOT_MAPPED) |
| 726 | not_mapped = 1; |
| 727 | |
| 728 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, |
| 729 | CASE_SENSITIVE, next_vcn, NULL, 0, ctx)) |
| 730 | break; |
| 731 | |
| 732 | a = ctx->attr; |
| 733 | |
| 734 | if (not_mapped) { |
| 735 | /* Decode the runlist. */ |
| 736 | rl = ntfs_mapping_pairs_decompress(na->ni->vol, |
| 737 | a, na->rl); |
| 738 | if (!rl) |
| 739 | goto err_out; |
| 740 | na->rl = rl; |
| 741 | } |
| 742 | |
| 743 | /* Are we in the first extent? */ |
| 744 | if (!next_vcn) { |
| 745 | if (a->lowest_vcn) { |
| 746 | errno = EIO; |
| 747 | ntfs_log_perror("First extent of inode %llu " |
| 748 | "attribute has non-zero lowest_vcn", |
| 749 | (unsigned long long)na->ni->mft_no); |
| 750 | goto err_out; |
| 751 | } |
| 752 | /* Get the last vcn in the attribute. */ |
| 753 | last_vcn = sle64_to_cpu(a->allocated_size) >> |
| 754 | vol->cluster_size_bits; |
| 755 | } |
| 756 | |
| 757 | /* Get the lowest vcn for the next extent. */ |
| 758 | highest_vcn = sle64_to_cpu(a->highest_vcn); |
| 759 | next_vcn = highest_vcn + 1; |
| 760 | |
| 761 | /* Only one extent or error, which we catch below. */ |
| 762 | if (next_vcn <= 0) { |
| 763 | errno = ENOENT; |
| 764 | break; |
| 765 | } |
| 766 | |
| 767 | /* Avoid endless loops due to corruption. */ |
| 768 | if (next_vcn < sle64_to_cpu(a->lowest_vcn)) { |
| 769 | errno = EIO; |
| 770 | ntfs_log_perror("Inode %llu has corrupt attribute list", |
| 771 | (unsigned long long)na->ni->mft_no); |
| 772 | goto err_out; |
| 773 | } |
| 774 | } |
| 775 | if (!a) { |
| 776 | ntfs_log_perror("Couldn't find attribute for runlist mapping"); |
| 777 | goto err_out; |
| 778 | } |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 779 | /* |
| 780 | * Cannot check highest_vcn when the last runlist has |
| 781 | * been modified earlier, as runlists and sizes may be |
| 782 | * updated without highest_vcn being in sync, when |
| 783 | * HOLES_DELAY is used |
| 784 | */ |
| 785 | if (not_mapped && highest_vcn && highest_vcn != last_vcn - 1) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 786 | errno = EIO; |
| 787 | ntfs_log_perror("Failed to load full runlist: inode: %llu " |
| 788 | "highest_vcn: 0x%llx last_vcn: 0x%llx", |
| 789 | (unsigned long long)na->ni->mft_no, |
| 790 | (long long)highest_vcn, (long long)last_vcn); |
| 791 | goto err_out; |
| 792 | } |
| 793 | if (errno == ENOENT) { |
| 794 | NAttrSetFullyMapped(na); |
| 795 | ret = 0; |
| 796 | } |
| 797 | err_out: |
| 798 | ntfs_attr_put_search_ctx(ctx); |
| 799 | out: |
| 800 | ntfs_log_leave("\n"); |
| 801 | return ret; |
| 802 | } |
| 803 | |
| 804 | /** |
| 805 | * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute |
| 806 | * @na: ntfs attribute whose runlist to use for conversion |
| 807 | * @vcn: vcn to convert |
| 808 | * |
| 809 | * Convert the virtual cluster number @vcn of an attribute into a logical |
| 810 | * cluster number (lcn) of a device using the runlist @na->rl to map vcns to |
| 811 | * their corresponding lcns. |
| 812 | * |
| 813 | * If the @vcn is not mapped yet, attempt to map the attribute extent |
| 814 | * containing the @vcn and retry the vcn to lcn conversion. |
| 815 | * |
| 816 | * Since lcns must be >= 0, we use negative return values with special meaning: |
| 817 | * |
| 818 | * Return value Meaning / Description |
| 819 | * ========================================== |
| 820 | * -1 = LCN_HOLE Hole / not allocated on disk. |
| 821 | * -3 = LCN_ENOENT There is no such vcn in the attribute. |
| 822 | * -4 = LCN_EINVAL Input parameter error. |
| 823 | * -5 = LCN_EIO Corrupt fs, disk i/o error, or not enough memory. |
| 824 | */ |
| 825 | LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn) |
| 826 | { |
| 827 | LCN lcn; |
| 828 | BOOL is_retry = FALSE; |
| 829 | |
| 830 | if (!na || !NAttrNonResident(na) || vcn < 0) |
| 831 | return (LCN)LCN_EINVAL; |
| 832 | |
| 833 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 834 | long)na->ni->mft_no, le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 835 | retry: |
| 836 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ |
| 837 | lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn); |
| 838 | if (lcn >= 0) |
| 839 | return lcn; |
| 840 | if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) { |
| 841 | is_retry = TRUE; |
| 842 | goto retry; |
| 843 | } |
| 844 | /* |
| 845 | * If the attempt to map the runlist failed, or we are getting |
| 846 | * LCN_RL_NOT_MAPPED despite having mapped the attribute extent |
| 847 | * successfully, something is really badly wrong... |
| 848 | */ |
| 849 | if (!is_retry || lcn == (LCN)LCN_RL_NOT_MAPPED) |
| 850 | return (LCN)LCN_EIO; |
| 851 | /* lcn contains the appropriate error code. */ |
| 852 | return lcn; |
| 853 | } |
| 854 | |
| 855 | /** |
| 856 | * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute |
| 857 | * @na: ntfs attribute whose runlist to search |
| 858 | * @vcn: vcn to find |
| 859 | * |
| 860 | * Find the virtual cluster number @vcn in the runlist of the ntfs attribute |
| 861 | * @na and return the the address of the runlist element containing the @vcn. |
| 862 | * |
| 863 | * Note you need to distinguish between the lcn of the returned runlist |
| 864 | * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes |
| 865 | * on read and allocate clusters on write. You need to update the runlist, the |
| 866 | * attribute itself as well as write the modified mft record to disk. |
| 867 | * |
| 868 | * If there is an error return NULL with errno set to the error code. The |
| 869 | * following error codes are defined: |
| 870 | * EINVAL Input parameter error. |
| 871 | * ENOENT There is no such vcn in the runlist. |
| 872 | * ENOMEM Not enough memory. |
| 873 | * EIO I/O error or corrupt metadata. |
| 874 | */ |
| 875 | runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn) |
| 876 | { |
| 877 | runlist_element *rl; |
| 878 | BOOL is_retry = FALSE; |
| 879 | |
| 880 | if (!na || !NAttrNonResident(na) || vcn < 0) { |
| 881 | errno = EINVAL; |
| 882 | return NULL; |
| 883 | } |
| 884 | |
| 885 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn %llx\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 886 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 887 | (long long)vcn); |
| 888 | retry: |
| 889 | rl = na->rl; |
| 890 | if (!rl) |
| 891 | goto map_rl; |
| 892 | if (vcn < rl[0].vcn) |
| 893 | goto map_rl; |
| 894 | while (rl->length) { |
| 895 | if (vcn < rl[1].vcn) { |
| 896 | if (rl->lcn >= (LCN)LCN_HOLE) |
| 897 | return rl; |
| 898 | break; |
| 899 | } |
| 900 | rl++; |
| 901 | } |
| 902 | switch (rl->lcn) { |
| 903 | case (LCN)LCN_RL_NOT_MAPPED: |
| 904 | goto map_rl; |
| 905 | case (LCN)LCN_ENOENT: |
| 906 | errno = ENOENT; |
| 907 | break; |
| 908 | case (LCN)LCN_EINVAL: |
| 909 | errno = EINVAL; |
| 910 | break; |
| 911 | default: |
| 912 | errno = EIO; |
| 913 | break; |
| 914 | } |
| 915 | return NULL; |
| 916 | map_rl: |
| 917 | /* The @vcn is in an unmapped region, map the runlist and retry. */ |
| 918 | if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) { |
| 919 | is_retry = TRUE; |
| 920 | goto retry; |
| 921 | } |
| 922 | /* |
| 923 | * If we already retried or the mapping attempt failed something has |
| 924 | * gone badly wrong. EINVAL and ENOENT coming from a failed mapping |
| 925 | * attempt are equivalent to errors for us as they should not happen |
| 926 | * in our code paths. |
| 927 | */ |
| 928 | if (is_retry || errno == EINVAL || errno == ENOENT) |
| 929 | errno = EIO; |
| 930 | return NULL; |
| 931 | } |
| 932 | |
| 933 | /** |
| 934 | * ntfs_attr_pread_i - see description at ntfs_attr_pread() |
| 935 | */ |
| 936 | static s64 ntfs_attr_pread_i(ntfs_attr *na, const s64 pos, s64 count, void *b) |
| 937 | { |
| 938 | s64 br, to_read, ofs, total, total2, max_read, max_init; |
| 939 | ntfs_volume *vol; |
| 940 | runlist_element *rl; |
| 941 | u16 efs_padding_length; |
| 942 | |
| 943 | /* Sanity checking arguments is done in ntfs_attr_pread(). */ |
| 944 | |
| 945 | if ((na->data_flags & ATTR_COMPRESSION_MASK) && NAttrNonResident(na)) { |
| 946 | if ((na->data_flags & ATTR_COMPRESSION_MASK) |
| 947 | == ATTR_IS_COMPRESSED) |
| 948 | return ntfs_compressed_attr_pread(na, pos, count, b); |
| 949 | else { |
| 950 | /* compression mode not supported */ |
| 951 | errno = EOPNOTSUPP; |
| 952 | return -1; |
| 953 | } |
| 954 | } |
| 955 | /* |
| 956 | * Encrypted non-resident attributes are not supported. We return |
| 957 | * access denied, which is what Windows NT4 does, too. |
| 958 | * However, allow if mounted with efs_raw option |
| 959 | */ |
| 960 | vol = na->ni->vol; |
| 961 | if (!vol->efs_raw && NAttrEncrypted(na) && NAttrNonResident(na)) { |
| 962 | errno = EACCES; |
| 963 | return -1; |
| 964 | } |
| 965 | |
| 966 | if (!count) |
| 967 | return 0; |
| 968 | /* |
| 969 | * Truncate reads beyond end of attribute, |
| 970 | * but round to next 512 byte boundary for encrypted |
| 971 | * attributes with efs_raw mount option |
| 972 | */ |
| 973 | max_read = na->data_size; |
| 974 | max_init = na->initialized_size; |
| 975 | if (na->ni->vol->efs_raw |
| 976 | && (na->data_flags & ATTR_IS_ENCRYPTED) |
| 977 | && NAttrNonResident(na)) { |
| 978 | if (na->data_size != na->initialized_size) { |
| 979 | ntfs_log_error("uninitialized encrypted file not supported\n"); |
| 980 | errno = EINVAL; |
| 981 | return -1; |
| 982 | } |
| 983 | max_init = max_read = ((na->data_size + 511) & ~511) + 2; |
| 984 | } |
| 985 | if (pos + count > max_read) { |
| 986 | if (pos >= max_read) |
| 987 | return 0; |
| 988 | count = max_read - pos; |
| 989 | } |
| 990 | /* If it is a resident attribute, get the value from the mft record. */ |
| 991 | if (!NAttrNonResident(na)) { |
| 992 | ntfs_attr_search_ctx *ctx; |
| 993 | char *val; |
| 994 | |
| 995 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 996 | if (!ctx) |
| 997 | return -1; |
| 998 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, |
| 999 | 0, NULL, 0, ctx)) { |
| 1000 | res_err_out: |
| 1001 | ntfs_attr_put_search_ctx(ctx); |
| 1002 | return -1; |
| 1003 | } |
| 1004 | val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset); |
| 1005 | if (val < (char*)ctx->attr || val + |
| 1006 | le32_to_cpu(ctx->attr->value_length) > |
| 1007 | (char*)ctx->mrec + vol->mft_record_size) { |
| 1008 | errno = EIO; |
| 1009 | ntfs_log_perror("%s: Sanity check failed", __FUNCTION__); |
| 1010 | goto res_err_out; |
| 1011 | } |
| 1012 | memcpy(b, val + pos, count); |
| 1013 | ntfs_attr_put_search_ctx(ctx); |
| 1014 | return count; |
| 1015 | } |
| 1016 | total = total2 = 0; |
| 1017 | /* Zero out reads beyond initialized size. */ |
| 1018 | if (pos + count > max_init) { |
| 1019 | if (pos >= max_init) { |
| 1020 | memset(b, 0, count); |
| 1021 | return count; |
| 1022 | } |
| 1023 | total2 = pos + count - max_init; |
| 1024 | count -= total2; |
| 1025 | memset((u8*)b + count, 0, total2); |
| 1026 | } |
| 1027 | /* |
| 1028 | * for encrypted non-resident attributes with efs_raw set |
| 1029 | * the last two bytes aren't read from disk but contain |
| 1030 | * the number of padding bytes so original size can be |
| 1031 | * restored |
| 1032 | */ |
| 1033 | if (na->ni->vol->efs_raw && |
| 1034 | (na->data_flags & ATTR_IS_ENCRYPTED) && |
| 1035 | ((pos + count) > max_init-2)) { |
| 1036 | efs_padding_length = 511 - ((na->data_size - 1) & 511); |
| 1037 | if (pos+count == max_init) { |
| 1038 | if (count == 1) { |
| 1039 | *((u8*)b+count-1) = (u8)(efs_padding_length >> 8); |
| 1040 | count--; |
| 1041 | total2++; |
| 1042 | } else { |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 1043 | *(le16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1044 | count -= 2; |
| 1045 | total2 +=2; |
| 1046 | } |
| 1047 | } else { |
| 1048 | *((u8*)b+count-1) = (u8)(efs_padding_length & 0xff); |
| 1049 | count--; |
| 1050 | total2++; |
| 1051 | } |
| 1052 | } |
| 1053 | |
| 1054 | /* Find the runlist element containing the vcn. */ |
| 1055 | rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); |
| 1056 | if (!rl) { |
| 1057 | /* |
| 1058 | * If the vcn is not present it is an out of bounds read. |
| 1059 | * However, we already truncated the read to the data_size, |
| 1060 | * so getting this here is an error. |
| 1061 | */ |
| 1062 | if (errno == ENOENT) { |
| 1063 | errno = EIO; |
| 1064 | ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__); |
| 1065 | } |
| 1066 | return -1; |
| 1067 | } |
| 1068 | /* |
| 1069 | * Gather the requested data into the linear destination buffer. Note, |
| 1070 | * a partial final vcn is taken care of by the @count capping of read |
| 1071 | * length. |
| 1072 | */ |
| 1073 | ofs = pos - (rl->vcn << vol->cluster_size_bits); |
| 1074 | for (; count; rl++, ofs = 0) { |
| 1075 | if (rl->lcn == LCN_RL_NOT_MAPPED) { |
| 1076 | rl = ntfs_attr_find_vcn(na, rl->vcn); |
| 1077 | if (!rl) { |
| 1078 | if (errno == ENOENT) { |
| 1079 | errno = EIO; |
| 1080 | ntfs_log_perror("%s: Failed to find VCN #2", |
| 1081 | __FUNCTION__); |
| 1082 | } |
| 1083 | goto rl_err_out; |
| 1084 | } |
| 1085 | /* Needed for case when runs merged. */ |
| 1086 | ofs = pos + total - (rl->vcn << vol->cluster_size_bits); |
| 1087 | } |
| 1088 | if (!rl->length) { |
| 1089 | errno = EIO; |
| 1090 | ntfs_log_perror("%s: Zero run length", __FUNCTION__); |
| 1091 | goto rl_err_out; |
| 1092 | } |
| 1093 | if (rl->lcn < (LCN)0) { |
| 1094 | if (rl->lcn != (LCN)LCN_HOLE) { |
| 1095 | ntfs_log_perror("%s: Bad run (%lld)", |
| 1096 | __FUNCTION__, |
| 1097 | (long long)rl->lcn); |
| 1098 | goto rl_err_out; |
| 1099 | } |
| 1100 | /* It is a hole, just zero the matching @b range. */ |
| 1101 | to_read = min(count, (rl->length << |
| 1102 | vol->cluster_size_bits) - ofs); |
| 1103 | memset(b, 0, to_read); |
| 1104 | /* Update progress counters. */ |
| 1105 | total += to_read; |
| 1106 | count -= to_read; |
| 1107 | b = (u8*)b + to_read; |
| 1108 | continue; |
| 1109 | } |
| 1110 | /* It is a real lcn, read it into @dst. */ |
| 1111 | to_read = min(count, (rl->length << vol->cluster_size_bits) - |
| 1112 | ofs); |
| 1113 | retry: |
| 1114 | ntfs_log_trace("Reading %lld bytes from vcn %lld, lcn %lld, ofs" |
| 1115 | " %lld.\n", (long long)to_read, (long long)rl->vcn, |
| 1116 | (long long )rl->lcn, (long long)ofs); |
| 1117 | br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) + |
| 1118 | ofs, to_read, b); |
| 1119 | /* If everything ok, update progress counters and continue. */ |
| 1120 | if (br > 0) { |
| 1121 | total += br; |
| 1122 | count -= br; |
| 1123 | b = (u8*)b + br; |
| 1124 | } |
| 1125 | if (br == to_read) |
| 1126 | continue; |
| 1127 | /* If the syscall was interrupted, try again. */ |
| 1128 | if (br == (s64)-1 && errno == EINTR) |
| 1129 | goto retry; |
| 1130 | if (total) |
| 1131 | return total; |
| 1132 | if (!br) |
| 1133 | errno = EIO; |
| 1134 | ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__); |
| 1135 | return -1; |
| 1136 | } |
| 1137 | /* Finally, return the number of bytes read. */ |
| 1138 | return total + total2; |
| 1139 | rl_err_out: |
| 1140 | if (total) |
| 1141 | return total; |
| 1142 | errno = EIO; |
| 1143 | return -1; |
| 1144 | } |
| 1145 | |
| 1146 | /** |
| 1147 | * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure |
| 1148 | * @na: ntfs attribute to read from |
| 1149 | * @pos: byte position in the attribute to begin reading from |
| 1150 | * @count: number of bytes to read |
| 1151 | * @b: output data buffer |
| 1152 | * |
| 1153 | * This function will read @count bytes starting at offset @pos from the ntfs |
| 1154 | * attribute @na into the data buffer @b. |
| 1155 | * |
| 1156 | * On success, return the number of successfully read bytes. If this number is |
| 1157 | * lower than @count this means that the read reached end of file or that an |
| 1158 | * error was encountered during the read so that the read is partial. 0 means |
| 1159 | * end of file or nothing was read (also return 0 when @count is 0). |
| 1160 | * |
| 1161 | * On error and nothing has been read, return -1 with errno set appropriately |
| 1162 | * to the return code of ntfs_pread(), or to EINVAL in case of invalid |
| 1163 | * arguments. |
| 1164 | */ |
| 1165 | s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) |
| 1166 | { |
| 1167 | s64 ret; |
| 1168 | |
| 1169 | if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { |
| 1170 | errno = EINVAL; |
| 1171 | ntfs_log_perror("%s: na=%p b=%p pos=%lld count=%lld", |
| 1172 | __FUNCTION__, na, b, (long long)pos, |
| 1173 | (long long)count); |
| 1174 | return -1; |
| 1175 | } |
| 1176 | |
| 1177 | ntfs_log_enter("Entering for inode %lld attr 0x%x pos %lld count " |
| 1178 | "%lld\n", (unsigned long long)na->ni->mft_no, |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 1179 | le32_to_cpu(na->type), (long long)pos, (long long)count); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1180 | |
| 1181 | ret = ntfs_attr_pread_i(na, pos, count, b); |
| 1182 | |
| 1183 | ntfs_log_leave("\n"); |
| 1184 | return ret; |
| 1185 | } |
| 1186 | |
| 1187 | static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count) |
| 1188 | { |
| 1189 | char *buf; |
| 1190 | s64 written, size, end = pos + count; |
| 1191 | s64 ofsi; |
| 1192 | const runlist_element *rli; |
| 1193 | ntfs_volume *vol; |
| 1194 | int ret = -1; |
| 1195 | |
| 1196 | ntfs_log_trace("pos %lld, count %lld\n", (long long)pos, |
| 1197 | (long long)count); |
| 1198 | |
| 1199 | if (!na || pos < 0 || count < 0) { |
| 1200 | errno = EINVAL; |
| 1201 | goto err_out; |
| 1202 | } |
| 1203 | |
| 1204 | buf = ntfs_calloc(NTFS_BUF_SIZE); |
| 1205 | if (!buf) |
| 1206 | goto err_out; |
| 1207 | |
| 1208 | rli = na->rl; |
| 1209 | ofsi = 0; |
| 1210 | vol = na->ni->vol; |
| 1211 | while (pos < end) { |
| 1212 | while (rli->length && (ofsi + (rli->length << |
| 1213 | vol->cluster_size_bits) <= pos)) { |
| 1214 | ofsi += (rli->length << vol->cluster_size_bits); |
| 1215 | rli++; |
| 1216 | } |
| 1217 | size = min(end - pos, NTFS_BUF_SIZE); |
| 1218 | /* |
| 1219 | * If the zeroed block is fully within a hole, |
| 1220 | * we need not write anything, so advance as far |
| 1221 | * as possible within the hole. |
| 1222 | */ |
| 1223 | if ((rli->lcn == (LCN)LCN_HOLE) |
| 1224 | && (ofsi <= pos) |
| 1225 | && (ofsi + (rli->length << vol->cluster_size_bits) |
| 1226 | >= (pos + size))) { |
| 1227 | size = min(end - pos, ofsi - pos |
| 1228 | + (rli->length << vol->cluster_size_bits)); |
| 1229 | pos += size; |
| 1230 | } else { |
| 1231 | written = ntfs_rl_pwrite(vol, rli, ofsi, pos, |
| 1232 | size, buf); |
| 1233 | if (written <= 0) { |
| 1234 | ntfs_log_perror("Failed to zero space"); |
| 1235 | goto err_free; |
| 1236 | } |
| 1237 | pos += written; |
| 1238 | } |
| 1239 | } |
| 1240 | |
| 1241 | ret = 0; |
| 1242 | err_free: |
| 1243 | free(buf); |
| 1244 | err_out: |
| 1245 | return ret; |
| 1246 | } |
| 1247 | |
| 1248 | static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, |
| 1249 | runlist_element **rl, VCN *update_from) |
| 1250 | { |
| 1251 | s64 to_write; |
| 1252 | s64 need; |
| 1253 | ntfs_volume *vol = na->ni->vol; |
| 1254 | int eo, ret = -1; |
| 1255 | runlist *rlc; |
| 1256 | LCN lcn_seek_from = -1; |
| 1257 | VCN cur_vcn, from_vcn; |
| 1258 | |
| 1259 | to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs); |
| 1260 | |
| 1261 | cur_vcn = (*rl)->vcn; |
| 1262 | from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits); |
| 1263 | |
| 1264 | ntfs_log_trace("count: %lld, cur_vcn: %lld, from: %lld, to: %lld, ofs: " |
| 1265 | "%lld\n", (long long)count, (long long)cur_vcn, |
| 1266 | (long long)from_vcn, (long long)to_write, (long long)*ofs); |
| 1267 | |
| 1268 | /* Map the runlist to be able to update mapping pairs later. */ |
| 1269 | #if PARTIAL_RUNLIST_UPDATING |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1270 | if (!na->rl) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1271 | if (ntfs_attr_map_whole_runlist(na)) |
| 1272 | goto err_out; |
| 1273 | } else { |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1274 | /* make sure the run ahead of hole is mapped */ |
| 1275 | if ((*rl)->lcn == LCN_HOLE) { |
| 1276 | if (ntfs_attr_map_partial_runlist(na, |
| 1277 | (cur_vcn ? cur_vcn - 1 : cur_vcn))) |
| 1278 | goto err_out; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1279 | } |
| 1280 | } |
| 1281 | #else |
| 1282 | if (ntfs_attr_map_whole_runlist(na)) |
| 1283 | goto err_out; |
| 1284 | #endif |
| 1285 | |
| 1286 | /* Restore @*rl, it probably get lost during runlist mapping. */ |
| 1287 | *rl = ntfs_attr_find_vcn(na, cur_vcn); |
| 1288 | if (!*rl) { |
| 1289 | ntfs_log_error("Failed to find run after mapping runlist. " |
| 1290 | "Please report to %s.\n", NTFS_DEV_LIST); |
| 1291 | errno = EIO; |
| 1292 | goto err_out; |
| 1293 | } |
| 1294 | |
| 1295 | /* Search backwards to find the best lcn to start seek from. */ |
| 1296 | rlc = *rl; |
| 1297 | while (rlc->vcn) { |
| 1298 | rlc--; |
| 1299 | if (rlc->lcn >= 0) { |
| 1300 | /* |
| 1301 | * avoid fragmenting a compressed file |
| 1302 | * Windows does not do that, and that may |
| 1303 | * not be desirable for files which can |
| 1304 | * be updated |
| 1305 | */ |
| 1306 | if (na->data_flags & ATTR_COMPRESSION_MASK) |
| 1307 | lcn_seek_from = rlc->lcn + rlc->length; |
| 1308 | else |
| 1309 | lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn); |
| 1310 | break; |
| 1311 | } |
| 1312 | } |
| 1313 | if (lcn_seek_from == -1) { |
| 1314 | /* Backwards search failed, search forwards. */ |
| 1315 | rlc = *rl; |
| 1316 | while (rlc->length) { |
| 1317 | rlc++; |
| 1318 | if (rlc->lcn >= 0) { |
| 1319 | lcn_seek_from = rlc->lcn - (rlc->vcn - from_vcn); |
| 1320 | if (lcn_seek_from < -1) |
| 1321 | lcn_seek_from = -1; |
| 1322 | break; |
| 1323 | } |
| 1324 | } |
| 1325 | } |
| 1326 | |
| 1327 | need = ((*ofs + to_write - 1) >> vol->cluster_size_bits) |
| 1328 | + 1 + (*rl)->vcn - from_vcn; |
| 1329 | if ((na->data_flags & ATTR_COMPRESSION_MASK) |
| 1330 | && (need < na->compression_block_clusters)) { |
| 1331 | /* |
| 1332 | * for a compressed file, be sure to allocate the full |
| 1333 | * compression block, as we may need space to decompress |
| 1334 | * existing compressed data. |
| 1335 | * So allocate the space common to compression block |
| 1336 | * and existing hole. |
| 1337 | */ |
| 1338 | VCN alloc_vcn; |
| 1339 | |
| 1340 | if ((from_vcn & -na->compression_block_clusters) <= (*rl)->vcn) |
| 1341 | alloc_vcn = (*rl)->vcn; |
| 1342 | else |
| 1343 | alloc_vcn = from_vcn & -na->compression_block_clusters; |
| 1344 | need = (alloc_vcn | (na->compression_block_clusters - 1)) |
| 1345 | + 1 - alloc_vcn; |
| 1346 | if (need > (*rl)->length) { |
| 1347 | ntfs_log_error("Cannot allocate %lld clusters" |
| 1348 | " within a hole of %lld\n", |
| 1349 | (long long)need, |
| 1350 | (long long)(*rl)->length); |
| 1351 | errno = EIO; |
| 1352 | goto err_out; |
| 1353 | } |
| 1354 | rlc = ntfs_cluster_alloc(vol, alloc_vcn, need, |
| 1355 | lcn_seek_from, DATA_ZONE); |
| 1356 | } else |
| 1357 | rlc = ntfs_cluster_alloc(vol, from_vcn, need, |
| 1358 | lcn_seek_from, DATA_ZONE); |
| 1359 | if (!rlc) |
| 1360 | goto err_out; |
| 1361 | if (na->data_flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) |
| 1362 | na->compressed_size += need << vol->cluster_size_bits; |
| 1363 | |
| 1364 | *rl = ntfs_runlists_merge(na->rl, rlc); |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1365 | NAttrSetRunlistDirty(na); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1366 | /* |
| 1367 | * For a compressed attribute, we must be sure there are two |
| 1368 | * available entries, so reserve them before it gets too late. |
| 1369 | */ |
| 1370 | if (*rl && (na->data_flags & ATTR_COMPRESSION_MASK)) { |
| 1371 | runlist_element *oldrl = na->rl; |
| 1372 | na->rl = *rl; |
| 1373 | *rl = ntfs_rl_extend(na,*rl,2); |
| 1374 | if (!*rl) na->rl = oldrl; /* restore to original if failed */ |
| 1375 | } |
| 1376 | if (!*rl) { |
| 1377 | eo = errno; |
| 1378 | ntfs_log_perror("Failed to merge runlists"); |
| 1379 | if (ntfs_cluster_free_from_rl(vol, rlc)) { |
| 1380 | ntfs_log_perror("Failed to free hot clusters. " |
| 1381 | "Please run chkdsk /f"); |
| 1382 | } |
| 1383 | errno = eo; |
| 1384 | goto err_out; |
| 1385 | } |
| 1386 | na->unused_runs = 2; |
| 1387 | na->rl = *rl; |
| 1388 | if ((*update_from == -1) || (from_vcn < *update_from)) |
| 1389 | *update_from = from_vcn; |
| 1390 | *rl = ntfs_attr_find_vcn(na, cur_vcn); |
| 1391 | if (!*rl) { |
| 1392 | /* |
| 1393 | * It's definitely a BUG, if we failed to find @cur_vcn, because |
| 1394 | * we missed it during instantiating of the hole. |
| 1395 | */ |
| 1396 | ntfs_log_error("Failed to find run after hole instantiation. " |
| 1397 | "Please report to %s.\n", NTFS_DEV_LIST); |
| 1398 | errno = EIO; |
| 1399 | goto err_out; |
| 1400 | } |
| 1401 | /* If leaved part of the hole go to the next run. */ |
| 1402 | if ((*rl)->lcn < 0) |
| 1403 | (*rl)++; |
| 1404 | /* Now LCN shoudn't be less than 0. */ |
| 1405 | if ((*rl)->lcn < 0) { |
| 1406 | ntfs_log_error("BUG! LCN is lesser than 0. " |
| 1407 | "Please report to the %s.\n", NTFS_DEV_LIST); |
| 1408 | errno = EIO; |
| 1409 | goto err_out; |
| 1410 | } |
| 1411 | if (*ofs) { |
| 1412 | /* Clear non-sparse region from @cur_vcn to @*ofs. */ |
| 1413 | if (ntfs_attr_fill_zero(na, cur_vcn << vol->cluster_size_bits, |
| 1414 | *ofs)) |
| 1415 | goto err_out; |
| 1416 | } |
| 1417 | if ((*rl)->vcn < cur_vcn) { |
| 1418 | /* |
| 1419 | * Clusters that replaced hole are merged with |
| 1420 | * previous run, so we need to update offset. |
| 1421 | */ |
| 1422 | *ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits; |
| 1423 | } |
| 1424 | if ((*rl)->vcn > cur_vcn) { |
| 1425 | /* |
| 1426 | * We left part of the hole, so we need to update offset |
| 1427 | */ |
| 1428 | *ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits; |
| 1429 | } |
| 1430 | |
| 1431 | ret = 0; |
| 1432 | err_out: |
| 1433 | return ret; |
| 1434 | } |
| 1435 | |
| 1436 | static int stuff_hole(ntfs_attr *na, const s64 pos); |
| 1437 | |
| 1438 | /* |
| 1439 | * Split an existing hole for overwriting with data |
| 1440 | * The hole may have to be split into two or three parts, so |
| 1441 | * that the overwritten part fits within a single compression block |
| 1442 | * |
| 1443 | * No cluster allocation is needed, this will be done later in |
| 1444 | * standard hole filling, hence no need to reserve runs for |
| 1445 | * future needs. |
| 1446 | * |
| 1447 | * Returns the number of clusters with existing compressed data |
| 1448 | * in the compression block to be written to |
| 1449 | * (or the full block, if it was a full hole) |
| 1450 | * -1 if there were an error |
| 1451 | */ |
| 1452 | |
| 1453 | static int split_compressed_hole(ntfs_attr *na, runlist_element **prl, |
| 1454 | s64 pos, s64 count, VCN *update_from) |
| 1455 | { |
| 1456 | int compressed_part; |
| 1457 | int cluster_size_bits = na->ni->vol->cluster_size_bits; |
| 1458 | runlist_element *rl = *prl; |
| 1459 | |
| 1460 | compressed_part |
| 1461 | = na->compression_block_clusters; |
| 1462 | /* reserve entries in runlist if we have to split */ |
| 1463 | if (rl->length > na->compression_block_clusters) { |
| 1464 | *prl = ntfs_rl_extend(na,*prl,2); |
| 1465 | if (!*prl) { |
| 1466 | compressed_part = -1; |
| 1467 | } else { |
| 1468 | rl = *prl; |
| 1469 | na->unused_runs = 2; |
| 1470 | } |
| 1471 | } |
| 1472 | if (*prl && (rl->length > na->compression_block_clusters)) { |
| 1473 | /* |
| 1474 | * Locate the update part relative to beginning of |
| 1475 | * current run |
| 1476 | */ |
| 1477 | int beginwrite = (pos >> cluster_size_bits) - rl->vcn; |
| 1478 | s32 endblock = (((pos + count - 1) >> cluster_size_bits) |
| 1479 | | (na->compression_block_clusters - 1)) + 1 - rl->vcn; |
| 1480 | |
| 1481 | compressed_part = na->compression_block_clusters |
| 1482 | - (rl->length & (na->compression_block_clusters - 1)); |
| 1483 | if ((beginwrite + compressed_part) >= na->compression_block_clusters) |
| 1484 | compressed_part = na->compression_block_clusters; |
| 1485 | /* |
| 1486 | * if the run ends beyond end of needed block |
| 1487 | * we have to split the run |
| 1488 | */ |
| 1489 | if (endblock < rl[0].length) { |
| 1490 | runlist_element *xrl; |
| 1491 | int n; |
| 1492 | |
| 1493 | /* |
| 1494 | * we have to split into three parts if the run |
| 1495 | * does not end within the first compression block. |
| 1496 | * This means the hole begins before the |
| 1497 | * compression block. |
| 1498 | */ |
| 1499 | if (endblock > na->compression_block_clusters) { |
| 1500 | if (na->unused_runs < 2) { |
| 1501 | ntfs_log_error("No free run, case 1\n"); |
| 1502 | } |
| 1503 | na->unused_runs -= 2; |
| 1504 | xrl = rl; |
| 1505 | n = 0; |
| 1506 | while (xrl->length) { |
| 1507 | xrl++; |
| 1508 | n++; |
| 1509 | } |
| 1510 | do { |
| 1511 | xrl[2] = *xrl; |
| 1512 | xrl--; |
| 1513 | } while (xrl != rl); |
| 1514 | rl[1].length = na->compression_block_clusters; |
| 1515 | rl[2].length = rl[0].length - endblock; |
| 1516 | rl[0].length = endblock |
| 1517 | - na->compression_block_clusters; |
| 1518 | rl[1].lcn = LCN_HOLE; |
| 1519 | rl[2].lcn = LCN_HOLE; |
| 1520 | rl[1].vcn = rl[0].vcn + rl[0].length; |
| 1521 | rl[2].vcn = rl[1].vcn |
| 1522 | + na->compression_block_clusters; |
| 1523 | rl = ++(*prl); |
| 1524 | } else { |
| 1525 | /* |
| 1526 | * split into two parts and use the |
| 1527 | * first one |
| 1528 | */ |
| 1529 | if (!na->unused_runs) { |
| 1530 | ntfs_log_error("No free run, case 2\n"); |
| 1531 | } |
| 1532 | na->unused_runs--; |
| 1533 | xrl = rl; |
| 1534 | n = 0; |
| 1535 | while (xrl->length) { |
| 1536 | xrl++; |
| 1537 | n++; |
| 1538 | } |
| 1539 | do { |
| 1540 | xrl[1] = *xrl; |
| 1541 | xrl--; |
| 1542 | } while (xrl != rl); |
| 1543 | if (beginwrite < endblock) { |
| 1544 | /* we will write into the first part of hole */ |
| 1545 | rl[1].length = rl[0].length - endblock; |
| 1546 | rl[0].length = endblock; |
| 1547 | rl[1].vcn = rl[0].vcn + rl[0].length; |
| 1548 | rl[1].lcn = LCN_HOLE; |
| 1549 | } else { |
| 1550 | /* we will write into the second part of hole */ |
| 1551 | // impossible ? |
| 1552 | rl[1].length = rl[0].length - endblock; |
| 1553 | rl[0].length = endblock; |
| 1554 | rl[1].vcn = rl[0].vcn + rl[0].length; |
| 1555 | rl[1].lcn = LCN_HOLE; |
| 1556 | rl = ++(*prl); |
| 1557 | } |
| 1558 | } |
| 1559 | } else { |
| 1560 | if (rl[1].length) { |
| 1561 | runlist_element *xrl; |
| 1562 | int n; |
| 1563 | |
| 1564 | /* |
| 1565 | * split into two parts and use the |
| 1566 | * last one |
| 1567 | */ |
| 1568 | if (!na->unused_runs) { |
| 1569 | ntfs_log_error("No free run, case 4\n"); |
| 1570 | } |
| 1571 | na->unused_runs--; |
| 1572 | xrl = rl; |
| 1573 | n = 0; |
| 1574 | while (xrl->length) { |
| 1575 | xrl++; |
| 1576 | n++; |
| 1577 | } |
| 1578 | do { |
| 1579 | xrl[1] = *xrl; |
| 1580 | xrl--; |
| 1581 | } while (xrl != rl); |
| 1582 | } else { |
| 1583 | rl[2].lcn = rl[1].lcn; |
| 1584 | rl[2].vcn = rl[1].vcn; |
| 1585 | rl[2].length = rl[1].length; |
| 1586 | } |
| 1587 | rl[1].vcn -= na->compression_block_clusters; |
| 1588 | rl[1].lcn = LCN_HOLE; |
| 1589 | rl[1].length = na->compression_block_clusters; |
| 1590 | rl[0].length -= na->compression_block_clusters; |
| 1591 | if (pos >= (rl[1].vcn << cluster_size_bits)) { |
| 1592 | rl = ++(*prl); |
| 1593 | } |
| 1594 | } |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1595 | NAttrSetRunlistDirty(na); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1596 | if ((*update_from == -1) || ((*prl)->vcn < *update_from)) |
| 1597 | *update_from = (*prl)->vcn; |
| 1598 | } |
| 1599 | return (compressed_part); |
| 1600 | } |
| 1601 | |
| 1602 | /* |
| 1603 | * Borrow space from adjacent hole for appending data |
| 1604 | * The hole may have to be split so that the end of hole is not |
| 1605 | * affected by cluster allocation and overwriting |
| 1606 | * Cluster allocation is needed for the overwritten compression block |
| 1607 | * |
| 1608 | * Must always leave two unused entries in the runlist |
| 1609 | * |
| 1610 | * Returns the number of clusters with existing compressed data |
| 1611 | * in the compression block to be written to |
| 1612 | * -1 if there were an error |
| 1613 | */ |
| 1614 | |
| 1615 | static int borrow_from_hole(ntfs_attr *na, runlist_element **prl, |
| 1616 | s64 pos, s64 count, VCN *update_from, BOOL wasnonresident) |
| 1617 | { |
| 1618 | int compressed_part = 0; |
| 1619 | int cluster_size_bits = na->ni->vol->cluster_size_bits; |
| 1620 | runlist_element *rl = *prl; |
| 1621 | s32 endblock; |
| 1622 | long long allocated; |
| 1623 | runlist_element *zrl; |
| 1624 | int irl; |
| 1625 | BOOL undecided; |
| 1626 | BOOL nothole; |
| 1627 | |
| 1628 | /* check whether the compression block is fully allocated */ |
| 1629 | endblock = (((pos + count - 1) >> cluster_size_bits) | (na->compression_block_clusters - 1)) + 1 - rl->vcn; |
| 1630 | allocated = 0; |
| 1631 | zrl = rl; |
| 1632 | irl = 0; |
| 1633 | while (zrl->length && (zrl->lcn >= 0) && (allocated < endblock)) { |
| 1634 | allocated += zrl->length; |
| 1635 | zrl++; |
| 1636 | irl++; |
| 1637 | } |
| 1638 | |
| 1639 | undecided = (allocated < endblock) && (zrl->lcn == LCN_RL_NOT_MAPPED); |
| 1640 | nothole = (allocated >= endblock) || (zrl->lcn != LCN_HOLE); |
| 1641 | |
| 1642 | if (undecided || nothole) { |
| 1643 | runlist_element *orl = na->rl; |
| 1644 | s64 olcn = (*prl)->lcn; |
| 1645 | #if PARTIAL_RUNLIST_UPDATING |
| 1646 | VCN prevblock; |
| 1647 | #endif |
| 1648 | /* |
| 1649 | * Map the runlist, unless it has not been created. |
| 1650 | * If appending data, a partial mapping from the |
| 1651 | * end of previous block will do. |
| 1652 | */ |
| 1653 | irl = *prl - na->rl; |
| 1654 | #if PARTIAL_RUNLIST_UPDATING |
| 1655 | prevblock = pos >> cluster_size_bits; |
| 1656 | if (prevblock) |
| 1657 | prevblock--; |
| 1658 | if (!NAttrBeingNonResident(na) |
| 1659 | && (NAttrDataAppending(na) |
| 1660 | ? ntfs_attr_map_partial_runlist(na,prevblock) |
| 1661 | : ntfs_attr_map_whole_runlist(na))) { |
| 1662 | #else |
| 1663 | if (!NAttrBeingNonResident(na) |
| 1664 | && ntfs_attr_map_whole_runlist(na)) { |
| 1665 | #endif |
| 1666 | rl = (runlist_element*)NULL; |
| 1667 | } else { |
| 1668 | /* |
| 1669 | * Mapping the runlist may cause its relocation, |
| 1670 | * and relocation may be at the same place with |
| 1671 | * relocated contents. |
| 1672 | * Have to find the current run again when this |
| 1673 | * happens. |
| 1674 | */ |
| 1675 | if ((na->rl != orl) || ((*prl)->lcn != olcn)) { |
| 1676 | zrl = &na->rl[irl]; |
| 1677 | while (zrl->length && (zrl->lcn != olcn)) |
| 1678 | zrl++; |
| 1679 | *prl = zrl; |
| 1680 | } |
| 1681 | if (!(*prl)->length) { |
| 1682 | ntfs_log_error("Mapped run not found," |
| 1683 | " inode %lld lcn 0x%llx\n", |
| 1684 | (long long)na->ni->mft_no, |
| 1685 | (long long)olcn); |
| 1686 | rl = (runlist_element*)NULL; |
| 1687 | } else { |
| 1688 | rl = ntfs_rl_extend(na,*prl,2); |
| 1689 | na->unused_runs = 2; |
| 1690 | } |
| 1691 | } |
| 1692 | *prl = rl; |
| 1693 | if (rl && undecided) { |
| 1694 | allocated = 0; |
| 1695 | zrl = rl; |
| 1696 | irl = 0; |
| 1697 | while (zrl->length && (zrl->lcn >= 0) |
| 1698 | && (allocated < endblock)) { |
| 1699 | allocated += zrl->length; |
| 1700 | zrl++; |
| 1701 | irl++; |
| 1702 | } |
| 1703 | } |
| 1704 | } |
| 1705 | /* |
| 1706 | * compression block not fully allocated and followed |
| 1707 | * by a hole : we must allocate in the hole. |
| 1708 | */ |
| 1709 | if (rl && (allocated < endblock) && (zrl->lcn == LCN_HOLE)) { |
| 1710 | s64 xofs; |
| 1711 | |
| 1712 | /* |
| 1713 | * split the hole if not fully needed |
| 1714 | */ |
| 1715 | if ((allocated + zrl->length) > endblock) { |
| 1716 | runlist_element *xrl; |
| 1717 | |
| 1718 | *prl = ntfs_rl_extend(na,*prl,1); |
| 1719 | if (*prl) { |
| 1720 | /* beware : rl was reallocated */ |
| 1721 | rl = *prl; |
| 1722 | zrl = &rl[irl]; |
| 1723 | na->unused_runs = 0; |
| 1724 | xrl = zrl; |
| 1725 | while (xrl->length) xrl++; |
| 1726 | do { |
| 1727 | xrl[1] = *xrl; |
| 1728 | } while (xrl-- != zrl); |
| 1729 | zrl->length = endblock - allocated; |
| 1730 | zrl[1].length -= zrl->length; |
| 1731 | zrl[1].vcn = zrl->vcn + zrl->length; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1732 | NAttrSetRunlistDirty(na); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1733 | } |
| 1734 | } |
| 1735 | if (*prl) { |
| 1736 | if (wasnonresident) |
| 1737 | compressed_part = na->compression_block_clusters |
| 1738 | - zrl->length; |
| 1739 | xofs = 0; |
| 1740 | if (ntfs_attr_fill_hole(na, |
| 1741 | zrl->length << cluster_size_bits, |
| 1742 | &xofs, &zrl, update_from)) |
| 1743 | compressed_part = -1; |
| 1744 | else { |
| 1745 | /* go back to initial cluster, now reallocated */ |
| 1746 | while (zrl->vcn > (pos >> cluster_size_bits)) |
| 1747 | zrl--; |
| 1748 | *prl = zrl; |
| 1749 | } |
| 1750 | } |
| 1751 | } |
| 1752 | if (!*prl) { |
| 1753 | ntfs_log_error("No elements to borrow from a hole\n"); |
| 1754 | compressed_part = -1; |
| 1755 | } else |
| 1756 | if ((*update_from == -1) || ((*prl)->vcn < *update_from)) |
| 1757 | *update_from = (*prl)->vcn; |
| 1758 | return (compressed_part); |
| 1759 | } |
| 1760 | |
| 1761 | static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize, |
| 1762 | hole_type holes); |
| 1763 | |
| 1764 | /** |
| 1765 | * ntfs_attr_pwrite - positioned write to an ntfs attribute |
| 1766 | * @na: ntfs attribute to write to |
| 1767 | * @pos: position in the attribute to write to |
| 1768 | * @count: number of bytes to write |
| 1769 | * @b: data buffer to write to disk |
| 1770 | * |
| 1771 | * This function will write @count bytes from data buffer @b to ntfs attribute |
| 1772 | * @na at position @pos. |
| 1773 | * |
| 1774 | * On success, return the number of successfully written bytes. If this number |
| 1775 | * is lower than @count this means that an error was encountered during the |
| 1776 | * write so that the write is partial. 0 means nothing was written (also return |
| 1777 | * 0 when @count is 0). |
| 1778 | * |
| 1779 | * On error and nothing has been written, return -1 with errno set |
| 1780 | * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of |
| 1781 | * invalid arguments. |
| 1782 | */ |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 1783 | static s64 ntfs_attr_pwrite_i(ntfs_attr *na, const s64 pos, s64 count, |
| 1784 | const void *b) |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1785 | { |
| 1786 | s64 written, to_write, ofs, old_initialized_size, old_data_size; |
| 1787 | s64 total = 0; |
| 1788 | VCN update_from = -1; |
| 1789 | ntfs_volume *vol; |
| 1790 | s64 fullcount; |
| 1791 | ntfs_attr_search_ctx *ctx = NULL; |
| 1792 | runlist_element *rl; |
| 1793 | s64 hole_end; |
| 1794 | int eo; |
| 1795 | int compressed_part; |
| 1796 | struct { |
| 1797 | unsigned int undo_initialized_size : 1; |
| 1798 | unsigned int undo_data_size : 1; |
| 1799 | } need_to = { 0, 0 }; |
| 1800 | BOOL wasnonresident = FALSE; |
| 1801 | BOOL compressed; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1802 | |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1803 | vol = na->ni->vol; |
| 1804 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
| 1805 | != const_cpu_to_le16(0); |
| 1806 | na->unused_runs = 0; /* prepare overflow checks */ |
| 1807 | /* |
| 1808 | * Encrypted attributes are only supported in raw mode. We return |
| 1809 | * access denied, which is what Windows NT4 does, too. |
| 1810 | * Moreover a file cannot be both encrypted and compressed. |
| 1811 | */ |
| 1812 | if ((na->data_flags & ATTR_IS_ENCRYPTED) |
| 1813 | && (compressed || !vol->efs_raw)) { |
| 1814 | errno = EACCES; |
| 1815 | goto errno_set; |
| 1816 | } |
| 1817 | /* |
| 1818 | * Fill the gap, when writing beyond the end of a compressed |
| 1819 | * file. This will make recursive calls |
| 1820 | */ |
| 1821 | if (compressed |
| 1822 | && (na->type == AT_DATA) |
| 1823 | && (pos > na->initialized_size) |
| 1824 | && stuff_hole(na,pos)) |
| 1825 | goto errno_set; |
| 1826 | /* If this is a compressed attribute it needs special treatment. */ |
| 1827 | wasnonresident = NAttrNonResident(na) != 0; |
| 1828 | /* |
| 1829 | * Compression is restricted to data streams and |
| 1830 | * only ATTR_IS_COMPRESSED compression mode is supported. |
| 1831 | */ |
| 1832 | if (compressed |
| 1833 | && ((na->type != AT_DATA) |
| 1834 | || ((na->data_flags & ATTR_COMPRESSION_MASK) |
| 1835 | != ATTR_IS_COMPRESSED))) { |
| 1836 | errno = EOPNOTSUPP; |
| 1837 | goto errno_set; |
| 1838 | } |
| 1839 | |
| 1840 | if (!count) |
| 1841 | goto out; |
| 1842 | /* for a compressed file, get prepared to reserve a full block */ |
| 1843 | fullcount = count; |
| 1844 | /* If the write reaches beyond the end, extend the attribute. */ |
| 1845 | old_data_size = na->data_size; |
| 1846 | /* identify whether this is appending to a non resident data attribute */ |
| 1847 | if ((na->type == AT_DATA) && (pos >= old_data_size) |
| 1848 | && NAttrNonResident(na)) |
| 1849 | NAttrSetDataAppending(na); |
| 1850 | if (pos + count > na->data_size) { |
| 1851 | #if PARTIAL_RUNLIST_UPDATING |
| 1852 | /* |
| 1853 | * When appending data, the attribute is first extended |
| 1854 | * before being filled with data. This may cause the |
| 1855 | * attribute to be made temporarily sparse, which |
| 1856 | * implies reformating the inode and reorganizing the |
| 1857 | * full runlist. To avoid unnecessary reorganization, |
| 1858 | * we avoid sparse testing until the data is filled in. |
| 1859 | */ |
| 1860 | if (ntfs_attr_truncate_i(na, pos + count, |
| 1861 | (NAttrDataAppending(na) ? |
| 1862 | HOLES_DELAY : HOLES_OK))) { |
| 1863 | ntfs_log_perror("Failed to enlarge attribute"); |
| 1864 | goto errno_set; |
| 1865 | } |
| 1866 | /* |
| 1867 | * If we avoided updating the runlist, we must be sure |
| 1868 | * to cancel the enlargement and put back the runlist to |
| 1869 | * a clean state if we get into some error. |
| 1870 | */ |
| 1871 | if (NAttrDataAppending(na)) |
| 1872 | need_to.undo_data_size = 1; |
| 1873 | #else |
| 1874 | if (ntfs_attr_truncate_i(na, pos + count, HOLES_OK)) { |
| 1875 | ntfs_log_perror("Failed to enlarge attribute"); |
| 1876 | goto errno_set; |
| 1877 | } |
| 1878 | #endif |
| 1879 | /* resizing may change the compression mode */ |
| 1880 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
| 1881 | != const_cpu_to_le16(0); |
| 1882 | need_to.undo_data_size = 1; |
| 1883 | } |
| 1884 | /* |
| 1885 | * For compressed data, a single full block was allocated |
| 1886 | * to deal with compression, possibly in a previous call. |
| 1887 | * We are not able to process several blocks because |
| 1888 | * some clusters are freed after compression and |
| 1889 | * new allocations have to be done before proceeding, |
| 1890 | * so truncate the requested count if needed (big buffers). |
| 1891 | */ |
| 1892 | if (compressed) { |
| 1893 | fullcount = (pos | (na->compression_block_size - 1)) + 1 - pos; |
| 1894 | if (count > fullcount) |
| 1895 | count = fullcount; |
| 1896 | } |
| 1897 | old_initialized_size = na->initialized_size; |
| 1898 | /* If it is a resident attribute, write the data to the mft record. */ |
| 1899 | if (!NAttrNonResident(na)) { |
| 1900 | char *val; |
| 1901 | |
| 1902 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 1903 | if (!ctx) |
| 1904 | goto err_out; |
| 1905 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, |
| 1906 | 0, NULL, 0, ctx)) { |
| 1907 | ntfs_log_perror("%s: lookup failed", __FUNCTION__); |
| 1908 | goto err_out; |
| 1909 | } |
| 1910 | val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset); |
| 1911 | if (val < (char*)ctx->attr || val + |
| 1912 | le32_to_cpu(ctx->attr->value_length) > |
| 1913 | (char*)ctx->mrec + vol->mft_record_size) { |
| 1914 | errno = EIO; |
| 1915 | ntfs_log_perror("%s: Sanity check failed", __FUNCTION__); |
| 1916 | goto err_out; |
| 1917 | } |
| 1918 | memcpy(val + pos, b, count); |
| 1919 | if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, |
| 1920 | ctx->mrec)) { |
| 1921 | /* |
| 1922 | * NOTE: We are in a bad state at this moment. We have |
| 1923 | * dirtied the mft record but we failed to commit it to |
| 1924 | * disk. Since we have read the mft record ok before, |
| 1925 | * it is unlikely to fail writing it, so is ok to just |
| 1926 | * return error here... (AIA) |
| 1927 | */ |
| 1928 | ntfs_log_perror("%s: failed to write mft record", __FUNCTION__); |
| 1929 | goto err_out; |
| 1930 | } |
| 1931 | ntfs_attr_put_search_ctx(ctx); |
| 1932 | total = count; |
| 1933 | goto out; |
| 1934 | } |
| 1935 | |
| 1936 | /* Handle writes beyond initialized_size. */ |
| 1937 | |
| 1938 | if (pos + count > na->initialized_size) { |
| 1939 | #if PARTIAL_RUNLIST_UPDATING |
| 1940 | /* |
| 1941 | * When appending, we only need to map the end of the runlist, |
| 1942 | * starting at the last previously allocated run, so that |
| 1943 | * we are able a new one to it. |
| 1944 | * However, for compressed file, we need the full compression |
| 1945 | * block, which may be split in several extents. |
| 1946 | */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1947 | if (compressed && !NAttrDataAppending(na)) { |
| 1948 | if (ntfs_attr_map_whole_runlist(na)) |
| 1949 | goto err_out; |
| 1950 | } else { |
| 1951 | VCN block_begin; |
| 1952 | |
| 1953 | if (NAttrDataAppending(na) |
| 1954 | || (pos < na->initialized_size)) |
| 1955 | block_begin = pos >> vol->cluster_size_bits; |
| 1956 | else |
| 1957 | block_begin = na->initialized_size >> vol->cluster_size_bits; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1958 | |
| 1959 | if (compressed) |
| 1960 | block_begin &= -na->compression_block_clusters; |
| 1961 | if (block_begin) |
| 1962 | block_begin--; |
| 1963 | if (ntfs_attr_map_partial_runlist(na, block_begin)) |
| 1964 | goto err_out; |
| 1965 | if ((update_from == -1) || (block_begin < update_from)) |
| 1966 | update_from = block_begin; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1967 | } |
| 1968 | #else |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1969 | if (ntfs_attr_map_whole_runlist(na)) |
| 1970 | goto err_out; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 1971 | #endif |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 1972 | /* |
| 1973 | * For a compressed attribute, we must be sure there is an |
| 1974 | * available entry, and, when reopening a compressed file, |
| 1975 | * we may need to split a hole. So reserve the entries |
| 1976 | * before it gets too late. |
| 1977 | */ |
| 1978 | if (compressed) { |
| 1979 | na->rl = ntfs_rl_extend(na,na->rl,2); |
| 1980 | if (!na->rl) |
| 1981 | goto err_out; |
| 1982 | na->unused_runs = 2; |
| 1983 | } |
| 1984 | /* Set initialized_size to @pos + @count. */ |
| 1985 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 1986 | if (!ctx) |
| 1987 | goto err_out; |
| 1988 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, |
| 1989 | 0, NULL, 0, ctx)) |
| 1990 | goto err_out; |
| 1991 | |
| 1992 | /* If write starts beyond initialized_size, zero the gap. */ |
| 1993 | if (pos > na->initialized_size) |
| 1994 | if (ntfs_attr_fill_zero(na, na->initialized_size, |
| 1995 | pos - na->initialized_size)) |
| 1996 | goto err_out; |
| 1997 | |
| 1998 | ctx->attr->initialized_size = cpu_to_sle64(pos + count); |
| 1999 | /* fix data_size for compressed files */ |
| 2000 | if (compressed) { |
| 2001 | na->data_size = pos + count; |
| 2002 | ctx->attr->data_size = ctx->attr->initialized_size; |
| 2003 | } |
| 2004 | if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, |
| 2005 | ctx->mrec)) { |
| 2006 | /* |
| 2007 | * Undo the change in the in-memory copy and send it |
| 2008 | * back for writing. |
| 2009 | */ |
| 2010 | ctx->attr->initialized_size = |
| 2011 | cpu_to_sle64(old_initialized_size); |
| 2012 | ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, |
| 2013 | ctx->mrec); |
| 2014 | goto err_out; |
| 2015 | } |
| 2016 | na->initialized_size = pos + count; |
| 2017 | #if CACHE_NIDATA_SIZE |
| 2018 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
| 2019 | ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 |
| 2020 | : na->type == AT_DATA && na->name == AT_UNNAMED) { |
| 2021 | na->ni->data_size = na->data_size; |
| 2022 | if ((compressed || NAttrSparse(na)) |
| 2023 | && NAttrNonResident(na)) |
| 2024 | na->ni->allocated_size = na->compressed_size; |
| 2025 | else |
| 2026 | na->ni->allocated_size = na->allocated_size; |
| 2027 | set_nino_flag(na->ni,KnownSize); |
| 2028 | } |
| 2029 | #endif |
| 2030 | ntfs_attr_put_search_ctx(ctx); |
| 2031 | ctx = NULL; |
| 2032 | /* |
| 2033 | * NOTE: At this point the initialized_size in the mft record |
| 2034 | * has been updated BUT there is random data on disk thus if |
| 2035 | * we decide to abort, we MUST change the initialized_size |
| 2036 | * again. |
| 2037 | */ |
| 2038 | need_to.undo_initialized_size = 1; |
| 2039 | } |
| 2040 | /* Find the runlist element containing the vcn. */ |
| 2041 | rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); |
| 2042 | if (!rl) { |
| 2043 | /* |
| 2044 | * If the vcn is not present it is an out of bounds write. |
| 2045 | * However, we already extended the size of the attribute, |
| 2046 | * so getting this here must be an error of some kind. |
| 2047 | */ |
| 2048 | if (errno == ENOENT) { |
| 2049 | errno = EIO; |
| 2050 | ntfs_log_perror("%s: Failed to find VCN #3", __FUNCTION__); |
| 2051 | } |
| 2052 | goto err_out; |
| 2053 | } |
| 2054 | /* |
| 2055 | * Determine if there is compressed data in the current |
| 2056 | * compression block (when appending to an existing file). |
| 2057 | * If so, decompression will be needed, and the full block |
| 2058 | * must be allocated to be identified as uncompressed. |
| 2059 | * This comes in two variants, depending on whether |
| 2060 | * compression has saved at least one cluster. |
| 2061 | * The compressed size can never be over full size by |
| 2062 | * more than 485 (maximum for 15 compression blocks |
| 2063 | * compressed to 4098 and the last 3640 bytes compressed |
| 2064 | * to 3640 + 3640/8 = 4095, with 15*2 + 4095 - 3640 = 485) |
| 2065 | * This is less than the smallest cluster, so the hole is |
| 2066 | * is never beyond the cluster next to the position of |
| 2067 | * the first uncompressed byte to write. |
| 2068 | */ |
| 2069 | compressed_part = 0; |
| 2070 | if (compressed) { |
| 2071 | if ((rl->lcn == (LCN)LCN_HOLE) |
| 2072 | && wasnonresident) { |
| 2073 | if (rl->length < na->compression_block_clusters) |
| 2074 | /* |
| 2075 | * the needed block is in a hole smaller |
| 2076 | * than the compression block : we can use |
| 2077 | * it fully |
| 2078 | */ |
| 2079 | compressed_part |
| 2080 | = na->compression_block_clusters |
| 2081 | - rl->length; |
| 2082 | else { |
| 2083 | /* |
| 2084 | * the needed block is in a hole bigger |
| 2085 | * than the compression block : we must |
| 2086 | * split the hole and use it partially |
| 2087 | */ |
| 2088 | compressed_part = split_compressed_hole(na, |
| 2089 | &rl, pos, count, &update_from); |
| 2090 | } |
| 2091 | } else { |
| 2092 | if (rl->lcn >= 0) { |
| 2093 | /* |
| 2094 | * the needed block contains data, make |
| 2095 | * sure the full compression block is |
| 2096 | * allocated. Borrow from hole if needed |
| 2097 | */ |
| 2098 | compressed_part = borrow_from_hole(na, |
| 2099 | &rl, pos, count, &update_from, |
| 2100 | wasnonresident); |
| 2101 | } |
| 2102 | } |
| 2103 | |
| 2104 | if (compressed_part < 0) |
| 2105 | goto err_out; |
| 2106 | |
| 2107 | /* just making non-resident, so not yet compressed */ |
| 2108 | if (NAttrBeingNonResident(na) |
| 2109 | && (compressed_part < na->compression_block_clusters)) |
| 2110 | compressed_part = 0; |
| 2111 | } |
| 2112 | ofs = pos - (rl->vcn << vol->cluster_size_bits); |
| 2113 | /* |
| 2114 | * Scatter the data from the linear data buffer to the volume. Note, a |
| 2115 | * partial final vcn is taken care of by the @count capping of write |
| 2116 | * length. |
| 2117 | */ |
| 2118 | for (hole_end = 0; count; rl++, ofs = 0) { |
| 2119 | if (rl->lcn == LCN_RL_NOT_MAPPED) { |
| 2120 | rl = ntfs_attr_find_vcn(na, rl->vcn); |
| 2121 | if (!rl) { |
| 2122 | if (errno == ENOENT) { |
| 2123 | errno = EIO; |
| 2124 | ntfs_log_perror("%s: Failed to find VCN" |
| 2125 | " #4", __FUNCTION__); |
| 2126 | } |
| 2127 | goto rl_err_out; |
| 2128 | } |
| 2129 | /* Needed for case when runs merged. */ |
| 2130 | ofs = pos + total - (rl->vcn << vol->cluster_size_bits); |
| 2131 | } |
| 2132 | if (!rl->length) { |
| 2133 | errno = EIO; |
| 2134 | ntfs_log_perror("%s: Zero run length", __FUNCTION__); |
| 2135 | goto rl_err_out; |
| 2136 | } |
| 2137 | if (rl->lcn < (LCN)0) { |
| 2138 | hole_end = rl->vcn + rl->length; |
| 2139 | |
| 2140 | if (rl->lcn != (LCN)LCN_HOLE) { |
| 2141 | errno = EIO; |
| 2142 | ntfs_log_perror("%s: Unexpected LCN (%lld)", |
| 2143 | __FUNCTION__, |
| 2144 | (long long)rl->lcn); |
| 2145 | goto rl_err_out; |
| 2146 | } |
| 2147 | if (ntfs_attr_fill_hole(na, fullcount, &ofs, &rl, |
| 2148 | &update_from)) |
| 2149 | goto err_out; |
| 2150 | } |
| 2151 | if (compressed) { |
| 2152 | while (rl->length |
| 2153 | && (ofs >= (rl->length << vol->cluster_size_bits))) { |
| 2154 | ofs -= rl->length << vol->cluster_size_bits; |
| 2155 | rl++; |
| 2156 | } |
| 2157 | } |
| 2158 | |
| 2159 | /* It is a real lcn, write it to the volume. */ |
| 2160 | to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); |
| 2161 | retry: |
| 2162 | ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs " |
| 2163 | "%lld.\n", (long long)to_write, (long long)rl->vcn, |
| 2164 | (long long)rl->lcn, (long long)ofs); |
| 2165 | if (!NVolReadOnly(vol)) { |
| 2166 | |
| 2167 | s64 wpos = (rl->lcn << vol->cluster_size_bits) + ofs; |
| 2168 | s64 wend = (rl->vcn << vol->cluster_size_bits) + ofs + to_write; |
| 2169 | u32 bsize = vol->cluster_size; |
| 2170 | /* Byte size needed to zero fill a cluster */ |
| 2171 | s64 rounding = ((wend + bsize - 1) & ~(s64)(bsize - 1)) - wend; |
| 2172 | /** |
| 2173 | * Zero fill to cluster boundary if we're writing at the |
| 2174 | * end of the attribute or into an ex-sparse cluster. |
| 2175 | * This will cause the kernel not to seek and read disk |
| 2176 | * blocks during write(2) to fill the end of the buffer |
| 2177 | * which increases write speed by 2-10 fold typically. |
| 2178 | * |
| 2179 | * This is done even for compressed files, because |
| 2180 | * data is generally first written uncompressed. |
| 2181 | */ |
| 2182 | if (rounding && ((wend == na->initialized_size) || |
| 2183 | (wend < (hole_end << vol->cluster_size_bits)))){ |
| 2184 | |
| 2185 | char *cb; |
| 2186 | |
| 2187 | rounding += to_write; |
| 2188 | |
| 2189 | cb = ntfs_malloc(rounding); |
| 2190 | if (!cb) |
| 2191 | goto err_out; |
| 2192 | |
| 2193 | memcpy(cb, b, to_write); |
| 2194 | memset(cb + to_write, 0, rounding - to_write); |
| 2195 | |
| 2196 | if (compressed) { |
| 2197 | written = ntfs_compressed_pwrite(na, |
| 2198 | rl, wpos, ofs, to_write, |
| 2199 | rounding, cb, compressed_part, |
| 2200 | &update_from); |
| 2201 | } else { |
| 2202 | written = ntfs_pwrite(vol->dev, wpos, |
| 2203 | rounding, cb); |
| 2204 | if (written == rounding) |
| 2205 | written = to_write; |
| 2206 | } |
| 2207 | |
| 2208 | free(cb); |
| 2209 | } else { |
| 2210 | if (compressed) { |
| 2211 | written = ntfs_compressed_pwrite(na, |
| 2212 | rl, wpos, ofs, to_write, |
| 2213 | to_write, b, compressed_part, |
| 2214 | &update_from); |
| 2215 | } else |
| 2216 | written = ntfs_pwrite(vol->dev, wpos, |
| 2217 | to_write, b); |
| 2218 | } |
| 2219 | } else |
| 2220 | written = to_write; |
| 2221 | /* If everything ok, update progress counters and continue. */ |
| 2222 | if (written > 0) { |
| 2223 | total += written; |
| 2224 | count -= written; |
| 2225 | fullcount -= written; |
| 2226 | b = (const u8*)b + written; |
| 2227 | } |
| 2228 | if (written != to_write) { |
| 2229 | /* Partial write cannot be dealt with, stop there */ |
| 2230 | /* If the syscall was interrupted, try again. */ |
| 2231 | if (written == (s64)-1 && errno == EINTR) |
| 2232 | goto retry; |
| 2233 | if (!written) |
| 2234 | errno = EIO; |
| 2235 | goto rl_err_out; |
| 2236 | } |
| 2237 | compressed_part = 0; |
| 2238 | } |
| 2239 | done: |
| 2240 | if (ctx) |
| 2241 | ntfs_attr_put_search_ctx(ctx); |
| 2242 | /* |
| 2243 | * Update mapping pairs if needed. |
| 2244 | * For a compressed file, we try to make a partial update |
| 2245 | * of the mapping list. This makes a difference only if |
| 2246 | * inode extents were needed. |
| 2247 | */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 2248 | if (NAttrRunlistDirty(na)) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2249 | if (ntfs_attr_update_mapping_pairs(na, |
| 2250 | (update_from < 0 ? 0 : update_from))) { |
| 2251 | /* |
| 2252 | * FIXME: trying to recover by goto rl_err_out; |
| 2253 | * could cause driver hang by infinite looping. |
| 2254 | */ |
| 2255 | total = -1; |
| 2256 | goto out; |
| 2257 | } |
| 2258 | if (!wasnonresident) |
| 2259 | NAttrClearBeingNonResident(na); |
| 2260 | NAttrClearDataAppending(na); |
| 2261 | } |
| 2262 | out: |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2263 | return total; |
| 2264 | rl_err_out: |
| 2265 | eo = errno; |
| 2266 | if (total) { |
| 2267 | if (need_to.undo_initialized_size) { |
| 2268 | if (pos + total > na->initialized_size) |
| 2269 | goto done; |
| 2270 | /* |
| 2271 | * TODO: Need to try to change initialized_size. If it |
| 2272 | * succeeds goto done, otherwise goto err_out. (AIA) |
| 2273 | */ |
| 2274 | goto err_out; |
| 2275 | } |
| 2276 | goto done; |
| 2277 | } |
| 2278 | errno = eo; |
| 2279 | err_out: |
| 2280 | eo = errno; |
| 2281 | if (need_to.undo_initialized_size) { |
| 2282 | int err; |
| 2283 | |
| 2284 | err = 0; |
| 2285 | if (!ctx) { |
| 2286 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 2287 | if (!ctx) |
| 2288 | err = 1; |
| 2289 | } else |
| 2290 | ntfs_attr_reinit_search_ctx(ctx); |
| 2291 | if (!err) { |
| 2292 | err = ntfs_attr_lookup(na->type, na->name, |
| 2293 | na->name_len, 0, 0, NULL, 0, ctx); |
| 2294 | if (!err) { |
| 2295 | na->initialized_size = old_initialized_size; |
| 2296 | ctx->attr->initialized_size = cpu_to_sle64( |
| 2297 | old_initialized_size); |
| 2298 | err = ntfs_mft_record_write(vol, |
| 2299 | ctx->ntfs_ino->mft_no, |
| 2300 | ctx->mrec); |
| 2301 | } |
| 2302 | } |
| 2303 | if (err) { |
| 2304 | /* |
| 2305 | * FIXME: At this stage could try to recover by filling |
| 2306 | * old_initialized_size -> new_initialized_size with |
| 2307 | * data or at least zeroes. (AIA) |
| 2308 | */ |
| 2309 | ntfs_log_error("Eeek! Failed to recover from error. " |
| 2310 | "Leaving metadata in inconsistent " |
| 2311 | "state! Run chkdsk!\n"); |
| 2312 | } |
| 2313 | } |
| 2314 | if (ctx) |
| 2315 | ntfs_attr_put_search_ctx(ctx); |
| 2316 | /* Update mapping pairs if needed. */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 2317 | if (NAttrRunlistDirty(na)) |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2318 | ntfs_attr_update_mapping_pairs(na, 0); |
| 2319 | /* Restore original data_size if needed. */ |
| 2320 | if (need_to.undo_data_size |
| 2321 | && ntfs_attr_truncate_i(na, old_data_size, HOLES_OK)) |
| 2322 | ntfs_log_perror("Failed to restore data_size"); |
| 2323 | errno = eo; |
| 2324 | errno_set: |
| 2325 | total = -1; |
| 2326 | goto out; |
| 2327 | } |
| 2328 | |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 2329 | s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) |
| 2330 | { |
| 2331 | s64 total; |
| 2332 | s64 written; |
| 2333 | |
| 2334 | ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count " |
| 2335 | "0x%llx.\n", (long long)na->ni->mft_no, le32_to_cpu(na->type), |
| 2336 | (long long)pos, (long long)count); |
| 2337 | |
| 2338 | total = 0; |
| 2339 | if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { |
| 2340 | errno = EINVAL; |
| 2341 | written = -1; |
| 2342 | ntfs_log_perror("%s", __FUNCTION__); |
| 2343 | goto out; |
| 2344 | } |
| 2345 | |
| 2346 | /* |
| 2347 | * Compressed attributes may be written partially, so |
| 2348 | * we may have to iterate. |
| 2349 | */ |
| 2350 | do { |
| 2351 | written = ntfs_attr_pwrite_i(na, pos + total, |
| 2352 | count - total, (const u8*)b + total); |
| 2353 | if (written > 0) |
| 2354 | total += written; |
| 2355 | } while ((written > 0) && (total < count)); |
| 2356 | out : |
| 2357 | ntfs_log_leave("\n"); |
| 2358 | return (total > 0 ? total : written); |
| 2359 | } |
| 2360 | |
| 2361 | |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2362 | int ntfs_attr_pclose(ntfs_attr *na) |
| 2363 | { |
| 2364 | s64 ofs; |
| 2365 | int failed; |
| 2366 | BOOL ok = TRUE; |
| 2367 | VCN update_from = -1; |
| 2368 | ntfs_volume *vol; |
| 2369 | ntfs_attr_search_ctx *ctx = NULL; |
| 2370 | runlist_element *rl; |
| 2371 | int eo; |
| 2372 | int compressed_part; |
| 2373 | BOOL compressed; |
| 2374 | |
| 2375 | ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 2376 | (unsigned long long)na->ni->mft_no, |
| 2377 | le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2378 | |
| 2379 | if (!na || !na->ni || !na->ni->vol) { |
| 2380 | errno = EINVAL; |
| 2381 | ntfs_log_perror("%s", __FUNCTION__); |
| 2382 | goto errno_set; |
| 2383 | } |
| 2384 | vol = na->ni->vol; |
| 2385 | na->unused_runs = 0; |
| 2386 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
| 2387 | != const_cpu_to_le16(0); |
| 2388 | /* |
| 2389 | * Encrypted non-resident attributes are not supported. We return |
| 2390 | * access denied, which is what Windows NT4 does, too. |
| 2391 | */ |
| 2392 | if (NAttrEncrypted(na) && NAttrNonResident(na)) { |
| 2393 | errno = EACCES; |
| 2394 | goto errno_set; |
| 2395 | } |
| 2396 | /* If this is not a compressed attribute get out */ |
| 2397 | /* same if it is resident */ |
| 2398 | if (!compressed || !NAttrNonResident(na)) |
| 2399 | goto out; |
| 2400 | |
| 2401 | /* safety check : no recursion on close */ |
| 2402 | if (NAttrComprClosing(na)) { |
| 2403 | errno = EIO; |
| 2404 | ntfs_log_error("Bad ntfs_attr_pclose" |
| 2405 | " recursion on inode %lld\n", |
| 2406 | (long long)na->ni->mft_no); |
| 2407 | goto out; |
| 2408 | } |
| 2409 | NAttrSetComprClosing(na); |
| 2410 | /* |
| 2411 | * For a compressed attribute, we must be sure there are two |
| 2412 | * available entries, so reserve them before it gets too late. |
| 2413 | */ |
| 2414 | if (ntfs_attr_map_whole_runlist(na)) |
| 2415 | goto err_out; |
| 2416 | na->rl = ntfs_rl_extend(na,na->rl,2); |
| 2417 | if (!na->rl) |
| 2418 | goto err_out; |
| 2419 | na->unused_runs = 2; |
| 2420 | /* Find the runlist element containing the terminal vcn. */ |
| 2421 | rl = ntfs_attr_find_vcn(na, (na->initialized_size - 1) >> vol->cluster_size_bits); |
| 2422 | if (!rl) { |
| 2423 | /* |
| 2424 | * If the vcn is not present it is an out of bounds write. |
| 2425 | * However, we have already written the last byte uncompressed, |
| 2426 | * so getting this here must be an error of some kind. |
| 2427 | */ |
| 2428 | if (errno == ENOENT) { |
| 2429 | errno = EIO; |
| 2430 | ntfs_log_perror("%s: Failed to find VCN #5", __FUNCTION__); |
| 2431 | } |
| 2432 | goto err_out; |
| 2433 | } |
| 2434 | /* |
| 2435 | * Scatter the data from the linear data buffer to the volume. Note, a |
| 2436 | * partial final vcn is taken care of by the @count capping of write |
| 2437 | * length. |
| 2438 | */ |
| 2439 | compressed_part = 0; |
| 2440 | if (rl->lcn >= 0) { |
| 2441 | runlist_element *xrl; |
| 2442 | |
| 2443 | xrl = rl; |
| 2444 | do { |
| 2445 | xrl++; |
| 2446 | } while (xrl->lcn >= 0); |
| 2447 | compressed_part = (-xrl->length) |
| 2448 | & (na->compression_block_clusters - 1); |
| 2449 | } else |
| 2450 | if (rl->lcn == (LCN)LCN_HOLE) { |
| 2451 | if (rl->length < na->compression_block_clusters) |
| 2452 | compressed_part |
| 2453 | = na->compression_block_clusters |
| 2454 | - rl->length; |
| 2455 | else |
| 2456 | compressed_part |
| 2457 | = na->compression_block_clusters; |
| 2458 | } |
| 2459 | /* done, if the last block set was compressed */ |
| 2460 | if (compressed_part) |
| 2461 | goto out; |
| 2462 | |
| 2463 | ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits); |
| 2464 | |
| 2465 | if (rl->lcn == LCN_RL_NOT_MAPPED) { |
| 2466 | rl = ntfs_attr_find_vcn(na, rl->vcn); |
| 2467 | if (!rl) { |
| 2468 | if (errno == ENOENT) { |
| 2469 | errno = EIO; |
| 2470 | ntfs_log_perror("%s: Failed to find VCN" |
| 2471 | " #6", __FUNCTION__); |
| 2472 | } |
| 2473 | goto rl_err_out; |
| 2474 | } |
| 2475 | /* Needed for case when runs merged. */ |
| 2476 | ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits); |
| 2477 | } |
| 2478 | if (!rl->length) { |
| 2479 | errno = EIO; |
| 2480 | ntfs_log_perror("%s: Zero run length", __FUNCTION__); |
| 2481 | goto rl_err_out; |
| 2482 | } |
| 2483 | if (rl->lcn < (LCN)0) { |
| 2484 | if (rl->lcn != (LCN)LCN_HOLE) { |
| 2485 | errno = EIO; |
| 2486 | ntfs_log_perror("%s: Unexpected LCN (%lld)", |
| 2487 | __FUNCTION__, |
| 2488 | (long long)rl->lcn); |
| 2489 | goto rl_err_out; |
| 2490 | } |
| 2491 | |
| 2492 | if (ntfs_attr_fill_hole(na, (s64)0, &ofs, &rl, &update_from)) |
| 2493 | goto err_out; |
| 2494 | } |
| 2495 | while (rl->length |
| 2496 | && (ofs >= (rl->length << vol->cluster_size_bits))) { |
| 2497 | ofs -= rl->length << vol->cluster_size_bits; |
| 2498 | rl++; |
| 2499 | } |
| 2500 | |
| 2501 | retry: |
| 2502 | failed = 0; |
| 2503 | if (update_from < 0) update_from = 0; |
| 2504 | if (!NVolReadOnly(vol)) { |
| 2505 | failed = ntfs_compressed_close(na, rl, ofs, &update_from); |
| 2506 | #if CACHE_NIDATA_SIZE |
| 2507 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
| 2508 | ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 |
| 2509 | : na->type == AT_DATA && na->name == AT_UNNAMED) { |
| 2510 | na->ni->data_size = na->data_size; |
| 2511 | na->ni->allocated_size = na->compressed_size; |
| 2512 | set_nino_flag(na->ni,KnownSize); |
| 2513 | } |
| 2514 | #endif |
| 2515 | } |
| 2516 | if (failed) { |
| 2517 | /* If the syscall was interrupted, try again. */ |
| 2518 | if (errno == EINTR) |
| 2519 | goto retry; |
| 2520 | else |
| 2521 | goto rl_err_out; |
| 2522 | } |
| 2523 | if (ctx) |
| 2524 | ntfs_attr_put_search_ctx(ctx); |
| 2525 | /* Update mapping pairs if needed. */ |
| 2526 | if (NAttrFullyMapped(na)) |
| 2527 | if (ntfs_attr_update_mapping_pairs(na, update_from)) { |
| 2528 | /* |
| 2529 | * FIXME: trying to recover by goto rl_err_out; |
| 2530 | * could cause driver hang by infinite looping. |
| 2531 | */ |
| 2532 | ok = FALSE; |
| 2533 | goto out; |
| 2534 | } |
| 2535 | out: |
| 2536 | NAttrClearComprClosing(na); |
| 2537 | ntfs_log_leave("\n"); |
| 2538 | return (!ok); |
| 2539 | rl_err_out: |
| 2540 | /* |
| 2541 | * need not restore old sizes, only compressed_size |
| 2542 | * can have changed. It has been set according to |
| 2543 | * the current runlist while updating the mapping pairs, |
| 2544 | * and must be kept consistent with the runlists. |
| 2545 | */ |
| 2546 | err_out: |
| 2547 | eo = errno; |
| 2548 | if (ctx) |
| 2549 | ntfs_attr_put_search_ctx(ctx); |
| 2550 | /* Update mapping pairs if needed. */ |
| 2551 | if (NAttrFullyMapped(na)) |
| 2552 | ntfs_attr_update_mapping_pairs(na, 0); |
| 2553 | errno = eo; |
| 2554 | errno_set: |
| 2555 | ok = FALSE; |
| 2556 | goto out; |
| 2557 | } |
| 2558 | |
| 2559 | /** |
| 2560 | * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read |
| 2561 | * @na: multi sector transfer protected ntfs attribute to read from |
| 2562 | * @pos: byte position in the attribute to begin reading from |
| 2563 | * @bk_cnt: number of mst protected blocks to read |
| 2564 | * @bk_size: size of each mst protected block in bytes |
| 2565 | * @dst: output data buffer |
| 2566 | * |
| 2567 | * This function will read @bk_cnt blocks of size @bk_size bytes each starting |
| 2568 | * at offset @pos from the ntfs attribute @na into the data buffer @b. |
| 2569 | * |
| 2570 | * On success, the multi sector transfer fixups are applied and the number of |
| 2571 | * read blocks is returned. If this number is lower than @bk_cnt this means |
| 2572 | * that the read has either reached end of attribute or that an error was |
| 2573 | * encountered during the read so that the read is partial. 0 means end of |
| 2574 | * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0). |
| 2575 | * |
| 2576 | * On error and nothing has been read, return -1 with errno set appropriately |
| 2577 | * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid |
| 2578 | * arguments. |
| 2579 | * |
| 2580 | * NOTE: If an incomplete multi sector transfer is detected the magic is |
| 2581 | * changed to BAAD but no error is returned, i.e. it is possible that any of |
| 2582 | * the returned blocks have multi sector transfer errors. This should be |
| 2583 | * detected by the caller by checking each block with is_baad_recordp(&block). |
| 2584 | * The reasoning is that we want to fixup as many blocks as possible and we |
| 2585 | * want to return even bad ones to the caller so, e.g. in case of ntfsck, the |
| 2586 | * errors can be repaired. |
| 2587 | */ |
| 2588 | s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, |
| 2589 | const u32 bk_size, void *dst) |
| 2590 | { |
| 2591 | s64 br; |
| 2592 | u8 *end; |
| 2593 | BOOL warn; |
| 2594 | |
| 2595 | ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 2596 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2597 | (long long)pos); |
| 2598 | if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { |
| 2599 | errno = EINVAL; |
| 2600 | ntfs_log_perror("%s", __FUNCTION__); |
| 2601 | return -1; |
| 2602 | } |
| 2603 | br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst); |
| 2604 | if (br <= 0) |
| 2605 | return br; |
| 2606 | br /= bk_size; |
| 2607 | /* log errors unless silenced */ |
| 2608 | warn = !na->ni || !na->ni->vol || !NVolNoFixupWarn(na->ni->vol); |
| 2609 | for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst + |
| 2610 | bk_size) |
| 2611 | ntfs_mst_post_read_fixup_warn((NTFS_RECORD*)dst, bk_size, warn); |
| 2612 | /* Finally, return the number of blocks read. */ |
| 2613 | return br; |
| 2614 | } |
| 2615 | |
| 2616 | /** |
| 2617 | * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write |
| 2618 | * @na: multi sector transfer protected ntfs attribute to write to |
| 2619 | * @pos: position in the attribute to write to |
| 2620 | * @bk_cnt: number of mst protected blocks to write |
| 2621 | * @bk_size: size of each mst protected block in bytes |
| 2622 | * @src: data buffer to write to disk |
| 2623 | * |
| 2624 | * This function will write @bk_cnt blocks of size @bk_size bytes each from |
| 2625 | * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na |
| 2626 | * at position @pos. |
| 2627 | * |
| 2628 | * On success, return the number of successfully written blocks. If this number |
| 2629 | * is lower than @bk_cnt this means that an error was encountered during the |
| 2630 | * write so that the write is partial. 0 means nothing was written (also |
| 2631 | * return 0 when @bk_cnt or @bk_size are 0). |
| 2632 | * |
| 2633 | * On error and nothing has been written, return -1 with errno set |
| 2634 | * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case |
| 2635 | * of invalid arguments. |
| 2636 | * |
| 2637 | * NOTE: We mst protect the data, write it, then mst deprotect it using a quick |
| 2638 | * deprotect algorithm (no checking). This saves us from making a copy before |
| 2639 | * the write and at the same time causes the usn to be incremented in the |
| 2640 | * buffer. This conceptually fits in better with the idea that cached data is |
| 2641 | * always deprotected and protection is performed when the data is actually |
| 2642 | * going to hit the disk and the cache is immediately deprotected again |
| 2643 | * simulating an mst read on the written data. This way cache coherency is |
| 2644 | * achieved. |
| 2645 | */ |
| 2646 | s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt, |
| 2647 | const u32 bk_size, void *src) |
| 2648 | { |
| 2649 | s64 written, i; |
| 2650 | |
| 2651 | ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 2652 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2653 | (long long)pos); |
| 2654 | if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { |
| 2655 | errno = EINVAL; |
| 2656 | return -1; |
| 2657 | } |
| 2658 | if (!bk_cnt) |
| 2659 | return 0; |
| 2660 | /* Prepare data for writing. */ |
| 2661 | for (i = 0; i < bk_cnt; ++i) { |
| 2662 | int err; |
| 2663 | |
| 2664 | err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) |
| 2665 | ((u8*)src + i * bk_size), bk_size); |
| 2666 | if (err < 0) { |
| 2667 | /* Abort write at this position. */ |
| 2668 | ntfs_log_perror("%s #1", __FUNCTION__); |
| 2669 | if (!i) |
| 2670 | return err; |
| 2671 | bk_cnt = i; |
| 2672 | break; |
| 2673 | } |
| 2674 | } |
| 2675 | /* Write the prepared data. */ |
| 2676 | written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, src); |
| 2677 | if (written <= 0) { |
| 2678 | ntfs_log_perror("%s: written=%lld", __FUNCTION__, |
| 2679 | (long long)written); |
| 2680 | } |
| 2681 | /* Quickly deprotect the data again. */ |
| 2682 | for (i = 0; i < bk_cnt; ++i) |
| 2683 | ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)src + i * |
| 2684 | bk_size)); |
| 2685 | if (written <= 0) |
| 2686 | return written; |
| 2687 | /* Finally, return the number of complete blocks written. */ |
| 2688 | return written / bk_size; |
| 2689 | } |
| 2690 | |
| 2691 | /** |
| 2692 | * ntfs_attr_find - find (next) attribute in mft record |
| 2693 | * @type: attribute type to find |
| 2694 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
| 2695 | * @name_len: attribute name length (only needed if @name present) |
| 2696 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
| 2697 | * @val: attribute value to find (optional, resident attributes only) |
| 2698 | * @val_len: attribute value length |
| 2699 | * @ctx: search context with mft record and attribute to search from |
| 2700 | * |
| 2701 | * You shouldn't need to call this function directly. Use lookup_attr() instead. |
| 2702 | * |
| 2703 | * ntfs_attr_find() takes a search context @ctx as parameter and searches the |
| 2704 | * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an |
| 2705 | * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() |
| 2706 | * returns 0 and @ctx->attr will point to the found attribute. |
| 2707 | * |
| 2708 | * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and |
| 2709 | * @ctx->attr will point to the attribute before which the attribute being |
| 2710 | * searched for would need to be inserted if such an action were to be desired. |
| 2711 | * |
| 2712 | * On actual error, ntfs_attr_find() returns -1 with errno set to the error |
| 2713 | * code but not to ENOENT. In this case @ctx->attr is undefined and in |
| 2714 | * particular do not rely on it not changing. |
| 2715 | * |
| 2716 | * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it |
| 2717 | * is FALSE, the search begins after @ctx->attr. |
| 2718 | * |
| 2719 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
| 2720 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
| 2721 | * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to |
| 2722 | * indicate that there are no more entries. During the enumeration, each |
| 2723 | * successful call of ntfs_attr_find() will return the next attribute in the |
| 2724 | * mft record @ctx->mrec. |
| 2725 | * |
| 2726 | * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. |
| 2727 | * AT_END is not a valid attribute, its length is zero for example, thus it is |
| 2728 | * safer to return error instead of success in this case. This also allows us |
| 2729 | * to interoperate cleanly with ntfs_external_attr_find(). |
| 2730 | * |
| 2731 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
| 2732 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
| 2733 | * match both named and unnamed attributes. |
| 2734 | * |
| 2735 | * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and |
| 2736 | * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record |
| 2737 | * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at |
| 2738 | * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case |
| 2739 | * sensitive. When @name is present, @name_len is the @name length in Unicode |
| 2740 | * characters. |
| 2741 | * |
| 2742 | * If @name is not present (NULL), we assume that the unnamed attribute is |
| 2743 | * being searched for. |
| 2744 | * |
| 2745 | * Finally, the resident attribute value @val is looked for, if present. |
| 2746 | * If @val is not present (NULL), @val_len is ignored. |
| 2747 | * |
| 2748 | * ntfs_attr_find() only searches the specified mft record and it ignores the |
| 2749 | * presence of an attribute list attribute (unless it is the one being searched |
| 2750 | * for, obviously). If you need to take attribute lists into consideration, use |
| 2751 | * ntfs_attr_lookup() instead (see below). This also means that you cannot use |
| 2752 | * ntfs_attr_find() to search for extent records of non-resident attributes, as |
| 2753 | * extents with lowest_vcn != 0 are usually described by the attribute list |
| 2754 | * attribute only. - Note that it is possible that the first extent is only in |
| 2755 | * the attribute list while the last extent is in the base mft record, so don't |
| 2756 | * rely on being able to find the first extent in the base mft record. |
| 2757 | * |
| 2758 | * Warning: Never use @val when looking for attribute types which can be |
| 2759 | * non-resident as this most likely will result in a crash! |
| 2760 | */ |
| 2761 | static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, |
| 2762 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
| 2763 | const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) |
| 2764 | { |
| 2765 | ATTR_RECORD *a; |
| 2766 | ntfs_volume *vol; |
| 2767 | ntfschar *upcase; |
| 2768 | u32 upcase_len; |
| 2769 | |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 2770 | ntfs_log_trace("attribute type 0x%x.\n", le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2771 | |
| 2772 | if (ctx->ntfs_ino) { |
| 2773 | vol = ctx->ntfs_ino->vol; |
| 2774 | upcase = vol->upcase; |
| 2775 | upcase_len = vol->upcase_len; |
| 2776 | } else { |
| 2777 | if (name && name != AT_UNNAMED) { |
| 2778 | errno = EINVAL; |
| 2779 | ntfs_log_perror("%s", __FUNCTION__); |
| 2780 | return -1; |
| 2781 | } |
| 2782 | vol = NULL; |
| 2783 | upcase = NULL; |
| 2784 | upcase_len = 0; |
| 2785 | } |
| 2786 | /* |
| 2787 | * Iterate over attributes in mft record starting at @ctx->attr, or the |
| 2788 | * attribute following that, if @ctx->is_first is TRUE. |
| 2789 | */ |
| 2790 | if (ctx->is_first) { |
| 2791 | a = ctx->attr; |
| 2792 | ctx->is_first = FALSE; |
| 2793 | } else |
| 2794 | a = (ATTR_RECORD*)((char*)ctx->attr + |
| 2795 | le32_to_cpu(ctx->attr->length)); |
| 2796 | for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) { |
| 2797 | if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec + |
| 2798 | le32_to_cpu(ctx->mrec->bytes_allocated)) |
| 2799 | break; |
| 2800 | ctx->attr = a; |
| 2801 | if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > |
| 2802 | le32_to_cpu(type))) || |
| 2803 | (a->type == AT_END)) { |
| 2804 | errno = ENOENT; |
| 2805 | return -1; |
| 2806 | } |
| 2807 | if (!a->length) |
| 2808 | break; |
| 2809 | /* If this is an enumeration return this attribute. */ |
| 2810 | if (type == AT_UNUSED) |
| 2811 | return 0; |
| 2812 | if (a->type != type) |
| 2813 | continue; |
| 2814 | /* |
| 2815 | * If @name is AT_UNNAMED we want an unnamed attribute. |
| 2816 | * If @name is present, compare the two names. |
| 2817 | * Otherwise, match any attribute. |
| 2818 | */ |
| 2819 | if (name == AT_UNNAMED) { |
| 2820 | /* The search failed if the found attribute is named. */ |
| 2821 | if (a->name_length) { |
| 2822 | errno = ENOENT; |
| 2823 | return -1; |
| 2824 | } |
| 2825 | } else { |
| 2826 | register int rc; |
| 2827 | if (name && ((rc = ntfs_names_full_collate(name, |
| 2828 | name_len, (ntfschar*)((char*)a + |
| 2829 | le16_to_cpu(a->name_offset)), |
| 2830 | a->name_length, ic, |
| 2831 | upcase, upcase_len)))) { |
| 2832 | /* |
| 2833 | * If @name collates before a->name, |
| 2834 | * there is no matching attribute. |
| 2835 | */ |
| 2836 | if (rc < 0) { |
| 2837 | errno = ENOENT; |
| 2838 | return -1; |
| 2839 | } |
| 2840 | /* If the strings are not equal, continue search. */ |
| 2841 | continue; |
| 2842 | } |
| 2843 | } |
| 2844 | /* |
| 2845 | * The names match or @name not present and attribute is |
| 2846 | * unnamed. If no @val specified, we have found the attribute |
| 2847 | * and are done. |
| 2848 | */ |
| 2849 | if (!val) |
| 2850 | return 0; |
| 2851 | /* @val is present; compare values. */ |
| 2852 | else { |
| 2853 | register int rc; |
| 2854 | |
| 2855 | rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset), |
| 2856 | min(val_len, |
| 2857 | le32_to_cpu(a->value_length))); |
| 2858 | /* |
| 2859 | * If @val collates before the current attribute's |
| 2860 | * value, there is no matching attribute. |
| 2861 | */ |
| 2862 | if (!rc) { |
| 2863 | register u32 avl; |
| 2864 | avl = le32_to_cpu(a->value_length); |
| 2865 | if (val_len == avl) |
| 2866 | return 0; |
| 2867 | if (val_len < avl) { |
| 2868 | errno = ENOENT; |
| 2869 | return -1; |
| 2870 | } |
| 2871 | } else if (rc < 0) { |
| 2872 | errno = ENOENT; |
| 2873 | return -1; |
| 2874 | } |
| 2875 | } |
| 2876 | } |
| 2877 | errno = EIO; |
| 2878 | ntfs_log_perror("%s: Corrupt inode (%lld)", __FUNCTION__, |
| 2879 | ctx->ntfs_ino ? (long long)ctx->ntfs_ino->mft_no : -1); |
| 2880 | return -1; |
| 2881 | } |
| 2882 | |
| 2883 | void ntfs_attr_name_free(char **name) |
| 2884 | { |
| 2885 | if (*name) { |
| 2886 | free(*name); |
| 2887 | *name = NULL; |
| 2888 | } |
| 2889 | } |
| 2890 | |
| 2891 | char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len) |
| 2892 | { |
| 2893 | char *name = NULL; |
| 2894 | int name_len; |
| 2895 | |
| 2896 | name_len = ntfs_ucstombs(uname, uname_len, &name, 0); |
| 2897 | if (name_len < 0) { |
| 2898 | ntfs_log_perror("ntfs_ucstombs"); |
| 2899 | return NULL; |
| 2900 | |
| 2901 | } else if (name_len > 0) |
| 2902 | return name; |
| 2903 | |
| 2904 | ntfs_attr_name_free(&name); |
| 2905 | return NULL; |
| 2906 | } |
| 2907 | |
| 2908 | /** |
| 2909 | * ntfs_external_attr_find - find an attribute in the attribute list of an inode |
| 2910 | * @type: attribute type to find |
| 2911 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
| 2912 | * @name_len: attribute name length (only needed if @name present) |
| 2913 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
| 2914 | * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) |
| 2915 | * @val: attribute value to find (optional, resident attributes only) |
| 2916 | * @val_len: attribute value length |
| 2917 | * @ctx: search context with mft record and attribute to search from |
| 2918 | * |
| 2919 | * You shouldn't need to call this function directly. Use ntfs_attr_lookup() |
| 2920 | * instead. |
| 2921 | * |
| 2922 | * Find an attribute by searching the attribute list for the corresponding |
| 2923 | * attribute list entry. Having found the entry, map the mft record for read |
| 2924 | * if the attribute is in a different mft record/inode, find the attribute in |
| 2925 | * there and return it. |
| 2926 | * |
| 2927 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
| 2928 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
| 2929 | * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to |
| 2930 | * ENOENT to indicate that there are no more entries. During the enumeration, |
| 2931 | * each successful call of ntfs_external_attr_find() will return the next |
| 2932 | * attribute described by the attribute list of the base mft record described |
| 2933 | * by the search context @ctx. |
| 2934 | * |
| 2935 | * If @type is AT_END, seek to the end of the base mft record ignoring the |
| 2936 | * attribute list completely and return -1 with errno set to ENOENT. AT_END is |
| 2937 | * not a valid attribute, its length is zero for example, thus it is safer to |
| 2938 | * return error instead of success in this case. |
| 2939 | * |
| 2940 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
| 2941 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
| 2942 | * match both named and unnamed attributes. |
| 2943 | * |
| 2944 | * On first search @ctx->ntfs_ino must be the inode of the base mft record and |
| 2945 | * @ctx must have been obtained from a call to ntfs_attr_get_search_ctx(). |
| 2946 | * On subsequent calls, @ctx->ntfs_ino can be any extent inode, too |
| 2947 | * (@ctx->base_ntfs_ino is then the base inode). |
| 2948 | * |
| 2949 | * After finishing with the attribute/mft record you need to call |
| 2950 | * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any |
| 2951 | * mapped extent inodes, etc). |
| 2952 | * |
| 2953 | * Return 0 if the search was successful and -1 if not, with errno set to the |
| 2954 | * error code. |
| 2955 | * |
| 2956 | * On success, @ctx->attr is the found attribute, it is in mft record |
| 2957 | * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this |
| 2958 | * attribute with @ctx->base_* being the base mft record to which @ctx->attr |
| 2959 | * belongs. |
| 2960 | * |
| 2961 | * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the |
| 2962 | * attribute which collates just after the attribute being searched for in the |
| 2963 | * base ntfs inode, i.e. if one wants to add the attribute to the mft record |
| 2964 | * this is the correct place to insert it into, and if there is not enough |
| 2965 | * space, the attribute should be placed in an extent mft record. |
| 2966 | * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list |
| 2967 | * at which the new attribute's attribute list entry should be inserted. The |
| 2968 | * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. |
| 2969 | * The only exception to this is when @type is AT_END, in which case |
| 2970 | * @ctx->al_entry is set to NULL also (see above). |
| 2971 | * |
| 2972 | * The following error codes are defined: |
| 2973 | * ENOENT Attribute not found, not an error as such. |
| 2974 | * EINVAL Invalid arguments. |
| 2975 | * EIO I/O error or corrupt data structures found. |
| 2976 | * ENOMEM Not enough memory to allocate necessary buffers. |
| 2977 | */ |
| 2978 | static int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name, |
| 2979 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
| 2980 | const VCN lowest_vcn, const u8 *val, const u32 val_len, |
| 2981 | ntfs_attr_search_ctx *ctx) |
| 2982 | { |
| 2983 | ntfs_inode *base_ni, *ni; |
| 2984 | ntfs_volume *vol; |
| 2985 | ATTR_LIST_ENTRY *al_entry, *next_al_entry; |
| 2986 | u8 *al_start, *al_end; |
| 2987 | ATTR_RECORD *a; |
| 2988 | ntfschar *al_name; |
| 2989 | u32 al_name_len; |
| 2990 | BOOL is_first_search = FALSE; |
| 2991 | |
| 2992 | ni = ctx->ntfs_ino; |
| 2993 | base_ni = ctx->base_ntfs_ino; |
| 2994 | ntfs_log_trace("Entering for inode %lld, attribute type 0x%x.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 2995 | (unsigned long long)ni->mft_no, le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 2996 | if (!base_ni) { |
| 2997 | /* First call happens with the base mft record. */ |
| 2998 | base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino; |
| 2999 | ctx->base_mrec = ctx->mrec; |
| 3000 | } |
| 3001 | if (ni == base_ni) |
| 3002 | ctx->base_attr = ctx->attr; |
| 3003 | if (type == AT_END) |
| 3004 | goto not_found; |
| 3005 | vol = base_ni->vol; |
| 3006 | al_start = base_ni->attr_list; |
| 3007 | al_end = al_start + base_ni->attr_list_size; |
| 3008 | if (!ctx->al_entry) { |
| 3009 | ctx->al_entry = (ATTR_LIST_ENTRY*)al_start; |
| 3010 | is_first_search = TRUE; |
| 3011 | } |
| 3012 | /* |
| 3013 | * Iterate over entries in attribute list starting at @ctx->al_entry, |
| 3014 | * or the entry following that, if @ctx->is_first is TRUE. |
| 3015 | */ |
| 3016 | if (ctx->is_first) { |
| 3017 | al_entry = ctx->al_entry; |
| 3018 | ctx->is_first = FALSE; |
| 3019 | /* |
| 3020 | * If an enumeration and the first attribute is higher than |
| 3021 | * the attribute list itself, need to return the attribute list |
| 3022 | * attribute. |
| 3023 | */ |
| 3024 | if ((type == AT_UNUSED) && is_first_search && |
| 3025 | le32_to_cpu(al_entry->type) > |
| 3026 | le32_to_cpu(AT_ATTRIBUTE_LIST)) |
| 3027 | goto find_attr_list_attr; |
| 3028 | } else { |
| 3029 | al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry + |
| 3030 | le16_to_cpu(ctx->al_entry->length)); |
| 3031 | /* |
| 3032 | * If this is an enumeration and the attribute list attribute |
| 3033 | * is the next one in the enumeration sequence, just return the |
| 3034 | * attribute list attribute from the base mft record as it is |
| 3035 | * not listed in the attribute list itself. |
| 3036 | */ |
| 3037 | if ((type == AT_UNUSED) && le32_to_cpu(ctx->al_entry->type) < |
| 3038 | le32_to_cpu(AT_ATTRIBUTE_LIST) && |
| 3039 | le32_to_cpu(al_entry->type) > |
| 3040 | le32_to_cpu(AT_ATTRIBUTE_LIST)) { |
| 3041 | int rc; |
| 3042 | find_attr_list_attr: |
| 3043 | |
| 3044 | /* Check for bogus calls. */ |
| 3045 | if (name || name_len || val || val_len || lowest_vcn) { |
| 3046 | errno = EINVAL; |
| 3047 | ntfs_log_perror("%s", __FUNCTION__); |
| 3048 | return -1; |
| 3049 | } |
| 3050 | |
| 3051 | /* We want the base record. */ |
| 3052 | ctx->ntfs_ino = base_ni; |
| 3053 | ctx->mrec = ctx->base_mrec; |
| 3054 | ctx->is_first = TRUE; |
| 3055 | /* Sanity checks are performed elsewhere. */ |
| 3056 | ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + |
| 3057 | le16_to_cpu(ctx->mrec->attrs_offset)); |
| 3058 | |
| 3059 | /* Find the attribute list attribute. */ |
| 3060 | rc = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0, |
| 3061 | IGNORE_CASE, NULL, 0, ctx); |
| 3062 | |
| 3063 | /* |
| 3064 | * Setup the search context so the correct |
| 3065 | * attribute is returned next time round. |
| 3066 | */ |
| 3067 | ctx->al_entry = al_entry; |
| 3068 | ctx->is_first = TRUE; |
| 3069 | |
| 3070 | /* Got it. Done. */ |
| 3071 | if (!rc) |
| 3072 | return 0; |
| 3073 | |
| 3074 | /* Error! If other than not found return it. */ |
| 3075 | if (errno != ENOENT) |
| 3076 | return rc; |
| 3077 | |
| 3078 | /* Not found?!? Absurd! */ |
| 3079 | errno = EIO; |
| 3080 | ntfs_log_error("Attribute list wasn't found"); |
| 3081 | return -1; |
| 3082 | } |
| 3083 | } |
| 3084 | for (;; al_entry = next_al_entry) { |
| 3085 | /* Out of bounds check. */ |
| 3086 | if ((u8*)al_entry < base_ni->attr_list || |
| 3087 | (u8*)al_entry > al_end) |
| 3088 | break; /* Inode is corrupt. */ |
| 3089 | ctx->al_entry = al_entry; |
| 3090 | /* Catch the end of the attribute list. */ |
| 3091 | if ((u8*)al_entry == al_end) |
| 3092 | goto not_found; |
| 3093 | if (!al_entry->length) |
| 3094 | break; |
| 3095 | if ((u8*)al_entry + 6 > al_end || (u8*)al_entry + |
| 3096 | le16_to_cpu(al_entry->length) > al_end) |
| 3097 | break; |
| 3098 | next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + |
| 3099 | le16_to_cpu(al_entry->length)); |
| 3100 | if (type != AT_UNUSED) { |
| 3101 | if (le32_to_cpu(al_entry->type) > le32_to_cpu(type)) |
| 3102 | goto not_found; |
| 3103 | if (type != al_entry->type) |
| 3104 | continue; |
| 3105 | } |
| 3106 | al_name_len = al_entry->name_length; |
| 3107 | al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset); |
| 3108 | /* |
| 3109 | * If !@type we want the attribute represented by this |
| 3110 | * attribute list entry. |
| 3111 | */ |
| 3112 | if (type == AT_UNUSED) |
| 3113 | goto is_enumeration; |
| 3114 | /* |
| 3115 | * If @name is AT_UNNAMED we want an unnamed attribute. |
| 3116 | * If @name is present, compare the two names. |
| 3117 | * Otherwise, match any attribute. |
| 3118 | */ |
| 3119 | if (name == AT_UNNAMED) { |
| 3120 | if (al_name_len) |
| 3121 | goto not_found; |
| 3122 | } else { |
| 3123 | int rc; |
| 3124 | |
| 3125 | if (name && ((rc = ntfs_names_full_collate(name, |
| 3126 | name_len, al_name, al_name_len, ic, |
| 3127 | vol->upcase, vol->upcase_len)))) { |
| 3128 | |
| 3129 | /* |
| 3130 | * If @name collates before al_name, |
| 3131 | * there is no matching attribute. |
| 3132 | */ |
| 3133 | if (rc < 0) |
| 3134 | goto not_found; |
| 3135 | /* If the strings are not equal, continue search. */ |
| 3136 | continue; |
| 3137 | } |
| 3138 | } |
| 3139 | /* |
| 3140 | * The names match or @name not present and attribute is |
| 3141 | * unnamed. Now check @lowest_vcn. Continue search if the |
| 3142 | * next attribute list entry still fits @lowest_vcn. Otherwise |
| 3143 | * we have reached the right one or the search has failed. |
| 3144 | */ |
| 3145 | if (lowest_vcn && (u8*)next_al_entry >= al_start && |
| 3146 | (u8*)next_al_entry + 6 < al_end && |
| 3147 | (u8*)next_al_entry + le16_to_cpu( |
| 3148 | next_al_entry->length) <= al_end && |
| 3149 | sle64_to_cpu(next_al_entry->lowest_vcn) <= |
| 3150 | lowest_vcn && |
| 3151 | next_al_entry->type == al_entry->type && |
| 3152 | next_al_entry->name_length == al_name_len && |
| 3153 | ntfs_names_are_equal((ntfschar*)((char*) |
| 3154 | next_al_entry + |
| 3155 | next_al_entry->name_offset), |
| 3156 | next_al_entry->name_length, |
| 3157 | al_name, al_name_len, CASE_SENSITIVE, |
| 3158 | vol->upcase, vol->upcase_len)) |
| 3159 | continue; |
| 3160 | is_enumeration: |
| 3161 | if (MREF_LE(al_entry->mft_reference) == ni->mft_no) { |
| 3162 | if (MSEQNO_LE(al_entry->mft_reference) != |
| 3163 | le16_to_cpu( |
| 3164 | ni->mrec->sequence_number)) { |
| 3165 | ntfs_log_error("Found stale mft reference in " |
| 3166 | "attribute list!\n"); |
| 3167 | break; |
| 3168 | } |
| 3169 | } else { /* Mft references do not match. */ |
| 3170 | /* Do we want the base record back? */ |
| 3171 | if (MREF_LE(al_entry->mft_reference) == |
| 3172 | base_ni->mft_no) { |
| 3173 | ni = ctx->ntfs_ino = base_ni; |
| 3174 | ctx->mrec = ctx->base_mrec; |
| 3175 | } else { |
| 3176 | /* We want an extent record. */ |
| 3177 | ni = ntfs_extent_inode_open(base_ni, |
| 3178 | al_entry->mft_reference); |
| 3179 | if (!ni) |
| 3180 | break; |
| 3181 | ctx->ntfs_ino = ni; |
| 3182 | ctx->mrec = ni->mrec; |
| 3183 | } |
| 3184 | } |
| 3185 | a = ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec + |
| 3186 | le16_to_cpu(ctx->mrec->attrs_offset)); |
| 3187 | /* |
| 3188 | * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the |
| 3189 | * mft record containing the attribute represented by the |
| 3190 | * current al_entry. |
| 3191 | * |
| 3192 | * We could call into ntfs_attr_find() to find the right |
| 3193 | * attribute in this mft record but this would be less |
| 3194 | * efficient and not quite accurate as ntfs_attr_find() ignores |
| 3195 | * the attribute instance numbers for example which become |
| 3196 | * important when one plays with attribute lists. Also, because |
| 3197 | * a proper match has been found in the attribute list entry |
| 3198 | * above, the comparison can now be optimized. So it is worth |
| 3199 | * re-implementing a simplified ntfs_attr_find() here. |
| 3200 | * |
| 3201 | * Use a manual loop so we can still use break and continue |
| 3202 | * with the same meanings as above. |
| 3203 | */ |
| 3204 | do_next_attr_loop: |
| 3205 | if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec + |
| 3206 | le32_to_cpu(ctx->mrec->bytes_allocated)) |
| 3207 | break; |
| 3208 | if (a->type == AT_END) |
| 3209 | continue; |
| 3210 | if (!a->length) |
| 3211 | break; |
| 3212 | if (al_entry->instance != a->instance) |
| 3213 | goto do_next_attr; |
| 3214 | /* |
| 3215 | * If the type and/or the name are/is mismatched between the |
| 3216 | * attribute list entry and the attribute record, there is |
| 3217 | * corruption so we break and return error EIO. |
| 3218 | */ |
| 3219 | if (al_entry->type != a->type) |
| 3220 | break; |
| 3221 | if (!ntfs_names_are_equal((ntfschar*)((char*)a + |
| 3222 | le16_to_cpu(a->name_offset)), |
| 3223 | a->name_length, al_name, |
| 3224 | al_name_len, CASE_SENSITIVE, |
| 3225 | vol->upcase, vol->upcase_len)) |
| 3226 | break; |
| 3227 | ctx->attr = a; |
| 3228 | /* |
| 3229 | * If no @val specified or @val specified and it matches, we |
| 3230 | * have found it! Also, if !@type, it is an enumeration, so we |
| 3231 | * want the current attribute. |
| 3232 | */ |
| 3233 | if ((type == AT_UNUSED) || !val || (!a->non_resident && |
| 3234 | le32_to_cpu(a->value_length) == val_len && |
| 3235 | !memcmp((char*)a + le16_to_cpu(a->value_offset), |
| 3236 | val, val_len))) { |
| 3237 | return 0; |
| 3238 | } |
| 3239 | do_next_attr: |
| 3240 | /* Proceed to the next attribute in the current mft record. */ |
| 3241 | a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length)); |
| 3242 | goto do_next_attr_loop; |
| 3243 | } |
| 3244 | if (ni != base_ni) { |
| 3245 | ctx->ntfs_ino = base_ni; |
| 3246 | ctx->mrec = ctx->base_mrec; |
| 3247 | ctx->attr = ctx->base_attr; |
| 3248 | } |
| 3249 | errno = EIO; |
| 3250 | ntfs_log_perror("Inode is corrupt (%lld)", (long long)base_ni->mft_no); |
| 3251 | return -1; |
| 3252 | not_found: |
| 3253 | /* |
| 3254 | * If we were looking for AT_END or we were enumerating and reached the |
| 3255 | * end, we reset the search context @ctx and use ntfs_attr_find() to |
| 3256 | * seek to the end of the base mft record. |
| 3257 | */ |
| 3258 | if (type == AT_UNUSED || type == AT_END) { |
| 3259 | ntfs_attr_reinit_search_ctx(ctx); |
| 3260 | return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len, |
| 3261 | ctx); |
| 3262 | } |
| 3263 | /* |
| 3264 | * The attribute wasn't found. Before we return, we want to ensure |
| 3265 | * @ctx->mrec and @ctx->attr indicate the position at which the |
| 3266 | * attribute should be inserted in the base mft record. Since we also |
| 3267 | * want to preserve @ctx->al_entry we cannot reinitialize the search |
| 3268 | * context using ntfs_attr_reinit_search_ctx() as this would set |
| 3269 | * @ctx->al_entry to NULL. Thus we do the necessary bits manually (see |
| 3270 | * ntfs_attr_init_search_ctx() below). Note, we _only_ preserve |
| 3271 | * @ctx->al_entry as the remaining fields (base_*) are identical to |
| 3272 | * their non base_ counterparts and we cannot set @ctx->base_attr |
| 3273 | * correctly yet as we do not know what @ctx->attr will be set to by |
| 3274 | * the call to ntfs_attr_find() below. |
| 3275 | */ |
| 3276 | ctx->mrec = ctx->base_mrec; |
| 3277 | ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + |
| 3278 | le16_to_cpu(ctx->mrec->attrs_offset)); |
| 3279 | ctx->is_first = TRUE; |
| 3280 | ctx->ntfs_ino = ctx->base_ntfs_ino; |
| 3281 | ctx->base_ntfs_ino = NULL; |
| 3282 | ctx->base_mrec = NULL; |
| 3283 | ctx->base_attr = NULL; |
| 3284 | /* |
| 3285 | * In case there are multiple matches in the base mft record, need to |
| 3286 | * keep enumerating until we get an attribute not found response (or |
| 3287 | * another error), otherwise we would keep returning the same attribute |
| 3288 | * over and over again and all programs using us for enumeration would |
| 3289 | * lock up in a tight loop. |
| 3290 | */ |
| 3291 | { |
| 3292 | int ret; |
| 3293 | |
| 3294 | do { |
| 3295 | ret = ntfs_attr_find(type, name, name_len, ic, val, |
| 3296 | val_len, ctx); |
| 3297 | } while (!ret); |
| 3298 | return ret; |
| 3299 | } |
| 3300 | } |
| 3301 | |
| 3302 | /** |
| 3303 | * ntfs_attr_lookup - find an attribute in an ntfs inode |
| 3304 | * @type: attribute type to find |
| 3305 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
| 3306 | * @name_len: attribute name length (only needed if @name present) |
| 3307 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
| 3308 | * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) |
| 3309 | * @val: attribute value to find (optional, resident attributes only) |
| 3310 | * @val_len: attribute value length |
| 3311 | * @ctx: search context with mft record and attribute to search from |
| 3312 | * |
| 3313 | * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must |
| 3314 | * be the base mft record and @ctx must have been obtained from a call to |
| 3315 | * ntfs_attr_get_search_ctx(). |
| 3316 | * |
| 3317 | * This function transparently handles attribute lists and @ctx is used to |
| 3318 | * continue searches where they were left off at. |
| 3319 | * |
| 3320 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
| 3321 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
| 3322 | * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT |
| 3323 | * to indicate that there are no more entries. During the enumeration, each |
| 3324 | * successful call of ntfs_attr_lookup() will return the next attribute, with |
| 3325 | * the current attribute being described by the search context @ctx. |
| 3326 | * |
| 3327 | * If @type is AT_END, seek to the end of the base mft record ignoring the |
| 3328 | * attribute list completely and return -1 with errno set to ENOENT. AT_END is |
| 3329 | * not a valid attribute, its length is zero for example, thus it is safer to |
| 3330 | * return error instead of success in this case. It should never be needed to |
| 3331 | * do this, but we implement the functionality because it allows for simpler |
| 3332 | * code inside ntfs_external_attr_find(). |
| 3333 | * |
| 3334 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
| 3335 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
| 3336 | * match both named and unnamed attributes. |
| 3337 | * |
| 3338 | * After finishing with the attribute/mft record you need to call |
| 3339 | * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any |
| 3340 | * mapped extent inodes, etc). |
| 3341 | * |
| 3342 | * Return 0 if the search was successful and -1 if not, with errno set to the |
| 3343 | * error code. |
| 3344 | * |
| 3345 | * On success, @ctx->attr is the found attribute, it is in mft record |
| 3346 | * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this |
| 3347 | * attribute with @ctx->base_* being the base mft record to which @ctx->attr |
| 3348 | * belongs. If no attribute list attribute is present @ctx->al_entry and |
| 3349 | * @ctx->base_* are NULL. |
| 3350 | * |
| 3351 | * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the |
| 3352 | * attribute which collates just after the attribute being searched for in the |
| 3353 | * base ntfs inode, i.e. if one wants to add the attribute to the mft record |
| 3354 | * this is the correct place to insert it into, and if there is not enough |
| 3355 | * space, the attribute should be placed in an extent mft record. |
| 3356 | * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list |
| 3357 | * at which the new attribute's attribute list entry should be inserted. The |
| 3358 | * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. |
| 3359 | * The only exception to this is when @type is AT_END, in which case |
| 3360 | * @ctx->al_entry is set to NULL also (see above). |
| 3361 | * |
| 3362 | * |
| 3363 | * The following error codes are defined: |
| 3364 | * ENOENT Attribute not found, not an error as such. |
| 3365 | * EINVAL Invalid arguments. |
| 3366 | * EIO I/O error or corrupt data structures found. |
| 3367 | * ENOMEM Not enough memory to allocate necessary buffers. |
| 3368 | */ |
| 3369 | int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, |
| 3370 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
| 3371 | const VCN lowest_vcn, const u8 *val, const u32 val_len, |
| 3372 | ntfs_attr_search_ctx *ctx) |
| 3373 | { |
| 3374 | ntfs_volume *vol; |
| 3375 | ntfs_inode *base_ni; |
| 3376 | int ret = -1; |
| 3377 | |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3378 | ntfs_log_enter("Entering for attribute type 0x%x\n", le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3379 | |
| 3380 | if (!ctx || !ctx->mrec || !ctx->attr || (name && name != AT_UNNAMED && |
| 3381 | (!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) || |
| 3382 | !vol->upcase || !vol->upcase_len))) { |
| 3383 | errno = EINVAL; |
| 3384 | ntfs_log_perror("%s", __FUNCTION__); |
| 3385 | goto out; |
| 3386 | } |
| 3387 | |
| 3388 | if (ctx->base_ntfs_ino) |
| 3389 | base_ni = ctx->base_ntfs_ino; |
| 3390 | else |
| 3391 | base_ni = ctx->ntfs_ino; |
| 3392 | if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) |
| 3393 | ret = ntfs_attr_find(type, name, name_len, ic, val, val_len, ctx); |
| 3394 | else |
| 3395 | ret = ntfs_external_attr_find(type, name, name_len, ic, |
| 3396 | lowest_vcn, val, val_len, ctx); |
| 3397 | out: |
| 3398 | ntfs_log_leave("\n"); |
| 3399 | return ret; |
| 3400 | } |
| 3401 | |
| 3402 | /** |
| 3403 | * ntfs_attr_position - find given or next attribute type in an ntfs inode |
| 3404 | * @type: attribute type to start lookup |
| 3405 | * @ctx: search context with mft record and attribute to search from |
| 3406 | * |
| 3407 | * Find an attribute type in an ntfs inode or the next attribute which is not |
| 3408 | * the AT_END attribute. Please see more details at ntfs_attr_lookup. |
| 3409 | * |
| 3410 | * Return 0 if the search was successful and -1 if not, with errno set to the |
| 3411 | * error code. |
| 3412 | * |
| 3413 | * The following error codes are defined: |
| 3414 | * EINVAL Invalid arguments. |
| 3415 | * EIO I/O error or corrupt data structures found. |
| 3416 | * ENOMEM Not enough memory to allocate necessary buffers. |
| 3417 | * ENOSPC No attribute was found after 'type', only AT_END. |
| 3418 | */ |
| 3419 | int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx) |
| 3420 | { |
| 3421 | if (ntfs_attr_lookup(type, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
| 3422 | if (errno != ENOENT) |
| 3423 | return -1; |
| 3424 | if (ctx->attr->type == AT_END) { |
| 3425 | errno = ENOSPC; |
| 3426 | return -1; |
| 3427 | } |
| 3428 | } |
| 3429 | return 0; |
| 3430 | } |
| 3431 | |
| 3432 | /** |
| 3433 | * ntfs_attr_init_search_ctx - initialize an attribute search context |
| 3434 | * @ctx: attribute search context to initialize |
| 3435 | * @ni: ntfs inode with which to initialize the search context |
| 3436 | * @mrec: mft record with which to initialize the search context |
| 3437 | * |
| 3438 | * Initialize the attribute search context @ctx with @ni and @mrec. |
| 3439 | */ |
| 3440 | static void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, |
| 3441 | ntfs_inode *ni, MFT_RECORD *mrec) |
| 3442 | { |
| 3443 | if (!mrec) |
| 3444 | mrec = ni->mrec; |
| 3445 | ctx->mrec = mrec; |
| 3446 | /* Sanity checks are performed elsewhere. */ |
| 3447 | ctx->attr = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset)); |
| 3448 | ctx->is_first = TRUE; |
| 3449 | ctx->ntfs_ino = ni; |
| 3450 | ctx->al_entry = NULL; |
| 3451 | ctx->base_ntfs_ino = NULL; |
| 3452 | ctx->base_mrec = NULL; |
| 3453 | ctx->base_attr = NULL; |
| 3454 | } |
| 3455 | |
| 3456 | /** |
| 3457 | * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context |
| 3458 | * @ctx: attribute search context to reinitialize |
| 3459 | * |
| 3460 | * Reinitialize the attribute search context @ctx. |
| 3461 | * |
| 3462 | * This is used when a search for a new attribute is being started to reset |
| 3463 | * the search context to the beginning. |
| 3464 | */ |
| 3465 | void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx) |
| 3466 | { |
| 3467 | if (!ctx->base_ntfs_ino) { |
| 3468 | /* No attribute list. */ |
| 3469 | ctx->is_first = TRUE; |
| 3470 | /* Sanity checks are performed elsewhere. */ |
| 3471 | ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + |
| 3472 | le16_to_cpu(ctx->mrec->attrs_offset)); |
| 3473 | /* |
| 3474 | * This needs resetting due to ntfs_external_attr_find() which |
| 3475 | * can leave it set despite having zeroed ctx->base_ntfs_ino. |
| 3476 | */ |
| 3477 | ctx->al_entry = NULL; |
| 3478 | return; |
| 3479 | } /* Attribute list. */ |
| 3480 | ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec); |
| 3481 | return; |
| 3482 | } |
| 3483 | |
| 3484 | /** |
| 3485 | * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context |
| 3486 | * @ni: ntfs inode with which to initialize the search context |
| 3487 | * @mrec: mft record with which to initialize the search context |
| 3488 | * |
| 3489 | * Allocate a new attribute search context, initialize it with @ni and @mrec, |
| 3490 | * and return it. Return NULL on error with errno set. |
| 3491 | * |
| 3492 | * @mrec can be NULL, in which case the mft record is taken from @ni. |
| 3493 | * |
| 3494 | * Note: For low level utilities which know what they are doing we allow @ni to |
| 3495 | * be NULL and @mrec to be set. Do NOT do this unless you understand the |
| 3496 | * implications!!! For example it is no longer safe to call ntfs_attr_lookup(). |
| 3497 | */ |
| 3498 | ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) |
| 3499 | { |
| 3500 | ntfs_attr_search_ctx *ctx; |
| 3501 | |
| 3502 | if (!ni && !mrec) { |
| 3503 | errno = EINVAL; |
| 3504 | ntfs_log_perror("NULL arguments"); |
| 3505 | return NULL; |
| 3506 | } |
| 3507 | ctx = ntfs_malloc(sizeof(ntfs_attr_search_ctx)); |
| 3508 | if (ctx) |
| 3509 | ntfs_attr_init_search_ctx(ctx, ni, mrec); |
| 3510 | return ctx; |
| 3511 | } |
| 3512 | |
| 3513 | /** |
| 3514 | * ntfs_attr_put_search_ctx - release an attribute search context |
| 3515 | * @ctx: attribute search context to free |
| 3516 | * |
| 3517 | * Release the attribute search context @ctx. |
| 3518 | */ |
| 3519 | void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) |
| 3520 | { |
| 3521 | // NOTE: save errno if it could change and function stays void! |
| 3522 | free(ctx); |
| 3523 | } |
| 3524 | |
| 3525 | /** |
| 3526 | * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file |
| 3527 | * @vol: ntfs volume to which the attribute belongs |
| 3528 | * @type: attribute type which to find |
| 3529 | * |
| 3530 | * Search for the attribute definition record corresponding to the attribute |
| 3531 | * @type in the $AttrDef system file. |
| 3532 | * |
| 3533 | * Return the attribute type definition record if found and NULL if not found |
| 3534 | * or an error occurred. On error the error code is stored in errno. The |
| 3535 | * following error codes are defined: |
| 3536 | * ENOENT - The attribute @type is not specified in $AttrDef. |
| 3537 | * EINVAL - Invalid parameters (e.g. @vol is not valid). |
| 3538 | */ |
| 3539 | ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, |
| 3540 | const ATTR_TYPES type) |
| 3541 | { |
| 3542 | ATTR_DEF *ad; |
| 3543 | |
| 3544 | if (!vol || !vol->attrdef || !type) { |
| 3545 | errno = EINVAL; |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3546 | ntfs_log_perror("%s: type=%d", __FUNCTION__, le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3547 | return NULL; |
| 3548 | } |
| 3549 | for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < |
| 3550 | vol->attrdef_len && ad->type; ++ad) { |
| 3551 | /* We haven't found it yet, carry on searching. */ |
| 3552 | if (le32_to_cpu(ad->type) < le32_to_cpu(type)) |
| 3553 | continue; |
| 3554 | /* We found the attribute; return it. */ |
| 3555 | if (ad->type == type) |
| 3556 | return ad; |
| 3557 | /* We have gone too far already. No point in continuing. */ |
| 3558 | break; |
| 3559 | } |
| 3560 | errno = ENOENT; |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3561 | ntfs_log_perror("%s: type=%d", __FUNCTION__, le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3562 | return NULL; |
| 3563 | } |
| 3564 | |
| 3565 | /** |
| 3566 | * ntfs_attr_size_bounds_check - check a size of an attribute type for validity |
| 3567 | * @vol: ntfs volume to which the attribute belongs |
| 3568 | * @type: attribute type which to check |
| 3569 | * @size: size which to check |
| 3570 | * |
| 3571 | * Check whether the @size in bytes is valid for an attribute of @type on the |
| 3572 | * ntfs volume @vol. This information is obtained from $AttrDef system file. |
| 3573 | * |
| 3574 | * Return 0 if valid and -1 if not valid or an error occurred. On error the |
| 3575 | * error code is stored in errno. The following error codes are defined: |
| 3576 | * ERANGE - @size is not valid for the attribute @type. |
| 3577 | * ENOENT - The attribute @type is not specified in $AttrDef. |
| 3578 | * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid). |
| 3579 | */ |
| 3580 | int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, |
| 3581 | const s64 size) |
| 3582 | { |
| 3583 | ATTR_DEF *ad; |
| 3584 | s64 min_size, max_size; |
| 3585 | |
| 3586 | if (size < 0) { |
| 3587 | errno = EINVAL; |
| 3588 | ntfs_log_perror("%s: size=%lld", __FUNCTION__, |
| 3589 | (long long)size); |
| 3590 | return -1; |
| 3591 | } |
| 3592 | |
| 3593 | /* |
| 3594 | * $ATTRIBUTE_LIST shouldn't be greater than 0x40000, otherwise |
| 3595 | * Windows would crash. This is not listed in the AttrDef. |
| 3596 | */ |
| 3597 | if (type == AT_ATTRIBUTE_LIST && size > 0x40000) { |
| 3598 | errno = ERANGE; |
| 3599 | ntfs_log_perror("Too large attrlist (%lld)", (long long)size); |
| 3600 | return -1; |
| 3601 | } |
| 3602 | |
| 3603 | ad = ntfs_attr_find_in_attrdef(vol, type); |
| 3604 | if (!ad) |
| 3605 | return -1; |
| 3606 | |
| 3607 | min_size = sle64_to_cpu(ad->min_size); |
| 3608 | max_size = sle64_to_cpu(ad->max_size); |
| 3609 | |
| 3610 | /* The $AttrDef generated by Windows specifies 2 as min_size for the |
| 3611 | * volume name attribute, but in reality Windows sets it to 0 when |
| 3612 | * clearing the volume name. If we want to be able to clear the volume |
| 3613 | * name we must also accept 0 as min_size, despite the $AttrDef |
| 3614 | * definition. */ |
| 3615 | if(type == AT_VOLUME_NAME) |
| 3616 | min_size = 0; |
| 3617 | |
| 3618 | if ((min_size && (size < min_size)) || |
| 3619 | ((max_size > 0) && (size > max_size))) { |
| 3620 | errno = ERANGE; |
| 3621 | ntfs_log_perror("Attr type %d size check failed (min,size,max=" |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3622 | "%lld,%lld,%lld)", le32_to_cpu(type), (long long)min_size, |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3623 | (long long)size, (long long)max_size); |
| 3624 | return -1; |
| 3625 | } |
| 3626 | return 0; |
| 3627 | } |
| 3628 | |
| 3629 | /** |
| 3630 | * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident |
| 3631 | * @vol: ntfs volume to which the attribute belongs |
| 3632 | * @type: attribute type to check |
| 3633 | * @name: attribute name to check |
| 3634 | * @name_len: attribute name length |
| 3635 | * |
| 3636 | * Check whether the attribute of @type and @name with name length @name_len on |
| 3637 | * the ntfs volume @vol is allowed to be non-resident. This information is |
| 3638 | * obtained from $AttrDef system file and is augmented by rules imposed by |
| 3639 | * Microsoft (e.g. see http://support.microsoft.com/kb/974729/). |
| 3640 | * |
| 3641 | * Return 0 if the attribute is allowed to be non-resident and -1 if not or an |
| 3642 | * error occurred. On error the error code is stored in errno. The following |
| 3643 | * error codes are defined: |
| 3644 | * EPERM - The attribute is not allowed to be non-resident. |
| 3645 | * ENOENT - The attribute @type is not specified in $AttrDef. |
| 3646 | * EINVAL - Invalid parameters (e.g. @vol is not valid). |
| 3647 | */ |
| 3648 | static int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type, |
| 3649 | const ntfschar *name, int name_len) |
| 3650 | { |
| 3651 | ATTR_DEF *ad; |
| 3652 | BOOL allowed; |
| 3653 | |
| 3654 | /* |
| 3655 | * Microsoft has decreed that $LOGGED_UTILITY_STREAM attributes with a |
| 3656 | * name of $TXF_DATA must be resident despite the entry for |
| 3657 | * $LOGGED_UTILITY_STREAM in $AttrDef allowing them to be non-resident. |
| 3658 | * Failure to obey this on the root directory mft record of a volume |
| 3659 | * causes Windows Vista and later to see the volume as a RAW volume and |
| 3660 | * thus cannot mount it at all. |
| 3661 | */ |
| 3662 | if ((type == AT_LOGGED_UTILITY_STREAM) |
| 3663 | && name |
| 3664 | && ntfs_names_are_equal(TXF_DATA, 9, name, name_len, |
| 3665 | CASE_SENSITIVE, vol->upcase, vol->upcase_len)) |
| 3666 | allowed = FALSE; |
| 3667 | else { |
| 3668 | /* Find the attribute definition record in $AttrDef. */ |
| 3669 | ad = ntfs_attr_find_in_attrdef(vol, type); |
| 3670 | if (!ad) |
| 3671 | return -1; |
| 3672 | /* Check the flags and return the result. */ |
| 3673 | allowed = !(ad->flags & ATTR_DEF_RESIDENT); |
| 3674 | } |
| 3675 | if (!allowed) { |
| 3676 | errno = EPERM; |
| 3677 | ntfs_log_trace("Attribute can't be non-resident\n"); |
| 3678 | return -1; |
| 3679 | } |
| 3680 | return 0; |
| 3681 | } |
| 3682 | |
| 3683 | /** |
| 3684 | * ntfs_attr_can_be_resident - check if an attribute can be resident |
| 3685 | * @vol: ntfs volume to which the attribute belongs |
| 3686 | * @type: attribute type which to check |
| 3687 | * |
| 3688 | * Check whether the attribute of @type on the ntfs volume @vol is allowed to |
| 3689 | * be resident. This information is derived from our ntfs knowledge and may |
| 3690 | * not be completely accurate, especially when user defined attributes are |
| 3691 | * present. Basically we allow everything to be resident except for index |
| 3692 | * allocation and extended attribute attributes. |
| 3693 | * |
| 3694 | * Return 0 if the attribute is allowed to be resident and -1 if not or an |
| 3695 | * error occurred. On error the error code is stored in errno. The following |
| 3696 | * error codes are defined: |
| 3697 | * EPERM - The attribute is not allowed to be resident. |
| 3698 | * EINVAL - Invalid parameters (e.g. @vol is not valid). |
| 3699 | * |
| 3700 | * Warning: In the system file $MFT the attribute $Bitmap must be non-resident |
| 3701 | * otherwise windows will not boot (blue screen of death)! We cannot |
| 3702 | * check for this here as we don't know which inode's $Bitmap is being |
| 3703 | * asked about so the caller needs to special case this. |
| 3704 | */ |
| 3705 | int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type) |
| 3706 | { |
| 3707 | if (!vol || !vol->attrdef || !type) { |
| 3708 | errno = EINVAL; |
| 3709 | return -1; |
| 3710 | } |
| 3711 | if (type != AT_INDEX_ALLOCATION) |
| 3712 | return 0; |
| 3713 | |
| 3714 | ntfs_log_trace("Attribute can't be resident\n"); |
| 3715 | errno = EPERM; |
| 3716 | return -1; |
| 3717 | } |
| 3718 | |
| 3719 | /** |
| 3720 | * ntfs_make_room_for_attr - make room for an attribute inside an mft record |
| 3721 | * @m: mft record |
| 3722 | * @pos: position at which to make space |
| 3723 | * @size: byte size to make available at this position |
| 3724 | * |
| 3725 | * @pos points to the attribute in front of which we want to make space. |
| 3726 | * |
| 3727 | * Return 0 on success or -1 on error. On error the error code is stored in |
| 3728 | * errno. Possible error codes are: |
| 3729 | * ENOSPC - There is not enough space available to complete operation. The |
| 3730 | * caller has to make space before calling this. |
| 3731 | * EINVAL - Input parameters were faulty. |
| 3732 | */ |
| 3733 | int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size) |
| 3734 | { |
| 3735 | u32 biu; |
| 3736 | |
| 3737 | ntfs_log_trace("Entering for pos 0x%d, size %u.\n", |
| 3738 | (int)(pos - (u8*)m), (unsigned) size); |
| 3739 | |
| 3740 | /* Make size 8-byte alignment. */ |
| 3741 | size = (size + 7) & ~7; |
| 3742 | |
| 3743 | /* Rigorous consistency checks. */ |
| 3744 | if (!m || !pos || pos < (u8*)m) { |
| 3745 | errno = EINVAL; |
| 3746 | ntfs_log_perror("%s: pos=%p m=%p", __FUNCTION__, pos, m); |
| 3747 | return -1; |
| 3748 | } |
| 3749 | /* The -8 is for the attribute terminator. */ |
| 3750 | if (pos - (u8*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) { |
| 3751 | errno = EINVAL; |
| 3752 | return -1; |
| 3753 | } |
| 3754 | /* Nothing to do. */ |
| 3755 | if (!size) |
| 3756 | return 0; |
| 3757 | |
| 3758 | biu = le32_to_cpu(m->bytes_in_use); |
| 3759 | /* Do we have enough space? */ |
| 3760 | if (biu + size > le32_to_cpu(m->bytes_allocated) || |
| 3761 | pos + size > (u8*)m + le32_to_cpu(m->bytes_allocated)) { |
| 3762 | errno = ENOSPC; |
| 3763 | ntfs_log_trace("No enough space in the MFT record\n"); |
| 3764 | return -1; |
| 3765 | } |
| 3766 | /* Move everything after pos to pos + size. */ |
| 3767 | memmove(pos + size, pos, biu - (pos - (u8*)m)); |
| 3768 | /* Update mft record. */ |
| 3769 | m->bytes_in_use = cpu_to_le32(biu + size); |
| 3770 | return 0; |
| 3771 | } |
| 3772 | |
| 3773 | /** |
| 3774 | * ntfs_resident_attr_record_add - add resident attribute to inode |
| 3775 | * @ni: opened ntfs inode to which MFT record add attribute |
| 3776 | * @type: type of the new attribute |
| 3777 | * @name: name of the new attribute |
| 3778 | * @name_len: name length of the new attribute |
| 3779 | * @val: value of the new attribute |
| 3780 | * @size: size of new attribute (length of @val, if @val != NULL) |
| 3781 | * @flags: flags of the new attribute |
| 3782 | * |
| 3783 | * Return offset to attribute from the beginning of the mft record on success |
| 3784 | * and -1 on error. On error the error code is stored in errno. |
| 3785 | * Possible error codes are: |
| 3786 | * EINVAL - Invalid arguments passed to function. |
| 3787 | * EEXIST - Attribute of such type and with same name already exists. |
| 3788 | * EIO - I/O error occurred or damaged filesystem. |
| 3789 | */ |
| 3790 | int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, |
| 3791 | const ntfschar *name, u8 name_len, const u8 *val, |
| 3792 | u32 size, ATTR_FLAGS data_flags) |
| 3793 | { |
| 3794 | ntfs_attr_search_ctx *ctx; |
| 3795 | u32 length; |
| 3796 | ATTR_RECORD *a; |
| 3797 | MFT_RECORD *m; |
| 3798 | int err, offset; |
| 3799 | ntfs_inode *base_ni; |
| 3800 | |
| 3801 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3802 | (long long) ni->mft_no, (unsigned) le32_to_cpu(type), (unsigned) le16_to_cpu(data_flags)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3803 | |
| 3804 | if (!ni || (!name && name_len)) { |
| 3805 | errno = EINVAL; |
| 3806 | return -1; |
| 3807 | } |
| 3808 | |
| 3809 | if (ntfs_attr_can_be_resident(ni->vol, type)) { |
| 3810 | if (errno == EPERM) |
| 3811 | ntfs_log_trace("Attribute can't be resident.\n"); |
| 3812 | else |
| 3813 | ntfs_log_trace("ntfs_attr_can_be_resident failed.\n"); |
| 3814 | return -1; |
| 3815 | } |
| 3816 | |
| 3817 | /* Locate place where record should be. */ |
| 3818 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 3819 | if (!ctx) |
| 3820 | return -1; |
| 3821 | /* |
| 3822 | * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for |
| 3823 | * attribute in @ni->mrec, not any extent inode in case if @ni is base |
| 3824 | * file record. |
| 3825 | */ |
| 3826 | if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, val, size, |
| 3827 | ctx)) { |
| 3828 | err = EEXIST; |
| 3829 | ntfs_log_trace("Attribute already present.\n"); |
| 3830 | goto put_err_out; |
| 3831 | } |
| 3832 | if (errno != ENOENT) { |
| 3833 | err = EIO; |
| 3834 | goto put_err_out; |
| 3835 | } |
| 3836 | a = ctx->attr; |
| 3837 | m = ctx->mrec; |
| 3838 | |
| 3839 | /* Make room for attribute. */ |
| 3840 | length = offsetof(ATTR_RECORD, resident_end) + |
| 3841 | ((name_len * sizeof(ntfschar) + 7) & ~7) + |
| 3842 | ((size + 7) & ~7); |
| 3843 | if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) { |
| 3844 | err = errno; |
| 3845 | ntfs_log_trace("Failed to make room for attribute.\n"); |
| 3846 | goto put_err_out; |
| 3847 | } |
| 3848 | |
| 3849 | /* Setup record fields. */ |
| 3850 | offset = ((u8*)a - (u8*)m); |
| 3851 | a->type = type; |
| 3852 | a->length = cpu_to_le32(length); |
| 3853 | a->non_resident = 0; |
| 3854 | a->name_length = name_len; |
| 3855 | a->name_offset = (name_len |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3856 | ? const_cpu_to_le16(offsetof(ATTR_RECORD, resident_end)) |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3857 | : const_cpu_to_le16(0)); |
| 3858 | a->flags = data_flags; |
| 3859 | a->instance = m->next_attr_instance; |
| 3860 | a->value_length = cpu_to_le32(size); |
| 3861 | a->value_offset = cpu_to_le16(length - ((size + 7) & ~7)); |
| 3862 | if (val) |
| 3863 | memcpy((u8*)a + le16_to_cpu(a->value_offset), val, size); |
| 3864 | else |
| 3865 | memset((u8*)a + le16_to_cpu(a->value_offset), 0, size); |
| 3866 | if (type == AT_FILE_NAME) |
| 3867 | a->resident_flags = RESIDENT_ATTR_IS_INDEXED; |
| 3868 | else |
| 3869 | a->resident_flags = 0; |
| 3870 | if (name_len) |
| 3871 | memcpy((u8*)a + le16_to_cpu(a->name_offset), |
| 3872 | name, sizeof(ntfschar) * name_len); |
| 3873 | m->next_attr_instance = |
| 3874 | cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); |
| 3875 | if (ni->nr_extents == -1) |
| 3876 | base_ni = ni->base_ni; |
| 3877 | else |
| 3878 | base_ni = ni; |
| 3879 | if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { |
| 3880 | if (ntfs_attrlist_entry_add(ni, a)) { |
| 3881 | err = errno; |
| 3882 | ntfs_attr_record_resize(m, a, 0); |
| 3883 | ntfs_log_trace("Failed add attribute entry to " |
| 3884 | "ATTRIBUTE_LIST.\n"); |
| 3885 | goto put_err_out; |
| 3886 | } |
| 3887 | } |
| 3888 | if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
| 3889 | ? type == AT_INDEX_ROOT && name == NTFS_INDEX_I30 |
| 3890 | : type == AT_DATA && name == AT_UNNAMED) { |
| 3891 | ni->data_size = size; |
| 3892 | ni->allocated_size = (size + 7) & ~7; |
| 3893 | set_nino_flag(ni,KnownSize); |
| 3894 | } |
| 3895 | ntfs_inode_mark_dirty(ni); |
| 3896 | ntfs_attr_put_search_ctx(ctx); |
| 3897 | return offset; |
| 3898 | put_err_out: |
| 3899 | ntfs_attr_put_search_ctx(ctx); |
| 3900 | errno = err; |
| 3901 | return -1; |
| 3902 | } |
| 3903 | |
| 3904 | /** |
| 3905 | * ntfs_non_resident_attr_record_add - add extent of non-resident attribute |
| 3906 | * @ni: opened ntfs inode to which MFT record add attribute |
| 3907 | * @type: type of the new attribute extent |
| 3908 | * @name: name of the new attribute extent |
| 3909 | * @name_len: name length of the new attribute extent |
| 3910 | * @lowest_vcn: lowest vcn of the new attribute extent |
| 3911 | * @dataruns_size: dataruns size of the new attribute extent |
| 3912 | * @flags: flags of the new attribute extent |
| 3913 | * |
| 3914 | * Return offset to attribute from the beginning of the mft record on success |
| 3915 | * and -1 on error. On error the error code is stored in errno. |
| 3916 | * Possible error codes are: |
| 3917 | * EINVAL - Invalid arguments passed to function. |
| 3918 | * EEXIST - Attribute of such type, with same lowest vcn and with same |
| 3919 | * name already exists. |
| 3920 | * EIO - I/O error occurred or damaged filesystem. |
| 3921 | */ |
| 3922 | int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, |
| 3923 | const ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size, |
| 3924 | ATTR_FLAGS flags) |
| 3925 | { |
| 3926 | ntfs_attr_search_ctx *ctx; |
| 3927 | u32 length; |
| 3928 | ATTR_RECORD *a; |
| 3929 | MFT_RECORD *m; |
| 3930 | ntfs_inode *base_ni; |
| 3931 | int err, offset; |
| 3932 | |
| 3933 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, " |
| 3934 | "dataruns_size %d, flags 0x%x.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3935 | (long long) ni->mft_no, (unsigned) le32_to_cpu(type), |
| 3936 | (long long) lowest_vcn, dataruns_size, (unsigned) le16_to_cpu(flags)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3937 | |
| 3938 | if (!ni || dataruns_size <= 0 || (!name && name_len)) { |
| 3939 | errno = EINVAL; |
| 3940 | return -1; |
| 3941 | } |
| 3942 | |
| 3943 | if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { |
| 3944 | if (errno == EPERM) |
| 3945 | ntfs_log_perror("Attribute can't be non resident"); |
| 3946 | else |
| 3947 | ntfs_log_perror("ntfs_attr_can_be_non_resident failed"); |
| 3948 | return -1; |
| 3949 | } |
| 3950 | |
| 3951 | /* Locate place where record should be. */ |
| 3952 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 3953 | if (!ctx) |
| 3954 | return -1; |
| 3955 | /* |
| 3956 | * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for |
| 3957 | * attribute in @ni->mrec, not any extent inode in case if @ni is base |
| 3958 | * file record. |
| 3959 | */ |
| 3960 | if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, NULL, 0, |
| 3961 | ctx)) { |
| 3962 | err = EEXIST; |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 3963 | ntfs_log_perror("Attribute 0x%x already present", le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 3964 | goto put_err_out; |
| 3965 | } |
| 3966 | if (errno != ENOENT) { |
| 3967 | ntfs_log_perror("ntfs_attr_find failed"); |
| 3968 | err = EIO; |
| 3969 | goto put_err_out; |
| 3970 | } |
| 3971 | a = ctx->attr; |
| 3972 | m = ctx->mrec; |
| 3973 | |
| 3974 | /* Make room for attribute. */ |
| 3975 | dataruns_size = (dataruns_size + 7) & ~7; |
| 3976 | length = offsetof(ATTR_RECORD, compressed_size) + ((sizeof(ntfschar) * |
| 3977 | name_len + 7) & ~7) + dataruns_size + |
| 3978 | ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? |
| 3979 | sizeof(a->compressed_size) : 0); |
| 3980 | if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) { |
| 3981 | err = errno; |
| 3982 | ntfs_log_perror("Failed to make room for attribute"); |
| 3983 | goto put_err_out; |
| 3984 | } |
| 3985 | |
| 3986 | /* Setup record fields. */ |
| 3987 | a->type = type; |
| 3988 | a->length = cpu_to_le32(length); |
| 3989 | a->non_resident = 1; |
| 3990 | a->name_length = name_len; |
| 3991 | a->name_offset = cpu_to_le16(offsetof(ATTR_RECORD, compressed_size) + |
| 3992 | ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? |
| 3993 | sizeof(a->compressed_size) : 0)); |
| 3994 | a->flags = flags; |
| 3995 | a->instance = m->next_attr_instance; |
| 3996 | a->lowest_vcn = cpu_to_sle64(lowest_vcn); |
| 3997 | a->mapping_pairs_offset = cpu_to_le16(length - dataruns_size); |
| 3998 | a->compression_unit = (flags & ATTR_IS_COMPRESSED) |
| 3999 | ? STANDARD_COMPRESSION_UNIT : 0; |
| 4000 | /* If @lowest_vcn == 0, than setup empty attribute. */ |
| 4001 | if (!lowest_vcn) { |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 4002 | a->highest_vcn = const_cpu_to_sle64(-1); |
| 4003 | a->allocated_size = const_cpu_to_sle64(0); |
| 4004 | a->data_size = const_cpu_to_sle64(0); |
| 4005 | a->initialized_size = const_cpu_to_sle64(0); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4006 | /* Set empty mapping pairs. */ |
| 4007 | *((u8*)a + le16_to_cpu(a->mapping_pairs_offset)) = 0; |
| 4008 | } |
| 4009 | if (name_len) |
| 4010 | memcpy((u8*)a + le16_to_cpu(a->name_offset), |
| 4011 | name, sizeof(ntfschar) * name_len); |
| 4012 | m->next_attr_instance = |
| 4013 | cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); |
| 4014 | if (ni->nr_extents == -1) |
| 4015 | base_ni = ni->base_ni; |
| 4016 | else |
| 4017 | base_ni = ni; |
| 4018 | if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { |
| 4019 | if (ntfs_attrlist_entry_add(ni, a)) { |
| 4020 | err = errno; |
| 4021 | ntfs_log_perror("Failed add attr entry to attrlist"); |
| 4022 | ntfs_attr_record_resize(m, a, 0); |
| 4023 | goto put_err_out; |
| 4024 | } |
| 4025 | } |
| 4026 | ntfs_inode_mark_dirty(ni); |
| 4027 | /* |
| 4028 | * Locate offset from start of the MFT record where new attribute is |
| 4029 | * placed. We need relookup it, because record maybe moved during |
| 4030 | * update of attribute list. |
| 4031 | */ |
| 4032 | ntfs_attr_reinit_search_ctx(ctx); |
| 4033 | if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, |
| 4034 | lowest_vcn, NULL, 0, ctx)) { |
| 4035 | ntfs_log_perror("%s: attribute lookup failed", __FUNCTION__); |
| 4036 | ntfs_attr_put_search_ctx(ctx); |
| 4037 | return -1; |
| 4038 | |
| 4039 | } |
| 4040 | offset = (u8*)ctx->attr - (u8*)ctx->mrec; |
| 4041 | ntfs_attr_put_search_ctx(ctx); |
| 4042 | return offset; |
| 4043 | put_err_out: |
| 4044 | ntfs_attr_put_search_ctx(ctx); |
| 4045 | errno = err; |
| 4046 | return -1; |
| 4047 | } |
| 4048 | |
| 4049 | /** |
| 4050 | * ntfs_attr_record_rm - remove attribute extent |
| 4051 | * @ctx: search context describing the attribute which should be removed |
| 4052 | * |
| 4053 | * If this function succeed, user should reinit search context if he/she wants |
| 4054 | * use it anymore. |
| 4055 | * |
| 4056 | * Return 0 on success and -1 on error. On error the error code is stored in |
| 4057 | * errno. Possible error codes are: |
| 4058 | * EINVAL - Invalid arguments passed to function. |
| 4059 | * EIO - I/O error occurred or damaged filesystem. |
| 4060 | */ |
| 4061 | int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) |
| 4062 | { |
| 4063 | ntfs_inode *base_ni, *ni; |
| 4064 | ATTR_TYPES type; |
| 4065 | |
| 4066 | if (!ctx || !ctx->ntfs_ino || !ctx->mrec || !ctx->attr) { |
| 4067 | errno = EINVAL; |
| 4068 | return -1; |
| 4069 | } |
| 4070 | |
| 4071 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", |
| 4072 | (long long) ctx->ntfs_ino->mft_no, |
| 4073 | (unsigned) le32_to_cpu(ctx->attr->type)); |
| 4074 | type = ctx->attr->type; |
| 4075 | ni = ctx->ntfs_ino; |
| 4076 | if (ctx->base_ntfs_ino) |
| 4077 | base_ni = ctx->base_ntfs_ino; |
| 4078 | else |
| 4079 | base_ni = ctx->ntfs_ino; |
| 4080 | |
| 4081 | /* Remove attribute itself. */ |
| 4082 | if (ntfs_attr_record_resize(ctx->mrec, ctx->attr, 0)) { |
| 4083 | ntfs_log_trace("Couldn't remove attribute record. Bug or damaged MFT " |
| 4084 | "record.\n"); |
| 4085 | if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) |
| 4086 | if (ntfs_attrlist_entry_add(ni, ctx->attr)) |
| 4087 | ntfs_log_trace("Rollback failed. Leaving inconstant " |
| 4088 | "metadata.\n"); |
| 4089 | errno = EIO; |
| 4090 | return -1; |
| 4091 | } |
| 4092 | ntfs_inode_mark_dirty(ni); |
| 4093 | |
| 4094 | /* |
| 4095 | * Remove record from $ATTRIBUTE_LIST if present and we don't want |
| 4096 | * delete $ATTRIBUTE_LIST itself. |
| 4097 | */ |
| 4098 | if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) { |
| 4099 | if (ntfs_attrlist_entry_rm(ctx)) { |
| 4100 | ntfs_log_trace("Couldn't delete record from " |
| 4101 | "$ATTRIBUTE_LIST.\n"); |
| 4102 | return -1; |
| 4103 | } |
| 4104 | } |
| 4105 | |
| 4106 | /* Post $ATTRIBUTE_LIST delete setup. */ |
| 4107 | if (type == AT_ATTRIBUTE_LIST) { |
| 4108 | if (NInoAttrList(base_ni) && base_ni->attr_list) |
| 4109 | free(base_ni->attr_list); |
| 4110 | base_ni->attr_list = NULL; |
| 4111 | NInoClearAttrList(base_ni); |
| 4112 | NInoAttrListClearDirty(base_ni); |
| 4113 | } |
| 4114 | |
| 4115 | /* Free MFT record, if it doesn't contain attributes. */ |
| 4116 | if (le32_to_cpu(ctx->mrec->bytes_in_use) - |
| 4117 | le16_to_cpu(ctx->mrec->attrs_offset) == 8) { |
| 4118 | if (ntfs_mft_record_free(ni->vol, ni)) { |
| 4119 | // FIXME: We need rollback here. |
| 4120 | ntfs_log_trace("Couldn't free MFT record.\n"); |
| 4121 | errno = EIO; |
| 4122 | return -1; |
| 4123 | } |
| 4124 | /* Remove done if we freed base inode. */ |
| 4125 | if (ni == base_ni) |
| 4126 | return 0; |
| 4127 | } |
| 4128 | |
| 4129 | if (type == AT_ATTRIBUTE_LIST || !NInoAttrList(base_ni)) |
| 4130 | return 0; |
| 4131 | |
| 4132 | /* Remove attribute list if we don't need it any more. */ |
| 4133 | if (!ntfs_attrlist_need(base_ni)) { |
| 4134 | ntfs_attr_reinit_search_ctx(ctx); |
| 4135 | if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, CASE_SENSITIVE, |
| 4136 | 0, NULL, 0, ctx)) { |
| 4137 | /* |
| 4138 | * FIXME: Should we succeed here? Definitely something |
| 4139 | * goes wrong because NInoAttrList(base_ni) returned |
| 4140 | * that we have got attribute list. |
| 4141 | */ |
| 4142 | ntfs_log_trace("Couldn't find attribute list. Succeed " |
| 4143 | "anyway.\n"); |
| 4144 | return 0; |
| 4145 | } |
| 4146 | /* Deallocate clusters. */ |
| 4147 | if (ctx->attr->non_resident) { |
| 4148 | runlist *al_rl; |
| 4149 | |
| 4150 | al_rl = ntfs_mapping_pairs_decompress(base_ni->vol, |
| 4151 | ctx->attr, NULL); |
| 4152 | if (!al_rl) { |
| 4153 | ntfs_log_trace("Couldn't decompress attribute list " |
| 4154 | "runlist. Succeed anyway.\n"); |
| 4155 | return 0; |
| 4156 | } |
| 4157 | if (ntfs_cluster_free_from_rl(base_ni->vol, al_rl)) { |
| 4158 | ntfs_log_trace("Leaking clusters! Run chkdsk. " |
| 4159 | "Couldn't free clusters from " |
| 4160 | "attribute list runlist.\n"); |
| 4161 | } |
| 4162 | free(al_rl); |
| 4163 | } |
| 4164 | /* Remove attribute record itself. */ |
| 4165 | if (ntfs_attr_record_rm(ctx)) { |
| 4166 | /* |
| 4167 | * FIXME: Should we succeed here? BTW, chkdsk doesn't |
| 4168 | * complain if it find MFT record with attribute list, |
| 4169 | * but without extents. |
| 4170 | */ |
| 4171 | ntfs_log_trace("Couldn't remove attribute list. Succeed " |
| 4172 | "anyway.\n"); |
| 4173 | return 0; |
| 4174 | } |
| 4175 | } |
| 4176 | return 0; |
| 4177 | } |
| 4178 | |
| 4179 | /** |
| 4180 | * ntfs_attr_add - add attribute to inode |
| 4181 | * @ni: opened ntfs inode to which add attribute |
| 4182 | * @type: type of the new attribute |
| 4183 | * @name: name in unicode of the new attribute |
| 4184 | * @name_len: name length in unicode characters of the new attribute |
| 4185 | * @val: value of new attribute |
| 4186 | * @size: size of the new attribute / length of @val (if specified) |
| 4187 | * |
| 4188 | * @val should always be specified for always resident attributes (eg. FILE_NAME |
| 4189 | * attribute), for attributes that can become non-resident @val can be NULL |
| 4190 | * (eg. DATA attribute). @size can be specified even if @val is NULL, in this |
| 4191 | * case data size will be equal to @size and initialized size will be equal |
| 4192 | * to 0. |
| 4193 | * |
| 4194 | * If inode haven't got enough space to add attribute, add attribute to one of |
| 4195 | * it extents, if no extents present or no one of them have enough space, than |
| 4196 | * allocate new extent and add attribute to it. |
| 4197 | * |
| 4198 | * If on one of this steps attribute list is needed but not present, than it is |
| 4199 | * added transparently to caller. So, this function should not be called with |
| 4200 | * @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call |
| 4201 | * ntfs_inode_add_attrlist instead. |
| 4202 | * |
| 4203 | * On success return 0. On error return -1 with errno set to the error code. |
| 4204 | */ |
| 4205 | int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, |
| 4206 | ntfschar *name, u8 name_len, const u8 *val, s64 size) |
| 4207 | { |
| 4208 | u32 attr_rec_size; |
| 4209 | int err, i, offset; |
| 4210 | BOOL is_resident; |
| 4211 | BOOL can_be_non_resident = FALSE; |
| 4212 | ntfs_inode *attr_ni; |
| 4213 | ntfs_attr *na; |
| 4214 | ATTR_FLAGS data_flags; |
| 4215 | |
| 4216 | if (!ni || size < 0 || type == AT_ATTRIBUTE_LIST) { |
| 4217 | errno = EINVAL; |
| 4218 | ntfs_log_perror("%s: ni=%p size=%lld", __FUNCTION__, ni, |
| 4219 | (long long)size); |
| 4220 | return -1; |
| 4221 | } |
| 4222 | |
| 4223 | ntfs_log_trace("Entering for inode %lld, attr %x, size %lld.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 4224 | (long long)ni->mft_no, le32_to_cpu(type), (long long)size); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4225 | |
| 4226 | if (ni->nr_extents == -1) |
| 4227 | ni = ni->base_ni; |
| 4228 | |
| 4229 | /* Check the attribute type and the size. */ |
| 4230 | if (ntfs_attr_size_bounds_check(ni->vol, type, size)) { |
| 4231 | if (errno == ENOENT) |
| 4232 | errno = EIO; |
| 4233 | return -1; |
| 4234 | } |
| 4235 | |
| 4236 | /* Sanity checks for always resident attributes. */ |
| 4237 | if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { |
| 4238 | if (errno != EPERM) { |
| 4239 | err = errno; |
| 4240 | ntfs_log_perror("ntfs_attr_can_be_non_resident failed"); |
| 4241 | goto err_out; |
| 4242 | } |
| 4243 | /* @val is mandatory. */ |
| 4244 | if (!val) { |
| 4245 | errno = EINVAL; |
| 4246 | ntfs_log_perror("val is mandatory for always resident " |
| 4247 | "attributes"); |
| 4248 | return -1; |
| 4249 | } |
| 4250 | if (size > ni->vol->mft_record_size) { |
| 4251 | errno = ERANGE; |
| 4252 | ntfs_log_perror("Attribute is too big"); |
| 4253 | return -1; |
| 4254 | } |
| 4255 | } else |
| 4256 | can_be_non_resident = TRUE; |
| 4257 | |
| 4258 | /* |
| 4259 | * Determine resident or not will be new attribute. We add 8 to size in |
| 4260 | * non resident case for mapping pairs. |
| 4261 | */ |
| 4262 | if (!ntfs_attr_can_be_resident(ni->vol, type)) { |
| 4263 | is_resident = TRUE; |
| 4264 | } else { |
| 4265 | if (errno != EPERM) { |
| 4266 | err = errno; |
| 4267 | ntfs_log_perror("ntfs_attr_can_be_resident failed"); |
| 4268 | goto err_out; |
| 4269 | } |
| 4270 | is_resident = FALSE; |
| 4271 | } |
| 4272 | /* Calculate attribute record size. */ |
| 4273 | if (is_resident) |
| 4274 | attr_rec_size = offsetof(ATTR_RECORD, resident_end) + |
| 4275 | ((name_len * sizeof(ntfschar) + 7) & ~7) + |
| 4276 | ((size + 7) & ~7); |
| 4277 | else |
| 4278 | attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) + |
| 4279 | ((name_len * sizeof(ntfschar) + 7) & ~7) + 8; |
| 4280 | |
| 4281 | /* |
| 4282 | * If we have enough free space for the new attribute in the base MFT |
| 4283 | * record, then add attribute to it. |
| 4284 | */ |
| 4285 | if (le32_to_cpu(ni->mrec->bytes_allocated) - |
| 4286 | le32_to_cpu(ni->mrec->bytes_in_use) >= attr_rec_size) { |
| 4287 | attr_ni = ni; |
| 4288 | goto add_attr_record; |
| 4289 | } |
| 4290 | |
| 4291 | /* Try to add to extent inodes. */ |
| 4292 | if (ntfs_inode_attach_all_extents(ni)) { |
| 4293 | err = errno; |
| 4294 | ntfs_log_perror("Failed to attach all extents to inode"); |
| 4295 | goto err_out; |
| 4296 | } |
| 4297 | for (i = 0; i < ni->nr_extents; i++) { |
| 4298 | attr_ni = ni->extent_nis[i]; |
| 4299 | if (le32_to_cpu(attr_ni->mrec->bytes_allocated) - |
| 4300 | le32_to_cpu(attr_ni->mrec->bytes_in_use) >= |
| 4301 | attr_rec_size) |
| 4302 | goto add_attr_record; |
| 4303 | } |
| 4304 | |
| 4305 | /* There is no extent that contain enough space for new attribute. */ |
| 4306 | if (!NInoAttrList(ni)) { |
| 4307 | /* Add attribute list not present, add it and retry. */ |
| 4308 | if (ntfs_inode_add_attrlist(ni)) { |
| 4309 | err = errno; |
| 4310 | ntfs_log_perror("Failed to add attribute list"); |
| 4311 | goto err_out; |
| 4312 | } |
| 4313 | return ntfs_attr_add(ni, type, name, name_len, val, size); |
| 4314 | } |
| 4315 | /* Allocate new extent. */ |
| 4316 | attr_ni = ntfs_mft_record_alloc(ni->vol, ni); |
| 4317 | if (!attr_ni) { |
| 4318 | err = errno; |
| 4319 | ntfs_log_perror("Failed to allocate extent record"); |
| 4320 | goto err_out; |
| 4321 | } |
| 4322 | |
| 4323 | add_attr_record: |
| 4324 | if ((ni->flags & FILE_ATTR_COMPRESSED) |
| 4325 | && (ni->vol->major_ver >= 3) |
| 4326 | && NVolCompression(ni->vol) |
| 4327 | && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) |
| 4328 | && ((type == AT_DATA) |
| 4329 | || ((type == AT_INDEX_ROOT) && (name == NTFS_INDEX_I30)))) |
| 4330 | data_flags = ATTR_IS_COMPRESSED; |
| 4331 | else |
| 4332 | data_flags = const_cpu_to_le16(0); |
| 4333 | if (is_resident) { |
| 4334 | /* Add resident attribute. */ |
| 4335 | offset = ntfs_resident_attr_record_add(attr_ni, type, name, |
| 4336 | name_len, val, size, data_flags); |
| 4337 | if (offset < 0) { |
| 4338 | if (errno == ENOSPC && can_be_non_resident) |
| 4339 | goto add_non_resident; |
| 4340 | err = errno; |
| 4341 | ntfs_log_perror("Failed to add resident attribute"); |
| 4342 | goto free_err_out; |
| 4343 | } |
| 4344 | return 0; |
| 4345 | } |
| 4346 | |
| 4347 | add_non_resident: |
| 4348 | /* Add non resident attribute. */ |
| 4349 | offset = ntfs_non_resident_attr_record_add(attr_ni, type, name, |
| 4350 | name_len, 0, 8, data_flags); |
| 4351 | if (offset < 0) { |
| 4352 | err = errno; |
| 4353 | ntfs_log_perror("Failed to add non resident attribute"); |
| 4354 | goto free_err_out; |
| 4355 | } |
| 4356 | |
| 4357 | /* If @size == 0, we are done. */ |
| 4358 | if (!size) |
| 4359 | return 0; |
| 4360 | |
| 4361 | /* Open new attribute and resize it. */ |
| 4362 | na = ntfs_attr_open(ni, type, name, name_len); |
| 4363 | if (!na) { |
| 4364 | err = errno; |
| 4365 | ntfs_log_perror("Failed to open just added attribute"); |
| 4366 | goto rm_attr_err_out; |
| 4367 | } |
| 4368 | /* Resize and set attribute value. */ |
| 4369 | if (ntfs_attr_truncate_i(na, size, HOLES_OK) || |
| 4370 | (val && (ntfs_attr_pwrite(na, 0, size, val) != size))) { |
| 4371 | err = errno; |
| 4372 | ntfs_log_perror("Failed to initialize just added attribute"); |
| 4373 | if (ntfs_attr_rm(na)) |
| 4374 | ntfs_log_perror("Failed to remove just added attribute"); |
| 4375 | ntfs_attr_close(na); |
| 4376 | goto err_out; |
| 4377 | } |
| 4378 | ntfs_attr_close(na); |
| 4379 | return 0; |
| 4380 | |
| 4381 | rm_attr_err_out: |
| 4382 | /* Remove just added attribute. */ |
| 4383 | if (ntfs_attr_record_resize(attr_ni->mrec, |
| 4384 | (ATTR_RECORD*)((u8*)attr_ni->mrec + offset), 0)) |
| 4385 | ntfs_log_perror("Failed to remove just added attribute #2"); |
| 4386 | free_err_out: |
| 4387 | /* Free MFT record, if it doesn't contain attributes. */ |
| 4388 | if (le32_to_cpu(attr_ni->mrec->bytes_in_use) - |
| 4389 | le16_to_cpu(attr_ni->mrec->attrs_offset) == 8) |
| 4390 | if (ntfs_mft_record_free(attr_ni->vol, attr_ni)) |
| 4391 | ntfs_log_perror("Failed to free MFT record"); |
| 4392 | err_out: |
| 4393 | errno = err; |
| 4394 | return -1; |
| 4395 | } |
| 4396 | |
| 4397 | /* |
| 4398 | * Change an attribute flag |
| 4399 | */ |
| 4400 | |
| 4401 | int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, const ntfschar *name, |
| 4402 | u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask) |
| 4403 | { |
| 4404 | ntfs_attr_search_ctx *ctx; |
| 4405 | int res; |
| 4406 | |
| 4407 | res = -1; |
| 4408 | /* Search for designated attribute */ |
| 4409 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 4410 | if (ctx) { |
| 4411 | if (!ntfs_attr_lookup(type, name, name_len, |
| 4412 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
| 4413 | /* do the requested change (all small endian le16) */ |
| 4414 | ctx->attr->flags = (ctx->attr->flags & ~mask) |
| 4415 | | (flags & mask); |
| 4416 | NInoSetDirty(ni); |
| 4417 | res = 0; |
| 4418 | } |
| 4419 | ntfs_attr_put_search_ctx(ctx); |
| 4420 | } |
| 4421 | return (res); |
| 4422 | } |
| 4423 | |
| 4424 | |
| 4425 | /** |
| 4426 | * ntfs_attr_rm - remove attribute from ntfs inode |
| 4427 | * @na: opened ntfs attribute to delete |
| 4428 | * |
| 4429 | * Remove attribute and all it's extents from ntfs inode. If attribute was non |
| 4430 | * resident also free all clusters allocated by attribute. |
| 4431 | * |
| 4432 | * Return 0 on success or -1 on error with errno set to the error code. |
| 4433 | */ |
| 4434 | int ntfs_attr_rm(ntfs_attr *na) |
| 4435 | { |
| 4436 | ntfs_attr_search_ctx *ctx; |
| 4437 | int ret = 0; |
| 4438 | |
| 4439 | if (!na) { |
| 4440 | ntfs_log_trace("Invalid arguments passed.\n"); |
| 4441 | errno = EINVAL; |
| 4442 | return -1; |
| 4443 | } |
| 4444 | |
| 4445 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 4446 | (long long) na->ni->mft_no, le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4447 | |
| 4448 | /* Free cluster allocation. */ |
| 4449 | if (NAttrNonResident(na)) { |
| 4450 | if (ntfs_attr_map_whole_runlist(na)) |
| 4451 | return -1; |
| 4452 | if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) { |
| 4453 | ntfs_log_trace("Failed to free cluster allocation. Leaving " |
| 4454 | "inconstant metadata.\n"); |
| 4455 | ret = -1; |
| 4456 | } |
| 4457 | } |
| 4458 | |
| 4459 | /* Search for attribute extents and remove them all. */ |
| 4460 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 4461 | if (!ctx) |
| 4462 | return -1; |
| 4463 | while (!ntfs_attr_lookup(na->type, na->name, na->name_len, |
| 4464 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
| 4465 | if (ntfs_attr_record_rm(ctx)) { |
| 4466 | ntfs_log_trace("Failed to remove attribute extent. Leaving " |
| 4467 | "inconstant metadata.\n"); |
| 4468 | ret = -1; |
| 4469 | } |
| 4470 | ntfs_attr_reinit_search_ctx(ctx); |
| 4471 | } |
| 4472 | ntfs_attr_put_search_ctx(ctx); |
| 4473 | if (errno != ENOENT) { |
| 4474 | ntfs_log_trace("Attribute lookup failed. Probably leaving inconstant " |
| 4475 | "metadata.\n"); |
| 4476 | ret = -1; |
| 4477 | } |
| 4478 | |
| 4479 | return ret; |
| 4480 | } |
| 4481 | |
| 4482 | /** |
| 4483 | * ntfs_attr_record_resize - resize an attribute record |
| 4484 | * @m: mft record containing attribute record |
| 4485 | * @a: attribute record to resize |
| 4486 | * @new_size: new size in bytes to which to resize the attribute record @a |
| 4487 | * |
| 4488 | * Resize the attribute record @a, i.e. the resident part of the attribute, in |
| 4489 | * the mft record @m to @new_size bytes. |
| 4490 | * |
| 4491 | * Return 0 on success and -1 on error with errno set to the error code. |
| 4492 | * The following error codes are defined: |
| 4493 | * ENOSPC - Not enough space in the mft record @m to perform the resize. |
| 4494 | * Note that on error no modifications have been performed whatsoever. |
| 4495 | * |
| 4496 | * Warning: If you make a record smaller without having copied all the data you |
| 4497 | * are interested in the data may be overwritten! |
| 4498 | */ |
| 4499 | int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) |
| 4500 | { |
| 4501 | u32 old_size, alloc_size, attr_size; |
| 4502 | |
| 4503 | old_size = le32_to_cpu(m->bytes_in_use); |
| 4504 | alloc_size = le32_to_cpu(m->bytes_allocated); |
| 4505 | attr_size = le32_to_cpu(a->length); |
| 4506 | |
| 4507 | ntfs_log_trace("Sizes: old=%u alloc=%u attr=%u new=%u\n", |
| 4508 | (unsigned)old_size, (unsigned)alloc_size, |
| 4509 | (unsigned)attr_size, (unsigned)new_size); |
| 4510 | |
| 4511 | /* Align to 8 bytes, just in case the caller hasn't. */ |
| 4512 | new_size = (new_size + 7) & ~7; |
| 4513 | |
| 4514 | /* If the actual attribute length has changed, move things around. */ |
| 4515 | if (new_size != attr_size) { |
| 4516 | |
| 4517 | u32 new_muse = old_size - attr_size + new_size; |
| 4518 | |
| 4519 | /* Not enough space in this mft record. */ |
| 4520 | if (new_muse > alloc_size) { |
| 4521 | errno = ENOSPC; |
| 4522 | ntfs_log_trace("Not enough space in the MFT record " |
| 4523 | "(%u > %u)\n", new_muse, alloc_size); |
| 4524 | return -1; |
| 4525 | } |
| 4526 | |
| 4527 | if (a->type == AT_INDEX_ROOT && new_size > attr_size && |
| 4528 | new_muse + 120 > alloc_size && old_size + 120 <= alloc_size) { |
| 4529 | errno = ENOSPC; |
| 4530 | ntfs_log_trace("Too big INDEX_ROOT (%u > %u)\n", |
| 4531 | new_muse, alloc_size); |
| 4532 | return STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; |
| 4533 | } |
| 4534 | |
| 4535 | /* Move attributes following @a to their new location. */ |
| 4536 | memmove((u8 *)a + new_size, (u8 *)a + attr_size, |
| 4537 | old_size - ((u8 *)a - (u8 *)m) - attr_size); |
| 4538 | |
| 4539 | /* Adjust @m to reflect the change in used space. */ |
| 4540 | m->bytes_in_use = cpu_to_le32(new_muse); |
| 4541 | |
| 4542 | /* Adjust @a to reflect the new size. */ |
| 4543 | if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length)) |
| 4544 | a->length = cpu_to_le32(new_size); |
| 4545 | } |
| 4546 | return 0; |
| 4547 | } |
| 4548 | |
| 4549 | /** |
| 4550 | * ntfs_resident_attr_value_resize - resize the value of a resident attribute |
| 4551 | * @m: mft record containing attribute record |
| 4552 | * @a: attribute record whose value to resize |
| 4553 | * @new_size: new size in bytes to which to resize the attribute value of @a |
| 4554 | * |
| 4555 | * Resize the value of the attribute @a in the mft record @m to @new_size bytes. |
| 4556 | * If the value is made bigger, the newly "allocated" space is cleared. |
| 4557 | * |
| 4558 | * Return 0 on success and -1 on error with errno set to the error code. |
| 4559 | * The following error codes are defined: |
| 4560 | * ENOSPC - Not enough space in the mft record @m to perform the resize. |
| 4561 | * Note that on error no modifications have been performed whatsoever. |
| 4562 | */ |
| 4563 | int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, |
| 4564 | const u32 new_size) |
| 4565 | { |
| 4566 | int ret; |
| 4567 | |
| 4568 | ntfs_log_trace("Entering for new size %u.\n", (unsigned)new_size); |
| 4569 | |
| 4570 | /* Resize the resident part of the attribute record. */ |
| 4571 | if ((ret = ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) + |
| 4572 | new_size + 7) & ~7)) < 0) |
| 4573 | return ret; |
| 4574 | /* |
| 4575 | * If we made the attribute value bigger, clear the area between the |
| 4576 | * old size and @new_size. |
| 4577 | */ |
| 4578 | if (new_size > le32_to_cpu(a->value_length)) |
| 4579 | memset((u8*)a + le16_to_cpu(a->value_offset) + |
| 4580 | le32_to_cpu(a->value_length), 0, new_size - |
| 4581 | le32_to_cpu(a->value_length)); |
| 4582 | /* Finally update the length of the attribute value. */ |
| 4583 | a->value_length = cpu_to_le32(new_size); |
| 4584 | return 0; |
| 4585 | } |
| 4586 | |
| 4587 | /** |
| 4588 | * ntfs_attr_record_move_to - move attribute record to target inode |
| 4589 | * @ctx: attribute search context describing the attribute record |
| 4590 | * @ni: opened ntfs inode to which move attribute record |
| 4591 | * |
| 4592 | * If this function succeed, user should reinit search context if he/she wants |
| 4593 | * use it anymore. |
| 4594 | * |
| 4595 | * Return 0 on success and -1 on error with errno set to the error code. |
| 4596 | */ |
| 4597 | int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) |
| 4598 | { |
| 4599 | ntfs_attr_search_ctx *nctx; |
| 4600 | ATTR_RECORD *a; |
| 4601 | int err; |
| 4602 | |
| 4603 | if (!ctx || !ctx->attr || !ctx->ntfs_ino || !ni) { |
| 4604 | ntfs_log_trace("Invalid arguments passed.\n"); |
| 4605 | errno = EINVAL; |
| 4606 | return -1; |
| 4607 | } |
| 4608 | |
| 4609 | ntfs_log_trace("Entering for ctx->attr->type 0x%x, ctx->ntfs_ino->mft_no " |
| 4610 | "0x%llx, ni->mft_no 0x%llx.\n", |
| 4611 | (unsigned) le32_to_cpu(ctx->attr->type), |
| 4612 | (long long) ctx->ntfs_ino->mft_no, |
| 4613 | (long long) ni->mft_no); |
| 4614 | |
| 4615 | if (ctx->ntfs_ino == ni) |
| 4616 | return 0; |
| 4617 | |
| 4618 | if (!ctx->al_entry) { |
| 4619 | ntfs_log_trace("Inode should contain attribute list to use this " |
| 4620 | "function.\n"); |
| 4621 | errno = EINVAL; |
| 4622 | return -1; |
| 4623 | } |
| 4624 | |
| 4625 | /* Find place in MFT record where attribute will be moved. */ |
| 4626 | a = ctx->attr; |
| 4627 | nctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 4628 | if (!nctx) |
| 4629 | return -1; |
| 4630 | |
| 4631 | /* |
| 4632 | * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for |
| 4633 | * attribute in @ni->mrec, not any extent inode in case if @ni is base |
| 4634 | * file record. |
| 4635 | */ |
| 4636 | if (!ntfs_attr_find(a->type, (ntfschar*)((u8*)a + le16_to_cpu( |
| 4637 | a->name_offset)), a->name_length, CASE_SENSITIVE, NULL, |
| 4638 | 0, nctx)) { |
| 4639 | ntfs_log_trace("Attribute of such type, with same name already " |
| 4640 | "present in this MFT record.\n"); |
| 4641 | err = EEXIST; |
| 4642 | goto put_err_out; |
| 4643 | } |
| 4644 | if (errno != ENOENT) { |
| 4645 | err = errno; |
| 4646 | ntfs_log_debug("Attribute lookup failed.\n"); |
| 4647 | goto put_err_out; |
| 4648 | } |
| 4649 | |
| 4650 | /* Make space and move attribute. */ |
| 4651 | if (ntfs_make_room_for_attr(ni->mrec, (u8*) nctx->attr, |
| 4652 | le32_to_cpu(a->length))) { |
| 4653 | err = errno; |
| 4654 | ntfs_log_trace("Couldn't make space for attribute.\n"); |
| 4655 | goto put_err_out; |
| 4656 | } |
| 4657 | memcpy(nctx->attr, a, le32_to_cpu(a->length)); |
| 4658 | nctx->attr->instance = nctx->mrec->next_attr_instance; |
| 4659 | nctx->mrec->next_attr_instance = cpu_to_le16( |
| 4660 | (le16_to_cpu(nctx->mrec->next_attr_instance) + 1) & 0xffff); |
| 4661 | ntfs_attr_record_resize(ctx->mrec, a, 0); |
| 4662 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
| 4663 | ntfs_inode_mark_dirty(ni); |
| 4664 | |
| 4665 | /* Update attribute list. */ |
| 4666 | ctx->al_entry->mft_reference = |
| 4667 | MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)); |
| 4668 | ctx->al_entry->instance = nctx->attr->instance; |
| 4669 | ntfs_attrlist_mark_dirty(ni); |
| 4670 | |
| 4671 | ntfs_attr_put_search_ctx(nctx); |
| 4672 | return 0; |
| 4673 | put_err_out: |
| 4674 | ntfs_attr_put_search_ctx(nctx); |
| 4675 | errno = err; |
| 4676 | return -1; |
| 4677 | } |
| 4678 | |
| 4679 | /** |
| 4680 | * ntfs_attr_record_move_away - move away attribute record from it's mft record |
| 4681 | * @ctx: attribute search context describing the attribute record |
| 4682 | * @extra: minimum amount of free space in the new holder of record |
| 4683 | * |
| 4684 | * New attribute record holder must have free @extra bytes after moving |
| 4685 | * attribute record to it. |
| 4686 | * |
| 4687 | * If this function succeed, user should reinit search context if he/she wants |
| 4688 | * use it anymore. |
| 4689 | * |
| 4690 | * Return 0 on success and -1 on error with errno set to the error code. |
| 4691 | */ |
| 4692 | int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra) |
| 4693 | { |
| 4694 | ntfs_inode *base_ni, *ni; |
| 4695 | MFT_RECORD *m; |
| 4696 | int i; |
| 4697 | |
| 4698 | if (!ctx || !ctx->attr || !ctx->ntfs_ino || extra < 0) { |
| 4699 | errno = EINVAL; |
| 4700 | ntfs_log_perror("%s: ctx=%p ctx->attr=%p extra=%d", __FUNCTION__, |
| 4701 | ctx, ctx ? ctx->attr : NULL, extra); |
| 4702 | return -1; |
| 4703 | } |
| 4704 | |
| 4705 | ntfs_log_trace("Entering for attr 0x%x, inode %llu\n", |
| 4706 | (unsigned) le32_to_cpu(ctx->attr->type), |
| 4707 | (unsigned long long)ctx->ntfs_ino->mft_no); |
| 4708 | |
| 4709 | if (ctx->ntfs_ino->nr_extents == -1) |
| 4710 | base_ni = ctx->base_ntfs_ino; |
| 4711 | else |
| 4712 | base_ni = ctx->ntfs_ino; |
| 4713 | |
| 4714 | if (!NInoAttrList(base_ni)) { |
| 4715 | errno = EINVAL; |
| 4716 | ntfs_log_perror("Inode %llu has no attrlist", |
| 4717 | (unsigned long long)base_ni->mft_no); |
| 4718 | return -1; |
| 4719 | } |
| 4720 | |
| 4721 | if (ntfs_inode_attach_all_extents(ctx->ntfs_ino)) { |
| 4722 | ntfs_log_perror("Couldn't attach extents, inode=%llu", |
| 4723 | (unsigned long long)base_ni->mft_no); |
| 4724 | return -1; |
| 4725 | } |
| 4726 | |
| 4727 | /* Walk through all extents and try to move attribute to them. */ |
| 4728 | for (i = 0; i < base_ni->nr_extents; i++) { |
| 4729 | ni = base_ni->extent_nis[i]; |
| 4730 | m = ni->mrec; |
| 4731 | |
| 4732 | if (ctx->ntfs_ino->mft_no == ni->mft_no) |
| 4733 | continue; |
| 4734 | |
| 4735 | if (le32_to_cpu(m->bytes_allocated) - |
| 4736 | le32_to_cpu(m->bytes_in_use) < |
| 4737 | le32_to_cpu(ctx->attr->length) + extra) |
| 4738 | continue; |
| 4739 | |
| 4740 | /* |
| 4741 | * ntfs_attr_record_move_to can fail if extent with other lowest |
| 4742 | * VCN already present in inode we trying move record to. So, |
| 4743 | * do not return error. |
| 4744 | */ |
| 4745 | if (!ntfs_attr_record_move_to(ctx, ni)) |
| 4746 | return 0; |
| 4747 | } |
| 4748 | |
| 4749 | /* |
| 4750 | * Failed to move attribute to one of the current extents, so allocate |
| 4751 | * new extent and move attribute to it. |
| 4752 | */ |
| 4753 | ni = ntfs_mft_record_alloc(base_ni->vol, base_ni); |
| 4754 | if (!ni) { |
| 4755 | ntfs_log_perror("Couldn't allocate MFT record"); |
| 4756 | return -1; |
| 4757 | } |
| 4758 | if (ntfs_attr_record_move_to(ctx, ni)) { |
| 4759 | ntfs_log_perror("Couldn't move attribute to MFT record"); |
| 4760 | return -1; |
| 4761 | } |
| 4762 | return 0; |
| 4763 | } |
| 4764 | |
| 4765 | /** |
| 4766 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute |
| 4767 | * @na: open ntfs attribute to make non-resident |
| 4768 | * @ctx: ntfs search context describing the attribute |
| 4769 | * |
| 4770 | * Convert a resident ntfs attribute to a non-resident one. |
| 4771 | * |
| 4772 | * Return 0 on success and -1 on error with errno set to the error code. The |
| 4773 | * following error codes are defined: |
| 4774 | * EPERM - The attribute is not allowed to be non-resident. |
| 4775 | * TODO: others... |
| 4776 | * |
| 4777 | * NOTE to self: No changes in the attribute list are required to move from |
| 4778 | * a resident to a non-resident attribute. |
| 4779 | * |
| 4780 | * Warning: We do not set the inode dirty and we do not write out anything! |
| 4781 | * We expect the caller to do this as this is a fairly low level |
| 4782 | * function and it is likely there will be further changes made. |
| 4783 | */ |
| 4784 | int ntfs_attr_make_non_resident(ntfs_attr *na, |
| 4785 | ntfs_attr_search_ctx *ctx) |
| 4786 | { |
| 4787 | s64 new_allocated_size, bw; |
| 4788 | ntfs_volume *vol = na->ni->vol; |
| 4789 | ATTR_REC *a = ctx->attr; |
| 4790 | runlist *rl; |
| 4791 | int mp_size, mp_ofs, name_ofs, arec_size, err; |
| 4792 | |
| 4793 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 4794 | long)na->ni->mft_no, le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4795 | |
| 4796 | /* Some preliminary sanity checking. */ |
| 4797 | if (NAttrNonResident(na)) { |
| 4798 | ntfs_log_trace("Eeek! Trying to make non-resident attribute " |
| 4799 | "non-resident. Aborting...\n"); |
| 4800 | errno = EINVAL; |
| 4801 | return -1; |
| 4802 | } |
| 4803 | |
| 4804 | /* Check that the attribute is allowed to be non-resident. */ |
| 4805 | if (ntfs_attr_can_be_non_resident(vol, na->type, na->name, na->name_len)) |
| 4806 | return -1; |
| 4807 | |
| 4808 | new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size |
| 4809 | - 1) & ~(vol->cluster_size - 1); |
| 4810 | |
| 4811 | if (new_allocated_size > 0) { |
| 4812 | if ((a->flags & ATTR_COMPRESSION_MASK) |
| 4813 | == ATTR_IS_COMPRESSED) { |
| 4814 | /* must allocate full compression blocks */ |
| 4815 | new_allocated_size = ((new_allocated_size - 1) |
| 4816 | | ((1L << (STANDARD_COMPRESSION_UNIT |
| 4817 | + vol->cluster_size_bits)) - 1)) + 1; |
| 4818 | } |
| 4819 | /* Start by allocating clusters to hold the attribute value. */ |
| 4820 | rl = ntfs_cluster_alloc(vol, 0, new_allocated_size >> |
| 4821 | vol->cluster_size_bits, -1, DATA_ZONE); |
| 4822 | if (!rl) |
| 4823 | return -1; |
| 4824 | } else |
| 4825 | rl = NULL; |
| 4826 | /* |
| 4827 | * Setup the in-memory attribute structure to be non-resident so that |
| 4828 | * we can use ntfs_attr_pwrite(). |
| 4829 | */ |
| 4830 | NAttrSetNonResident(na); |
| 4831 | NAttrSetBeingNonResident(na); |
| 4832 | na->rl = rl; |
| 4833 | na->allocated_size = new_allocated_size; |
| 4834 | na->data_size = na->initialized_size = le32_to_cpu(a->value_length); |
| 4835 | /* |
| 4836 | * FIXME: For now just clear all of these as we don't support them when |
| 4837 | * writing. |
| 4838 | */ |
| 4839 | NAttrClearSparse(na); |
| 4840 | NAttrClearEncrypted(na); |
| 4841 | if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) { |
| 4842 | /* set compression writing parameters */ |
| 4843 | na->compression_block_size |
| 4844 | = 1 << (STANDARD_COMPRESSION_UNIT + vol->cluster_size_bits); |
| 4845 | na->compression_block_clusters = 1 << STANDARD_COMPRESSION_UNIT; |
| 4846 | } |
| 4847 | |
| 4848 | if (rl) { |
| 4849 | /* Now copy the attribute value to the allocated cluster(s). */ |
| 4850 | bw = ntfs_attr_pwrite(na, 0, le32_to_cpu(a->value_length), |
| 4851 | (u8*)a + le16_to_cpu(a->value_offset)); |
| 4852 | if (bw != le32_to_cpu(a->value_length)) { |
| 4853 | err = errno; |
| 4854 | ntfs_log_debug("Eeek! Failed to write out attribute value " |
| 4855 | "(bw = %lli, errno = %i). " |
| 4856 | "Aborting...\n", (long long)bw, err); |
| 4857 | if (bw >= 0) |
| 4858 | err = EIO; |
| 4859 | goto cluster_free_err_out; |
| 4860 | } |
| 4861 | } |
| 4862 | /* Determine the size of the mapping pairs array. */ |
| 4863 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, INT_MAX); |
| 4864 | if (mp_size < 0) { |
| 4865 | err = errno; |
| 4866 | ntfs_log_debug("Eeek! Failed to get size for mapping pairs array. " |
| 4867 | "Aborting...\n"); |
| 4868 | goto cluster_free_err_out; |
| 4869 | } |
| 4870 | /* Calculate new offsets for the name and the mapping pairs array. */ |
| 4871 | if (na->ni->flags & FILE_ATTR_COMPRESSED) |
| 4872 | name_ofs = (sizeof(ATTR_REC) + 7) & ~7; |
| 4873 | else |
| 4874 | name_ofs = (sizeof(ATTR_REC) - sizeof(a->compressed_size) + 7) & ~7; |
| 4875 | mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; |
| 4876 | /* |
| 4877 | * Determine the size of the resident part of the non-resident |
| 4878 | * attribute record. (Not compressed thus no compressed_size element |
| 4879 | * present.) |
| 4880 | */ |
| 4881 | arec_size = (mp_ofs + mp_size + 7) & ~7; |
| 4882 | |
| 4883 | /* Resize the resident part of the attribute record. */ |
| 4884 | if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { |
| 4885 | err = errno; |
| 4886 | goto cluster_free_err_out; |
| 4887 | } |
| 4888 | |
| 4889 | /* |
| 4890 | * Convert the resident part of the attribute record to describe a |
| 4891 | * non-resident attribute. |
| 4892 | */ |
| 4893 | a->non_resident = 1; |
| 4894 | |
| 4895 | /* Move the attribute name if it exists and update the offset. */ |
| 4896 | if (a->name_length) |
| 4897 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), |
| 4898 | a->name_length * sizeof(ntfschar)); |
| 4899 | a->name_offset = cpu_to_le16(name_ofs); |
| 4900 | |
| 4901 | /* Setup the fields specific to non-resident attributes. */ |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 4902 | a->lowest_vcn = const_cpu_to_sle64(0); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4903 | a->highest_vcn = cpu_to_sle64((new_allocated_size - 1) >> |
| 4904 | vol->cluster_size_bits); |
| 4905 | |
| 4906 | a->mapping_pairs_offset = cpu_to_le16(mp_ofs); |
| 4907 | |
| 4908 | /* |
| 4909 | * Update the flags to match the in-memory ones. |
| 4910 | * However cannot change the compression state if we had |
| 4911 | * a fuse_file_info open with a mark for release. |
| 4912 | * The decisions about compression can only be made when |
| 4913 | * creating/recreating the stream, not when making non resident. |
| 4914 | */ |
| 4915 | a->flags &= ~(ATTR_IS_SPARSE | ATTR_IS_ENCRYPTED); |
| 4916 | if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) { |
| 4917 | /* support only ATTR_IS_COMPRESSED compression mode */ |
| 4918 | a->compression_unit = STANDARD_COMPRESSION_UNIT; |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 4919 | a->compressed_size = const_cpu_to_sle64(0); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4920 | } else { |
| 4921 | a->compression_unit = 0; |
| 4922 | a->flags &= ~ATTR_COMPRESSION_MASK; |
| 4923 | na->data_flags = a->flags; |
| 4924 | } |
| 4925 | |
| 4926 | memset(&a->reserved1, 0, sizeof(a->reserved1)); |
| 4927 | |
| 4928 | a->allocated_size = cpu_to_sle64(new_allocated_size); |
| 4929 | a->data_size = a->initialized_size = cpu_to_sle64(na->data_size); |
| 4930 | |
| 4931 | /* Generate the mapping pairs array in the attribute record. */ |
| 4932 | if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs, |
| 4933 | rl, 0, NULL) < 0) { |
| 4934 | // FIXME: Eeek! We need rollback! (AIA) |
| 4935 | ntfs_log_trace("Eeek! Failed to build mapping pairs. Leaving " |
| 4936 | "corrupt attribute record on disk. In memory " |
| 4937 | "runlist is still intact! Error code is %i. " |
| 4938 | "FIXME: Need to rollback instead!\n", errno); |
| 4939 | return -1; |
| 4940 | } |
| 4941 | |
| 4942 | /* Done! */ |
| 4943 | return 0; |
| 4944 | |
| 4945 | cluster_free_err_out: |
| 4946 | if (rl && ntfs_cluster_free(vol, na, 0, -1) < 0) |
| 4947 | ntfs_log_trace("Eeek! Failed to release allocated clusters in error " |
| 4948 | "code path. Leaving inconsistent metadata...\n"); |
| 4949 | NAttrClearNonResident(na); |
| 4950 | NAttrClearFullyMapped(na); |
| 4951 | na->allocated_size = na->data_size; |
| 4952 | na->rl = NULL; |
| 4953 | free(rl); |
| 4954 | errno = err; |
| 4955 | return -1; |
| 4956 | } |
| 4957 | |
| 4958 | |
| 4959 | static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize); |
| 4960 | |
| 4961 | /** |
| 4962 | * ntfs_resident_attr_resize - resize a resident, open ntfs attribute |
| 4963 | * @na: resident ntfs attribute to resize |
| 4964 | * @newsize: new size (in bytes) to which to resize the attribute |
| 4965 | * |
| 4966 | * Change the size of a resident, open ntfs attribute @na to @newsize bytes. |
| 4967 | * Can also be used to force an attribute non-resident. In this case, the |
| 4968 | * size cannot be changed. |
| 4969 | * |
| 4970 | * On success return 0 |
| 4971 | * On error return values are: |
| 4972 | * STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT |
| 4973 | * STATUS_ERROR - otherwise |
| 4974 | * The following error codes are defined: |
| 4975 | * ENOMEM - Not enough memory to complete operation. |
| 4976 | * ERANGE - @newsize is not valid for the attribute type of @na. |
| 4977 | * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. |
| 4978 | */ |
| 4979 | static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize, |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 4980 | hole_type holes) |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4981 | { |
| 4982 | ntfs_attr_search_ctx *ctx; |
| 4983 | ntfs_volume *vol; |
| 4984 | ntfs_inode *ni; |
| 4985 | int err, ret = STATUS_ERROR; |
| 4986 | |
| 4987 | ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 4988 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 4989 | (long long)newsize); |
| 4990 | |
| 4991 | /* Get the attribute record that needs modification. */ |
| 4992 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 4993 | if (!ctx) |
| 4994 | return -1; |
| 4995 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0, |
| 4996 | ctx)) { |
| 4997 | err = errno; |
| 4998 | ntfs_log_perror("ntfs_attr_lookup failed"); |
| 4999 | goto put_err_out; |
| 5000 | } |
| 5001 | vol = na->ni->vol; |
| 5002 | /* |
| 5003 | * Check the attribute type and the corresponding minimum and maximum |
| 5004 | * sizes against @newsize and fail if @newsize is out of bounds. |
| 5005 | */ |
| 5006 | if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { |
| 5007 | err = errno; |
| 5008 | if (err == ENOENT) |
| 5009 | err = EIO; |
| 5010 | ntfs_log_perror("%s: bounds check failed", __FUNCTION__); |
| 5011 | goto put_err_out; |
| 5012 | } |
| 5013 | /* |
| 5014 | * If @newsize is bigger than the mft record we need to make the |
| 5015 | * attribute non-resident if the attribute type supports it. If it is |
| 5016 | * smaller we can go ahead and attempt the resize. |
| 5017 | */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5018 | if ((newsize < vol->mft_record_size) && (holes != HOLES_NONRES)) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5019 | /* Perform the resize of the attribute record. */ |
| 5020 | if (!(ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, |
| 5021 | newsize))) { |
| 5022 | /* Update attribute size everywhere. */ |
| 5023 | na->data_size = na->initialized_size = newsize; |
| 5024 | na->allocated_size = (newsize + 7) & ~7; |
| 5025 | if ((na->data_flags & ATTR_COMPRESSION_MASK) |
| 5026 | || NAttrSparse(na)) |
| 5027 | na->compressed_size = na->allocated_size; |
| 5028 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
| 5029 | ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 |
| 5030 | : na->type == AT_DATA && na->name == AT_UNNAMED) { |
| 5031 | na->ni->data_size = na->data_size; |
| 5032 | if (((na->data_flags & ATTR_COMPRESSION_MASK) |
| 5033 | || NAttrSparse(na)) |
| 5034 | && NAttrNonResident(na)) |
| 5035 | na->ni->allocated_size |
| 5036 | = na->compressed_size; |
| 5037 | else |
| 5038 | na->ni->allocated_size |
| 5039 | = na->allocated_size; |
| 5040 | set_nino_flag(na->ni,KnownSize); |
| 5041 | if (na->type == AT_DATA) |
| 5042 | NInoFileNameSetDirty(na->ni); |
| 5043 | } |
| 5044 | goto resize_done; |
| 5045 | } |
| 5046 | /* Prefer AT_INDEX_ALLOCATION instead of AT_ATTRIBUTE_LIST */ |
| 5047 | if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { |
| 5048 | err = errno; |
| 5049 | goto put_err_out; |
| 5050 | } |
| 5051 | } |
| 5052 | /* There is not enough space in the mft record to perform the resize. */ |
| 5053 | |
| 5054 | /* Make the attribute non-resident if possible. */ |
| 5055 | if (!ntfs_attr_make_non_resident(na, ctx)) { |
| 5056 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
| 5057 | ntfs_attr_put_search_ctx(ctx); |
| 5058 | /* |
| 5059 | * do not truncate when forcing non-resident, this |
| 5060 | * could cause the attribute to be made resident again, |
| 5061 | * so size changes are not allowed. |
| 5062 | */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5063 | if (holes == HOLES_NONRES) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5064 | ret = 0; |
| 5065 | if (newsize != na->data_size) { |
| 5066 | ntfs_log_error("Cannot change size when" |
| 5067 | " forcing non-resident\n"); |
| 5068 | errno = EIO; |
| 5069 | ret = STATUS_ERROR; |
| 5070 | } |
| 5071 | return (ret); |
| 5072 | } |
| 5073 | /* Resize non-resident attribute */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5074 | return ntfs_attr_truncate_i(na, newsize, holes); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5075 | } else if (errno != ENOSPC && errno != EPERM) { |
| 5076 | err = errno; |
| 5077 | ntfs_log_perror("Failed to make attribute non-resident"); |
| 5078 | goto put_err_out; |
| 5079 | } |
| 5080 | |
| 5081 | /* Try to make other attributes non-resident and retry each time. */ |
| 5082 | ntfs_attr_init_search_ctx(ctx, NULL, na->ni->mrec); |
| 5083 | while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { |
| 5084 | ntfs_attr *tna; |
| 5085 | ATTR_RECORD *a; |
| 5086 | |
| 5087 | a = ctx->attr; |
| 5088 | if (a->non_resident) |
| 5089 | continue; |
| 5090 | |
| 5091 | /* |
| 5092 | * Check out whether convert is reasonable. Assume that mapping |
| 5093 | * pairs will take 8 bytes. |
| 5094 | */ |
| 5095 | if (le32_to_cpu(a->length) <= offsetof(ATTR_RECORD, |
| 5096 | compressed_size) + ((a->name_length * |
| 5097 | sizeof(ntfschar) + 7) & ~7) + 8) |
| 5098 | continue; |
| 5099 | |
| 5100 | tna = ntfs_attr_open(na->ni, a->type, (ntfschar*)((u8*)a + |
| 5101 | le16_to_cpu(a->name_offset)), a->name_length); |
| 5102 | if (!tna) { |
| 5103 | err = errno; |
| 5104 | ntfs_log_perror("Couldn't open attribute"); |
| 5105 | goto put_err_out; |
| 5106 | } |
| 5107 | if (ntfs_attr_make_non_resident(tna, ctx)) { |
| 5108 | ntfs_attr_close(tna); |
| 5109 | continue; |
| 5110 | } |
| 5111 | if ((tna->type == AT_DATA) && !tna->name_len) { |
| 5112 | /* |
| 5113 | * If we had to make the unnamed data attribute |
| 5114 | * non-resident, propagate its new allocated size |
| 5115 | * to all name attributes and directory indexes |
| 5116 | */ |
| 5117 | tna->ni->allocated_size = tna->allocated_size; |
| 5118 | NInoFileNameSetDirty(tna->ni); |
| 5119 | } |
| 5120 | if (((tna->data_flags & ATTR_COMPRESSION_MASK) |
| 5121 | == ATTR_IS_COMPRESSED) |
| 5122 | && ntfs_attr_pclose(tna)) { |
| 5123 | err = errno; |
| 5124 | ntfs_attr_close(tna); |
| 5125 | goto put_err_out; |
| 5126 | } |
| 5127 | ntfs_inode_mark_dirty(tna->ni); |
| 5128 | ntfs_attr_close(tna); |
| 5129 | ntfs_attr_put_search_ctx(ctx); |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5130 | return ntfs_resident_attr_resize_i(na, newsize, holes); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5131 | } |
| 5132 | /* Check whether error occurred. */ |
| 5133 | if (errno != ENOENT) { |
| 5134 | err = errno; |
| 5135 | ntfs_log_perror("%s: Attribute lookup failed 1", __FUNCTION__); |
| 5136 | goto put_err_out; |
| 5137 | } |
| 5138 | |
| 5139 | /* |
| 5140 | * The standard information and attribute list attributes can't be |
| 5141 | * moved out from the base MFT record, so try to move out others. |
| 5142 | */ |
| 5143 | if (na->type==AT_STANDARD_INFORMATION || na->type==AT_ATTRIBUTE_LIST) { |
| 5144 | ntfs_attr_put_search_ctx(ctx); |
| 5145 | if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD, |
| 5146 | non_resident_end) + 8)) { |
| 5147 | ntfs_log_perror("Could not free space in MFT record"); |
| 5148 | return -1; |
| 5149 | } |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5150 | return ntfs_resident_attr_resize_i(na, newsize, holes); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5151 | } |
| 5152 | |
| 5153 | /* |
| 5154 | * Move the attribute to a new mft record, creating an attribute list |
| 5155 | * attribute or modifying it if it is already present. |
| 5156 | */ |
| 5157 | |
| 5158 | /* Point search context back to attribute which we need resize. */ |
| 5159 | ntfs_attr_init_search_ctx(ctx, na->ni, NULL); |
| 5160 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
| 5161 | 0, NULL, 0, ctx)) { |
| 5162 | ntfs_log_perror("%s: Attribute lookup failed 2", __FUNCTION__); |
| 5163 | err = errno; |
| 5164 | goto put_err_out; |
| 5165 | } |
| 5166 | |
| 5167 | /* |
| 5168 | * Check whether attribute is already single in this MFT record. |
| 5169 | * 8 added for the attribute terminator. |
| 5170 | */ |
| 5171 | if (le32_to_cpu(ctx->mrec->bytes_in_use) == |
| 5172 | le16_to_cpu(ctx->mrec->attrs_offset) + |
| 5173 | le32_to_cpu(ctx->attr->length) + 8) { |
| 5174 | err = ENOSPC; |
| 5175 | ntfs_log_trace("MFT record is filled with one attribute\n"); |
| 5176 | ret = STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; |
| 5177 | goto put_err_out; |
| 5178 | } |
| 5179 | |
| 5180 | /* Add attribute list if not present. */ |
| 5181 | if (na->ni->nr_extents == -1) |
| 5182 | ni = na->ni->base_ni; |
| 5183 | else |
| 5184 | ni = na->ni; |
| 5185 | if (!NInoAttrList(ni)) { |
| 5186 | ntfs_attr_put_search_ctx(ctx); |
| 5187 | if (ntfs_inode_add_attrlist(ni)) |
| 5188 | return -1; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5189 | return ntfs_resident_attr_resize_i(na, newsize, holes); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5190 | } |
| 5191 | /* Allocate new mft record. */ |
| 5192 | ni = ntfs_mft_record_alloc(vol, ni); |
| 5193 | if (!ni) { |
| 5194 | err = errno; |
| 5195 | ntfs_log_perror("Couldn't allocate new MFT record"); |
| 5196 | goto put_err_out; |
| 5197 | } |
| 5198 | /* Move attribute to it. */ |
| 5199 | if (ntfs_attr_record_move_to(ctx, ni)) { |
| 5200 | err = errno; |
| 5201 | ntfs_log_perror("Couldn't move attribute to new MFT record"); |
| 5202 | goto put_err_out; |
| 5203 | } |
| 5204 | /* Update ntfs attribute. */ |
| 5205 | if (na->ni->nr_extents == -1) |
| 5206 | na->ni = ni; |
| 5207 | |
| 5208 | ntfs_attr_put_search_ctx(ctx); |
| 5209 | /* Try to perform resize once again. */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5210 | return ntfs_resident_attr_resize_i(na, newsize, holes); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5211 | |
| 5212 | resize_done: |
| 5213 | /* |
| 5214 | * Set the inode (and its base inode if it exists) dirty so it is |
| 5215 | * written out later. |
| 5216 | */ |
| 5217 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
| 5218 | ntfs_attr_put_search_ctx(ctx); |
| 5219 | return 0; |
| 5220 | put_err_out: |
| 5221 | ntfs_attr_put_search_ctx(ctx); |
| 5222 | errno = err; |
| 5223 | return ret; |
| 5224 | } |
| 5225 | |
| 5226 | static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) |
| 5227 | { |
| 5228 | int ret; |
| 5229 | |
| 5230 | ntfs_log_enter("Entering\n"); |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5231 | ret = ntfs_resident_attr_resize_i(na, newsize, HOLES_OK); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5232 | ntfs_log_leave("\n"); |
| 5233 | return ret; |
| 5234 | } |
| 5235 | |
| 5236 | /* |
| 5237 | * Force an attribute to be made non-resident without |
| 5238 | * changing its size. |
| 5239 | * |
| 5240 | * This is particularly needed when the attribute has no data, |
| 5241 | * as the non-resident variant requires more space in the MFT |
| 5242 | * record, and may imply expelling some other attribute. |
| 5243 | * |
| 5244 | * As a consequence the existing ntfs_attr_search_ctx's have to |
| 5245 | * be closed or reinitialized. |
| 5246 | * |
| 5247 | * returns 0 if successful, |
| 5248 | * < 0 if failed, with errno telling why |
| 5249 | */ |
| 5250 | |
| 5251 | int ntfs_attr_force_non_resident(ntfs_attr *na) |
| 5252 | { |
| 5253 | int res; |
| 5254 | |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5255 | res = ntfs_resident_attr_resize_i(na, na->data_size, HOLES_NONRES); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5256 | if (!res && !NAttrNonResident(na)) { |
| 5257 | res = -1; |
| 5258 | errno = EIO; |
| 5259 | ntfs_log_error("Failed to force non-resident\n"); |
| 5260 | } |
| 5261 | return (res); |
| 5262 | } |
| 5263 | |
| 5264 | /** |
| 5265 | * ntfs_attr_make_resident - convert a non-resident to a resident attribute |
| 5266 | * @na: open ntfs attribute to make resident |
| 5267 | * @ctx: ntfs search context describing the attribute |
| 5268 | * |
| 5269 | * Convert a non-resident ntfs attribute to a resident one. |
| 5270 | * |
| 5271 | * Return 0 on success and -1 on error with errno set to the error code. The |
| 5272 | * following error codes are defined: |
| 5273 | * EINVAL - Invalid arguments passed. |
| 5274 | * EPERM - The attribute is not allowed to be resident. |
| 5275 | * EIO - I/O error, damaged inode or bug. |
| 5276 | * ENOSPC - There is no enough space to perform conversion. |
| 5277 | * EOPNOTSUPP - Requested conversion is not supported yet. |
| 5278 | * |
| 5279 | * Warning: We do not set the inode dirty and we do not write out anything! |
| 5280 | * We expect the caller to do this as this is a fairly low level |
| 5281 | * function and it is likely there will be further changes made. |
| 5282 | */ |
| 5283 | static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) |
| 5284 | { |
| 5285 | ntfs_volume *vol = na->ni->vol; |
| 5286 | ATTR_REC *a = ctx->attr; |
| 5287 | int name_ofs, val_ofs, err = EIO; |
| 5288 | s64 arec_size, bytes_read; |
| 5289 | |
| 5290 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 5291 | long)na->ni->mft_no, le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5292 | |
| 5293 | /* Should be called for the first extent of the attribute. */ |
| 5294 | if (sle64_to_cpu(a->lowest_vcn)) { |
| 5295 | ntfs_log_trace("Eeek! Should be called for the first extent of the " |
| 5296 | "attribute. Aborting...\n"); |
| 5297 | errno = EINVAL; |
| 5298 | return -1; |
| 5299 | } |
| 5300 | |
| 5301 | /* Some preliminary sanity checking. */ |
| 5302 | if (!NAttrNonResident(na)) { |
| 5303 | ntfs_log_trace("Eeek! Trying to make resident attribute resident. " |
| 5304 | "Aborting...\n"); |
| 5305 | errno = EINVAL; |
| 5306 | return -1; |
| 5307 | } |
| 5308 | |
| 5309 | /* Make sure this is not $MFT/$BITMAP or Windows will not boot! */ |
| 5310 | if (na->type == AT_BITMAP && na->ni->mft_no == FILE_MFT) { |
| 5311 | errno = EPERM; |
| 5312 | return -1; |
| 5313 | } |
| 5314 | |
| 5315 | /* Check that the attribute is allowed to be resident. */ |
| 5316 | if (ntfs_attr_can_be_resident(vol, na->type)) |
| 5317 | return -1; |
| 5318 | |
| 5319 | if (na->data_flags & ATTR_IS_ENCRYPTED) { |
| 5320 | ntfs_log_trace("Making encrypted streams resident is not " |
| 5321 | "implemented yet.\n"); |
| 5322 | errno = EOPNOTSUPP; |
| 5323 | return -1; |
| 5324 | } |
| 5325 | |
| 5326 | /* Work out offsets into and size of the resident attribute. */ |
| 5327 | name_ofs = 24; /* = sizeof(resident_ATTR_REC); */ |
| 5328 | val_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; |
| 5329 | arec_size = (val_ofs + na->data_size + 7) & ~7; |
| 5330 | |
| 5331 | /* Sanity check the size before we start modifying the attribute. */ |
| 5332 | if (le32_to_cpu(ctx->mrec->bytes_in_use) - le32_to_cpu(a->length) + |
| 5333 | arec_size > le32_to_cpu(ctx->mrec->bytes_allocated)) { |
| 5334 | errno = ENOSPC; |
| 5335 | ntfs_log_trace("Not enough space to make attribute resident\n"); |
| 5336 | return -1; |
| 5337 | } |
| 5338 | |
| 5339 | /* Read and cache the whole runlist if not already done. */ |
| 5340 | if (ntfs_attr_map_whole_runlist(na)) |
| 5341 | return -1; |
| 5342 | |
| 5343 | /* Move the attribute name if it exists and update the offset. */ |
| 5344 | if (a->name_length) { |
| 5345 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), |
| 5346 | a->name_length * sizeof(ntfschar)); |
| 5347 | } |
| 5348 | a->name_offset = cpu_to_le16(name_ofs); |
| 5349 | |
| 5350 | /* Resize the resident part of the attribute record. */ |
| 5351 | if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { |
| 5352 | /* |
| 5353 | * Bug, because ntfs_attr_record_resize should not fail (we |
| 5354 | * already checked that attribute fits MFT record). |
| 5355 | */ |
| 5356 | ntfs_log_error("BUG! Failed to resize attribute record. " |
| 5357 | "Please report to the %s. Aborting...\n", |
| 5358 | NTFS_DEV_LIST); |
| 5359 | errno = EIO; |
| 5360 | return -1; |
| 5361 | } |
| 5362 | |
| 5363 | /* Convert the attribute record to describe a resident attribute. */ |
| 5364 | a->non_resident = 0; |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 5365 | a->flags = const_cpu_to_le16(0); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5366 | a->value_length = cpu_to_le32(na->data_size); |
| 5367 | a->value_offset = cpu_to_le16(val_ofs); |
| 5368 | /* |
| 5369 | * If a data stream was wiped out, adjust the compression mode |
| 5370 | * to current state of compression flag |
| 5371 | */ |
| 5372 | if (!na->data_size |
| 5373 | && (na->type == AT_DATA) |
| 5374 | && (na->ni->vol->major_ver >= 3) |
| 5375 | && NVolCompression(na->ni->vol) |
| 5376 | && (na->ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) |
| 5377 | && (na->ni->flags & FILE_ATTR_COMPRESSED)) { |
| 5378 | a->flags |= ATTR_IS_COMPRESSED; |
| 5379 | na->data_flags = a->flags; |
| 5380 | } |
| 5381 | /* |
| 5382 | * File names cannot be non-resident so we would never see this here |
| 5383 | * but at least it serves as a reminder that there may be attributes |
| 5384 | * for which we do need to set this flag. (AIA) |
| 5385 | */ |
| 5386 | if (a->type == AT_FILE_NAME) |
| 5387 | a->resident_flags = RESIDENT_ATTR_IS_INDEXED; |
| 5388 | else |
| 5389 | a->resident_flags = 0; |
| 5390 | a->reservedR = 0; |
| 5391 | |
| 5392 | /* Sanity fixup... Shouldn't really happen. (AIA) */ |
| 5393 | if (na->initialized_size > na->data_size) |
| 5394 | na->initialized_size = na->data_size; |
| 5395 | |
| 5396 | /* Copy data from run list to resident attribute value. */ |
| 5397 | bytes_read = ntfs_rl_pread(vol, na->rl, 0, na->initialized_size, |
| 5398 | (u8*)a + val_ofs); |
| 5399 | if (bytes_read != na->initialized_size) { |
| 5400 | if (bytes_read < 0) |
| 5401 | err = errno; |
| 5402 | ntfs_log_trace("Eeek! Failed to read attribute data. Leaving " |
| 5403 | "inconstant metadata. Run chkdsk. " |
| 5404 | "Aborting...\n"); |
| 5405 | errno = err; |
| 5406 | return -1; |
| 5407 | } |
| 5408 | |
| 5409 | /* Clear memory in gap between initialized_size and data_size. */ |
| 5410 | if (na->initialized_size < na->data_size) |
| 5411 | memset((u8*)a + val_ofs + na->initialized_size, 0, |
| 5412 | na->data_size - na->initialized_size); |
| 5413 | |
| 5414 | /* |
| 5415 | * Deallocate clusters from the runlist. |
| 5416 | * |
| 5417 | * NOTE: We can use ntfs_cluster_free() because we have already mapped |
| 5418 | * the whole run list and thus it doesn't matter that the attribute |
| 5419 | * record is in a transiently corrupted state at this moment in time. |
| 5420 | */ |
| 5421 | if (ntfs_cluster_free(vol, na, 0, -1) < 0) { |
| 5422 | ntfs_log_perror("Eeek! Failed to release allocated clusters"); |
| 5423 | ntfs_log_trace("Ignoring error and leaving behind wasted " |
| 5424 | "clusters.\n"); |
| 5425 | } |
| 5426 | |
| 5427 | /* Throw away the now unused runlist. */ |
| 5428 | free(na->rl); |
| 5429 | na->rl = NULL; |
| 5430 | |
| 5431 | /* Update in-memory struct ntfs_attr. */ |
| 5432 | NAttrClearNonResident(na); |
| 5433 | NAttrClearFullyMapped(na); |
| 5434 | NAttrClearSparse(na); |
| 5435 | NAttrClearEncrypted(na); |
| 5436 | na->initialized_size = na->data_size; |
| 5437 | na->allocated_size = na->compressed_size = (na->data_size + 7) & ~7; |
| 5438 | na->compression_block_size = 0; |
| 5439 | na->compression_block_size_bits = na->compression_block_clusters = 0; |
| 5440 | return 0; |
| 5441 | } |
| 5442 | |
| 5443 | /* |
| 5444 | * If we are in the first extent, then set/clean sparse bit, |
| 5445 | * update allocated and compressed size. |
| 5446 | */ |
| 5447 | static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m, |
| 5448 | hole_type holes, ntfs_attr_search_ctx *ctx) |
| 5449 | { |
| 5450 | int sparse, ret = 0; |
| 5451 | |
| 5452 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 5453 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5454 | |
| 5455 | if (a->lowest_vcn) |
| 5456 | goto out; |
| 5457 | |
| 5458 | a->allocated_size = cpu_to_sle64(na->allocated_size); |
| 5459 | |
| 5460 | /* Update sparse bit, unless this is an intermediate state */ |
| 5461 | if (holes == HOLES_DELAY) |
| 5462 | sparse = (a->flags & ATTR_IS_SPARSE) != const_cpu_to_le16(0); |
| 5463 | else { |
| 5464 | sparse = ntfs_rl_sparse(na->rl); |
| 5465 | if (sparse == -1) { |
| 5466 | errno = EIO; |
| 5467 | goto error; |
| 5468 | } |
| 5469 | } |
| 5470 | |
| 5471 | /* Check whether attribute becomes sparse, unless check is delayed. */ |
| 5472 | if ((holes != HOLES_DELAY) |
| 5473 | && sparse |
| 5474 | && !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) { |
| 5475 | /* |
| 5476 | * Move attribute to another mft record, if attribute is too |
| 5477 | * small to add compressed_size field to it and we have no |
| 5478 | * free space in the current mft record. |
| 5479 | */ |
| 5480 | if ((le32_to_cpu(a->length) - |
| 5481 | le16_to_cpu(a->mapping_pairs_offset) == 8) |
| 5482 | && !(le32_to_cpu(m->bytes_allocated) - |
| 5483 | le32_to_cpu(m->bytes_in_use))) { |
| 5484 | |
| 5485 | if (!NInoAttrList(na->ni)) { |
| 5486 | ntfs_attr_put_search_ctx(ctx); |
| 5487 | if (ntfs_inode_add_attrlist(na->ni)) |
| 5488 | goto leave; |
| 5489 | goto retry; |
| 5490 | } |
| 5491 | if (ntfs_attr_record_move_away(ctx, 8)) { |
| 5492 | ntfs_log_perror("Failed to move attribute"); |
| 5493 | goto error; |
| 5494 | } |
| 5495 | ntfs_attr_put_search_ctx(ctx); |
| 5496 | goto retry; |
| 5497 | } |
| 5498 | if (!(le32_to_cpu(a->length) - le16_to_cpu( |
| 5499 | a->mapping_pairs_offset))) { |
| 5500 | errno = EIO; |
| 5501 | ntfs_log_perror("Mapping pairs space is 0"); |
| 5502 | goto error; |
| 5503 | } |
| 5504 | |
| 5505 | NAttrSetSparse(na); |
| 5506 | a->flags |= ATTR_IS_SPARSE; |
| 5507 | na->data_flags = a->flags; |
| 5508 | a->compression_unit = STANDARD_COMPRESSION_UNIT; /* Windows |
| 5509 | set it so, even if attribute is not actually compressed. */ |
| 5510 | |
| 5511 | memmove((u8*)a + le16_to_cpu(a->name_offset) + 8, |
| 5512 | (u8*)a + le16_to_cpu(a->name_offset), |
| 5513 | a->name_length * sizeof(ntfschar)); |
| 5514 | |
| 5515 | a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) + 8); |
| 5516 | |
| 5517 | a->mapping_pairs_offset = |
| 5518 | cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) + 8); |
| 5519 | } |
| 5520 | |
| 5521 | /* Attribute no longer sparse. */ |
| 5522 | if (!sparse && (a->flags & ATTR_IS_SPARSE) && |
| 5523 | !(a->flags & ATTR_IS_COMPRESSED)) { |
| 5524 | |
| 5525 | NAttrClearSparse(na); |
| 5526 | a->flags &= ~ATTR_IS_SPARSE; |
| 5527 | na->data_flags = a->flags; |
| 5528 | a->compression_unit = 0; |
| 5529 | |
| 5530 | memmove((u8*)a + le16_to_cpu(a->name_offset) - 8, |
| 5531 | (u8*)a + le16_to_cpu(a->name_offset), |
| 5532 | a->name_length * sizeof(ntfschar)); |
| 5533 | |
| 5534 | if (le16_to_cpu(a->name_offset) >= 8) |
| 5535 | a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) - 8); |
| 5536 | |
| 5537 | a->mapping_pairs_offset = |
| 5538 | cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) - 8); |
| 5539 | } |
| 5540 | |
| 5541 | /* Update compressed size if required. */ |
| 5542 | if (NAttrFullyMapped(na) |
| 5543 | && (sparse || (na->data_flags & ATTR_COMPRESSION_MASK))) { |
| 5544 | s64 new_compr_size; |
| 5545 | |
| 5546 | new_compr_size = ntfs_rl_get_compressed_size(na->ni->vol, na->rl); |
| 5547 | if (new_compr_size == -1) |
| 5548 | goto error; |
| 5549 | |
| 5550 | na->compressed_size = new_compr_size; |
| 5551 | a->compressed_size = cpu_to_sle64(new_compr_size); |
| 5552 | } |
| 5553 | /* |
| 5554 | * Set FILE_NAME dirty flag, to update sparse bit and |
| 5555 | * allocated size in the index. |
| 5556 | */ |
| 5557 | if (na->type == AT_DATA && na->name == AT_UNNAMED) { |
| 5558 | if (sparse || (na->data_flags & ATTR_COMPRESSION_MASK)) |
| 5559 | na->ni->allocated_size = na->compressed_size; |
| 5560 | else |
| 5561 | na->ni->allocated_size = na->allocated_size; |
| 5562 | NInoFileNameSetDirty(na->ni); |
| 5563 | } |
| 5564 | out: |
| 5565 | return ret; |
| 5566 | leave: ret = -1; goto out; /* return -1 */ |
| 5567 | retry: ret = -2; goto out; |
| 5568 | error: ret = -3; goto out; |
| 5569 | } |
| 5570 | |
| 5571 | #define NTFS_VCN_DELETE_MARK -2 |
| 5572 | /** |
| 5573 | * ntfs_attr_update_mapping_pairs_i - see ntfs_attr_update_mapping_pairs |
| 5574 | */ |
| 5575 | static int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn, |
| 5576 | hole_type holes) |
| 5577 | { |
| 5578 | ntfs_attr_search_ctx *ctx; |
| 5579 | ntfs_inode *ni, *base_ni; |
| 5580 | MFT_RECORD *m; |
| 5581 | ATTR_RECORD *a; |
| 5582 | VCN stop_vcn; |
| 5583 | const runlist_element *stop_rl; |
| 5584 | int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1; |
| 5585 | BOOL finished_build; |
| 5586 | BOOL first_updated = FALSE; |
| 5587 | |
| 5588 | retry: |
| 5589 | if (!na || !na->rl) { |
| 5590 | errno = EINVAL; |
| 5591 | ntfs_log_perror("%s: na=%p", __FUNCTION__, na); |
| 5592 | return -1; |
| 5593 | } |
| 5594 | |
| 5595 | ntfs_log_trace("Entering for inode %llu, attr 0x%x\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 5596 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5597 | |
| 5598 | if (!NAttrNonResident(na)) { |
| 5599 | errno = EINVAL; |
| 5600 | ntfs_log_perror("%s: resident attribute", __FUNCTION__); |
| 5601 | return -1; |
| 5602 | } |
| 5603 | |
| 5604 | #if PARTIAL_RUNLIST_UPDATING |
| 5605 | /* |
| 5606 | * For a file just been made sparse, we will have |
| 5607 | * to reformat the first extent, so be sure the |
| 5608 | * runlist is fully mapped and fully processed. |
| 5609 | * Same if the file was sparse and is not any more. |
| 5610 | * Note : not needed if the full runlist is to be processed |
| 5611 | */ |
| 5612 | if ((holes != HOLES_DELAY) |
| 5613 | && (!NAttrFullyMapped(na) || from_vcn) |
| 5614 | && !(na->data_flags & ATTR_IS_COMPRESSED)) { |
| 5615 | BOOL changed; |
| 5616 | |
| 5617 | if (!(na->data_flags & ATTR_IS_SPARSE)) { |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5618 | int sparse = 0; |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5619 | runlist_element *xrl; |
| 5620 | |
| 5621 | /* |
| 5622 | * If attribute was not sparse, we only |
| 5623 | * have to check whether there is a hole |
| 5624 | * in the updated region. |
| 5625 | */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5626 | for (xrl = na->rl; xrl->length; xrl++) { |
| 5627 | if (xrl->lcn < 0) { |
| 5628 | if (xrl->lcn == LCN_HOLE) { |
| 5629 | sparse = 1; |
| 5630 | break; |
| 5631 | } |
| 5632 | if (xrl->lcn != LCN_RL_NOT_MAPPED) { |
| 5633 | sparse = -1; |
| 5634 | break; |
| 5635 | } |
| 5636 | } |
| 5637 | } |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5638 | if (sparse < 0) { |
| 5639 | ntfs_log_error("Could not check whether sparse\n"); |
| 5640 | errno = EIO; |
| 5641 | return (-1); |
| 5642 | } |
| 5643 | changed = sparse > 0; |
| 5644 | } else { |
| 5645 | /* |
| 5646 | * If attribute was sparse, the compressed |
| 5647 | * size has been maintained, and it gives |
| 5648 | * and easy way to check whether the |
| 5649 | * attribute is still sparse. |
| 5650 | */ |
| 5651 | changed = (((na->data_size - 1) |
| 5652 | | (na->ni->vol->cluster_size - 1)) + 1) |
| 5653 | == na->compressed_size; |
| 5654 | } |
| 5655 | if (changed) { |
| 5656 | if (ntfs_attr_map_whole_runlist(na)) { |
| 5657 | ntfs_log_error("Could not map whole for sparse change\n"); |
| 5658 | errno = EIO; |
| 5659 | return (-1); |
| 5660 | } |
| 5661 | from_vcn = 0; |
| 5662 | } |
| 5663 | } |
| 5664 | #endif |
| 5665 | if (na->ni->nr_extents == -1) |
| 5666 | base_ni = na->ni->base_ni; |
| 5667 | else |
| 5668 | base_ni = na->ni; |
| 5669 | |
| 5670 | ctx = ntfs_attr_get_search_ctx(base_ni, NULL); |
| 5671 | if (!ctx) |
| 5672 | return -1; |
| 5673 | |
| 5674 | /* Fill attribute records with new mapping pairs. */ |
| 5675 | stop_vcn = 0; |
| 5676 | stop_rl = na->rl; |
| 5677 | finished_build = FALSE; |
| 5678 | while (!ntfs_attr_lookup(na->type, na->name, na->name_len, |
| 5679 | CASE_SENSITIVE, from_vcn, NULL, 0, ctx)) { |
| 5680 | a = ctx->attr; |
| 5681 | m = ctx->mrec; |
| 5682 | if (!a->lowest_vcn) |
| 5683 | first_updated = TRUE; |
| 5684 | /* |
| 5685 | * If runlist is updating not from the beginning, then set |
| 5686 | * @stop_vcn properly, i.e. to the lowest vcn of record that |
| 5687 | * contain @from_vcn. Also we do not need @from_vcn anymore, |
| 5688 | * set it to 0 to make ntfs_attr_lookup enumerate attributes. |
| 5689 | */ |
| 5690 | if (from_vcn) { |
| 5691 | LCN first_lcn; |
| 5692 | |
| 5693 | stop_vcn = sle64_to_cpu(a->lowest_vcn); |
| 5694 | from_vcn = 0; |
| 5695 | /* |
| 5696 | * Check whether the first run we need to update is |
| 5697 | * the last run in runlist, if so, then deallocate |
| 5698 | * all attrubute extents starting this one. |
| 5699 | */ |
| 5700 | first_lcn = ntfs_rl_vcn_to_lcn(na->rl, stop_vcn); |
| 5701 | if (first_lcn == LCN_EINVAL) { |
| 5702 | errno = EIO; |
| 5703 | ntfs_log_perror("Bad runlist"); |
| 5704 | goto put_err_out; |
| 5705 | } |
| 5706 | if (first_lcn == LCN_ENOENT || |
| 5707 | first_lcn == LCN_RL_NOT_MAPPED) |
| 5708 | finished_build = TRUE; |
| 5709 | } |
| 5710 | |
| 5711 | /* |
| 5712 | * Check whether we finished mapping pairs build, if so mark |
| 5713 | * extent as need to delete (by setting highest vcn to |
| 5714 | * NTFS_VCN_DELETE_MARK (-2), we shall check it later and |
| 5715 | * delete extent) and continue search. |
| 5716 | */ |
| 5717 | if (finished_build) { |
| 5718 | ntfs_log_trace("Mark attr 0x%x for delete in inode " |
| 5719 | "%lld.\n", (unsigned)le32_to_cpu(a->type), |
| 5720 | (long long)ctx->ntfs_ino->mft_no); |
| 5721 | a->highest_vcn = cpu_to_sle64(NTFS_VCN_DELETE_MARK); |
| 5722 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
| 5723 | continue; |
| 5724 | } |
| 5725 | |
| 5726 | switch (ntfs_attr_update_meta(a, na, m, holes, ctx)) { |
| 5727 | case -1: return -1; |
| 5728 | case -2: goto retry; |
| 5729 | case -3: goto put_err_out; |
| 5730 | } |
| 5731 | |
| 5732 | /* |
| 5733 | * Determine maximum possible length of mapping pairs, |
| 5734 | * if we shall *not* expand space for mapping pairs. |
| 5735 | */ |
| 5736 | cur_max_mp_size = le32_to_cpu(a->length) - |
| 5737 | le16_to_cpu(a->mapping_pairs_offset); |
| 5738 | /* |
| 5739 | * Determine maximum possible length of mapping pairs in the |
| 5740 | * current mft record, if we shall expand space for mapping |
| 5741 | * pairs. |
| 5742 | */ |
| 5743 | exp_max_mp_size = le32_to_cpu(m->bytes_allocated) - |
| 5744 | le32_to_cpu(m->bytes_in_use) + cur_max_mp_size; |
| 5745 | /* Get the size for the rest of mapping pairs array. */ |
| 5746 | mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, stop_rl, |
| 5747 | stop_vcn, exp_max_mp_size); |
| 5748 | if (mp_size <= 0) { |
| 5749 | ntfs_log_perror("%s: get MP size failed", __FUNCTION__); |
| 5750 | goto put_err_out; |
| 5751 | } |
| 5752 | /* Test mapping pairs for fitting in the current mft record. */ |
| 5753 | if (mp_size > exp_max_mp_size) { |
| 5754 | /* |
| 5755 | * Mapping pairs of $ATTRIBUTE_LIST attribute must fit |
| 5756 | * in the base mft record. Try to move out other |
| 5757 | * attributes and try again. |
| 5758 | */ |
| 5759 | if (na->type == AT_ATTRIBUTE_LIST) { |
| 5760 | ntfs_attr_put_search_ctx(ctx); |
| 5761 | if (ntfs_inode_free_space(na->ni, mp_size - |
| 5762 | cur_max_mp_size)) { |
| 5763 | ntfs_log_perror("Attribute list is too " |
| 5764 | "big. Defragment the " |
| 5765 | "volume\n"); |
| 5766 | return -1; |
| 5767 | } |
| 5768 | goto retry; |
| 5769 | } |
| 5770 | |
| 5771 | /* Add attribute list if it isn't present, and retry. */ |
| 5772 | if (!NInoAttrList(base_ni)) { |
| 5773 | ntfs_attr_put_search_ctx(ctx); |
| 5774 | if (ntfs_inode_add_attrlist(base_ni)) { |
| 5775 | ntfs_log_perror("Can not add attrlist"); |
| 5776 | return -1; |
| 5777 | } |
| 5778 | goto retry; |
| 5779 | } |
| 5780 | |
| 5781 | /* |
| 5782 | * Set mapping pairs size to maximum possible for this |
| 5783 | * mft record. We shall write the rest of mapping pairs |
| 5784 | * to another MFT records. |
| 5785 | */ |
| 5786 | mp_size = exp_max_mp_size; |
| 5787 | } |
| 5788 | |
| 5789 | /* Change space for mapping pairs if we need it. */ |
| 5790 | if (((mp_size + 7) & ~7) != cur_max_mp_size) { |
| 5791 | if (ntfs_attr_record_resize(m, a, |
| 5792 | le16_to_cpu(a->mapping_pairs_offset) + |
| 5793 | mp_size)) { |
| 5794 | errno = EIO; |
| 5795 | ntfs_log_perror("Failed to resize attribute"); |
| 5796 | goto put_err_out; |
| 5797 | } |
| 5798 | } |
| 5799 | |
| 5800 | /* Update lowest vcn. */ |
| 5801 | a->lowest_vcn = cpu_to_sle64(stop_vcn); |
| 5802 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
| 5803 | if ((ctx->ntfs_ino->nr_extents == -1 || |
| 5804 | NInoAttrList(ctx->ntfs_ino)) && |
| 5805 | ctx->attr->type != AT_ATTRIBUTE_LIST) { |
| 5806 | ctx->al_entry->lowest_vcn = cpu_to_sle64(stop_vcn); |
| 5807 | ntfs_attrlist_mark_dirty(ctx->ntfs_ino); |
| 5808 | } |
| 5809 | |
| 5810 | /* |
| 5811 | * Generate the new mapping pairs array directly into the |
| 5812 | * correct destination, i.e. the attribute record itself. |
| 5813 | */ |
| 5814 | if (!ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + le16_to_cpu( |
| 5815 | a->mapping_pairs_offset), mp_size, na->rl, |
| 5816 | stop_vcn, &stop_rl)) |
| 5817 | finished_build = TRUE; |
| 5818 | if (stop_rl) |
| 5819 | stop_vcn = stop_rl->vcn; |
| 5820 | else |
| 5821 | stop_vcn = 0; |
| 5822 | if (!finished_build && errno != ENOSPC) { |
| 5823 | ntfs_log_perror("Failed to build mapping pairs"); |
| 5824 | goto put_err_out; |
| 5825 | } |
| 5826 | a->highest_vcn = cpu_to_sle64(stop_vcn - 1); |
| 5827 | } |
| 5828 | /* Check whether error occurred. */ |
| 5829 | if (errno != ENOENT) { |
| 5830 | ntfs_log_perror("%s: Attribute lookup failed", __FUNCTION__); |
| 5831 | goto put_err_out; |
| 5832 | } |
| 5833 | /* |
| 5834 | * If the base extent was skipped in the above process, |
| 5835 | * we still may have to update the sizes. |
| 5836 | */ |
| 5837 | if (!first_updated) { |
| 5838 | le16 spcomp; |
| 5839 | |
| 5840 | ntfs_attr_reinit_search_ctx(ctx); |
| 5841 | if (!ntfs_attr_lookup(na->type, na->name, na->name_len, |
| 5842 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
| 5843 | a = ctx->attr; |
| 5844 | a->allocated_size = cpu_to_sle64(na->allocated_size); |
| 5845 | spcomp = na->data_flags |
| 5846 | & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); |
| 5847 | if (spcomp) |
| 5848 | a->compressed_size = cpu_to_sle64(na->compressed_size); |
| 5849 | if ((na->type == AT_DATA) && (na->name == AT_UNNAMED)) { |
| 5850 | na->ni->allocated_size |
| 5851 | = (spcomp |
| 5852 | ? na->compressed_size |
| 5853 | : na->allocated_size); |
| 5854 | NInoFileNameSetDirty(na->ni); |
| 5855 | } |
| 5856 | } else { |
| 5857 | ntfs_log_error("Failed to update sizes in base extent\n"); |
| 5858 | goto put_err_out; |
| 5859 | } |
| 5860 | } |
| 5861 | |
| 5862 | /* Deallocate not used attribute extents and return with success. */ |
| 5863 | if (finished_build) { |
| 5864 | ntfs_attr_reinit_search_ctx(ctx); |
| 5865 | ntfs_log_trace("Deallocate marked extents.\n"); |
| 5866 | while (!ntfs_attr_lookup(na->type, na->name, na->name_len, |
| 5867 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
| 5868 | if (sle64_to_cpu(ctx->attr->highest_vcn) != |
| 5869 | NTFS_VCN_DELETE_MARK) |
| 5870 | continue; |
| 5871 | /* Remove unused attribute record. */ |
| 5872 | if (ntfs_attr_record_rm(ctx)) { |
| 5873 | ntfs_log_perror("Could not remove unused attr"); |
| 5874 | goto put_err_out; |
| 5875 | } |
| 5876 | ntfs_attr_reinit_search_ctx(ctx); |
| 5877 | } |
| 5878 | if (errno != ENOENT) { |
| 5879 | ntfs_log_perror("%s: Attr lookup failed", __FUNCTION__); |
| 5880 | goto put_err_out; |
| 5881 | } |
| 5882 | ntfs_log_trace("Deallocate done.\n"); |
| 5883 | ntfs_attr_put_search_ctx(ctx); |
| 5884 | goto ok; |
| 5885 | } |
| 5886 | ntfs_attr_put_search_ctx(ctx); |
| 5887 | ctx = NULL; |
| 5888 | |
| 5889 | /* Allocate new MFT records for the rest of mapping pairs. */ |
| 5890 | while (1) { |
| 5891 | /* Calculate size of rest mapping pairs. */ |
| 5892 | mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, |
| 5893 | na->rl, stop_vcn, INT_MAX); |
| 5894 | if (mp_size <= 0) { |
| 5895 | ntfs_log_perror("%s: get mp size failed", __FUNCTION__); |
| 5896 | goto put_err_out; |
| 5897 | } |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5898 | /* Allocate new mft record, with special case for mft itself */ |
| 5899 | if (!na->ni->mft_no) |
| 5900 | ni = ntfs_mft_rec_alloc(na->ni->vol, |
| 5901 | na->type == AT_DATA); |
| 5902 | else |
| 5903 | ni = ntfs_mft_record_alloc(na->ni->vol, base_ni); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5904 | if (!ni) { |
| 5905 | ntfs_log_perror("Could not allocate new MFT record"); |
| 5906 | goto put_err_out; |
| 5907 | } |
| 5908 | m = ni->mrec; |
| 5909 | /* |
| 5910 | * If mapping size exceed available space, set them to |
| 5911 | * possible maximum. |
| 5912 | */ |
| 5913 | cur_max_mp_size = le32_to_cpu(m->bytes_allocated) - |
| 5914 | le32_to_cpu(m->bytes_in_use) - |
| 5915 | (offsetof(ATTR_RECORD, compressed_size) + |
| 5916 | (((na->data_flags & ATTR_COMPRESSION_MASK) |
| 5917 | || NAttrSparse(na)) ? |
| 5918 | sizeof(a->compressed_size) : 0)) - |
| 5919 | ((sizeof(ntfschar) * na->name_len + 7) & ~7); |
| 5920 | if (mp_size > cur_max_mp_size) |
| 5921 | mp_size = cur_max_mp_size; |
| 5922 | /* Add attribute extent to new record. */ |
| 5923 | err = ntfs_non_resident_attr_record_add(ni, na->type, |
| 5924 | na->name, na->name_len, stop_vcn, mp_size, |
| 5925 | na->data_flags); |
| 5926 | if (err == -1) { |
| 5927 | err = errno; |
| 5928 | ntfs_log_perror("Could not add attribute extent"); |
| 5929 | if (ntfs_mft_record_free(na->ni->vol, ni)) |
| 5930 | ntfs_log_perror("Could not free MFT record"); |
| 5931 | errno = err; |
| 5932 | goto put_err_out; |
| 5933 | } |
| 5934 | a = (ATTR_RECORD*)((u8*)m + err); |
| 5935 | |
| 5936 | err = ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + |
| 5937 | le16_to_cpu(a->mapping_pairs_offset), mp_size, na->rl, |
| 5938 | stop_vcn, &stop_rl); |
| 5939 | if (stop_rl) |
| 5940 | stop_vcn = stop_rl->vcn; |
| 5941 | else |
| 5942 | stop_vcn = 0; |
| 5943 | if (err < 0 && errno != ENOSPC) { |
| 5944 | err = errno; |
| 5945 | ntfs_log_perror("Failed to build MP"); |
| 5946 | if (ntfs_mft_record_free(na->ni->vol, ni)) |
| 5947 | ntfs_log_perror("Couldn't free MFT record"); |
| 5948 | errno = err; |
| 5949 | goto put_err_out; |
| 5950 | } |
| 5951 | a->highest_vcn = cpu_to_sle64(stop_vcn - 1); |
| 5952 | ntfs_inode_mark_dirty(ni); |
| 5953 | /* All mapping pairs has been written. */ |
| 5954 | if (!err) |
| 5955 | break; |
| 5956 | } |
| 5957 | ok: |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 5958 | NAttrClearRunlistDirty(na); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 5959 | ret = 0; |
| 5960 | out: |
| 5961 | return ret; |
| 5962 | put_err_out: |
| 5963 | if (ctx) |
| 5964 | ntfs_attr_put_search_ctx(ctx); |
| 5965 | goto out; |
| 5966 | } |
| 5967 | #undef NTFS_VCN_DELETE_MARK |
| 5968 | |
| 5969 | /** |
| 5970 | * ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute |
| 5971 | * @na: non-resident ntfs open attribute for which we need update |
| 5972 | * @from_vcn: update runlist starting this VCN |
| 5973 | * |
| 5974 | * Build mapping pairs from @na->rl and write them to the disk. Also, this |
| 5975 | * function updates sparse bit, allocated and compressed size (allocates/frees |
| 5976 | * space for this field if required). |
| 5977 | * |
| 5978 | * @na->allocated_size should be set to correct value for the new runlist before |
| 5979 | * call to this function. Vice-versa @na->compressed_size will be calculated and |
| 5980 | * set to correct value during this function. |
| 5981 | * |
| 5982 | * FIXME: This function does not update sparse bit and compressed size correctly |
| 5983 | * if called with @from_vcn != 0. |
| 5984 | * |
| 5985 | * FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define. |
| 5986 | * |
| 5987 | * On success return 0 and on error return -1 with errno set to the error code. |
| 5988 | * The following error codes are defined: |
| 5989 | * EINVAL - Invalid arguments passed. |
| 5990 | * ENOMEM - Not enough memory to complete operation. |
| 5991 | * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST |
| 5992 | * or there is no free MFT records left to allocate. |
| 5993 | */ |
| 5994 | int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn) |
| 5995 | { |
| 5996 | int ret; |
| 5997 | |
| 5998 | ntfs_log_enter("Entering\n"); |
| 5999 | ret = ntfs_attr_update_mapping_pairs_i(na, from_vcn, HOLES_OK); |
| 6000 | ntfs_log_leave("\n"); |
| 6001 | return ret; |
| 6002 | } |
| 6003 | |
| 6004 | /** |
| 6005 | * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute |
| 6006 | * @na: non-resident ntfs attribute to shrink |
| 6007 | * @newsize: new size (in bytes) to which to shrink the attribute |
| 6008 | * |
| 6009 | * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes. |
| 6010 | * |
| 6011 | * On success return 0 and on error return -1 with errno set to the error code. |
| 6012 | * The following error codes are defined: |
| 6013 | * ENOMEM - Not enough memory to complete operation. |
| 6014 | * ERANGE - @newsize is not valid for the attribute type of @na. |
| 6015 | */ |
| 6016 | static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) |
| 6017 | { |
| 6018 | ntfs_volume *vol; |
| 6019 | ntfs_attr_search_ctx *ctx; |
| 6020 | VCN first_free_vcn; |
| 6021 | s64 nr_freed_clusters; |
| 6022 | int err; |
| 6023 | |
| 6024 | ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", (unsigned long long) |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 6025 | na->ni->mft_no, le32_to_cpu(na->type), (long long)newsize); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6026 | |
| 6027 | vol = na->ni->vol; |
| 6028 | |
| 6029 | /* |
| 6030 | * Check the attribute type and the corresponding minimum size |
| 6031 | * against @newsize and fail if @newsize is too small. |
| 6032 | */ |
| 6033 | if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { |
| 6034 | if (errno == ERANGE) { |
| 6035 | ntfs_log_trace("Eeek! Size bounds check failed. " |
| 6036 | "Aborting...\n"); |
| 6037 | } else if (errno == ENOENT) |
| 6038 | errno = EIO; |
| 6039 | return -1; |
| 6040 | } |
| 6041 | |
| 6042 | /* The first cluster outside the new allocation. */ |
| 6043 | if (na->data_flags & ATTR_COMPRESSION_MASK) |
| 6044 | /* |
| 6045 | * For compressed files we must keep full compressions blocks, |
| 6046 | * but currently we do not decompress/recompress the last |
| 6047 | * block to truncate the data, so we may leave more allocated |
| 6048 | * clusters than really needed. |
| 6049 | */ |
| 6050 | first_free_vcn = (((newsize - 1) |
| 6051 | | (na->compression_block_size - 1)) + 1) |
| 6052 | >> vol->cluster_size_bits; |
| 6053 | else |
| 6054 | first_free_vcn = (newsize + vol->cluster_size - 1) >> |
| 6055 | vol->cluster_size_bits; |
| 6056 | /* |
| 6057 | * Compare the new allocation with the old one and only deallocate |
| 6058 | * clusters if there is a change. |
| 6059 | */ |
| 6060 | if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) { |
| 6061 | if (ntfs_attr_map_whole_runlist(na)) { |
| 6062 | ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist " |
| 6063 | "failed.\n"); |
| 6064 | return -1; |
| 6065 | } |
| 6066 | /* Deallocate all clusters starting with the first free one. */ |
| 6067 | nr_freed_clusters = ntfs_cluster_free(vol, na, first_free_vcn, |
| 6068 | -1); |
| 6069 | if (nr_freed_clusters < 0) { |
| 6070 | ntfs_log_trace("Eeek! Freeing of clusters failed. " |
| 6071 | "Aborting...\n"); |
| 6072 | return -1; |
| 6073 | } |
| 6074 | |
| 6075 | /* Truncate the runlist itself. */ |
| 6076 | if (ntfs_rl_truncate(&na->rl, first_free_vcn)) { |
| 6077 | /* |
| 6078 | * Failed to truncate the runlist, so just throw it |
| 6079 | * away, it will be mapped afresh on next use. |
| 6080 | */ |
| 6081 | free(na->rl); |
| 6082 | na->rl = NULL; |
| 6083 | ntfs_log_trace("Eeek! Run list truncation failed.\n"); |
| 6084 | return -1; |
| 6085 | } |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6086 | NAttrSetRunlistDirty(na); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6087 | |
| 6088 | /* Prepare to mapping pairs update. */ |
| 6089 | na->allocated_size = first_free_vcn << vol->cluster_size_bits; |
| 6090 | /* Write mapping pairs for new runlist. */ |
| 6091 | if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) { |
| 6092 | ntfs_log_trace("Eeek! Mapping pairs update failed. " |
| 6093 | "Leaving inconstant metadata. " |
| 6094 | "Run chkdsk.\n"); |
| 6095 | return -1; |
| 6096 | } |
| 6097 | } |
| 6098 | |
| 6099 | /* Get the first attribute record. */ |
| 6100 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 6101 | if (!ctx) |
| 6102 | return -1; |
| 6103 | |
| 6104 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
| 6105 | 0, NULL, 0, ctx)) { |
| 6106 | err = errno; |
| 6107 | if (err == ENOENT) |
| 6108 | err = EIO; |
| 6109 | ntfs_log_trace("Eeek! Lookup of first attribute extent failed. " |
| 6110 | "Leaving inconstant metadata.\n"); |
| 6111 | goto put_err_out; |
| 6112 | } |
| 6113 | |
| 6114 | /* Update data and initialized size. */ |
| 6115 | na->data_size = newsize; |
| 6116 | ctx->attr->data_size = cpu_to_sle64(newsize); |
| 6117 | if (newsize < na->initialized_size) { |
| 6118 | na->initialized_size = newsize; |
| 6119 | ctx->attr->initialized_size = cpu_to_sle64(newsize); |
| 6120 | } |
| 6121 | /* Update data size in the index. */ |
| 6122 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { |
| 6123 | if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) { |
| 6124 | na->ni->data_size = na->data_size; |
| 6125 | na->ni->allocated_size = na->allocated_size; |
| 6126 | set_nino_flag(na->ni,KnownSize); |
| 6127 | } |
| 6128 | } else { |
| 6129 | if (na->type == AT_DATA && na->name == AT_UNNAMED) { |
| 6130 | na->ni->data_size = na->data_size; |
| 6131 | NInoFileNameSetDirty(na->ni); |
| 6132 | } |
| 6133 | } |
| 6134 | |
| 6135 | /* If the attribute now has zero size, make it resident. */ |
| 6136 | if (!newsize) { |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6137 | if (!(na->data_flags & ATTR_IS_ENCRYPTED) |
| 6138 | && ntfs_attr_make_resident(na, ctx)) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6139 | /* If couldn't make resident, just continue. */ |
| 6140 | if (errno != EPERM) |
| 6141 | ntfs_log_error("Failed to make attribute " |
| 6142 | "resident. Leaving as is...\n"); |
| 6143 | } |
| 6144 | } |
| 6145 | |
| 6146 | /* Set the inode dirty so it is written out later. */ |
| 6147 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
| 6148 | /* Done! */ |
| 6149 | ntfs_attr_put_search_ctx(ctx); |
| 6150 | return 0; |
| 6151 | put_err_out: |
| 6152 | ntfs_attr_put_search_ctx(ctx); |
| 6153 | errno = err; |
| 6154 | return -1; |
| 6155 | } |
| 6156 | |
| 6157 | /** |
| 6158 | * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute |
| 6159 | * @na: non-resident ntfs attribute to expand |
| 6160 | * @newsize: new size (in bytes) to which to expand the attribute |
| 6161 | * |
| 6162 | * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes, |
| 6163 | * by allocating new clusters. |
| 6164 | * |
| 6165 | * On success return 0 and on error return -1 with errno set to the error code. |
| 6166 | * The following error codes are defined: |
| 6167 | * ENOMEM - Not enough memory to complete operation. |
| 6168 | * ERANGE - @newsize is not valid for the attribute type of @na. |
| 6169 | * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. |
| 6170 | */ |
| 6171 | static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize, |
| 6172 | hole_type holes) |
| 6173 | { |
| 6174 | LCN lcn_seek_from; |
| 6175 | VCN first_free_vcn; |
| 6176 | ntfs_volume *vol; |
| 6177 | ntfs_attr_search_ctx *ctx; |
| 6178 | runlist *rl, *rln; |
| 6179 | s64 org_alloc_size; |
| 6180 | int err; |
| 6181 | |
| 6182 | ntfs_log_trace("Inode %lld, attr 0x%x, new size %lld old size %lld\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 6183 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6184 | (long long)newsize, (long long)na->data_size); |
| 6185 | |
| 6186 | vol = na->ni->vol; |
| 6187 | |
| 6188 | /* |
| 6189 | * Check the attribute type and the corresponding maximum size |
| 6190 | * against @newsize and fail if @newsize is too big. |
| 6191 | */ |
| 6192 | if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { |
| 6193 | if (errno == ENOENT) |
| 6194 | errno = EIO; |
| 6195 | ntfs_log_perror("%s: bounds check failed", __FUNCTION__); |
| 6196 | return -1; |
| 6197 | } |
| 6198 | |
| 6199 | if (na->type == AT_DATA) |
| 6200 | NAttrSetDataAppending(na); |
| 6201 | /* Save for future use. */ |
| 6202 | org_alloc_size = na->allocated_size; |
| 6203 | /* The first cluster outside the new allocation. */ |
| 6204 | first_free_vcn = (newsize + vol->cluster_size - 1) >> |
| 6205 | vol->cluster_size_bits; |
| 6206 | /* |
| 6207 | * Compare the new allocation with the old one and only allocate |
| 6208 | * clusters if there is a change. |
| 6209 | */ |
| 6210 | if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) { |
| 6211 | #if PARTIAL_RUNLIST_UPDATING |
| 6212 | s64 start_update; |
| 6213 | |
| 6214 | /* |
| 6215 | * Update from the last previously allocated run, |
| 6216 | * as we may have to expand an existing hole. |
| 6217 | */ |
| 6218 | start_update = na->allocated_size >> vol->cluster_size_bits; |
| 6219 | if (start_update) |
| 6220 | start_update--; |
| 6221 | if (ntfs_attr_map_partial_runlist(na, start_update)) { |
| 6222 | ntfs_log_perror("failed to map partial runlist"); |
| 6223 | return -1; |
| 6224 | } |
| 6225 | #else |
| 6226 | if (ntfs_attr_map_whole_runlist(na)) { |
| 6227 | ntfs_log_perror("ntfs_attr_map_whole_runlist failed"); |
| 6228 | return -1; |
| 6229 | } |
| 6230 | #endif |
| 6231 | |
| 6232 | /* |
| 6233 | * If we extend $DATA attribute on NTFS 3+ volume, we can add |
| 6234 | * sparse runs instead of real allocation of clusters. |
| 6235 | */ |
| 6236 | if ((na->type == AT_DATA) && (vol->major_ver >= 3) |
| 6237 | && (holes != HOLES_NO)) { |
| 6238 | rl = ntfs_malloc(0x1000); |
| 6239 | if (!rl) |
| 6240 | return -1; |
| 6241 | |
| 6242 | rl[0].vcn = (na->allocated_size >> |
| 6243 | vol->cluster_size_bits); |
| 6244 | rl[0].lcn = LCN_HOLE; |
| 6245 | rl[0].length = first_free_vcn - |
| 6246 | (na->allocated_size >> vol->cluster_size_bits); |
| 6247 | rl[1].vcn = first_free_vcn; |
| 6248 | rl[1].lcn = LCN_ENOENT; |
| 6249 | rl[1].length = 0; |
| 6250 | } else { |
| 6251 | /* |
| 6252 | * Determine first after last LCN of attribute. |
| 6253 | * We will start seek clusters from this LCN to avoid |
| 6254 | * fragmentation. If there are no valid LCNs in the |
| 6255 | * attribute let the cluster allocator choose the |
| 6256 | * starting LCN. |
| 6257 | */ |
| 6258 | lcn_seek_from = -1; |
| 6259 | if (na->rl->length) { |
| 6260 | /* Seek to the last run list element. */ |
| 6261 | for (rl = na->rl; (rl + 1)->length; rl++) |
| 6262 | ; |
| 6263 | /* |
| 6264 | * If the last LCN is a hole or similar seek |
| 6265 | * back to last valid LCN. |
| 6266 | */ |
| 6267 | while (rl->lcn < 0 && rl != na->rl) |
| 6268 | rl--; |
| 6269 | /* |
| 6270 | * Only set lcn_seek_from it the LCN is valid. |
| 6271 | */ |
| 6272 | if (rl->lcn >= 0) |
| 6273 | lcn_seek_from = rl->lcn + rl->length; |
| 6274 | } |
| 6275 | |
| 6276 | rl = ntfs_cluster_alloc(vol, na->allocated_size >> |
| 6277 | vol->cluster_size_bits, first_free_vcn - |
| 6278 | (na->allocated_size >> |
| 6279 | vol->cluster_size_bits), lcn_seek_from, |
| 6280 | DATA_ZONE); |
| 6281 | if (!rl) { |
| 6282 | ntfs_log_perror("Cluster allocation failed " |
| 6283 | "(%lld)", |
| 6284 | (long long)first_free_vcn - |
| 6285 | ((long long)na->allocated_size >> |
| 6286 | vol->cluster_size_bits)); |
| 6287 | return -1; |
| 6288 | } |
| 6289 | } |
| 6290 | |
| 6291 | /* Append new clusters to attribute runlist. */ |
| 6292 | rln = ntfs_runlists_merge(na->rl, rl); |
| 6293 | if (!rln) { |
| 6294 | /* Failed, free just allocated clusters. */ |
| 6295 | err = errno; |
| 6296 | ntfs_log_perror("Run list merge failed"); |
| 6297 | ntfs_cluster_free_from_rl(vol, rl); |
| 6298 | free(rl); |
| 6299 | errno = err; |
| 6300 | return -1; |
| 6301 | } |
| 6302 | na->rl = rln; |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6303 | NAttrSetRunlistDirty(na); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6304 | |
| 6305 | /* Prepare to mapping pairs update. */ |
| 6306 | na->allocated_size = first_free_vcn << vol->cluster_size_bits; |
| 6307 | #if PARTIAL_RUNLIST_UPDATING |
| 6308 | /* |
| 6309 | * Write mapping pairs for new runlist, unless this is |
| 6310 | * a temporary state before appending data. |
| 6311 | * If the update is not done, we must be sure to do |
| 6312 | * it later, and to get to a clean state even on errors. |
| 6313 | */ |
| 6314 | if ((holes != HOLES_DELAY) |
| 6315 | && ntfs_attr_update_mapping_pairs_i(na, start_update, |
| 6316 | holes)) { |
| 6317 | #else |
| 6318 | /* Write mapping pairs for new runlist. */ |
| 6319 | if (ntfs_attr_update_mapping_pairs(na, 0)) { |
| 6320 | #endif |
| 6321 | err = errno; |
| 6322 | ntfs_log_perror("Mapping pairs update failed"); |
| 6323 | goto rollback; |
| 6324 | } |
| 6325 | } |
| 6326 | |
| 6327 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
| 6328 | if (!ctx) { |
| 6329 | err = errno; |
| 6330 | if (na->allocated_size == org_alloc_size) { |
| 6331 | errno = err; |
| 6332 | return -1; |
| 6333 | } else |
| 6334 | goto rollback; |
| 6335 | } |
| 6336 | |
| 6337 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
| 6338 | 0, NULL, 0, ctx)) { |
| 6339 | err = errno; |
| 6340 | ntfs_log_perror("Lookup of first attribute extent failed"); |
| 6341 | if (err == ENOENT) |
| 6342 | err = EIO; |
| 6343 | if (na->allocated_size != org_alloc_size) { |
| 6344 | ntfs_attr_put_search_ctx(ctx); |
| 6345 | goto rollback; |
| 6346 | } else |
| 6347 | goto put_err_out; |
| 6348 | } |
| 6349 | |
| 6350 | /* Update data size. */ |
| 6351 | na->data_size = newsize; |
| 6352 | ctx->attr->data_size = cpu_to_sle64(newsize); |
| 6353 | /* Update data size in the index. */ |
| 6354 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { |
| 6355 | if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) { |
| 6356 | na->ni->data_size = na->data_size; |
| 6357 | na->ni->allocated_size = na->allocated_size; |
| 6358 | set_nino_flag(na->ni,KnownSize); |
| 6359 | } |
| 6360 | } else { |
| 6361 | if (na->type == AT_DATA && na->name == AT_UNNAMED) { |
| 6362 | na->ni->data_size = na->data_size; |
| 6363 | NInoFileNameSetDirty(na->ni); |
| 6364 | } |
| 6365 | } |
| 6366 | /* Set the inode dirty so it is written out later. */ |
| 6367 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
| 6368 | /* Done! */ |
| 6369 | ntfs_attr_put_search_ctx(ctx); |
| 6370 | return 0; |
| 6371 | rollback: |
| 6372 | /* Free allocated clusters. */ |
| 6373 | if (ntfs_cluster_free(vol, na, org_alloc_size >> |
| 6374 | vol->cluster_size_bits, -1) < 0) { |
| 6375 | err = EIO; |
| 6376 | ntfs_log_perror("Leaking clusters"); |
| 6377 | } |
| 6378 | /* Now, truncate the runlist itself. */ |
| 6379 | if (ntfs_rl_truncate(&na->rl, org_alloc_size >> |
| 6380 | vol->cluster_size_bits)) { |
| 6381 | /* |
| 6382 | * Failed to truncate the runlist, so just throw it away, it |
| 6383 | * will be mapped afresh on next use. |
| 6384 | */ |
| 6385 | free(na->rl); |
| 6386 | na->rl = NULL; |
| 6387 | ntfs_log_perror("Couldn't truncate runlist. Rollback failed"); |
| 6388 | } else { |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6389 | NAttrSetRunlistDirty(na); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6390 | /* Prepare to mapping pairs update. */ |
| 6391 | na->allocated_size = org_alloc_size; |
| 6392 | /* Restore mapping pairs. */ |
| 6393 | if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >> |
| 6394 | vol->cluster_size_bits*/)) { |
| 6395 | ntfs_log_perror("Failed to restore old mapping pairs"); |
| 6396 | } |
| 6397 | } |
| 6398 | errno = err; |
| 6399 | return -1; |
| 6400 | put_err_out: |
| 6401 | ntfs_attr_put_search_ctx(ctx); |
| 6402 | errno = err; |
| 6403 | return -1; |
| 6404 | } |
| 6405 | |
| 6406 | |
| 6407 | static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize, |
| 6408 | hole_type holes) |
| 6409 | { |
| 6410 | int ret; |
| 6411 | |
| 6412 | ntfs_log_enter("Entering\n"); |
| 6413 | ret = ntfs_non_resident_attr_expand_i(na, newsize, holes); |
| 6414 | ntfs_log_leave("\n"); |
| 6415 | return ret; |
| 6416 | } |
| 6417 | |
| 6418 | /** |
| 6419 | * ntfs_attr_truncate - resize an ntfs attribute |
| 6420 | * @na: open ntfs attribute to resize |
| 6421 | * @newsize: new size (in bytes) to which to resize the attribute |
| 6422 | * @holes: how to create a hole if expanding |
| 6423 | * |
| 6424 | * Change the size of an open ntfs attribute @na to @newsize bytes. If the |
| 6425 | * attribute is made bigger and the attribute is resident the newly |
| 6426 | * "allocated" space is cleared and if the attribute is non-resident the |
| 6427 | * newly allocated space is marked as not initialised and no real allocation |
| 6428 | * on disk is performed. |
| 6429 | * |
| 6430 | * On success return 0. |
| 6431 | * On error return values are: |
| 6432 | * STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT |
| 6433 | * STATUS_ERROR - otherwise |
| 6434 | * The following error codes are defined: |
| 6435 | * EINVAL - Invalid arguments were passed to the function. |
| 6436 | * EOPNOTSUPP - The desired resize is not implemented yet. |
| 6437 | * EACCES - Encrypted attribute. |
| 6438 | */ |
| 6439 | static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize, |
| 6440 | hole_type holes) |
| 6441 | { |
| 6442 | int ret = STATUS_ERROR; |
| 6443 | s64 fullsize; |
| 6444 | BOOL compressed; |
| 6445 | |
| 6446 | if (!na || newsize < 0 || |
| 6447 | (na->ni->mft_no == FILE_MFT && na->type == AT_DATA)) { |
| 6448 | ntfs_log_trace("Invalid arguments passed.\n"); |
| 6449 | errno = EINVAL; |
| 6450 | return STATUS_ERROR; |
| 6451 | } |
| 6452 | |
| 6453 | ntfs_log_enter("Entering for inode %lld, attr 0x%x, size %lld\n", |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 6454 | (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6455 | (long long)newsize); |
| 6456 | |
| 6457 | if (na->data_size == newsize) { |
| 6458 | ntfs_log_trace("Size is already ok\n"); |
| 6459 | ret = STATUS_OK; |
| 6460 | goto out; |
| 6461 | } |
| 6462 | /* |
| 6463 | * Encrypted attributes are not supported. We return access denied, |
| 6464 | * which is what Windows NT4 does, too. |
| 6465 | */ |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6466 | if ((na->data_flags & ATTR_IS_ENCRYPTED) && !na->ni->vol->efs_raw) { |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6467 | errno = EACCES; |
| 6468 | ntfs_log_trace("Cannot truncate encrypted attribute\n"); |
| 6469 | goto out; |
| 6470 | } |
| 6471 | /* |
| 6472 | * TODO: Implement making handling of compressed attributes. |
| 6473 | * Currently we can only expand the attribute or delete it, |
| 6474 | * and only for ATTR_IS_COMPRESSED. This is however possible |
| 6475 | * for resident attributes when there is no open fuse context |
| 6476 | * (important case : $INDEX_ROOT:$I30) |
| 6477 | */ |
| 6478 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
| 6479 | != const_cpu_to_le16(0); |
| 6480 | if (compressed |
| 6481 | && NAttrNonResident(na) |
| 6482 | && ((na->data_flags & ATTR_COMPRESSION_MASK) != ATTR_IS_COMPRESSED)) { |
| 6483 | errno = EOPNOTSUPP; |
| 6484 | ntfs_log_perror("Failed to truncate compressed attribute"); |
| 6485 | goto out; |
| 6486 | } |
| 6487 | if (NAttrNonResident(na)) { |
| 6488 | /* |
| 6489 | * For compressed data, the last block must be fully |
| 6490 | * allocated, and we do not know the size of compression |
| 6491 | * block until the attribute has been made non-resident. |
| 6492 | * Moreover we can only process a single compression |
| 6493 | * block at a time (from where we are about to write), |
| 6494 | * so we silently do not allocate more. |
| 6495 | * |
| 6496 | * Note : do not request upsizing of compressed files |
| 6497 | * unless being able to face the consequences ! |
| 6498 | */ |
| 6499 | if (compressed && newsize && (newsize > na->data_size)) |
| 6500 | fullsize = (na->initialized_size |
| 6501 | | (na->compression_block_size - 1)) + 1; |
| 6502 | else |
| 6503 | fullsize = newsize; |
| 6504 | if (fullsize > na->data_size) |
| 6505 | ret = ntfs_non_resident_attr_expand(na, fullsize, |
| 6506 | holes); |
| 6507 | else |
| 6508 | ret = ntfs_non_resident_attr_shrink(na, fullsize); |
| 6509 | } else |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6510 | ret = ntfs_resident_attr_resize_i(na, newsize, holes); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6511 | out: |
| 6512 | ntfs_log_leave("Return status %d\n", ret); |
| 6513 | return ret; |
| 6514 | } |
| 6515 | |
| 6516 | /* |
| 6517 | * Resize an attribute, creating a hole if relevant |
| 6518 | */ |
| 6519 | |
| 6520 | int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) |
| 6521 | { |
| 6522 | int r; |
| 6523 | |
| 6524 | r = ntfs_attr_truncate_i(na, newsize, HOLES_OK); |
| 6525 | NAttrClearDataAppending(na); |
| 6526 | NAttrClearBeingNonResident(na); |
| 6527 | return (r); |
| 6528 | } |
| 6529 | |
| 6530 | /* |
| 6531 | * Resize an attribute, avoiding hole creation |
| 6532 | */ |
| 6533 | |
| 6534 | int ntfs_attr_truncate_solid(ntfs_attr *na, const s64 newsize) |
| 6535 | { |
| 6536 | return (ntfs_attr_truncate_i(na, newsize, HOLES_NO)); |
| 6537 | } |
| 6538 | |
| 6539 | /* |
| 6540 | * Stuff a hole in a compressed file |
| 6541 | * |
| 6542 | * An unallocated hole must be aligned on compression block size. |
| 6543 | * If needed current block and target block are stuffed with zeroes. |
| 6544 | * |
| 6545 | * Returns 0 if succeeded, |
| 6546 | * -1 if it failed (as explained in errno) |
| 6547 | */ |
| 6548 | |
| 6549 | static int stuff_hole(ntfs_attr *na, const s64 pos) |
| 6550 | { |
| 6551 | s64 size; |
| 6552 | s64 begin_size; |
| 6553 | s64 end_size; |
| 6554 | char *buf; |
| 6555 | int ret; |
| 6556 | |
| 6557 | ret = 0; |
| 6558 | /* |
| 6559 | * If the attribute is resident, the compression block size |
| 6560 | * is not defined yet and we can make no decision. |
| 6561 | * So we first try resizing to the target and if the |
| 6562 | * attribute is still resident, we're done |
| 6563 | */ |
| 6564 | if (!NAttrNonResident(na)) { |
| 6565 | ret = ntfs_resident_attr_resize(na, pos); |
| 6566 | if (!ret && !NAttrNonResident(na)) |
| 6567 | na->initialized_size = na->data_size = pos; |
| 6568 | } |
| 6569 | if (!ret && NAttrNonResident(na)) { |
| 6570 | /* does the hole span over several compression block ? */ |
| 6571 | if ((pos ^ na->initialized_size) |
| 6572 | & ~(na->compression_block_size - 1)) { |
| 6573 | begin_size = ((na->initialized_size - 1) |
| 6574 | | (na->compression_block_size - 1)) |
| 6575 | + 1 - na->initialized_size; |
| 6576 | end_size = pos & (na->compression_block_size - 1); |
| 6577 | size = (begin_size > end_size ? begin_size : end_size); |
| 6578 | } else { |
| 6579 | /* short stuffing in a single compression block */ |
| 6580 | begin_size = size = pos - na->initialized_size; |
| 6581 | end_size = 0; |
| 6582 | } |
| 6583 | if (size) |
| 6584 | buf = (char*)ntfs_malloc(size); |
| 6585 | else |
| 6586 | buf = (char*)NULL; |
| 6587 | if (buf || !size) { |
| 6588 | memset(buf,0,size); |
| 6589 | /* stuff into current block */ |
| 6590 | if (begin_size |
| 6591 | && (ntfs_attr_pwrite(na, |
| 6592 | na->initialized_size, begin_size, buf) |
| 6593 | != begin_size)) |
| 6594 | ret = -1; |
| 6595 | /* create an unstuffed hole */ |
| 6596 | if (!ret |
| 6597 | && ((na->initialized_size + end_size) < pos) |
| 6598 | && ntfs_non_resident_attr_expand(na, |
| 6599 | pos - end_size, HOLES_OK)) |
| 6600 | ret = -1; |
| 6601 | else |
| 6602 | na->initialized_size |
| 6603 | = na->data_size = pos - end_size; |
| 6604 | /* stuff into the target block */ |
| 6605 | if (!ret && end_size |
| 6606 | && (ntfs_attr_pwrite(na, |
| 6607 | na->initialized_size, end_size, buf) |
| 6608 | != end_size)) |
| 6609 | ret = -1; |
| 6610 | if (buf) |
| 6611 | free(buf); |
| 6612 | } else |
| 6613 | ret = -1; |
| 6614 | } |
| 6615 | /* make absolutely sure we have reached the target */ |
| 6616 | if (!ret && (na->initialized_size != pos)) { |
| 6617 | ntfs_log_error("Failed to stuff a compressed file" |
| 6618 | "target %lld reached %lld\n", |
| 6619 | (long long)pos, (long long)na->initialized_size); |
| 6620 | errno = EIO; |
| 6621 | ret = -1; |
| 6622 | } |
| 6623 | return (ret); |
| 6624 | } |
| 6625 | |
| 6626 | /** |
| 6627 | * ntfs_attr_readall - read the entire data from an ntfs attribute |
| 6628 | * @ni: open ntfs inode in which the ntfs attribute resides |
| 6629 | * @type: attribute type |
| 6630 | * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL |
| 6631 | * @name_len: length of attribute @name in Unicode characters (if @name given) |
| 6632 | * @data_size: if non-NULL then store here the data size |
| 6633 | * |
| 6634 | * This function will read the entire content of an ntfs attribute. |
| 6635 | * If @name is AT_UNNAMED then look specifically for an unnamed attribute. |
| 6636 | * If @name is NULL then the attribute could be either named or not. |
| 6637 | * In both those cases @name_len is not used at all. |
| 6638 | * |
| 6639 | * On success a buffer is allocated with the content of the attribute |
| 6640 | * and which needs to be freed when it's not needed anymore. If the |
| 6641 | * @data_size parameter is non-NULL then the data size is set there. |
| 6642 | * |
| 6643 | * On error NULL is returned with errno set to the error code. |
| 6644 | */ |
| 6645 | void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, |
| 6646 | ntfschar *name, u32 name_len, s64 *data_size) |
| 6647 | { |
| 6648 | ntfs_attr *na; |
| 6649 | void *data, *ret = NULL; |
| 6650 | s64 size; |
| 6651 | |
| 6652 | ntfs_log_enter("Entering\n"); |
| 6653 | |
| 6654 | na = ntfs_attr_open(ni, type, name, name_len); |
| 6655 | if (!na) { |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6656 | ntfs_log_perror("ntfs_attr_open failed, inode %lld attr 0x%lx", |
| 6657 | (long long)ni->mft_no,(long)le32_to_cpu(type)); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6658 | goto err_exit; |
| 6659 | } |
| 6660 | data = ntfs_malloc(na->data_size); |
| 6661 | if (!data) |
| 6662 | goto out; |
| 6663 | |
| 6664 | size = ntfs_attr_pread(na, 0, na->data_size, data); |
| 6665 | if (size != na->data_size) { |
| 6666 | ntfs_log_perror("ntfs_attr_pread failed"); |
| 6667 | free(data); |
| 6668 | goto out; |
| 6669 | } |
| 6670 | ret = data; |
| 6671 | if (data_size) |
| 6672 | *data_size = size; |
| 6673 | out: |
| 6674 | ntfs_attr_close(na); |
| 6675 | err_exit: |
| 6676 | ntfs_log_leave("\n"); |
| 6677 | return ret; |
| 6678 | } |
| 6679 | |
| 6680 | /* |
| 6681 | * Read some data from a data attribute |
| 6682 | * |
| 6683 | * Returns the amount of data read, negative if there was an error |
| 6684 | */ |
| 6685 | |
| 6686 | int ntfs_attr_data_read(ntfs_inode *ni, |
| 6687 | ntfschar *stream_name, int stream_name_len, |
| 6688 | char *buf, size_t size, off_t offset) |
| 6689 | { |
| 6690 | ntfs_attr *na = NULL; |
| 6691 | int res, total = 0; |
| 6692 | |
| 6693 | na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); |
| 6694 | if (!na) { |
| 6695 | res = -errno; |
| 6696 | goto exit; |
| 6697 | } |
| 6698 | if ((size_t)offset < (size_t)na->data_size) { |
| 6699 | if (offset + size > (size_t)na->data_size) |
| 6700 | size = na->data_size - offset; |
| 6701 | while (size) { |
| 6702 | res = ntfs_attr_pread(na, offset, size, buf + total); |
| 6703 | if ((off_t)res < (off_t)size) |
| 6704 | ntfs_log_perror("ntfs_attr_pread partial read " |
| 6705 | "(%lld : %lld <> %d)", |
| 6706 | (long long)offset, |
| 6707 | (long long)size, res); |
| 6708 | if (res <= 0) { |
| 6709 | res = -errno; |
| 6710 | goto exit; |
| 6711 | } |
| 6712 | size -= res; |
| 6713 | offset += res; |
| 6714 | total += res; |
| 6715 | } |
| 6716 | } |
| 6717 | res = total; |
| 6718 | exit: |
| 6719 | if (na) |
| 6720 | ntfs_attr_close(na); |
| 6721 | return res; |
| 6722 | } |
| 6723 | |
| 6724 | |
| 6725 | /* |
| 6726 | * Write some data into a data attribute |
| 6727 | * |
| 6728 | * Returns the amount of data written, negative if there was an error |
| 6729 | */ |
| 6730 | |
| 6731 | int ntfs_attr_data_write(ntfs_inode *ni, ntfschar *stream_name, |
| 6732 | int stream_name_len, const char *buf, size_t size, off_t offset) |
| 6733 | { |
| 6734 | ntfs_attr *na = NULL; |
| 6735 | int res, total = 0; |
| 6736 | |
| 6737 | na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); |
| 6738 | if (!na) { |
| 6739 | res = -errno; |
| 6740 | goto exit; |
| 6741 | } |
| 6742 | while (size) { |
| 6743 | res = ntfs_attr_pwrite(na, offset, size, buf + total); |
| 6744 | if (res < (s64)size) |
| 6745 | ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: " |
| 6746 | "%lld <> %d)", (long long)offset, |
| 6747 | (long long)size, res); |
| 6748 | if (res <= 0) { |
| 6749 | res = -errno; |
| 6750 | goto exit; |
| 6751 | } |
| 6752 | size -= res; |
| 6753 | offset += res; |
| 6754 | total += res; |
| 6755 | } |
| 6756 | res = total; |
| 6757 | exit: |
| 6758 | if (na) |
| 6759 | ntfs_attr_close(na); |
| 6760 | return res; |
| 6761 | } |
| 6762 | |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6763 | /* |
| 6764 | * Shrink the size of a data attribute if needed |
| 6765 | * |
| 6766 | * For non-resident attributes only. |
| 6767 | * The space remains allocated. |
| 6768 | * |
| 6769 | * Returns 0 if successful |
| 6770 | * -1 if failed, with errno telling why |
| 6771 | */ |
| 6772 | |
| 6773 | |
| 6774 | int ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name, |
| 6775 | int stream_name_len, off_t offset) |
| 6776 | { |
| 6777 | ntfs_attr_search_ctx *ctx; |
| 6778 | ATTR_RECORD *a; |
| 6779 | int res; |
| 6780 | |
| 6781 | res = -1; |
| 6782 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 6783 | if (ctx) { |
| 6784 | if (!ntfs_attr_lookup(AT_DATA, stream_name, stream_name_len, |
| 6785 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
| 6786 | a = ctx->attr; |
| 6787 | |
| 6788 | if (a->non_resident |
| 6789 | && (sle64_to_cpu(a->initialized_size) > offset)) { |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 6790 | a->initialized_size = cpu_to_sle64(offset); |
Steve Kondik | 79165c3 | 2015-11-09 19:43:00 -0800 | [diff] [blame] | 6791 | a->data_size = a->initialized_size; |
| 6792 | } |
| 6793 | res = 0; |
| 6794 | } |
| 6795 | ntfs_attr_put_search_ctx(ctx); |
| 6796 | } |
| 6797 | return (res); |
| 6798 | } |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6799 | |
| 6800 | int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, const ntfschar *name, |
| 6801 | u32 name_len) |
| 6802 | { |
| 6803 | ntfs_attr_search_ctx *ctx; |
| 6804 | int ret; |
| 6805 | |
| 6806 | ntfs_log_trace("Entering\n"); |
| 6807 | |
| 6808 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
| 6809 | if (!ctx) |
| 6810 | return 0; |
| 6811 | |
| 6812 | ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, |
| 6813 | ctx); |
| 6814 | |
| 6815 | ntfs_attr_put_search_ctx(ctx); |
| 6816 | |
| 6817 | return !ret; |
| 6818 | } |
| 6819 | |
| 6820 | int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, |
| 6821 | u32 name_len) |
| 6822 | { |
| 6823 | ntfs_attr *na; |
| 6824 | int ret; |
| 6825 | |
| 6826 | ntfs_log_trace("Entering\n"); |
| 6827 | |
| 6828 | if (!ni) { |
| 6829 | ntfs_log_error("%s: NULL inode pointer", __FUNCTION__); |
| 6830 | errno = EINVAL; |
| 6831 | return -1; |
| 6832 | } |
| 6833 | |
| 6834 | na = ntfs_attr_open(ni, type, name, name_len); |
| 6835 | if (!na) { |
| 6836 | /* do not log removal of non-existent stream */ |
| 6837 | if (type != AT_DATA) { |
| 6838 | ntfs_log_perror("Failed to open attribute 0x%02x of inode " |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 6839 | "0x%llx", le32_to_cpu(type), (unsigned long long)ni->mft_no); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6840 | } |
| 6841 | return -1; |
| 6842 | } |
| 6843 | |
| 6844 | ret = ntfs_attr_rm(na); |
| 6845 | if (ret) |
| 6846 | ntfs_log_perror("Failed to remove attribute 0x%02x of inode " |
Steve Kondik | e68cb60 | 2016-08-28 00:45:36 -0700 | [diff] [blame] | 6847 | "0x%llx", le32_to_cpu(type), (unsigned long long)ni->mft_no); |
Steve Kondik | 2111ad7 | 2013-07-07 12:07:44 -0700 | [diff] [blame] | 6848 | ntfs_attr_close(na); |
| 6849 | |
| 6850 | return ret; |
| 6851 | } |
| 6852 | |
| 6853 | /* Below macros are 32-bit ready. */ |
| 6854 | #define BCX(x) ((x) - (((x) >> 1) & 0x77777777) - \ |
| 6855 | (((x) >> 2) & 0x33333333) - \ |
| 6856 | (((x) >> 3) & 0x11111111)) |
| 6857 | #define BITCOUNT(x) (((BCX(x) + (BCX(x) >> 4)) & 0x0F0F0F0F) % 255) |
| 6858 | |
| 6859 | static u8 *ntfs_init_lut256(void) |
| 6860 | { |
| 6861 | int i; |
| 6862 | u8 *lut; |
| 6863 | |
| 6864 | lut = ntfs_malloc(256); |
| 6865 | if (lut) |
| 6866 | for(i = 0; i < 256; i++) |
| 6867 | *(lut + i) = 8 - BITCOUNT(i); |
| 6868 | return lut; |
| 6869 | } |
| 6870 | |
| 6871 | s64 ntfs_attr_get_free_bits(ntfs_attr *na) |
| 6872 | { |
| 6873 | u8 *buf, *lut; |
| 6874 | s64 br = 0; |
| 6875 | s64 total = 0; |
| 6876 | s64 nr_free = 0; |
| 6877 | |
| 6878 | lut = ntfs_init_lut256(); |
| 6879 | if (!lut) |
| 6880 | return -1; |
| 6881 | |
| 6882 | buf = ntfs_malloc(65536); |
| 6883 | if (!buf) |
| 6884 | goto out; |
| 6885 | |
| 6886 | while (1) { |
| 6887 | u32 *p; |
| 6888 | br = ntfs_attr_pread(na, total, 65536, buf); |
| 6889 | if (br <= 0) |
| 6890 | break; |
| 6891 | total += br; |
| 6892 | p = (u32 *)buf + br / 4 - 1; |
| 6893 | for (; (u8 *)p >= buf; p--) { |
| 6894 | nr_free += lut[ *p & 255] + |
| 6895 | lut[(*p >> 8) & 255] + |
| 6896 | lut[(*p >> 16) & 255] + |
| 6897 | lut[(*p >> 24) ]; |
| 6898 | } |
| 6899 | switch (br % 4) { |
| 6900 | case 3: nr_free += lut[*(buf + br - 3)]; |
| 6901 | case 2: nr_free += lut[*(buf + br - 2)]; |
| 6902 | case 1: nr_free += lut[*(buf + br - 1)]; |
| 6903 | } |
| 6904 | } |
| 6905 | free(buf); |
| 6906 | out: |
| 6907 | free(lut); |
| 6908 | if (!total || br < 0) |
| 6909 | return -1; |
| 6910 | return nr_free; |
| 6911 | } |