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; |