external/ntfs-3g
Revisión | 23a4e18bfaa64a15019bee1960992bd51bd7363a (tree) |
---|---|
Tiempo | 2019-02-22 01:33:58 |
Autor | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
Merge branch 'edge' of git://git.code.sf.net/p/ntfs-3g/ntfs-3g into oreo-x86
@@ -1,9 +1,10 @@ | ||
1 | 1 | /* |
2 | - * compat.h - Tweaks for Windows compatibility. | |
2 | + * compat.h - Tweaks for compatibility with non-Linux systems. | |
3 | 3 | * |
4 | 4 | * Copyright (c) 2002 Richard Russon |
5 | 5 | * Copyright (c) 2002-2004 Anton Altaparmakov |
6 | 6 | * Copyright (c) 2008-2009 Szabolcs Szakacsits |
7 | + * Copyright (c) 2019 Jean-Pierre Andre | |
7 | 8 | * |
8 | 9 | * This program/include file is free software; you can redistribute it and/or |
9 | 10 | * modify it under the terms of the GNU General Public License as published |
@@ -41,6 +42,10 @@ | ||
41 | 42 | #define ELIBBAD ENOEXEC |
42 | 43 | #endif |
43 | 44 | |
45 | +#ifndef ELIBACC | |
46 | +#define ELIBACC ENOENT | |
47 | +#endif | |
48 | + | |
44 | 49 | #ifndef PATH_MAX |
45 | 50 | #define PATH_MAX 4096 |
46 | 51 | #endif |
@@ -2403,17 +2403,23 @@ typedef struct { | ||
2403 | 2403 | * |
2404 | 2404 | * 1. The least significant 16 bits (i.e. bits 0 to 15) specify the type of |
2405 | 2405 | * the reparse point. |
2406 | - * 2. The 13 bits after this (i.e. bits 16 to 28) are reserved for future use. | |
2407 | - * 3. The most significant three bits are flags describing the reparse point. | |
2406 | + * 2. The 12 bits after this (i.e. bits 16 to 27) are reserved for future use. | |
2407 | + * 3. The most significant four bits are flags describing the reparse point. | |
2408 | 2408 | * They are defined as follows: |
2409 | + * bit 28: Directory bit. If set, the directory is not a surrogate | |
2410 | + * and can be used the usual way. | |
2409 | 2411 | * bit 29: Name surrogate bit. If set, the filename is an alias for |
2410 | 2412 | * another object in the system. |
2411 | 2413 | * bit 30: High-latency bit. If set, accessing the first byte of data will |
2412 | 2414 | * be slow. (E.g. the data is stored on a tape drive.) |
2413 | 2415 | * bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User |
2414 | 2416 | * defined tags have to use zero here. |
2417 | + * 4. Moreover, on Windows 10 : | |
2418 | + * Some flags may be used in bits 12 to 15 to further describe the | |
2419 | + * reparse point. | |
2415 | 2420 | */ |
2416 | 2421 | typedef enum { |
2422 | + IO_REPARSE_TAG_DIRECTORY = const_cpu_to_le32(0x10000000), | |
2417 | 2423 | IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32(0x20000000), |
2418 | 2424 | IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32(0x40000000), |
2419 | 2425 | IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32(0x80000000), |
@@ -2436,10 +2442,12 @@ typedef enum { | ||
2436 | 2442 | IO_REPARSE_TAG_DFM = const_cpu_to_le32(0x80000016), |
2437 | 2443 | IO_REPARSE_TAG_WOF = const_cpu_to_le32(0x80000017), |
2438 | 2444 | IO_REPARSE_TAG_WCI = const_cpu_to_le32(0x80000018), |
2445 | + IO_REPARSE_TAG_CLOUD = const_cpu_to_le32(0x9000001A), | |
2439 | 2446 | IO_REPARSE_TAG_GVFS = const_cpu_to_le32(0x9000001C), |
2440 | 2447 | IO_REPARSE_TAG_LX_SYMLINK = const_cpu_to_le32(0xA000001D), |
2441 | 2448 | |
2442 | 2449 | IO_REPARSE_TAG_VALID_VALUES = const_cpu_to_le32(0xf000ffff), |
2450 | + IO_REPARSE_PLUGIN_SELECT = const_cpu_to_le32(0xffff0fff), | |
2443 | 2451 | } PREDEFINED_REPARSE_TAGS; |
2444 | 2452 | |
2445 | 2453 | /** |
@@ -40,6 +40,13 @@ enum { | ||
40 | 40 | }; |
41 | 41 | |
42 | 42 | /* |
43 | + * Parameters for formatting | |
44 | + */ | |
45 | + | |
46 | + /* Up to Windows 10, the cluster size was limited to 64K */ | |
47 | +#define NTFS_MAX_CLUSTER_SIZE 2097152 /* Windows 10 Creators allows 2MB */ | |
48 | + | |
49 | +/* | |
43 | 50 | * Parameters for compression |
44 | 51 | */ |
45 | 52 |
@@ -7,7 +7,10 @@ endif | ||
7 | 7 | |
8 | 8 | libfuse_lite_la_CFLAGS= \ |
9 | 9 | $(AM_CFLAGS) \ |
10 | - $(LIBFUSE_LITE_CFLAGS) \ | |
10 | + $(LIBFUSE_LITE_CFLAGS) | |
11 | + | |
12 | +libfuse_lite_la_CPPFLAGS= \ | |
13 | + $(AM_CPPFLAGS) \ | |
11 | 14 | -I$(top_srcdir)/include/fuse-lite |
12 | 15 | |
13 | 16 | libfuse_lite_la_LIBADD = $(LIBFUSE_LITE_LIBS) |
@@ -134,7 +134,6 @@ struct fuse_dh { | ||
134 | 134 | struct fuse *fuse; |
135 | 135 | fuse_req_t req; |
136 | 136 | char *contents; |
137 | - int allocated; | |
138 | 137 | unsigned len; |
139 | 138 | unsigned size; |
140 | 139 | unsigned needlen; |
@@ -2782,8 +2781,10 @@ static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, | ||
2782 | 2781 | fuse_finish_interrupt(f, req, &d); |
2783 | 2782 | free(path); |
2784 | 2783 | |
2785 | - fuse_reply_ioctl(req, err, out_buf, out_bufsz); | |
2784 | + if (err >= 0) { /* not an error */ | |
2785 | + fuse_reply_ioctl(req, err, out_buf, out_bufsz); | |
2786 | 2786 | goto out; |
2787 | + } | |
2787 | 2788 | err: |
2788 | 2789 | reply_err(req, err); |
2789 | 2790 | out: |
@@ -9,8 +9,8 @@ else | ||
9 | 9 | noinst_LTLIBRARIES = libntfs-3g.la |
10 | 10 | endif |
11 | 11 | |
12 | -libntfs_3g_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g | |
13 | -libntfs_3g_la_CPPFLAGS= $(AM_CPPFLAGS) $(LIBNTFS_CPPFLAGS) | |
12 | +libntfs_3g_la_CFLAGS = $(AM_CFLAGS) | |
13 | +libntfs_3g_la_CPPFLAGS= $(AM_CPPFLAGS) $(LIBNTFS_CPPFLAGS) -I$(top_srcdir)/include/ntfs-3g | |
14 | 14 | libntfs_3g_la_LIBADD = $(LIBNTFS_LIBS) |
15 | 15 | libntfs_3g_la_LDFLAGS = -version-info $(LIBNTFS_3G_VERSION) -no-undefined |
16 | 16 |
@@ -38,6 +38,7 @@ | ||
38 | 38 | #include <errno.h> |
39 | 39 | #endif |
40 | 40 | |
41 | +#include "param.h" | |
41 | 42 | #include "compat.h" |
42 | 43 | #include "bootsect.h" |
43 | 44 | #include "debug.h" |
@@ -61,6 +62,7 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b) | ||
61 | 62 | { |
62 | 63 | u32 i; |
63 | 64 | BOOL ret = FALSE; |
65 | + u16 sectors_per_cluster; | |
64 | 66 | |
65 | 67 | ntfs_log_debug("Beginning bootsector check.\n"); |
66 | 68 |
@@ -83,15 +85,27 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b) | ||
83 | 85 | case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: |
84 | 86 | break; |
85 | 87 | default: |
86 | - ntfs_log_error("Unexpected sectors per cluster value (%d).\n", | |
87 | - b->bpb.sectors_per_cluster); | |
88 | - goto not_ntfs; | |
88 | + if ((b->bpb.sectors_per_cluster < 240) | |
89 | + || (b->bpb.sectors_per_cluster > 249)) { | |
90 | + if (b->bpb.sectors_per_cluster > 128) | |
91 | + ntfs_log_error("Unexpected sectors" | |
92 | + " per cluster value (code 0x%x)\n", | |
93 | + b->bpb.sectors_per_cluster); | |
94 | + else | |
95 | + ntfs_log_error("Unexpected sectors" | |
96 | + " per cluster value (%d).\n", | |
97 | + b->bpb.sectors_per_cluster); | |
98 | + goto not_ntfs; | |
99 | + } | |
89 | 100 | } |
90 | 101 | |
91 | 102 | ntfs_log_debug("Checking cluster size.\n"); |
92 | - i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) * | |
93 | - b->bpb.sectors_per_cluster; | |
94 | - if (i > 65536) { | |
103 | + if (b->bpb.sectors_per_cluster > 128) | |
104 | + sectors_per_cluster = 1 << (256 - b->bpb.sectors_per_cluster); | |
105 | + else | |
106 | + sectors_per_cluster = b->bpb.sectors_per_cluster; | |
107 | + i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) * sectors_per_cluster; | |
108 | + if (i > NTFS_MAX_CLUSTER_SIZE) { | |
95 | 109 | ntfs_log_error("Unexpected cluster size (%d).\n", i); |
96 | 110 | goto not_ntfs; |
97 | 111 | } |
@@ -171,7 +185,7 @@ static const char *last_sector_error = | ||
171 | 185 | int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) |
172 | 186 | { |
173 | 187 | s64 sectors; |
174 | - u8 sectors_per_cluster; | |
188 | + u16 sectors_per_cluster; | |
175 | 189 | s8 c; |
176 | 190 | |
177 | 191 | /* We return -1 with errno = EINVAL on error. */ |
@@ -186,7 +200,10 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) | ||
186 | 200 | * below or equal the number_of_clusters) really belong in the |
187 | 201 | * ntfs_boot_sector_is_ntfs but in this way we can just do this once. |
188 | 202 | */ |
189 | - sectors_per_cluster = bs->bpb.sectors_per_cluster; | |
203 | + if (bs->bpb.sectors_per_cluster > 128) | |
204 | + sectors_per_cluster = 1 << (256 - bs->bpb.sectors_per_cluster); | |
205 | + else | |
206 | + sectors_per_cluster = bs->bpb.sectors_per_cluster; | |
190 | 207 | ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster); |
191 | 208 | if (sectors_per_cluster & (sectors_per_cluster - 1)) { |
192 | 209 | ntfs_log_error("sectors_per_cluster (%d) is not a power of 2." |
@@ -837,7 +837,7 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni) | ||
837 | 837 | if (!err) |
838 | 838 | err = errno; |
839 | 839 | ntfs_log_perror("Failed to open inode %lld with index", |
840 | - (long long)le64_to_cpu(fn->parent_directory)); | |
840 | + (long long)MREF_LE(fn->parent_directory)); | |
841 | 841 | continue; |
842 | 842 | } |
843 | 843 | ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); |
@@ -1518,14 +1518,16 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, | ||
1518 | 1518 | ntfs_attr_search_ctx *ctx; |
1519 | 1519 | STANDARD_INFORMATION *std_info; |
1520 | 1520 | FILE_NAME_ATTR *fn; |
1521 | - const u64 *times; | |
1521 | + u64 times[4]; | |
1522 | 1522 | ntfs_time now; |
1523 | 1523 | int cnt; |
1524 | 1524 | int ret; |
1525 | 1525 | |
1526 | 1526 | ret = -1; |
1527 | 1527 | if ((size >= 8) && !(flags & XATTR_CREATE)) { |
1528 | - times = (const u64*)value; | |
1528 | + /* Copy, to avoid alignment issue encountered on ARM */ | |
1529 | + memcpy(times, value, | |
1530 | + (size < sizeof(times) ? size : sizeof(times))); | |
1529 | 1531 | now = ntfs_current_time(); |
1530 | 1532 | /* update the standard information attribute */ |
1531 | 1533 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
@@ -3,7 +3,7 @@ | ||
3 | 3 | * |
4 | 4 | * This module is part of ntfs-3g library |
5 | 5 | * |
6 | - * Copyright (c) 2014-2015 Jean-Pierre Andre | |
6 | + * Copyright (c) 2014-2019 Jean-Pierre Andre | |
7 | 7 | * Copyright (c) 2014 Red Hat, Inc. |
8 | 8 | * |
9 | 9 | * This program/include file is free software; you can redistribute it and/or |
@@ -225,6 +225,24 @@ not_found: | ||
225 | 225 | return 0; |
226 | 226 | } |
227 | 227 | |
228 | +static inline LCN align_up(ntfs_volume *vol, LCN lcn, u64 granularity) | |
229 | +{ | |
230 | + u64 aligned; | |
231 | + | |
232 | + aligned = (lcn << vol->cluster_size_bits) + granularity - 1; | |
233 | + aligned -= aligned % granularity; | |
234 | + return (aligned >> vol->cluster_size_bits); | |
235 | +} | |
236 | + | |
237 | +static inline u64 align_down(ntfs_volume *vol, u64 count, u64 granularity) | |
238 | +{ | |
239 | + u64 aligned; | |
240 | + | |
241 | + aligned = count << vol->cluster_size_bits; | |
242 | + aligned -= aligned % granularity; | |
243 | + return (aligned >> vol->cluster_size_bits); | |
244 | +} | |
245 | + | |
228 | 246 | #define FSTRIM_BUFSIZ 4096 |
229 | 247 | |
230 | 248 | /* Trim the filesystem. |
@@ -255,11 +273,11 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed) | ||
255 | 273 | * XXX We could fix these limitations in future. |
256 | 274 | */ |
257 | 275 | if (start != 0 || len != (uint64_t)-1) { |
258 | - ntfs_log_debug("fstrim: setting start or length is not supported\n"); | |
276 | + ntfs_log_error("fstrim: setting start or length is not supported\n"); | |
259 | 277 | return -EINVAL; |
260 | 278 | } |
261 | 279 | if (minlen > vol->cluster_size) { |
262 | - ntfs_log_debug("fstrim: minlen > cluster size is not supported\n"); | |
280 | + ntfs_log_error("fstrim: minlen > cluster size is not supported\n"); | |
263 | 281 | return -EINVAL; |
264 | 282 | } |
265 | 283 |
@@ -269,7 +287,7 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed) | ||
269 | 287 | * different. |
270 | 288 | */ |
271 | 289 | if (!NDevBlock(vol->dev)) { |
272 | - ntfs_log_debug("fstrim: not supported for non-block-device\n"); | |
290 | + ntfs_log_error("fstrim: not supported for non-block-device\n"); | |
273 | 291 | return -EOPNOTSUPP; |
274 | 292 | } |
275 | 293 |
@@ -278,15 +296,12 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed) | ||
278 | 296 | if (ret) |
279 | 297 | return ret; |
280 | 298 | if (discard_alignment != 0) { |
281 | - ntfs_log_debug("fstrim: backing device is not aligned for discards\n"); | |
282 | - return -EOPNOTSUPP; | |
283 | - } | |
284 | - if (discard_granularity > vol->cluster_size) { | |
285 | - ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n"); | |
299 | + ntfs_log_error("fstrim: backing device is not aligned for discards\n"); | |
286 | 300 | return -EOPNOTSUPP; |
287 | 301 | } |
302 | + | |
288 | 303 | if (discard_max_bytes == 0) { |
289 | - ntfs_log_debug("fstrim: backing device does not support discard (discard_max_bytes == 0)\n"); | |
304 | + ntfs_log_error("fstrim: backing device does not support discard (discard_max_bytes == 0)\n"); | |
290 | 305 | return -EOPNOTSUPP; |
291 | 306 | } |
292 | 307 |
@@ -323,11 +338,14 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed) | ||
323 | 338 | } |
324 | 339 | |
325 | 340 | /* Trim the clusters in large as possible blocks, but |
326 | - * not larger than discard_max_bytes. | |
341 | + * not larger than discard_max_bytes, and compatible | |
342 | + * with the supported trim granularity. | |
327 | 343 | */ |
328 | 344 | for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) { |
329 | 345 | if (!ntfs_bit_get(buf, start_lcn-start_buf)) { |
330 | 346 | LCN end_lcn; |
347 | + LCN aligned_lcn; | |
348 | + u64 aligned_count; | |
331 | 349 | |
332 | 350 | /* Cluster 'start_lcn' is not in use, |
333 | 351 | * find end of this run. |
@@ -338,14 +356,25 @@ static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed) | ||
338 | 356 | < discard_max_bytes && |
339 | 357 | !ntfs_bit_get(buf, end_lcn-start_buf)) |
340 | 358 | end_lcn++; |
341 | - | |
342 | - ret = fstrim_clusters(vol, | |
343 | - start_lcn, end_lcn-start_lcn); | |
344 | - if (ret) | |
345 | - goto free_out; | |
346 | - | |
347 | - *trimmed += (end_lcn - start_lcn) | |
359 | + aligned_lcn = align_up(vol, start_lcn, | |
360 | + discard_granularity); | |
361 | + if (aligned_lcn >= end_lcn) | |
362 | + aligned_count = 0; | |
363 | + else { | |
364 | + aligned_count = | |
365 | + align_down(vol, | |
366 | + end_lcn - aligned_lcn, | |
367 | + discard_granularity); | |
368 | + } | |
369 | + if (aligned_count) { | |
370 | + ret = fstrim_clusters(vol, | |
371 | + aligned_lcn, aligned_count); | |
372 | + if (ret) | |
373 | + goto free_out; | |
374 | + | |
375 | + *trimmed += aligned_count | |
348 | 376 | << vol->cluster_size_bits; |
377 | + } | |
349 | 378 | start_lcn = end_lcn-1; |
350 | 379 | } |
351 | 380 | } |
@@ -5,7 +5,7 @@ | ||
5 | 5 | * Copyright (c) 2004-2005 Richard Russon |
6 | 6 | * Copyright (c) 2004-2008 Szabolcs Szakacsits |
7 | 7 | * Copyright (c) 2005 Yura Pakhuchiy |
8 | - * Copyright (c) 2014-2015 Jean-Pierre Andre | |
8 | + * Copyright (c) 2014-2018 Jean-Pierre Andre | |
9 | 9 | * |
10 | 10 | * This program/include file is free software; you can redistribute it and/or |
11 | 11 | * modify it under the terms of the GNU General Public License as published |
@@ -1389,16 +1389,27 @@ ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data) | ||
1389 | 1389 | */ |
1390 | 1390 | if (ext_ni) { |
1391 | 1391 | /* |
1392 | - * Make sure record 15 is a base extent and has | |
1393 | - * no extents. | |
1394 | - * Also make sure it has no name : a base inode with | |
1395 | - * no extents and no name cannot be in use. | |
1396 | - * Otherwise apply standard procedure. | |
1392 | + * Make sure record 15 is a base extent and it has | |
1393 | + * no name. A base inode with no name cannot be in use. | |
1394 | + * The test based on base_mft_record fails for | |
1395 | + * extents of MFT, so we need a special check. | |
1396 | + * If already used, apply standard procedure. | |
1397 | 1397 | */ |
1398 | 1398 | if (!ext_ni->mrec->base_mft_record |
1399 | - && !ext_ni->nr_extents) | |
1399 | + && !ext_ni->mrec->link_count) | |
1400 | 1400 | forced_mft_data = TRUE; |
1401 | 1401 | ntfs_inode_close(ext_ni); |
1402 | + /* Double-check, in case it is used for MFT */ | |
1403 | + if (forced_mft_data && base_ni->nr_extents) { | |
1404 | + int i; | |
1405 | + | |
1406 | + for (i=0; i<base_ni->nr_extents; i++) { | |
1407 | + if (base_ni->extent_nis[i] | |
1408 | + && (base_ni->extent_nis[i]->mft_no | |
1409 | + == FILE_mft_data)) | |
1410 | + forced_mft_data = FALSE; | |
1411 | + } | |
1412 | + } | |
1402 | 1413 | } |
1403 | 1414 | } |
1404 | 1415 | if (forced_mft_data) |
@@ -3,7 +3,7 @@ | ||
3 | 3 | * |
4 | 4 | * This module is part of ntfs-3g library |
5 | 5 | * |
6 | - * Copyright (c) 2009 Jean-Pierre Andre | |
6 | + * Copyright (c) 2009-2019 Jean-Pierre Andre | |
7 | 7 | * |
8 | 8 | * This program/include file is free software; you can redistribute it and/or |
9 | 9 | * modify it under the terms of the GNU General Public License as published |
@@ -63,9 +63,13 @@ | ||
63 | 63 | * significant byte first, and the six fields be compared individually |
64 | 64 | * for ordering. RFC 4122 does not define the internal representation. |
65 | 65 | * |
66 | + * Windows apparently stores the first three fields in little endian | |
67 | + * order, and the last two fields in big endian order. | |
68 | + * | |
66 | 69 | * Here we always copy disk images with no endianness change, |
67 | 70 | * and, for indexing, GUIDs are compared as if they were a sequence |
68 | - * of four unsigned 32 bit integers. | |
71 | + * of four little-endian unsigned 32 bit integers (as Windows | |
72 | + * does it that way.) | |
69 | 73 | * |
70 | 74 | * --------------------- begin from RFC 4122 ---------------------- |
71 | 75 | * Consider each field of the UUID to be an unsigned integer as shown |
@@ -329,7 +333,7 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo, | ||
329 | 333 | |
330 | 334 | na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); |
331 | 335 | if (na) { |
332 | - | |
336 | + memset(&old_attr, 0, sizeof(OBJECT_ID_ATTR)); | |
333 | 337 | /* remove the existing index entry */ |
334 | 338 | oldsize = remove_object_id_index(na,xo,&old_attr); |
335 | 339 | if (oldsize < 0) |
@@ -349,10 +353,12 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo, | ||
349 | 353 | res = -1; |
350 | 354 | } |
351 | 355 | } |
352 | - /* write index part if provided */ | |
356 | + /* overwrite index data with new value */ | |
357 | + memcpy(&old_attr, value, | |
358 | + (size < sizeof(OBJECT_ID_ATTR) | |
359 | + ? size : sizeof(OBJECT_ID_ATTR))); | |
353 | 360 | if (!res |
354 | - && ((size < sizeof(OBJECT_ID_ATTR)) | |
355 | - || set_object_id_index(ni,xo,value))) { | |
361 | + && set_object_id_index(ni,xo,&old_attr)) { | |
356 | 362 | /* |
357 | 363 | * If cannot index, try to remove the object |
358 | 364 | * id and log the error. There will be an |
@@ -500,9 +506,11 @@ int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size) | ||
500 | 506 | /* |
501 | 507 | * Set the object id from an extended attribute |
502 | 508 | * |
503 | - * If the size is 64, the attribute and index are set. | |
504 | - * else if the size is not less than 16 only the attribute is set. | |
505 | - * The object id index is set accordingly. | |
509 | + * The first 16 bytes are the new object id, they can be followed | |
510 | + * by the birth volume id, the birth object id and the domain id. | |
511 | + * If they are not present, their previous value is kept. | |
512 | + * Only the object id is stored into the attribute, all the fields | |
513 | + * are stored into the index. | |
506 | 514 | * |
507 | 515 | * Returns 0, or -1 if there is a problem |
508 | 516 | */ |
@@ -519,10 +527,12 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni, | ||
519 | 527 | if (ni && value && (size >= sizeof(GUID))) { |
520 | 528 | xo = open_object_id_index(ni->vol); |
521 | 529 | if (xo) { |
522 | - /* make sure the GUID was not used somewhere */ | |
530 | + /* make sure the GUID was not used elsewhere */ | |
523 | 531 | memcpy(&key.object_id, value, sizeof(GUID)); |
524 | - if (ntfs_index_lookup(&key, | |
525 | - sizeof(OBJECT_ID_INDEX_KEY), xo)) { | |
532 | + if ((ntfs_index_lookup(&key, | |
533 | + sizeof(OBJECT_ID_INDEX_KEY), xo)) | |
534 | + || (MREF_LE(((struct OBJECT_ID_INDEX*)xo->entry) | |
535 | + ->data.file_id) == ni->mft_no)) { | |
526 | 536 | ntfs_index_ctx_reinit(xo); |
527 | 537 | res = add_object_id(ni, flags); |
528 | 538 | if (!res) { |
@@ -53,6 +53,9 @@ | ||
53 | 53 | #ifdef HAVE_LINUX_FD_H |
54 | 54 | #include <linux/fd.h> |
55 | 55 | #endif |
56 | +#ifdef HAVE_LINUX_FS_H | |
57 | +#include <linux/fs.h> | |
58 | +#endif | |
56 | 59 | |
57 | 60 | #include "types.h" |
58 | 61 | #include "mst.h" |
@@ -140,8 +143,26 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) | ||
140 | 143 | *(int*)dev->d_private = open(dev->d_name, flags); |
141 | 144 | if (*(int*)dev->d_private == -1) { |
142 | 145 | err = errno; |
146 | + /* if permission error and rw, retry read-only */ | |
147 | + if ((err == EACCES) && ((flags & O_RDWR) == O_RDWR)) | |
148 | + err = EROFS; | |
143 | 149 | goto err_out; |
144 | 150 | } |
151 | +#ifdef HAVE_LINUX_FS_H | |
152 | + /* Check whether the device was forced read-only */ | |
153 | + if (NDevBlock(dev) && ((flags & O_RDWR) == O_RDWR)) { | |
154 | + int r; | |
155 | + int state; | |
156 | + | |
157 | + r = ioctl(DEV_FD(dev), BLKROGET, &state); | |
158 | + if (!r && state) { | |
159 | + err = EROFS; | |
160 | + if (close(DEV_FD(dev))) | |
161 | + err = errno; | |
162 | + goto err_out; | |
163 | + } | |
164 | + } | |
165 | +#endif | |
145 | 166 | |
146 | 167 | if ((flags & O_RDWR) != O_RDWR) |
147 | 168 | NDevSetReadOnly(dev); |
@@ -533,7 +533,7 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, | ||
533 | 533 | dev->d_name); |
534 | 534 | goto error_exit; |
535 | 535 | } else { |
536 | - ntfs_log_info("Can only open '%s' as read-only\n", | |
536 | + ntfs_log_info("Error opening '%s' read-write\n", | |
537 | 537 | dev->d_name); |
538 | 538 | NVolSetReadOnly(vol); |
539 | 539 | } |
@@ -963,7 +963,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags) | ||
963 | 963 | vol->mftmirr_size = l; |
964 | 964 | } |
965 | 965 | ntfs_log_debug("Comparing $MFTMirr to $MFT...\n"); |
966 | - for (i = 0; i < vol->mftmirr_size; ++i) { | |
966 | + /* Windows 10 does not update the full $MFTMirr any more */ | |
967 | + for (i = 0; (i < vol->mftmirr_size) && (i < FILE_first_user); ++i) { | |
967 | 968 | MFT_RECORD *mrec, *mrec2; |
968 | 969 | const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", |
969 | 970 | "$Volume", "$AttrDef", "root directory", "$Bitmap", |
@@ -132,7 +132,7 @@ actual writing to the device. | ||
132 | 132 | .TP |
133 | 133 | \fB\-c\fR, \fB\-\-cluster\-size\fR BYTES |
134 | 134 | Specify the size of clusters in bytes. Valid cluster size values are powers of |
135 | -two, with at least 256, and at most 65536 bytes per cluster. If omitted, | |
135 | +two, with at least 256, and at most 2097152 bytes (2MB) per cluster. If omitted, | |
136 | 136 | .B mkntfs |
137 | 137 | uses 4096 bytes as the default cluster size. |
138 | 138 | .sp |
@@ -6,7 +6,7 @@ | ||
6 | 6 | * Copyright (c) 2002-2006 Szabolcs Szakacsits |
7 | 7 | * Copyright (c) 2005 Erik Sornes |
8 | 8 | * Copyright (c) 2007 Yura Pakhuchiy |
9 | - * Copyright (c) 2010-2014 Jean-Pierre Andre | |
9 | + * Copyright (c) 2010-2018 Jean-Pierre Andre | |
10 | 10 | * |
11 | 11 | * This utility will create an NTFS 1.2 or 3.1 volume on a user |
12 | 12 | * specified (block) device. |
@@ -119,6 +119,7 @@ | ||
119 | 119 | # endif |
120 | 120 | #endif |
121 | 121 | |
122 | +#include "param.h" | |
122 | 123 | #include "security.h" |
123 | 124 | #include "types.h" |
124 | 125 | #include "attrib.h" |
@@ -287,7 +288,7 @@ static void mkntfs_version(void) | ||
287 | 288 | ntfs_log_info("Copyright (c) 2002-2006 Szabolcs Szakacsits\n"); |
288 | 289 | ntfs_log_info("Copyright (c) 2005 Erik Sornes\n"); |
289 | 290 | ntfs_log_info("Copyright (c) 2007 Yura Pakhuchiy\n"); |
290 | - ntfs_log_info("Copyright (c) 2010-2014 Jean-Pierre Andre\n"); | |
291 | + ntfs_log_info("Copyright (c) 2010-2018 Jean-Pierre Andre\n"); | |
291 | 292 | ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); |
292 | 293 | } |
293 | 294 |
@@ -669,7 +670,7 @@ static int mkntfs_parse_options(int argc, char *argv[], struct mkntfs_options *o | ||
669 | 670 | break; |
670 | 671 | case 'L': |
671 | 672 | if (!opts2->label) { |
672 | - opts2->label = argv[optind-1]; | |
673 | + opts2->label = optarg; | |
673 | 674 | } else { |
674 | 675 | ntfs_log_error("You may only specify the label " |
675 | 676 | "once.\n"); |
@@ -3719,11 +3720,11 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol) | ||
3719 | 3720 | /* |
3720 | 3721 | * For huge volumes, grow the cluster size until the number of |
3721 | 3722 | * clusters fits into 32 bits or the cluster size exceeds the |
3722 | - * maximum limit of 64kiB. | |
3723 | + * maximum limit of NTFS_MAX_CLUSTER_SIZE. | |
3723 | 3724 | */ |
3724 | 3725 | while (volume_size >> (ffs(vol->cluster_size) - 1 + 32)) { |
3725 | 3726 | vol->cluster_size <<= 1; |
3726 | - if (vol->cluster_size > 65535) { | |
3727 | + if (vol->cluster_size >= NTFS_MAX_CLUSTER_SIZE) { | |
3727 | 3728 | ntfs_log_error("Device is too large to hold an " |
3728 | 3729 | "NTFS volume (maximum size is " |
3729 | 3730 | "256TiB).\n"); |
@@ -3744,15 +3745,18 @@ static BOOL mkntfs_override_vol_params(ntfs_volume *vol) | ||
3744 | 3745 | "to, or larger than, the sector size.\n"); |
3745 | 3746 | return FALSE; |
3746 | 3747 | } |
3747 | - if (vol->cluster_size > 128 * (u32)opts.sector_size) { | |
3748 | + /* Before Windows 10 Creators, the limit was 128 */ | |
3749 | + if (vol->cluster_size > 4096 * (u32)opts.sector_size) { | |
3748 | 3750 | ntfs_log_error("The cluster size is invalid. It cannot be " |
3749 | - "more that 128 times the size of the sector " | |
3751 | + "more that 4096 times the size of the sector " | |
3750 | 3752 | "size.\n"); |
3751 | 3753 | return FALSE; |
3752 | 3754 | } |
3753 | - if (vol->cluster_size > 65536) { | |
3755 | + if (vol->cluster_size > NTFS_MAX_CLUSTER_SIZE) { | |
3754 | 3756 | ntfs_log_error("The cluster size is invalid. The maximum " |
3755 | - "cluster size is 65536 bytes (64kiB).\n"); | |
3757 | + "cluster size is %lu bytes (%lukiB).\n", | |
3758 | + (unsigned long)NTFS_MAX_CLUSTER_SIZE, | |
3759 | + (unsigned long)(NTFS_MAX_CLUSTER_SIZE >> 10)); | |
3756 | 3760 | return FALSE; |
3757 | 3761 | } |
3758 | 3762 | vol->cluster_size_bits = ffs(vol->cluster_size) - 1; |
@@ -4387,6 +4391,7 @@ static BOOL mkntfs_create_root_structures(void) | ||
4387 | 4391 | u8 *sd; |
4388 | 4392 | FILE_ATTR_FLAGS extend_flags; |
4389 | 4393 | VOLUME_FLAGS volume_flags = const_cpu_to_le16(0); |
4394 | + int sectors_per_cluster; | |
4390 | 4395 | int nr_sysfiles; |
4391 | 4396 | int buf_sds_first_size; |
4392 | 4397 | char *buf_sds; |
@@ -4639,8 +4644,11 @@ static BOOL mkntfs_create_root_structures(void) | ||
4639 | 4644 | * already inserted, so no need to worry about these things. |
4640 | 4645 | */ |
4641 | 4646 | bs->bpb.bytes_per_sector = cpu_to_le16(opts.sector_size); |
4642 | - bs->bpb.sectors_per_cluster = (u8)(g_vol->cluster_size / | |
4643 | - opts.sector_size); | |
4647 | + sectors_per_cluster = g_vol->cluster_size / opts.sector_size; | |
4648 | + if (sectors_per_cluster > 128) | |
4649 | + bs->bpb.sectors_per_cluster = 257 - ffs(sectors_per_cluster); | |
4650 | + else | |
4651 | + bs->bpb.sectors_per_cluster = sectors_per_cluster; | |
4644 | 4652 | bs->bpb.media_type = 0xf8; /* hard disk */ |
4645 | 4653 | bs->bpb.sectors_per_track = cpu_to_le16(opts.sectors_per_track); |
4646 | 4654 | ntfs_log_debug("sectors per track = %ld (0x%lx)\n", |
@@ -3,7 +3,7 @@ | ||
3 | 3 | * |
4 | 4 | * Copyright (c) 2003-2006 Szabolcs Szakacsits |
5 | 5 | * Copyright (c) 2004-2006 Anton Altaparmakov |
6 | - * Copyright (c) 2010-2017 Jean-Pierre Andre | |
6 | + * Copyright (c) 2010-2018 Jean-Pierre Andre | |
7 | 7 | * Special image format support copyright (c) 2004 Per Olofsson |
8 | 8 | * |
9 | 9 | * Clone NTFS data and/or metadata to a sparse file, image, device or stdout. |
@@ -71,6 +71,7 @@ | ||
71 | 71 | */ |
72 | 72 | #define NTFS_DO_NOT_CHECK_ENDIANS |
73 | 73 | |
74 | +#include "param.h" | |
74 | 75 | #include "debug.h" |
75 | 76 | #include "types.h" |
76 | 77 | #include "support.h" |
@@ -270,7 +271,6 @@ static int compare_bitmaps(struct bitmap *a, BOOL copy); | ||
270 | 271 | |
271 | 272 | #define LAST_METADATA_INODE 11 |
272 | 273 | |
273 | -#define NTFS_MAX_CLUSTER_SIZE 65536 | |
274 | 274 | #define NTFS_SECTOR_SIZE 512 |
275 | 275 | |
276 | 276 | #define rounded_up_division(a, b) (((a) + (b - 1)) / (b)) |
@@ -393,7 +393,7 @@ static void version(void) | ||
393 | 393 | "Efficiently clone, image, restore or rescue an NTFS Volume.\n\n" |
394 | 394 | "Copyright (c) 2003-2006 Szabolcs Szakacsits\n" |
395 | 395 | "Copyright (c) 2004-2006 Anton Altaparmakov\n" |
396 | - "Copyright (c) 2010-2016 Jean-Pierre Andre\n\n"); | |
396 | + "Copyright (c) 2010-2018 Jean-Pierre Andre\n\n"); | |
397 | 397 | fprintf(stderr, "%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); |
398 | 398 | exit(0); |
399 | 399 | } |
@@ -756,7 +756,7 @@ static void read_rescue(void *fd, char *buff, u32 csize, u32 bytes_per_sector, | ||
756 | 756 | |
757 | 757 | static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn) |
758 | 758 | { |
759 | - char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ | |
759 | + char *buff; | |
760 | 760 | /* vol is NULL if opt.restore_image is set */ |
761 | 761 | s32 csize = le32_to_cpu(image_hdr.cluster_size); |
762 | 762 | BOOL backup_bootsector; |
@@ -773,6 +773,9 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn) | ||
773 | 773 | } |
774 | 774 | |
775 | 775 | rescue_pos = (off_t)(rescue_lcn * csize); |
776 | + buff = (char*)ntfs_malloc(csize); | |
777 | + if (!buff) | |
778 | + err_exit("Not enough memory"); | |
776 | 779 | |
777 | 780 | /* possible partial cluster holding the backup boot sector */ |
778 | 781 | backup_bootsector = (lcn + 1)*csize >= full_device_size; |
@@ -858,6 +861,7 @@ static void copy_cluster(int rescue, u64 rescue_lcn, u64 lcn) | ||
858 | 861 | perr_printf("Write failed"); |
859 | 862 | #endif |
860 | 863 | } |
864 | + free(buff); | |
861 | 865 | } |
862 | 866 | |
863 | 867 | static s64 lseek_out(int fd, s64 pos, int mode) |
@@ -995,7 +999,11 @@ static void write_empty_clusters(s32 csize, s64 count, | ||
995 | 999 | struct progress_bar *progress, u64 *p_counter) |
996 | 1000 | { |
997 | 1001 | s64 i; |
998 | - char buff[NTFS_MAX_CLUSTER_SIZE]; | |
1002 | + char *buff; | |
1003 | + | |
1004 | + buff = (char*)ntfs_malloc(csize); | |
1005 | + if (!buff) | |
1006 | + err_exit("Not enough memory"); | |
999 | 1007 | |
1000 | 1008 | memset(buff, 0, csize); |
1001 | 1009 |
@@ -1004,6 +1012,7 @@ static void write_empty_clusters(s32 csize, s64 count, | ||
1004 | 1012 | perr_exit("write_all"); |
1005 | 1013 | progress_update(progress, ++(*p_counter)); |
1006 | 1014 | } |
1015 | + free(buff); | |
1007 | 1016 | } |
1008 | 1017 | |
1009 | 1018 | static void restore_image(void) |
@@ -1492,11 +1501,12 @@ static void write_set(char *buff, u32 csize, s64 *current_lcn, | ||
1492 | 1501 | |
1493 | 1502 | static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl) |
1494 | 1503 | { |
1495 | - char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ | |
1504 | + char *buff; | |
1496 | 1505 | void *fd; |
1497 | 1506 | s64 mft_no; |
1498 | 1507 | u32 mft_record_size; |
1499 | 1508 | u32 csize; |
1509 | + u32 buff_size; | |
1500 | 1510 | u32 bytes_per_sector; |
1501 | 1511 | u32 records_per_set; |
1502 | 1512 | u32 clusters_per_set; |
@@ -1514,14 +1524,21 @@ static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl) | ||
1514 | 1524 | /* |
1515 | 1525 | * Depending on the sizes, there may be several records |
1516 | 1526 | * per cluster, or several clusters per record. |
1527 | + * Anyway, records are read and rescued by full clusters. | |
1517 | 1528 | */ |
1518 | 1529 | if (csize >= mft_record_size) { |
1519 | 1530 | records_per_set = csize/mft_record_size; |
1520 | 1531 | clusters_per_set = 1; |
1532 | + buff_size = csize; | |
1521 | 1533 | } else { |
1522 | 1534 | clusters_per_set = mft_record_size/csize; |
1523 | 1535 | records_per_set = 1; |
1536 | + buff_size = mft_record_size; | |
1524 | 1537 | } |
1538 | + buff = (char*)ntfs_malloc(buff_size); | |
1539 | + if (!buff) | |
1540 | + err_exit("Not enough memory"); | |
1541 | + | |
1525 | 1542 | mft_no = 0; |
1526 | 1543 | ri = rj = 0; |
1527 | 1544 | wi = wj = 0; |
@@ -1554,6 +1571,7 @@ static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl) | ||
1554 | 1571 | } |
1555 | 1572 | } |
1556 | 1573 | image->current_lcn = current_lcn; |
1574 | + free(buff); | |
1557 | 1575 | } |
1558 | 1576 | |
1559 | 1577 | /* |
@@ -1566,10 +1584,11 @@ static void copy_wipe_mft(ntfs_walk_clusters_ctx *image, runlist *rl) | ||
1566 | 1584 | |
1567 | 1585 | static void copy_wipe_i30(ntfs_walk_clusters_ctx *image, runlist *rl) |
1568 | 1586 | { |
1569 | - char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ | |
1587 | + char *buff; | |
1570 | 1588 | void *fd; |
1571 | 1589 | u32 indx_record_size; |
1572 | 1590 | u32 csize; |
1591 | + u32 buff_size; | |
1573 | 1592 | u32 bytes_per_sector; |
1574 | 1593 | u32 records_per_set; |
1575 | 1594 | u32 clusters_per_set; |
@@ -1586,15 +1605,22 @@ static void copy_wipe_i30(ntfs_walk_clusters_ctx *image, runlist *rl) | ||
1586 | 1605 | /* |
1587 | 1606 | * Depending on the sizes, there may be several records |
1588 | 1607 | * per cluster, or several clusters per record. |
1608 | + * Anyway, records are read and rescued by full clusters. | |
1589 | 1609 | */ |
1590 | 1610 | indx_record_size = image->ni->vol->indx_record_size; |
1591 | 1611 | if (csize >= indx_record_size) { |
1592 | 1612 | records_per_set = csize/indx_record_size; |
1593 | 1613 | clusters_per_set = 1; |
1614 | + buff_size = csize; | |
1594 | 1615 | } else { |
1595 | 1616 | clusters_per_set = indx_record_size/csize; |
1596 | 1617 | records_per_set = 1; |
1618 | + buff_size = indx_record_size; | |
1597 | 1619 | } |
1620 | + buff = (char*)ntfs_malloc(buff_size); | |
1621 | + if (!buff) | |
1622 | + err_exit("Not enough memory"); | |
1623 | + | |
1598 | 1624 | ri = rj = 0; |
1599 | 1625 | wi = wj = 0; |
1600 | 1626 | if (rl[ri].length) |
@@ -1627,6 +1653,7 @@ static void copy_wipe_i30(ntfs_walk_clusters_ctx *image, runlist *rl) | ||
1627 | 1653 | } |
1628 | 1654 | } |
1629 | 1655 | image->current_lcn = current_lcn; |
1656 | + free(buff); | |
1630 | 1657 | } |
1631 | 1658 | |
1632 | 1659 | static void dump_clusters(ntfs_walk_clusters_ctx *image, runlist *rl) |
@@ -69,7 +69,7 @@ This option is not yet implemented. | ||
69 | 69 | .TP |
70 | 70 | \fB\-q\fR, \fB\-\-quiet\fR |
71 | 71 | Reduce the amount of output to a minimum. Naturally, it doesn't make sense to |
72 | -combine this option with | |
72 | +combine this option with \fB\-\-verbose\fR | |
73 | 73 | .TP |
74 | 74 | \fB\-s\fR, \fB\-\-sector\fR RANGE |
75 | 75 | Any files whose data is in this range of sectors will be displayed. |
@@ -59,6 +59,10 @@ Show a list of options with a brief description of each one. | ||
59 | 59 | \fB\-q\fR, \fB\-\-quiet\fR |
60 | 60 | Suppress some debug/warning/error messages. |
61 | 61 | .TP |
62 | +\fB\-t\fR, \fB\-\-timestamp\fR | |
63 | +Copy the modification time of source_file to destination. This is | |
64 | +not compatible with \fB\-\-attr\-name\fR and \fB\-\-attribute\fR. | |
65 | +.TP | |
62 | 66 | \fB\-V\fR, \fB\-\-version\fR |
63 | 67 | Show the version number, copyright and license |
64 | 68 | .BR ntfscp . |
@@ -4,7 +4,7 @@ | ||
4 | 4 | * Copyright (c) 2004-2007 Yura Pakhuchiy |
5 | 5 | * Copyright (c) 2005 Anton Altaparmakov |
6 | 6 | * Copyright (c) 2006 Hil Liao |
7 | - * Copyright (c) 2014 Jean-Pierre Andre | |
7 | + * Copyright (c) 2014-2019 Jean-Pierre Andre | |
8 | 8 | * |
9 | 9 | * This utility will copy file to an NTFS volume. |
10 | 10 | * |
@@ -58,6 +58,7 @@ | ||
58 | 58 | #include "debug.h" |
59 | 59 | /* #include "version.h" */ |
60 | 60 | #include "logging.h" |
61 | +#include "ntfstime.h" | |
61 | 62 | #include "misc.h" |
62 | 63 | |
63 | 64 | struct options { |
@@ -69,6 +70,7 @@ struct options { | ||
69 | 70 | int quiet; /* Less output */ |
70 | 71 | int verbose; /* Extra output */ |
71 | 72 | int minfragments; /* Do minimal fragmentation */ |
73 | + int timestamp; /* Copy the modification time */ | |
72 | 74 | int noaction; /* Do not write to disk */ |
73 | 75 | ATTR_TYPES attribute; /* Write to this attribute. */ |
74 | 76 | int inode; /* Treat dest_file as inode number. */ |
@@ -129,6 +131,7 @@ static void usage(void) | ||
129 | 131 | " -N, --attr-name NAME Write to attribute with this name\n" |
130 | 132 | " -n, --no-action Do not write to disk\n" |
131 | 133 | " -q, --quiet Less output\n" |
134 | + " -t, --timestamp Copy the modification time\n" | |
132 | 135 | " -V, --version Version information\n" |
133 | 136 | " -v, --verbose More output\n\n", |
134 | 137 | EXEC_NAME); |
@@ -146,7 +149,7 @@ static void usage(void) | ||
146 | 149 | */ |
147 | 150 | static int parse_options(int argc, char **argv) |
148 | 151 | { |
149 | - static const char *sopt = "-a:ifh?mN:no:qVv"; | |
152 | + static const char *sopt = "-a:ifh?mN:no:qtVv"; | |
150 | 153 | static const struct option lopt[] = { |
151 | 154 | { "attribute", required_argument, NULL, 'a' }, |
152 | 155 | { "inode", no_argument, NULL, 'i' }, |
@@ -156,6 +159,7 @@ static int parse_options(int argc, char **argv) | ||
156 | 159 | { "attr-name", required_argument, NULL, 'N' }, |
157 | 160 | { "no-action", no_argument, NULL, 'n' }, |
158 | 161 | { "quiet", no_argument, NULL, 'q' }, |
162 | + { "timestamp", no_argument, NULL, 't' }, | |
159 | 163 | { "version", no_argument, NULL, 'V' }, |
160 | 164 | { "verbose", no_argument, NULL, 'v' }, |
161 | 165 | { NULL, 0, NULL, 0 } |
@@ -175,6 +179,7 @@ static int parse_options(int argc, char **argv) | ||
175 | 179 | opts.attr_name = NULL; |
176 | 180 | opts.inode = 0; |
177 | 181 | opts.attribute = AT_DATA; |
182 | + opts.timestamp = 0; | |
178 | 183 | |
179 | 184 | opterr = 0; /* We'll handle the errors, thank you. */ |
180 | 185 |
@@ -235,6 +240,9 @@ static int parse_options(int argc, char **argv) | ||
235 | 240 | opts.quiet++; |
236 | 241 | ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); |
237 | 242 | break; |
243 | + case 't': | |
244 | + opts.timestamp++; | |
245 | + break; | |
238 | 246 | case 'V': |
239 | 247 | ver++; |
240 | 248 | break; |
@@ -284,6 +292,12 @@ static int parse_options(int argc, char **argv) | ||
284 | 292 | "at the same time.\n"); |
285 | 293 | err++; |
286 | 294 | } |
295 | + if (opts.timestamp | |
296 | + && (opts.attr_name || (opts.attribute != AT_DATA))) { | |
297 | + ntfs_log_error("Setting --timestamp is only possible" | |
298 | + " with unname data attribute.\n"); | |
299 | + err++; | |
300 | + } | |
287 | 301 | } |
288 | 302 | |
289 | 303 | if (ver) |
@@ -822,6 +836,7 @@ static ntfs_inode *ntfs_new_file(ntfs_inode *dir_ni, | ||
822 | 836 | int main(int argc, char *argv[]) |
823 | 837 | { |
824 | 838 | FILE *in; |
839 | + struct stat st; | |
825 | 840 | ntfs_volume *vol; |
826 | 841 | ntfs_inode *out; |
827 | 842 | ntfs_attr *na; |
@@ -1136,6 +1151,16 @@ int main(int argc, char *argv[]) | ||
1136 | 1151 | free(buf); |
1137 | 1152 | close_attr: |
1138 | 1153 | ntfs_attr_close(na); |
1154 | + if (opts.timestamp) { | |
1155 | + if (!fstat(fileno(in),&st)) { | |
1156 | + s64 change_time = st.st_mtime*10000000LL | |
1157 | + + NTFS_TIME_OFFSET; | |
1158 | + out->last_data_change_time = cpu_to_le64(change_time); | |
1159 | + ntfs_inode_update_times(out, 0); | |
1160 | + } else { | |
1161 | + ntfs_log_error("Failed to get the time stamp.\n"); | |
1162 | + } | |
1163 | + } | |
1139 | 1164 | close_dst: |
1140 | 1165 | while (ntfs_inode_close(out) && !opts.noaction) { |
1141 | 1166 | if (errno != EBUSY) { |
@@ -506,6 +506,11 @@ static int fix_mftmirr(ntfs_volume *vol) | ||
506 | 506 | |
507 | 507 | ntfs_log_info("Comparing $MFTMirr to $MFT... "); |
508 | 508 | done = FALSE; |
509 | + /* | |
510 | + * Since 2017, Windows 10 does not mirror to full $MFTMirr when | |
511 | + * using big clusters, and some records may be found different. | |
512 | + * Nevertheless chkdsk.exe mirrors it fully, so we do similarly. | |
513 | + */ | |
509 | 514 | for (i = 0; i < vol->mftmirr_size; ++i) { |
510 | 515 | MFT_RECORD *mrec, *mrec2; |
511 | 516 | const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile", |
@@ -8,7 +8,7 @@ | ||
8 | 8 | * Copyright (c) 2004-2005 Yuval Fledel |
9 | 9 | * Copyright (c) 2004-2007 Yura Pakhuchiy |
10 | 10 | * Copyright (c) 2005 Cristian Klein |
11 | - * Copyright (c) 2011-2017 Jean-Pierre Andre | |
11 | + * Copyright (c) 2011-2018 Jean-Pierre Andre | |
12 | 12 | * |
13 | 13 | * This utility will dump a file's attributes. |
14 | 14 | * |
@@ -119,7 +119,7 @@ static void version(void) | ||
119 | 119 | printf(" 2003 Leonard Norrgård\n"); |
120 | 120 | printf(" 2004-2005 Yuval Fledel\n"); |
121 | 121 | printf(" 2004-2007 Yura Pakhuchiy\n"); |
122 | - printf(" 2011-2017 Jean-Pierre Andre\n"); | |
122 | + printf(" 2011-2018 Jean-Pierre Andre\n"); | |
123 | 123 | printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); |
124 | 124 | } |
125 | 125 |
@@ -411,8 +411,10 @@ static char *ntfs_attr_get_name_mbs(ATTR_RECORD *attr) | ||
411 | 411 | static const char *reparse_type_name(le32 tag) |
412 | 412 | { |
413 | 413 | const char *name; |
414 | + le32 seltag; | |
414 | 415 | |
415 | - switch (tag) { | |
416 | + seltag = tag & IO_REPARSE_PLUGIN_SELECT; | |
417 | + switch (seltag) { | |
416 | 418 | case IO_REPARSE_TAG_MOUNT_POINT : |
417 | 419 | name = " (mount point)"; |
418 | 420 | break; |
@@ -428,6 +430,9 @@ static const char *reparse_type_name(le32 tag) | ||
428 | 430 | case IO_REPARSE_TAG_WCI : |
429 | 431 | name = " (Windows container)"; |
430 | 432 | break; |
433 | + case IO_REPARSE_TAG_CLOUD : | |
434 | + name = " (Cloud)"; | |
435 | + break; | |
431 | 436 | case IO_REPARSE_TAG_NFS : |
432 | 437 | name = " (NFS symlink)"; |
433 | 438 | break; |
@@ -3698,7 +3698,7 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk, | ||
3698 | 3698 | * use a different layout of temporary blocks. |
3699 | 3699 | */ |
3700 | 3700 | |
3701 | -const struct BUFFER *find_latest_block(CONTEXT *ctx, u32 baseblk, | |
3701 | +static const struct BUFFER *find_latest_block(CONTEXT *ctx, u32 baseblk, | |
3702 | 3702 | const struct BUFFER *basebuf) |
3703 | 3703 | { |
3704 | 3704 | le64 offset; |
@@ -3710,6 +3710,9 @@ const struct BUFFER *find_latest_block(CONTEXT *ctx, u32 baseblk, | ||
3710 | 3710 | const struct BUFFER *curbuf; |
3711 | 3711 | |
3712 | 3712 | offset = basebuf->block.record.copy.file_offset; |
3713 | + curbuf = (const struct BUFFER*)NULL; | |
3714 | + curlsn = const_cpu_to_le64(0); | |
3715 | + prevblk = 0; | |
3713 | 3716 | curblk = baseblk; |
3714 | 3717 | do { |
3715 | 3718 | if (curblk < BASEBLKS) { |
@@ -243,10 +243,9 @@ Display help and exit. | ||
243 | 243 | .SH EXIT CODES |
244 | 244 | The exit code is 0 on success, non\-zero otherwise. |
245 | 245 | .SH KNOWN ISSUES |
246 | -No reliability problem is known. If you need | |
247 | -help please try the Ntfsresize FAQ first (see below) and if you | |
248 | -don't find your answer then send your question, comment or bug report to | |
249 | -the development team: | |
246 | +No reliability problem is known. | |
247 | +If you find a bug please send an email describing the problem to the | |
248 | +development team at: | |
250 | 249 | .br |
251 | 250 | .nh |
252 | 251 | ntfs\-3g\-devel@lists.sf.net |
@@ -308,14 +307,6 @@ package and is available from: | ||
308 | 307 | .nh |
309 | 308 | http://www.tuxera.com/community/ |
310 | 309 | .hy |
311 | -.sp | |
312 | -.B Ntfsresize | |
313 | -related news, example of usage, troubleshooting, statically linked binary and | |
314 | -FAQ (frequently asked questions) are maintained at: | |
315 | -.br | |
316 | -.nh | |
317 | -http://mlf.linux.rulez.org/mlf/ezaz/ntfsresize.html | |
318 | -.hy | |
319 | 310 | .SH SEE ALSO |
320 | 311 | .BR fdisk (8), |
321 | 312 | .BR cfdisk (8), |
@@ -5,7 +5,7 @@ | ||
5 | 5 | * Copyright (c) 2002-2005 Anton Altaparmakov |
6 | 6 | * Copyright (c) 2002-2003 Richard Russon |
7 | 7 | * Copyright (c) 2007 Yura Pakhuchiy |
8 | - * Copyright (c) 2011-2016 Jean-Pierre Andre | |
8 | + * Copyright (c) 2011-2018 Jean-Pierre Andre | |
9 | 9 | * |
10 | 10 | * This utility will resize an NTFS volume without data loss. |
11 | 11 | * |
@@ -59,6 +59,7 @@ | ||
59 | 59 | #include <fcntl.h> |
60 | 60 | #endif |
61 | 61 | |
62 | +#include "param.h" | |
62 | 63 | #include "debug.h" |
63 | 64 | #include "types.h" |
64 | 65 | #include "support.h" |
@@ -137,6 +138,8 @@ static const char *many_bad_sectors_msg = | ||
137 | 138 | "* other reason. We suggest to get a replacement disk as soon as possible. *\n" |
138 | 139 | "***************************************************************************\n"; |
139 | 140 | |
141 | +enum mirror_source { MIRR_OLD, MIRR_NEWMFT, MIRR_MFT }; | |
142 | + | |
140 | 143 | static struct { |
141 | 144 | int verbose; |
142 | 145 | int debug; |
@@ -226,6 +229,7 @@ typedef struct { | ||
226 | 229 | struct llcn_t last_compressed; |
227 | 230 | struct llcn_t last_lcn; |
228 | 231 | s64 last_unsupp; /* last unsupported cluster */ |
232 | + enum mirror_source mirr_from; | |
229 | 233 | } ntfs_resize_t; |
230 | 234 | |
231 | 235 | /* FIXME: This, lcn_bitmap and pos from find_free_cluster() will make a cluster |
@@ -243,8 +247,6 @@ static s64 max_free_cluster_range = 0; | ||
243 | 247 | #define DIRTY_INODE (1) |
244 | 248 | #define DIRTY_ATTRIB (2) |
245 | 249 | |
246 | -#define NTFS_MAX_CLUSTER_SIZE (65536) | |
247 | - | |
248 | 250 | static s64 rounded_up_division(s64 numer, s64 denom) |
249 | 251 | { |
250 | 252 | return (numer + (denom - 1)) / denom; |
@@ -404,7 +406,7 @@ static void version(void) | ||
404 | 406 | printf("Copyright (c) 2002-2005 Anton Altaparmakov\n"); |
405 | 407 | printf("Copyright (c) 2002-2003 Richard Russon\n"); |
406 | 408 | printf("Copyright (c) 2007 Yura Pakhuchiy\n"); |
407 | - printf("Copyright (c) 2011-2016 Jean-Pierre Andre\n"); | |
409 | + printf("Copyright (c) 2011-2018 Jean-Pierre Andre\n"); | |
408 | 410 | printf("\n%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home); |
409 | 411 | } |
410 | 412 |
@@ -1459,10 +1461,13 @@ static int record_mft_in_bitmap(ntfs_resize_t *resize) | ||
1459 | 1461 | static void delayed_updates(ntfs_resize_t *resize) |
1460 | 1462 | { |
1461 | 1463 | struct DELAYED *delayed; |
1464 | + struct DELAYED *delayed_mft_data; | |
1465 | + int nr_extents; | |
1462 | 1466 | |
1463 | 1467 | if (ntfs_volume_get_free_space(resize->vol)) |
1464 | 1468 | err_exit("Failed to determine free space\n"); |
1465 | 1469 | |
1470 | + delayed_mft_data = (struct DELAYED*)NULL; | |
1466 | 1471 | if (resize->delayed_runlists && reload_mft(resize)) |
1467 | 1472 | err_exit("Failed to reload the MFT for delayed updates\n"); |
1468 | 1473 |
@@ -1476,19 +1481,55 @@ static void delayed_updates(ntfs_resize_t *resize) | ||
1476 | 1481 | * So we update MFT data first, and we record the MFT |
1477 | 1482 | * extents again in the MFT bitmap if they were recorded |
1478 | 1483 | * in the old location. |
1484 | + * | |
1485 | + * However, if we are operating in "no action" mode, the | |
1486 | + * MFT records to update are not written to their new location | |
1487 | + * and the MFT data runlist has to be updated last in order | |
1488 | + * to have the entries read from their old location. | |
1489 | + * In this situation the MFT bitmap is never written to | |
1490 | + * disk, so the same extents are reallocated repeatedly, | |
1491 | + * which is not what would be done in a real resizing. | |
1479 | 1492 | */ |
1480 | 1493 | |
1494 | + if (opt.ro_flag | |
1495 | + && resize->delayed_runlists | |
1496 | + && (resize->delayed_runlists->mref == FILE_MFT) | |
1497 | + && (resize->delayed_runlists->type == AT_DATA)) { | |
1498 | + /* Update the MFT data runlist later */ | |
1499 | + delayed_mft_data = resize->delayed_runlists; | |
1500 | + resize->delayed_runlists = resize->delayed_runlists->next; | |
1501 | + } | |
1502 | + | |
1481 | 1503 | while (resize->delayed_runlists) { |
1482 | 1504 | delayed = resize->delayed_runlists; |
1483 | 1505 | expand_attribute_runlist(resize->vol, delayed); |
1484 | - if ((delayed->mref == FILE_MFT) && (delayed->type == AT_BITMAP)) | |
1485 | - record_mft_in_bitmap(resize); | |
1506 | + if (delayed->mref == FILE_MFT) { | |
1507 | + if (delayed->type == AT_BITMAP) | |
1508 | + record_mft_in_bitmap(resize); | |
1509 | + if (delayed->type == AT_DATA) | |
1510 | + resize->mirr_from = MIRR_MFT; | |
1511 | + } | |
1486 | 1512 | resize->delayed_runlists = resize->delayed_runlists->next; |
1487 | 1513 | if (delayed->attr_name) |
1488 | 1514 | free(delayed->attr_name); |
1489 | 1515 | free(delayed->head_rl); |
1490 | 1516 | free(delayed); |
1491 | 1517 | } |
1518 | + if (opt.ro_flag && delayed_mft_data) { | |
1519 | + /* in "no action" mode, check updating the MFT runlist now */ | |
1520 | + expand_attribute_runlist(resize->vol, delayed_mft_data); | |
1521 | + resize->mirr_from = MIRR_MFT; | |
1522 | + if (delayed_mft_data->attr_name) | |
1523 | + free(delayed_mft_data->attr_name); | |
1524 | + free(delayed_mft_data->head_rl); | |
1525 | + free(delayed_mft_data); | |
1526 | + } | |
1527 | + /* Beware of MFT fragmentation when the target size is too small */ | |
1528 | + nr_extents = resize->vol->mft_ni->nr_extents; | |
1529 | + if (nr_extents > 2) { | |
1530 | + printf("WARNING: The MFT is now severely fragmented" | |
1531 | + " (%d extents)\n", nr_extents); | |
1532 | + } | |
1492 | 1533 | } |
1493 | 1534 | |
1494 | 1535 | /* |
@@ -1849,9 +1890,13 @@ static void lseek_to_cluster(ntfs_volume *vol, s64 lcn) | ||
1849 | 1890 | static void copy_clusters(ntfs_resize_t *resize, s64 dest, s64 src, s64 len) |
1850 | 1891 | { |
1851 | 1892 | s64 i; |
1852 | - char buff[NTFS_MAX_CLUSTER_SIZE]; /* overflow checked at mount time */ | |
1893 | + char *buff; | |
1853 | 1894 | ntfs_volume *vol = resize->vol; |
1854 | 1895 | |
1896 | + buff = (char*)ntfs_malloc(vol->cluster_size); | |
1897 | + if (!buff) | |
1898 | + perr_exit("ntfs_malloc"); | |
1899 | + | |
1855 | 1900 | for (i = 0; i < len; i++) { |
1856 | 1901 | |
1857 | 1902 | lseek_to_cluster(vol, src + i); |
@@ -1875,6 +1920,7 @@ static void copy_clusters(ntfs_resize_t *resize, s64 dest, s64 src, s64 len) | ||
1875 | 1920 | resize->relocations++; |
1876 | 1921 | progress_update(&resize->progress, resize->relocations); |
1877 | 1922 | } |
1923 | + free(buff); | |
1878 | 1924 | } |
1879 | 1925 | |
1880 | 1926 | static void relocate_clusters(ntfs_resize_t *r, runlist *dest_rl, s64 src_lcn) |
@@ -2262,6 +2308,7 @@ static void relocate_inodes(ntfs_resize_t *resize) | ||
2262 | 2308 | err_exit("Could not allocate 16 records in" |
2263 | 2309 | " the first MFT chunk\n"); |
2264 | 2310 | } |
2311 | + resize->mirr_from = MIRR_NEWMFT; | |
2265 | 2312 | } |
2266 | 2313 | |
2267 | 2314 | for (mref = 0; mref < (MFT_REF)nr_mft_records; mref++) |
@@ -2715,19 +2762,34 @@ static void update_bootsector(ntfs_resize_t *r) | ||
2715 | 2762 | if (vol->dev->d_ops->read(vol->dev, bs, bs_size) == -1) |
2716 | 2763 | perr_exit("read() error"); |
2717 | 2764 | |
2718 | - bs->number_of_sectors = cpu_to_sle64(r->new_volume_size * | |
2719 | - bs->bpb.sectors_per_cluster); | |
2765 | + if (bs->bpb.sectors_per_cluster > 128) | |
2766 | + bs->number_of_sectors = cpu_to_sle64(r->new_volume_size | |
2767 | + << (256 - bs->bpb.sectors_per_cluster)); | |
2768 | + else | |
2769 | + bs->number_of_sectors = cpu_to_sle64(r->new_volume_size * | |
2770 | + bs->bpb.sectors_per_cluster); | |
2720 | 2771 | |
2721 | - if (r->mftmir_old) { | |
2772 | + if (r->mftmir_old || (r->mirr_from == MIRR_MFT)) { | |
2722 | 2773 | r->progress.flags |= NTFS_PROGBAR_SUPPRESS; |
2723 | 2774 | /* Be sure the MFTMirr holds the updated MFT runlist */ |
2724 | - if (r->new_mft_start) | |
2775 | + switch (r->mirr_from) { | |
2776 | + case MIRR_MFT : | |
2777 | + /* The late updates of MFT have not been synced */ | |
2778 | + ntfs_inode_sync(vol->mft_ni); | |
2779 | + copy_clusters(r, r->mftmir_rl.lcn, | |
2780 | + vol->mft_na->rl->lcn, r->mftmir_rl.length); | |
2781 | + break; | |
2782 | + case MIRR_NEWMFT : | |
2725 | 2783 | copy_clusters(r, r->mftmir_rl.lcn, |
2726 | 2784 | r->new_mft_start->lcn, r->mftmir_rl.length); |
2727 | - else | |
2785 | + break; | |
2786 | + default : | |
2728 | 2787 | copy_clusters(r, r->mftmir_rl.lcn, r->mftmir_old, |
2729 | 2788 | r->mftmir_rl.length); |
2730 | - bs->mftmirr_lcn = cpu_to_sle64(r->mftmir_rl.lcn); | |
2789 | + break; | |
2790 | + } | |
2791 | + if (r->mftmir_old) | |
2792 | + bs->mftmirr_lcn = cpu_to_sle64(r->mftmir_rl.lcn); | |
2731 | 2793 | r->progress.flags &= ~NTFS_PROGBAR_SUPPRESS; |
2732 | 2794 | } |
2733 | 2795 | /* Set the start of the relocated MFT */ |
@@ -3904,6 +3966,7 @@ static int update_runlist(expand_t *expand, s64 inum, | ||
3904 | 3966 | ctx.mrec = mrec; |
3905 | 3967 | resize.mref = inum; |
3906 | 3968 | resize.delayed_runlists = expand->delayed_runlists; |
3969 | + resize.mirr_from = MIRR_OLD; | |
3907 | 3970 | must_delay = 1; |
3908 | 3971 | replace_later(&resize,rl,head_rl); |
3909 | 3972 | expand->delayed_runlists = resize.delayed_runlists; |
@@ -4577,6 +4640,7 @@ int main(int argc, char **argv) | ||
4577 | 4640 | |
4578 | 4641 | resize.inuse = fsck.inuse; |
4579 | 4642 | resize.lcn_bitmap = fsck.lcn_bitmap; |
4643 | + resize.mirr_from = MIRR_OLD; | |
4580 | 4644 | |
4581 | 4645 | set_resize_constraints(&resize); |
4582 | 4646 | set_disk_usage_constraint(&resize); |
@@ -5,7 +5,7 @@ | ||
5 | 5 | * Copyright (c) 2004-2005 Holger Ohmacht |
6 | 6 | * Copyright (c) 2005 Anton Altaparmakov |
7 | 7 | * Copyright (c) 2007 Yura Pakhuchiy |
8 | - * Copyright (c) 2013-2014 Jean-Pierre Andre | |
8 | + * Copyright (c) 2013-2018 Jean-Pierre Andre | |
9 | 9 | * |
10 | 10 | * This utility will recover deleted files from an NTFS volume. |
11 | 11 | * |
@@ -392,7 +392,7 @@ static void version(void) | ||
392 | 392 | "Copyright (c) 2004-2005 Holger Ohmacht\n" |
393 | 393 | "Copyright (c) 2005 Anton Altaparmakov\n" |
394 | 394 | "Copyright (c) 2007 Yura Pakhuchiy\n" |
395 | - "Copyright (c) 2013-2014 Jean-Pierre Andre\n"); | |
395 | + "Copyright (c) 2013-2018 Jean-Pierre Andre\n"); | |
396 | 396 | ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); |
397 | 397 | } |
398 | 398 |
@@ -1835,19 +1835,49 @@ static unsigned int write_data(int fd, const char *buffer, | ||
1835 | 1835 | static int create_pathname(const char *dir, const char *name, |
1836 | 1836 | const char *stream, char *buffer, int bufsize) |
1837 | 1837 | { |
1838 | + struct stat st; | |
1839 | + int s; | |
1840 | + int len; | |
1841 | + int suffix; | |
1842 | + | |
1838 | 1843 | if (!name) |
1839 | 1844 | name = UNKNOWN; |
1840 | 1845 | |
1841 | - if (dir) | |
1846 | + if (dir) { | |
1847 | +#ifdef HAVE_WINDOWS_H | |
1842 | 1848 | if (stream) |
1843 | - snprintf(buffer, bufsize, "%s/%s:%s", dir, name, stream); | |
1849 | + snprintf(buffer, bufsize, "%s\\%s:%s", dir, name, | |
1850 | + stream); | |
1851 | + else | |
1852 | + snprintf(buffer, bufsize, "%s\\%s", dir, name); | |
1853 | +#else | |
1854 | + if (stream) | |
1855 | + snprintf(buffer, bufsize, "%s/%s:%s", dir, name, | |
1856 | + stream); | |
1844 | 1857 | else |
1845 | 1858 | snprintf(buffer, bufsize, "%s/%s", dir, name); |
1846 | - else | |
1859 | +#endif | |
1860 | + } else | |
1847 | 1861 | if (stream) |
1848 | 1862 | snprintf(buffer, bufsize, "%s:%s", name, stream); |
1849 | 1863 | else |
1850 | 1864 | snprintf(buffer, bufsize, "%s", name); |
1865 | + len = strlen(buffer); | |
1866 | + suffix = 0; | |
1867 | +#ifdef HAVE_WINDOWS_H | |
1868 | + s = stat(buffer, &st); | |
1869 | +#else | |
1870 | + s = lstat(buffer, &st); | |
1871 | +#endif | |
1872 | + while (!s && (suffix < 999)) { | |
1873 | + suffix++; | |
1874 | + snprintf(&buffer[len], bufsize - len, ".%d", suffix); | |
1875 | +#ifdef HAVE_WINDOWS_H | |
1876 | + s = stat(buffer, &st); | |
1877 | +#else | |
1878 | + s = lstat(buffer, &st); | |
1879 | +#endif | |
1880 | + } | |
1851 | 1881 | |
1852 | 1882 | return strlen(buffer); |
1853 | 1883 | } |
@@ -2012,7 +2042,8 @@ static int undelete_file(ntfs_volume *vol, long long inode) | ||
2012 | 2042 | if (d->resident) { |
2013 | 2043 | fd = open_file(pathname); |
2014 | 2044 | if (fd < 0) { |
2015 | - ntfs_log_perror("Couldn't create file"); | |
2045 | + ntfs_log_perror("Couldn't create file %s", | |
2046 | + pathname); | |
2016 | 2047 | goto free; |
2017 | 2048 | } |
2018 | 2049 |
@@ -2041,7 +2072,8 @@ static int undelete_file(ntfs_volume *vol, long long inode) | ||
2041 | 2072 | |
2042 | 2073 | fd = open_file(pathname); |
2043 | 2074 | if (fd < 0) { |
2044 | - ntfs_log_perror("Couldn't create output file"); | |
2075 | + ntfs_log_perror("Couldn't create file %s", | |
2076 | + pathname); | |
2045 | 2077 | goto free; |
2046 | 2078 | } |
2047 | 2079 |
@@ -2151,9 +2183,11 @@ static int undelete_file(ntfs_volume *vol, long long inode) | ||
2151 | 2183 | } |
2152 | 2184 | set_date(pathname, file->date); |
2153 | 2185 | if (d->name) |
2154 | - ntfs_log_quiet("Undeleted '%s:%s' successfully.\n", file->pref_name, d->name); | |
2186 | + ntfs_log_quiet("Undeleted '%s:%s' successfully to %s.\n", | |
2187 | + file->pref_name, d->name, pathname); | |
2155 | 2188 | else |
2156 | - ntfs_log_quiet("Undeleted '%s' successfully.\n", file->pref_name); | |
2189 | + ntfs_log_quiet("Undeleted '%s' successfully to %s.\n", | |
2190 | + file->pref_name, pathname); | |
2157 | 2191 | } |
2158 | 2192 | result = 1; |
2159 | 2193 | free: |
@@ -2348,7 +2382,7 @@ static int copy_mft(ntfs_volume *vol, long long mft_begin, long long mft_end) | ||
2348 | 2382 | create_pathname(opts.dest, name, NULL, pathname, sizeof(pathname)); |
2349 | 2383 | fd = open_file(pathname); |
2350 | 2384 | if (fd < 0) { |
2351 | - ntfs_log_perror("Couldn't open output file '%s'", name); | |
2385 | + ntfs_log_perror("Couldn't create output file '%s'", name); | |
2352 | 2386 | goto attr; |
2353 | 2387 | } |
2354 | 2388 |
@@ -2376,6 +2410,7 @@ static int copy_mft(ntfs_volume *vol, long long mft_begin, long long mft_end) | ||
2376 | 2410 | } |
2377 | 2411 | |
2378 | 2412 | ntfs_log_verbose("Read %lld MFT Records\n", mft_end - mft_begin + 1); |
2413 | + ntfs_log_quiet("MFT extracted to file %s\n", pathname); | |
2379 | 2414 | result = 0; |
2380 | 2415 | close: |
2381 | 2416 | close(fd); |
@@ -4,7 +4,7 @@ | ||
4 | 4 | * Copyright (c) 2005-2007 Yura Pakhuchiy |
5 | 5 | * Copyright (c) 2005 Yuval Fledel |
6 | 6 | * Copyright (c) 2006-2009 Szabolcs Szakacsits |
7 | - * Copyright (c) 2007-2017 Jean-Pierre Andre | |
7 | + * Copyright (c) 2007-2019 Jean-Pierre Andre | |
8 | 8 | * Copyright (c) 2009 Erik Larsson |
9 | 9 | * |
10 | 10 | * This file is originated from the Linux-NTFS project. |
@@ -263,7 +263,7 @@ static const char *usage_msg = | ||
263 | 263 | "\n" |
264 | 264 | "Copyright (C) 2005-2007 Yura Pakhuchiy\n" |
265 | 265 | "Copyright (C) 2006-2009 Szabolcs Szakacsits\n" |
266 | -"Copyright (C) 2007-2017 Jean-Pierre Andre\n" | |
266 | +"Copyright (C) 2007-2019 Jean-Pierre Andre\n" | |
267 | 267 | "Copyright (C) 2009 Erik Larsson\n" |
268 | 268 | "\n" |
269 | 269 | "Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n" |
@@ -1074,10 +1074,9 @@ static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino) | ||
1074 | 1074 | REPARSE_POINT *reparse; |
1075 | 1075 | |
1076 | 1076 | res = CALL_REPARSE_PLUGIN(ni, readlink, &buf); |
1077 | - if (res) { | |
1077 | + if (res || !buf) { | |
1078 | 1078 | buf = strdup(ntfs_bad_reparse); |
1079 | - if (!buf) | |
1080 | - res = -errno; | |
1079 | + res = (buf ? 0 : -errno); | |
1081 | 1080 | } |
1082 | 1081 | #else /* DISABLE_PLUGINS */ |
1083 | 1082 | errno = 0; |
@@ -3152,7 +3151,7 @@ static ntfs_inode *ntfs_check_access_xattr(fuse_req_t req, | ||
3152 | 3151 | || !(ctx->secure_flags & (1 << SECURITY_ACL)) |
3153 | 3152 | || (setting && ctx->inherit)) |
3154 | 3153 | && foracl) { |
3155 | - if (ctx->silent) | |
3154 | + if (ctx->silent && !ctx->security.mapping[MAPUSERS]) | |
3156 | 3155 | errno = 0; |
3157 | 3156 | else |
3158 | 3157 | errno = EOPNOTSUPP; |
@@ -4411,7 +4410,8 @@ int main(int argc, char *argv[]) | ||
4411 | 4410 | else { |
4412 | 4411 | ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX); |
4413 | 4412 | if (ctx->abs_mnt_point) { |
4414 | - if (getcwd(ctx->abs_mnt_point, | |
4413 | + if ((strlen(opts.mnt_point) < PATH_MAX) | |
4414 | + && getcwd(ctx->abs_mnt_point, | |
4415 | 4415 | PATH_MAX - strlen(opts.mnt_point) - 1)) { |
4416 | 4416 | strcat(ctx->abs_mnt_point, "/"); |
4417 | 4417 | strcat(ctx->abs_mnt_point, opts.mnt_point); |
@@ -4419,6 +4419,9 @@ int main(int argc, char *argv[]) | ||
4419 | 4419 | /* Solaris also wants the absolute mount point */ |
4420 | 4420 | opts.mnt_point = ctx->abs_mnt_point; |
4421 | 4421 | #endif /* defined(__sun) && defined (__SVR4) */ |
4422 | + } else { | |
4423 | + free(ctx->abs_mnt_point); | |
4424 | + ctx->abs_mnt_point = (char*)NULL; | |
4422 | 4425 | } |
4423 | 4426 | } |
4424 | 4427 | } |
@@ -52,6 +52,8 @@ hibernation and fast restarting : | ||
52 | 52 | powercfg /h off |
53 | 53 | .sp |
54 | 54 | .RE |
55 | +If either Windows is hibernated or its fast restart is enabled, partitions | |
56 | +on internal disks are forced to be mounted in read-only mode. | |
55 | 57 | .SS Access Handling and Security |
56 | 58 | By default, files and directories are owned by the effective |
57 | 59 | user and group of the mounting process, and everybody has |
@@ -2879,7 +2879,7 @@ static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security, | ||
2879 | 2879 | || !(ctx->secure_flags & (1 << SECURITY_ACL)) |
2880 | 2880 | || (setting && ctx->inherit)) |
2881 | 2881 | && foracl) { |
2882 | - if (ctx->silent) | |
2882 | + if (ctx->silent && !ctx->security.mapping[MAPUSERS]) | |
2883 | 2883 | errno = 0; |
2884 | 2884 | else |
2885 | 2885 | errno = EOPNOTSUPP; |
@@ -4148,7 +4148,8 @@ int main(int argc, char *argv[]) | ||
4148 | 4148 | else { |
4149 | 4149 | ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX); |
4150 | 4150 | if (ctx->abs_mnt_point) { |
4151 | - if (getcwd(ctx->abs_mnt_point, | |
4151 | + if ((strlen(opts.mnt_point) < PATH_MAX) | |
4152 | + && getcwd(ctx->abs_mnt_point, | |
4152 | 4153 | PATH_MAX - strlen(opts.mnt_point) - 1)) { |
4153 | 4154 | strcat(ctx->abs_mnt_point, "/"); |
4154 | 4155 | strcat(ctx->abs_mnt_point, opts.mnt_point); |
@@ -4156,6 +4157,9 @@ int main(int argc, char *argv[]) | ||
4156 | 4157 | /* Solaris also wants the absolute mount point */ |
4157 | 4158 | opts.mnt_point = ctx->abs_mnt_point; |
4158 | 4159 | #endif /* defined(__sun) && defined (__SVR4) */ |
4160 | + } else { | |
4161 | + free(ctx->abs_mnt_point); | |
4162 | + ctx->abs_mnt_point = (char*)NULL; | |
4159 | 4163 | } |
4160 | 4164 | } |
4161 | 4165 | } |
@@ -1,7 +1,7 @@ | ||
1 | 1 | /** |
2 | 2 | * ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g. |
3 | 3 | * |
4 | - * Copyright (c) 2010-2016 Jean-Pierre Andre | |
4 | + * Copyright (c) 2010-2019 Jean-Pierre Andre | |
5 | 5 | * Copyright (c) 2010 Erik Larsson |
6 | 6 | * |
7 | 7 | * This program/include file is free software; you can redistribute it and/or |
@@ -801,7 +801,7 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, | ||
801 | 801 | const struct plugin_operations *ops; |
802 | 802 | void *handle; |
803 | 803 | REPARSE_POINT *reparse; |
804 | - le32 tag; | |
804 | + le32 tag, seltag; | |
805 | 805 | plugin_list_t *plugin; |
806 | 806 | plugin_init_t pinit; |
807 | 807 |
@@ -809,7 +809,8 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, | ||
809 | 809 | reparse = ntfs_get_reparse_point(ni); |
810 | 810 | if (reparse) { |
811 | 811 | tag = reparse->reparse_tag; |
812 | - for (plugin=ctx->plugins; plugin && (plugin->tag != tag); | |
812 | + seltag = tag & IO_REPARSE_PLUGIN_SELECT; | |
813 | + for (plugin=ctx->plugins; plugin && (plugin->tag != seltag); | |
813 | 814 | plugin = plugin->next) { } |
814 | 815 | if (plugin) { |
815 | 816 | ops = plugin->ops; |
@@ -819,12 +820,12 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, | ||
819 | 820 | |
820 | 821 | snprintf(name,sizeof(name), PLUGIN_DIR |
821 | 822 | "/ntfs-plugin-%08lx.so", |
822 | - (long)le32_to_cpu(tag)); | |
823 | + (long)le32_to_cpu(seltag)); | |
823 | 824 | #else |
824 | 825 | char name[64]; |
825 | 826 | |
826 | 827 | snprintf(name,sizeof(name), "ntfs-plugin-%08lx.so", |
827 | - (long)le32_to_cpu(tag)); | |
828 | + (long)le32_to_cpu(seltag)); | |
828 | 829 | #endif |
829 | 830 | handle = dlopen(name, RTLD_LAZY); |
830 | 831 | if (handle) { |
@@ -833,13 +834,14 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, | ||
833 | 834 | /* pinit() should set errno if it fails */ |
834 | 835 | ops = (*pinit)(tag); |
835 | 836 | if (ops && register_reparse_plugin(ctx, |
836 | - tag, ops, handle)) | |
837 | + seltag, ops, handle)) | |
837 | 838 | ops = (struct plugin_operations*)NULL; |
838 | 839 | } else |
839 | 840 | errno = ELIBBAD; |
840 | 841 | if (!ops) |
841 | 842 | dlclose(handle); |
842 | 843 | } else { |
844 | + errno = ELIBACC; | |
843 | 845 | if (!(ctx->errors_logged & ERR_PLUGIN)) { |
844 | 846 | ntfs_log_perror( |
845 | 847 | "Could not load plugin %s", |