diff options
Diffstat (limited to 'fs/ntfs/attrib.c')
| -rw-r--r-- | fs/ntfs/attrib.c | 125 |
1 files changed, 107 insertions, 18 deletions
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index cd0f9e740b14..3f9a4ff42ee5 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
| @@ -43,6 +43,9 @@ | |||
| 43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out | 43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out |
| 44 | * of bounds of the runlist. | 44 | * of bounds of the runlist. |
| 45 | * | 45 | * |
| 46 | * Note the runlist can be NULL after this function returns if @vcn is zero and | ||
| 47 | * the attribute has zero allocated size, i.e. there simply is no runlist. | ||
| 48 | * | ||
| 46 | * Locking: - The runlist must be locked for writing. | 49 | * Locking: - The runlist must be locked for writing. |
| 47 | * - This function modifies the runlist. | 50 | * - This function modifies the runlist. |
| 48 | */ | 51 | */ |
| @@ -54,6 +57,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
| 54 | ATTR_RECORD *a; | 57 | ATTR_RECORD *a; |
| 55 | ntfs_attr_search_ctx *ctx; | 58 | ntfs_attr_search_ctx *ctx; |
| 56 | runlist_element *rl; | 59 | runlist_element *rl; |
| 60 | unsigned long flags; | ||
| 57 | int err = 0; | 61 | int err = 0; |
| 58 | 62 | ||
| 59 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", | 63 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", |
| @@ -85,8 +89,11 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
| 85 | * ntfs_mapping_pairs_decompress() fails. | 89 | * ntfs_mapping_pairs_decompress() fails. |
| 86 | */ | 90 | */ |
| 87 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; | 91 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; |
| 88 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) | 92 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) { |
| 93 | read_lock_irqsave(&ni->size_lock, flags); | ||
| 89 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; | 94 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; |
| 95 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
| 96 | } | ||
| 90 | if (unlikely(vcn >= end_vcn)) { | 97 | if (unlikely(vcn >= end_vcn)) { |
| 91 | err = -ENOENT; | 98 | err = -ENOENT; |
| 92 | goto err_out; | 99 | goto err_out; |
| @@ -165,6 +172,7 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
| 165 | const BOOL write_locked) | 172 | const BOOL write_locked) |
| 166 | { | 173 | { |
| 167 | LCN lcn; | 174 | LCN lcn; |
| 175 | unsigned long flags; | ||
| 168 | BOOL is_retry = FALSE; | 176 | BOOL is_retry = FALSE; |
| 169 | 177 | ||
| 170 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", | 178 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", |
| @@ -173,6 +181,14 @@ LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
| 173 | BUG_ON(!ni); | 181 | BUG_ON(!ni); |
| 174 | BUG_ON(!NInoNonResident(ni)); | 182 | BUG_ON(!NInoNonResident(ni)); |
| 175 | BUG_ON(vcn < 0); | 183 | BUG_ON(vcn < 0); |
| 184 | if (!ni->runlist.rl) { | ||
| 185 | read_lock_irqsave(&ni->size_lock, flags); | ||
| 186 | if (!ni->allocated_size) { | ||
| 187 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
| 188 | return LCN_ENOENT; | ||
| 189 | } | ||
| 190 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
| 191 | } | ||
| 176 | retry_remap: | 192 | retry_remap: |
| 177 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ | 193 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ |
| 178 | lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); | 194 | lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); |
| @@ -255,6 +271,7 @@ retry_remap: | |||
| 255 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | 271 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
| 256 | const BOOL write_locked) | 272 | const BOOL write_locked) |
| 257 | { | 273 | { |
| 274 | unsigned long flags; | ||
| 258 | runlist_element *rl; | 275 | runlist_element *rl; |
| 259 | int err = 0; | 276 | int err = 0; |
| 260 | BOOL is_retry = FALSE; | 277 | BOOL is_retry = FALSE; |
| @@ -265,6 +282,14 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | |||
| 265 | BUG_ON(!ni); | 282 | BUG_ON(!ni); |
| 266 | BUG_ON(!NInoNonResident(ni)); | 283 | BUG_ON(!NInoNonResident(ni)); |
| 267 | BUG_ON(vcn < 0); | 284 | BUG_ON(vcn < 0); |
| 285 | if (!ni->runlist.rl) { | ||
| 286 | read_lock_irqsave(&ni->size_lock, flags); | ||
| 287 | if (!ni->allocated_size) { | ||
| 288 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
| 289 | return ERR_PTR(-ENOENT); | ||
| 290 | } | ||
| 291 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
| 292 | } | ||
| 268 | retry_remap: | 293 | retry_remap: |
| 269 | rl = ni->runlist.rl; | 294 | rl = ni->runlist.rl; |
| 270 | if (likely(rl && vcn >= rl[0].vcn)) { | 295 | if (likely(rl && vcn >= rl[0].vcn)) { |
| @@ -528,6 +553,11 @@ int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start, | |||
| 528 | block_size_bits = sb->s_blocksize_bits; | 553 | block_size_bits = sb->s_blocksize_bits; |
| 529 | down_read(&runlist->lock); | 554 | down_read(&runlist->lock); |
| 530 | rl = runlist->rl; | 555 | rl = runlist->rl; |
| 556 | if (!rl) { | ||
| 557 | ntfs_error(sb, "Cannot read attribute list since runlist is " | ||
| 558 | "missing."); | ||
| 559 | goto err_out; | ||
| 560 | } | ||
| 531 | /* Read all clusters specified by the runlist one run at a time. */ | 561 | /* Read all clusters specified by the runlist one run at a time. */ |
| 532 | while (rl->length) { | 562 | while (rl->length) { |
| 533 | lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn); | 563 | lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn); |
| @@ -1247,6 +1277,46 @@ int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) | |||
| 1247 | } | 1277 | } |
| 1248 | 1278 | ||
| 1249 | /** | 1279 | /** |
| 1280 | * ntfs_resident_attr_value_resize - resize the value of a resident attribute | ||
| 1281 | * @m: mft record containing attribute record | ||
| 1282 | * @a: attribute record whose value to resize | ||
| 1283 | * @new_size: new size in bytes to which to resize the attribute value of @a | ||
| 1284 | * | ||
| 1285 | * Resize the value of the attribute @a in the mft record @m to @new_size bytes. | ||
| 1286 | * If the value is made bigger, the newly allocated space is cleared. | ||
| 1287 | * | ||
| 1288 | * Return 0 on success and -errno on error. The following error codes are | ||
| 1289 | * defined: | ||
| 1290 | * -ENOSPC - Not enough space in the mft record @m to perform the resize. | ||
| 1291 | * | ||
| 1292 | * Note: On error, no modifications have been performed whatsoever. | ||
| 1293 | * | ||
| 1294 | * Warning: If you make a record smaller without having copied all the data you | ||
| 1295 | * are interested in the data may be overwritten. | ||
| 1296 | */ | ||
| 1297 | int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, | ||
| 1298 | const u32 new_size) | ||
| 1299 | { | ||
| 1300 | u32 old_size; | ||
| 1301 | |||
| 1302 | /* Resize the resident part of the attribute record. */ | ||
| 1303 | if (ntfs_attr_record_resize(m, a, | ||
| 1304 | le16_to_cpu(a->data.resident.value_offset) + new_size)) | ||
| 1305 | return -ENOSPC; | ||
| 1306 | /* | ||
| 1307 | * The resize succeeded! If we made the attribute value bigger, clear | ||
| 1308 | * the area between the old size and @new_size. | ||
| 1309 | */ | ||
| 1310 | old_size = le32_to_cpu(a->data.resident.value_length); | ||
| 1311 | if (new_size > old_size) | ||
| 1312 | memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) + | ||
| 1313 | old_size, 0, new_size - old_size); | ||
| 1314 | /* Finally update the length of the attribute value. */ | ||
| 1315 | a->data.resident.value_length = cpu_to_le32(new_size); | ||
| 1316 | return 0; | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | /** | ||
| 1250 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute | 1320 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute |
| 1251 | * @ni: ntfs inode describing the attribute to convert | 1321 | * @ni: ntfs inode describing the attribute to convert |
| 1252 | * | 1322 | * |
| @@ -1302,6 +1372,12 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
| 1302 | return err; | 1372 | return err; |
| 1303 | } | 1373 | } |
| 1304 | /* | 1374 | /* |
| 1375 | * FIXME: Compressed and encrypted attributes are not supported when | ||
| 1376 | * writing and we should never have gotten here for them. | ||
| 1377 | */ | ||
| 1378 | BUG_ON(NInoCompressed(ni)); | ||
| 1379 | BUG_ON(NInoEncrypted(ni)); | ||
| 1380 | /* | ||
| 1305 | * The size needs to be aligned to a cluster boundary for allocation | 1381 | * The size needs to be aligned to a cluster boundary for allocation |
| 1306 | * purposes. | 1382 | * purposes. |
| 1307 | */ | 1383 | */ |
| @@ -1377,10 +1453,15 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
| 1377 | BUG_ON(a->non_resident); | 1453 | BUG_ON(a->non_resident); |
| 1378 | /* | 1454 | /* |
| 1379 | * Calculate new offsets for the name and the mapping pairs array. | 1455 | * Calculate new offsets for the name and the mapping pairs array. |
| 1380 | * We assume the attribute is not compressed or sparse. | ||
| 1381 | */ | 1456 | */ |
| 1382 | name_ofs = (offsetof(ATTR_REC, | 1457 | if (NInoSparse(ni) || NInoCompressed(ni)) |
| 1383 | data.non_resident.compressed_size) + 7) & ~7; | 1458 | name_ofs = (offsetof(ATTR_REC, |
| 1459 | data.non_resident.compressed_size) + | ||
| 1460 | sizeof(a->data.non_resident.compressed_size) + | ||
| 1461 | 7) & ~7; | ||
| 1462 | else | ||
| 1463 | name_ofs = (offsetof(ATTR_REC, | ||
| 1464 | data.non_resident.compressed_size) + 7) & ~7; | ||
| 1384 | mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; | 1465 | mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; |
| 1385 | /* | 1466 | /* |
| 1386 | * Determine the size of the resident part of the now non-resident | 1467 | * Determine the size of the resident part of the now non-resident |
| @@ -1419,24 +1500,23 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
| 1419 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), | 1500 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), |
| 1420 | a->name_length * sizeof(ntfschar)); | 1501 | a->name_length * sizeof(ntfschar)); |
| 1421 | a->name_offset = cpu_to_le16(name_ofs); | 1502 | a->name_offset = cpu_to_le16(name_ofs); |
| 1422 | /* | ||
| 1423 | * FIXME: For now just clear all of these as we do not support them | ||
| 1424 | * when writing. | ||
| 1425 | */ | ||
| 1426 | a->flags &= cpu_to_le16(0xffff & ~le16_to_cpu(ATTR_IS_SPARSE | | ||
| 1427 | ATTR_IS_ENCRYPTED | ATTR_COMPRESSION_MASK)); | ||
| 1428 | /* Setup the fields specific to non-resident attributes. */ | 1503 | /* Setup the fields specific to non-resident attributes. */ |
| 1429 | a->data.non_resident.lowest_vcn = 0; | 1504 | a->data.non_resident.lowest_vcn = 0; |
| 1430 | a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >> | 1505 | a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >> |
| 1431 | vol->cluster_size_bits); | 1506 | vol->cluster_size_bits); |
| 1432 | a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs); | 1507 | a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs); |
| 1433 | a->data.non_resident.compression_unit = 0; | ||
| 1434 | memset(&a->data.non_resident.reserved, 0, | 1508 | memset(&a->data.non_resident.reserved, 0, |
| 1435 | sizeof(a->data.non_resident.reserved)); | 1509 | sizeof(a->data.non_resident.reserved)); |
| 1436 | a->data.non_resident.allocated_size = cpu_to_sle64(new_size); | 1510 | a->data.non_resident.allocated_size = cpu_to_sle64(new_size); |
| 1437 | a->data.non_resident.data_size = | 1511 | a->data.non_resident.data_size = |
| 1438 | a->data.non_resident.initialized_size = | 1512 | a->data.non_resident.initialized_size = |
| 1439 | cpu_to_sle64(attr_size); | 1513 | cpu_to_sle64(attr_size); |
| 1514 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
| 1515 | a->data.non_resident.compression_unit = 4; | ||
| 1516 | a->data.non_resident.compressed_size = | ||
| 1517 | a->data.non_resident.allocated_size; | ||
| 1518 | } else | ||
| 1519 | a->data.non_resident.compression_unit = 0; | ||
| 1440 | /* Generate the mapping pairs array into the attribute record. */ | 1520 | /* Generate the mapping pairs array into the attribute record. */ |
| 1441 | err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, | 1521 | err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, |
| 1442 | arec_size - mp_ofs, rl, 0, -1, NULL); | 1522 | arec_size - mp_ofs, rl, 0, -1, NULL); |
| @@ -1446,16 +1526,19 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
| 1446 | goto undo_err_out; | 1526 | goto undo_err_out; |
| 1447 | } | 1527 | } |
| 1448 | /* Setup the in-memory attribute structure to be non-resident. */ | 1528 | /* Setup the in-memory attribute structure to be non-resident. */ |
| 1449 | /* | ||
| 1450 | * FIXME: For now just clear all of these as we do not support them | ||
| 1451 | * when writing. | ||
| 1452 | */ | ||
| 1453 | NInoClearSparse(ni); | ||
| 1454 | NInoClearEncrypted(ni); | ||
| 1455 | NInoClearCompressed(ni); | ||
| 1456 | ni->runlist.rl = rl; | 1529 | ni->runlist.rl = rl; |
| 1457 | write_lock_irqsave(&ni->size_lock, flags); | 1530 | write_lock_irqsave(&ni->size_lock, flags); |
| 1458 | ni->allocated_size = new_size; | 1531 | ni->allocated_size = new_size; |
| 1532 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
| 1533 | ni->itype.compressed.size = ni->allocated_size; | ||
| 1534 | ni->itype.compressed.block_size = 1U << | ||
| 1535 | (a->data.non_resident.compression_unit + | ||
| 1536 | vol->cluster_size_bits); | ||
| 1537 | ni->itype.compressed.block_size_bits = | ||
| 1538 | ffs(ni->itype.compressed.block_size) - 1; | ||
| 1539 | ni->itype.compressed.block_clusters = 1U << | ||
| 1540 | a->data.non_resident.compression_unit; | ||
| 1541 | } | ||
| 1459 | write_unlock_irqrestore(&ni->size_lock, flags); | 1542 | write_unlock_irqrestore(&ni->size_lock, flags); |
| 1460 | /* | 1543 | /* |
| 1461 | * This needs to be last since the address space operations ->readpage | 1544 | * This needs to be last since the address space operations ->readpage |
| @@ -1603,6 +1686,12 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) | |||
| 1603 | BUG_ON(cnt < 0); | 1686 | BUG_ON(cnt < 0); |
| 1604 | if (!cnt) | 1687 | if (!cnt) |
| 1605 | goto done; | 1688 | goto done; |
| 1689 | /* | ||
| 1690 | * FIXME: Compressed and encrypted attributes are not supported when | ||
| 1691 | * writing and we should never have gotten here for them. | ||
| 1692 | */ | ||
| 1693 | BUG_ON(NInoCompressed(ni)); | ||
| 1694 | BUG_ON(NInoEncrypted(ni)); | ||
| 1606 | mapping = VFS_I(ni)->i_mapping; | 1695 | mapping = VFS_I(ni)->i_mapping; |
| 1607 | /* Work out the starting index and page offset. */ | 1696 | /* Work out the starting index and page offset. */ |
| 1608 | idx = ofs >> PAGE_CACHE_SHIFT; | 1697 | idx = ofs >> PAGE_CACHE_SHIFT; |
