1 /**
2 * ntfscp - Part of the Linux-NTFS project.
3 *
4 * Copyright (c) 2004-2007 Yura Pakhuchiy
5 * Copyright (c) 2005 Anton Altaparmakov
6 * Copyright (c) 2006 Hil Liao
7 * Copyright (c) 2014-2019 Jean-Pierre Andre
8 *
9 * This utility will copy file to an NTFS volume.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program (in the main directory of the Linux-NTFS
23 * distribution in the file COPYING); if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27 #include "config.h"
28
29 #ifdef HAVE_STDIO_H
30 #include <stdio.h>
31 #endif
32 #ifdef HAVE_GETOPT_H
33 #include <getopt.h>
34 #endif
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 #ifdef HAVE_STRING_H
39 #include <string.h>
40 #endif
41 #include <signal.h>
42 #ifdef HAVE_SYS_STAT_H
43 #include <sys/stat.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #ifdef HAVE_LIBGEN_H
49 #include <libgen.h>
50 #endif
51
52 #include "types.h"
53 #include "attrib.h"
54 #include "utils.h"
55 #include "volume.h"
56 #include "dir.h"
57 #include "bitmap.h"
58 #include "debug.h"
59 /* #include "version.h" */
60 #include "logging.h"
61 #include "ntfstime.h"
62 #include "misc.h"
63
64 struct options {
65 char *device; /* Device/File to work with */
66 char *src_file; /* Source file */
67 char *dest_file; /* Destination file */
68 char *attr_name; /* Write to attribute with this name. */
69 int force; /* Override common sense */
70 int quiet; /* Less output */
71 int verbose; /* Extra output */
72 int minfragments; /* Do minimal fragmentation */
73 int timestamp; /* Copy the modification time */
74 int noaction; /* Do not write to disk */
75 ATTR_TYPES attribute; /* Write to this attribute. */
76 int inode; /* Treat dest_file as inode number. */
77 };
78
79 struct ALLOC_CONTEXT {
80 ntfs_volume *vol;
81 ntfs_attr *na;
82 runlist_element *rl;
83 unsigned char *buf;
84 s64 gathered_clusters;
85 s64 wanted_clusters;
86 s64 new_size;
87 s64 lcn;
88 int rl_allocated;
89 int rl_count;
90 } ;
91
92 enum STEP { STEP_ERR, STEP_ZERO, STEP_ONE } ;
93
94 static const char *EXEC_NAME = "ntfscp";
95 static struct options opts;
96 static volatile sig_atomic_t caught_terminate = 0;
97
98 /**
99 * version - Print version information about the program
100 *
101 * Print a copyright statement and a brief description of the program.
102 *
103 * Return: none
104 */
version(void)105 static void version(void)
106 {
107 ntfs_log_info("\n%s v%s (libntfs-3g) - Copy file to an NTFS "
108 "volume.\n\n", EXEC_NAME, VERSION);
109 ntfs_log_info("Copyright (c) 2004-2007 Yura Pakhuchiy\n");
110 ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n");
111 ntfs_log_info("Copyright (c) 2006 Hil Liao\n");
112 ntfs_log_info("Copyright (c) 2014 Jean-Pierre Andre\n");
113 ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
114 }
115
116 /**
117 * usage - Print a list of the parameters to the program
118 *
119 * Print a list of the parameters and options for the program.
120 *
121 * Return: none
122 */
usage(void)123 static void usage(void)
124 {
125 ntfs_log_info("\nUsage: %s [options] device src_file dest_file\n\n"
126 " -a, --attribute NUM Write to this attribute\n"
127 " -i, --inode Treat dest_file as inode number\n"
128 " -f, --force Use less caution\n"
129 " -h, --help Print this help\n"
130 " -m, --min_fragments Do minimal fragmentation\n"
131 " -N, --attr-name NAME Write to attribute with this name\n"
132 " -n, --no-action Do not write to disk\n"
133 " -q, --quiet Less output\n"
134 " -t, --timestamp Copy the modification time\n"
135 " -V, --version Version information\n"
136 " -v, --verbose More output\n\n",
137 EXEC_NAME);
138 ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
139 }
140
141 /**
142 * parse_options - Read and validate the programs command line
143 *
144 * Read the command line, verify the syntax and parse the options.
145 * This function is very long, but quite simple.
146 *
147 * Return: 1 Success
148 * 0 Error, one or more problems
149 */
parse_options(int argc,char ** argv)150 static int parse_options(int argc, char **argv)
151 {
152 static const char *sopt = "-a:ifh?mN:no:qtVv";
153 static const struct option lopt[] = {
154 { "attribute", required_argument, NULL, 'a' },
155 { "inode", no_argument, NULL, 'i' },
156 { "force", no_argument, NULL, 'f' },
157 { "help", no_argument, NULL, 'h' },
158 { "min-fragments", no_argument, NULL, 'm' },
159 { "attr-name", required_argument, NULL, 'N' },
160 { "no-action", no_argument, NULL, 'n' },
161 { "quiet", no_argument, NULL, 'q' },
162 { "timestamp", no_argument, NULL, 't' },
163 { "version", no_argument, NULL, 'V' },
164 { "verbose", no_argument, NULL, 'v' },
165 { NULL, 0, NULL, 0 }
166 };
167
168 char *s;
169 int c = -1;
170 int err = 0;
171 int ver = 0;
172 int help = 0;
173 int levels = 0;
174 s64 attr;
175
176 opts.device = NULL;
177 opts.src_file = NULL;
178 opts.dest_file = NULL;
179 opts.attr_name = NULL;
180 opts.inode = 0;
181 opts.attribute = AT_DATA;
182 opts.timestamp = 0;
183
184 opterr = 0; /* We'll handle the errors, thank you. */
185
186 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
187 switch (c) {
188 case 1: /* A non-option argument */
189 if (!opts.device) {
190 opts.device = argv[optind - 1];
191 } else if (!opts.src_file) {
192 opts.src_file = argv[optind - 1];
193 } else if (!opts.dest_file) {
194 opts.dest_file = argv[optind - 1];
195 } else {
196 ntfs_log_error("You must specify exactly two "
197 "files.\n");
198 err++;
199 }
200 break;
201 case 'a':
202 if (opts.attribute != AT_DATA) {
203 ntfs_log_error("You can specify only one "
204 "attribute.\n");
205 err++;
206 break;
207 }
208
209 attr = strtol(optarg, &s, 0);
210 if (*s) {
211 ntfs_log_error("Couldn't parse attribute.\n");
212 err++;
213 } else
214 opts.attribute = (ATTR_TYPES)cpu_to_le32(attr);
215 break;
216 case 'i':
217 opts.inode++;
218 break;
219 case 'f':
220 opts.force++;
221 break;
222 case 'h':
223 help++;
224 break;
225 case 'm':
226 opts.minfragments++;
227 break;
228 case 'N':
229 if (opts.attr_name) {
230 ntfs_log_error("You can specify only one "
231 "attribute name.\n");
232 err++;
233 } else
234 opts.attr_name = argv[optind - 1];
235 break;
236 case 'n':
237 opts.noaction++;
238 break;
239 case 'q':
240 opts.quiet++;
241 ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
242 break;
243 case 't':
244 opts.timestamp++;
245 break;
246 case 'V':
247 ver++;
248 break;
249 case 'v':
250 opts.verbose++;
251 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
252 break;
253 case '?':
254 if (strncmp(argv[optind - 1], "--log-", 6) == 0) {
255 if (!ntfs_log_parse_option(argv[optind - 1]))
256 err++;
257 break;
258 }
259 /* fall through */
260 default:
261 ntfs_log_error("Unknown option '%s'.\n",
262 argv[optind - 1]);
263 err++;
264 break;
265 }
266 }
267
268 /* Make sure we're in sync with the log levels */
269 levels = ntfs_log_get_levels();
270 if (levels & NTFS_LOG_LEVEL_VERBOSE)
271 opts.verbose++;
272 if (!(levels & NTFS_LOG_LEVEL_QUIET))
273 opts.quiet++;
274
275 if (help || ver) {
276 opts.quiet = 0;
277 } else {
278 if (!opts.device) {
279 ntfs_log_error("You must specify a device.\n");
280 err++;
281 } else if (!opts.src_file) {
282 ntfs_log_error("You must specify a source file.\n");
283 err++;
284 } else if (!opts.dest_file) {
285 ntfs_log_error("You must specify a destination "
286 "file.\n");
287 err++;
288 }
289
290 if (opts.quiet && opts.verbose) {
291 ntfs_log_error("You may not use --quiet and --verbose "
292 "at the same time.\n");
293 err++;
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 }
301 }
302
303 if (ver)
304 version();
305 if (help || err)
306 usage();
307
308 /* tri-state 0 : done, 1 : error, -1 : proceed */
309 return (err ? 1 : (help || ver ? 0 : -1));
310 }
311
312 /**
313 * signal_handler - Handle SIGINT and SIGTERM: abort write, sync and exit.
314 */
signal_handler(int arg)315 static void signal_handler(int arg __attribute__((unused)))
316 {
317 caught_terminate++;
318 }
319
320 /*
321 * Search for the next '0' in a bitmap chunk
322 *
323 * Returns the position of next '0'
324 * or -1 if there are no more '0's
325 */
326
next_zero(struct ALLOC_CONTEXT * alctx,s32 bufpos,s32 count)327 static int next_zero(struct ALLOC_CONTEXT *alctx, s32 bufpos, s32 count)
328 {
329 s32 index;
330 unsigned int q,b;
331
332 index = -1;
333 while ((index < 0) && (bufpos < count)) {
334 q = alctx->buf[bufpos >> 3];
335 if (q == 255)
336 bufpos = (bufpos | 7) + 1;
337 else {
338 b = bufpos & 7;
339 while ((b < 8)
340 && ((1 << b) & q))
341 b++;
342 if (b < 8) {
343 index = (bufpos & -8) | b;
344 } else {
345 bufpos = (bufpos | 7) + 1;
346 }
347 }
348 }
349 return (index);
350 }
351
352 /*
353 * Search for the next '1' in a bitmap chunk
354 *
355 * Returns the position of next '1'
356 * or -1 if there are no more '1's
357 */
358
next_one(struct ALLOC_CONTEXT * alctx,s32 bufpos,s32 count)359 static int next_one(struct ALLOC_CONTEXT *alctx, s32 bufpos, s32 count)
360 {
361 s32 index;
362 unsigned int q,b;
363
364 index = -1;
365 while ((index < 0) && (bufpos < count)) {
366 q = alctx->buf[bufpos >> 3];
367 if (q == 0)
368 bufpos = (bufpos | 7) + 1;
369 else {
370 b = bufpos & 7;
371 while ((b < 8)
372 && !((1 << b) & q))
373 b++;
374 if (b < 8) {
375 index = (bufpos & -8) | b;
376 } else {
377 bufpos = (bufpos | 7) + 1;
378 }
379 }
380 }
381 return (index);
382 }
383
384 /*
385 * Allocate a bigger runlist when needed
386 *
387 * The allocation is done by multiple of 4096 entries to avoid
388 * frequent reallocations.
389 *
390 * Returns 0 if successful
391 * -1 otherwise, with errno set accordingly
392 */
393
run_alloc(struct ALLOC_CONTEXT * alctx,s32 count)394 static int run_alloc(struct ALLOC_CONTEXT *alctx, s32 count)
395 {
396 runlist_element *prl;
397 int err;
398
399 err = 0;
400 if (count > alctx->rl_allocated) {
401 prl = (runlist_element*)ntfs_malloc(
402 (alctx->rl_allocated + 4096)*sizeof(runlist_element));
403 if (prl) {
404 if (alctx->rl) {
405 memcpy(prl, alctx->rl, alctx->rl_allocated
406 *sizeof(runlist_element));
407 free(alctx->rl);
408 }
409 alctx->rl = prl;
410 alctx->rl_allocated += 4096;
411 } else
412 err = -1;
413 }
414 return (err);
415 }
416
417 /*
418 * Merge a new run into the current optimal runlist
419 *
420 * The new run is inserted only if it leads to improving the runlist.
421 * Runs in the current list are dropped when inserting the new one
422 * make them unneeded.
423 * The current runlist is sorted by run sizes, and there is no
424 * terminator.
425 *
426 * Returns 0 if successful
427 * -1 otherwise, with errno set accordingly
428 */
429
merge_run(struct ALLOC_CONTEXT * alctx,s64 lcn,s32 count)430 static int merge_run(struct ALLOC_CONTEXT *alctx, s64 lcn, s32 count)
431 {
432 s64 excess;
433 BOOL replace;
434 int k;
435 int drop;
436 int err;
437
438 err = 0;
439 if (alctx->rl_count) {
440 excess = alctx->gathered_clusters + count
441 - alctx->wanted_clusters;
442 if (alctx->rl_count > 1)
443 /* replace if we can reduce the number of runs */
444 replace = excess > (alctx->rl[0].length
445 + alctx->rl[1].length);
446 else
447 /* replace if we can shorten a single run */
448 replace = (excess > alctx->rl[0].length)
449 && (count < alctx->rl[0].length);
450 } else
451 replace = FALSE;
452 if (replace) {
453 /* Using this run, we can now drop smaller runs */
454 drop = 0;
455 excess = alctx->gathered_clusters + count
456 - alctx->wanted_clusters;
457 /* Compute how many clusters we can drop */
458 while ((drop < alctx->rl_count)
459 && (alctx->rl[drop].length <= excess)) {
460 excess -= alctx->rl[drop].length;
461 drop++;
462 }
463 k = 0;
464 while (((k + drop) < alctx->rl_count)
465 && (alctx->rl[k + drop].length < count)) {
466 alctx->rl[k] = alctx->rl[k + drop];
467 k++;
468 }
469 alctx->rl[k].length = count;
470 alctx->rl[k].lcn = lcn;
471 if (drop > 1) {
472 while ((k + drop) < alctx->rl_count) {
473 alctx->rl[k + 1] = alctx->rl[k + drop];
474 k++;
475 }
476 }
477 alctx->rl_count -= (drop - 1);
478 alctx->gathered_clusters = alctx->wanted_clusters + excess;
479 } else {
480 if (alctx->gathered_clusters < alctx->wanted_clusters) {
481 /* We had not gathered enough clusters */
482 if (!run_alloc(alctx, alctx->rl_count + 1)) {
483 k = alctx->rl_count - 1;
484 while ((k >= 0)
485 && (alctx->rl[k].length > count)) {
486 alctx->rl[k+1] = alctx->rl[k];
487 k--;
488 }
489 alctx->rl[k+1].length = count;
490 alctx->rl[k+1].lcn = lcn;
491 alctx->rl_count++;
492 alctx->gathered_clusters += count;
493 }
494 }
495 }
496 return (err);
497 }
498
499 /*
500 * Examine a buffer from the global bitmap
501 * in order to locate free runs of clusters
502 *
503 * Returns STEP_ZERO or STEP_ONE depending on whether the last
504 * bit examined was in a search for '0' or '1'. This must be
505 * put as argument to next examination.
506 * Returns STEP_ERR if there was an error.
507 */
508
examine_buf(struct ALLOC_CONTEXT * alctx,s64 pos,s64 br,enum STEP step)509 static enum STEP examine_buf(struct ALLOC_CONTEXT *alctx, s64 pos, s64 br,
510 enum STEP step)
511 {
512 s32 count;
513 s64 offbuf; /* first bit available in buf */
514 s32 bufpos; /* bit index in buf */
515 s32 index;
516
517 bufpos = pos & ((alctx->vol->cluster_size << 3) - 1);
518 offbuf = pos - bufpos;
519 while (bufpos < (br << 3)) {
520 if (step == STEP_ZERO) {
521 /* find first zero */
522 index = next_zero(alctx, bufpos, br << 3);
523 if (index >= 0) {
524 alctx->lcn = offbuf + index;
525 step = STEP_ONE;
526 bufpos = index;
527 } else {
528 bufpos = br << 3;
529 }
530 } else {
531 /* find first one */
532 index = next_one(alctx, bufpos, br << 3);
533 if (index >= 0) {
534 count = offbuf + index - alctx->lcn;
535 step = STEP_ZERO;
536 bufpos = index;
537 if (merge_run(alctx, alctx->lcn, count)) {
538 step = STEP_ERR;
539 bufpos = br << 3;
540 }
541 } else {
542 bufpos = br << 3;
543 }
544 }
545 }
546 return (step);
547 }
548
549 /*
550 * Sort the final runlist by lcn's and insert a terminator
551 *
552 * Returns 0 if successful
553 * -1 otherwise, with errno set accordingly
554 */
555
sort_runlist(struct ALLOC_CONTEXT * alctx)556 static int sort_runlist(struct ALLOC_CONTEXT *alctx)
557 {
558 LCN lcn;
559 VCN vcn;
560 s64 length;
561 BOOL sorted;
562 int err;
563 int k;
564
565 err = 0;
566 /* This sorting can be much improved... */
567 do {
568 sorted = TRUE;
569 for (k=0; (k+1)<alctx->rl_count; k++) {
570 if (alctx->rl[k+1].lcn < alctx->rl[k].lcn) {
571 length = alctx->rl[k].length;
572 lcn = alctx->rl[k].lcn;
573 alctx->rl[k] = alctx->rl[k+1];
574 alctx->rl[k+1].length = length;
575 alctx->rl[k+1].lcn = lcn;
576 sorted = FALSE;
577 }
578 }
579 } while (!sorted);
580 /* compute the vcns */
581 vcn = 0;
582 for (k=0; k<alctx->rl_count; k++) {
583 alctx->rl[k].vcn = vcn;
584 vcn += alctx->rl[k].length;
585 }
586 /* Shorten the last run if we got too much */
587 if (vcn > alctx->wanted_clusters) {
588 k = alctx->rl_count - 1;
589 alctx->rl[k].length -= vcn - alctx->wanted_clusters;
590 vcn = alctx->wanted_clusters;
591 }
592 /* Append terminator */
593 if (run_alloc(alctx, alctx->rl_count + 1))
594 err = -1;
595 else {
596 k = alctx->rl_count++;
597 alctx->rl[k].vcn = vcn;
598 alctx->rl[k].length = 0;
599 alctx->rl[k].lcn = LCN_ENOENT;
600 }
601 return (err);
602 }
603
604 /*
605 * Update the sizes of an attribute
606 *
607 * Returns 0 if successful
608 * -1 otherwise, with errno set accordingly
609 */
610
set_sizes(struct ALLOC_CONTEXT * alctx,ntfs_attr_search_ctx * ctx)611 static int set_sizes(struct ALLOC_CONTEXT *alctx, ntfs_attr_search_ctx *ctx)
612 {
613 ntfs_attr *na;
614 ntfs_inode *ni;
615 ATTR_RECORD *attr;
616
617 na = alctx->na;
618 /* Compute the sizes */
619 na->data_size = alctx->new_size;
620 na->initialized_size = 0;
621 na->allocated_size = alctx->wanted_clusters
622 << alctx->vol->cluster_size_bits;
623 /* Feed the sizes into the attribute */
624 attr = ctx->attr;
625 attr->non_resident = 1;
626 attr->data_size = cpu_to_sle64(na->data_size);
627 attr->initialized_size = cpu_to_sle64(na->initialized_size);
628 attr->allocated_size = cpu_to_sle64(na->allocated_size);
629 if (na->data_flags & ATTR_IS_SPARSE)
630 attr->compressed_size = cpu_to_sle64(na->compressed_size);
631 /* Copy the unnamed data attribute sizes to inode */
632 if ((opts.attribute == AT_DATA) && !na->name_len) {
633 ni = na->ni;
634 ni->data_size = na->data_size;
635 if (na->data_flags & ATTR_IS_SPARSE) {
636 ni->allocated_size = na->compressed_size;
637 ni->flags |= FILE_ATTR_SPARSE_FILE;
638 } else
639 ni->allocated_size = na->allocated_size;
640 }
641 return (0);
642 }
643
644 /*
645 * Assign a runlist to an attribute and store
646 *
647 * Returns 0 if successful
648 * -1 otherwise, with errno set accordingly
649 */
650
assign_runlist(struct ALLOC_CONTEXT * alctx)651 static int assign_runlist(struct ALLOC_CONTEXT *alctx)
652 {
653 ntfs_attr *na;
654 ntfs_attr_search_ctx *ctx;
655 int k;
656 int err;
657
658 err = 0;
659 na = alctx->na;
660 if (na->rl)
661 free(na->rl);
662 na->rl = alctx->rl;
663 /* Allocate the clusters */
664 for (k=0; ((k + 1) < alctx->rl_count) && !err; k++) {
665 if (ntfs_bitmap_set_run(alctx->vol->lcnbmp_na,
666 alctx->rl[k].lcn, alctx->rl[k].length)) {
667 err = -1;
668 }
669 }
670 na->allocated_size = alctx->wanted_clusters
671 << alctx->vol->cluster_size_bits;
672 NAttrSetNonResident(na);
673 NAttrSetFullyMapped(na);
674 if (err || ntfs_attr_update_mapping_pairs(na, 0)) {
675 err = -1;
676 } else {
677 ctx = ntfs_attr_get_search_ctx(alctx->na->ni, NULL);
678 if (ctx) {
679 if (ntfs_attr_lookup(opts.attribute, na->name,
680 na->name_len,
681 CASE_SENSITIVE, 0, NULL, 0, ctx)) {
682 err = -1;
683 } else {
684 if (set_sizes(alctx, ctx))
685 err = -1;
686 }
687 } else
688 err = -1;
689 ntfs_attr_put_search_ctx(ctx);
690 }
691 return (err);
692 }
693
694 /*
695 * Find the runs which minimize fragmentation
696 *
697 * Only the first and second data zones are examined, the MFT zone
698 * is preserved.
699 *
700 * Returns 0 if successful
701 * -1 otherwise, with errno set accordingly
702 */
703
find_best_runs(struct ALLOC_CONTEXT * alctx)704 static int find_best_runs(struct ALLOC_CONTEXT *alctx)
705 {
706 ntfs_volume *vol;
707 s64 pos; /* bit index in bitmap */
708 s64 br; /* byte count in buf */
709 int err;
710 enum STEP step;
711
712 err = 0;
713 vol = alctx->vol;
714 /* examine the first data zone */
715 pos = vol->mft_zone_end;
716 br = vol->cluster_size;
717 step = STEP_ZERO;
718 while ((step != STEP_ERR)
719 && (br == vol->cluster_size)
720 && (pos < vol->nr_clusters)) {
721 br = ntfs_attr_pread(vol->lcnbmp_na,
722 (pos >> 3) & -vol->cluster_size,
723 vol->cluster_size, alctx->buf);
724 if (br > 0) {
725 step = examine_buf(alctx, pos, br, step);
726 pos = (pos | ((vol->cluster_size << 3) - 1)) + 1;
727 }
728 }
729 /* examine the second data zone */
730 pos = 0;
731 br = vol->cluster_size;
732 step = STEP_ZERO;
733 while ((step != STEP_ERR)
734 && (br == vol->cluster_size)
735 && (pos < vol->mft_zone_start)) {
736 br = ntfs_attr_pread(vol->lcnbmp_na,
737 (pos >> 3) & -vol->cluster_size,
738 vol->cluster_size, alctx->buf);
739 if (br > 0) {
740 step = examine_buf(alctx, pos, br, step);
741 pos = (pos | ((vol->cluster_size << 3) - 1)) + 1;
742 }
743 }
744 if (alctx->gathered_clusters < alctx->wanted_clusters) {
745 errno = ENOSPC;
746 ntfs_log_error("Error : not enough space on device\n");
747 err = -1;
748 } else {
749 if ((step == STEP_ERR) || sort_runlist(alctx))
750 err = -1;
751 }
752 return (err);
753 }
754
755 /*
756 * Preallocate clusters with minimal fragmentation
757 *
758 * Returns 0 if successful
759 * -1 otherwise, with errno set accordingly
760 */
761
preallocate(ntfs_attr * na,s64 new_size)762 static int preallocate(ntfs_attr *na, s64 new_size)
763 {
764 struct ALLOC_CONTEXT *alctx;
765 ntfs_volume *vol;
766 int err;
767
768 err = 0;
769 vol = na->ni->vol;
770 alctx = (struct ALLOC_CONTEXT*)ntfs_malloc(sizeof(struct ALLOC_CONTEXT));
771 if (alctx) {
772 alctx->buf = (unsigned char*)ntfs_malloc(vol->cluster_size);
773 if (alctx->buf) {
774 alctx->na = na;
775 alctx->vol = vol;
776 alctx->rl_count = 0;
777 alctx->rl_allocated = 0;
778 alctx->rl = (runlist_element*)NULL;
779 alctx->new_size = new_size;
780 alctx->wanted_clusters = (new_size
781 + vol->cluster_size - 1)
782 >> vol->cluster_size_bits;
783 alctx->gathered_clusters = 0;
784 if (find_best_runs(alctx))
785 err = -1;
786 if (!err && !opts.noaction) {
787 if (assign_runlist(alctx))
788 err = -1;
789 } else
790 free(alctx->rl);
791 free(alctx->buf);
792 } else
793 err = -1;
794 free(alctx);
795 } else
796 err = -1;
797 return (err);
798 }
799
800 /**
801 * Create a regular file under the given directory inode
802 *
803 * It is a wrapper function to ntfs_create(...)
804 *
805 * Return: the created file inode
806 */
ntfs_new_file(ntfs_inode * dir_ni,const char * filename)807 static ntfs_inode *ntfs_new_file(ntfs_inode *dir_ni,
808 const char *filename)
809 {
810 ntfschar *ufilename;
811 /* inode to the file that is being created */
812 ntfs_inode *ni;
813 int ufilename_len;
814
815 /* ntfs_mbstoucs(...) will allocate memory for ufilename if it's NULL */
816 ufilename = NULL;
817 ufilename_len = ntfs_mbstoucs(filename, &ufilename);
818 if (ufilename_len == -1) {
819 ntfs_log_perror("ERROR: Failed to convert '%s' to unicode",
820 filename);
821 return NULL;
822 }
823 ni = ntfs_create(dir_ni, const_cpu_to_le32(0), ufilename, ufilename_len, S_IFREG);
824 free(ufilename);
825 return ni;
826 }
827
828 /**
829 * main - Begin here
830 *
831 * Start from here.
832 *
833 * Return: 0 Success, the program worked
834 * 1 Error, something went wrong
835 */
main(int argc,char * argv[])836 int main(int argc, char *argv[])
837 {
838 FILE *in;
839 struct stat st;
840 ntfs_volume *vol;
841 ntfs_inode *out;
842 ntfs_attr *na;
843 int flags = 0;
844 int res;
845 int result = 1;
846 s64 new_size;
847 u64 offset;
848 char *buf;
849 s64 br, bw;
850 ntfschar *attr_name;
851 int attr_name_len = 0;
852 #ifdef HAVE_WINDOWS_H
853 char *unix_name;
854 #endif
855
856 ntfs_log_set_handler(ntfs_log_handler_stderr);
857
858 res = parse_options(argc, argv);
859 if (res >= 0)
860 return (res);
861
862 utils_set_locale();
863
864 /* Set SIGINT handler. */
865 if (signal(SIGINT, signal_handler) == SIG_ERR) {
866 ntfs_log_perror("Failed to set SIGINT handler");
867 return 1;
868 }
869 /* Set SIGTERM handler. */
870 if (signal(SIGTERM, signal_handler) == SIG_ERR) {
871 ntfs_log_perror("Failed to set SIGTERM handler");
872 return 1;
873 }
874
875 if (opts.noaction)
876 flags = NTFS_MNT_RDONLY;
877 if (opts.force)
878 flags |= NTFS_MNT_RECOVER;
879
880 vol = utils_mount_volume(opts.device, flags);
881 if (!vol) {
882 ntfs_log_perror("ERROR: couldn't mount volume");
883 return 1;
884 }
885
886 if ((vol->flags & VOLUME_IS_DIRTY) && !opts.force)
887 goto umount;
888
889 NVolSetCompression(vol); /* allow compression */
890 if (ntfs_volume_get_free_space(vol)) {
891 ntfs_log_perror("ERROR: couldn't get free space");
892 goto umount;
893 }
894
895 {
896 struct stat fst;
897 if (stat(opts.src_file, &fst) == -1) {
898 ntfs_log_perror("ERROR: Couldn't stat source file");
899 goto umount;
900 }
901 new_size = fst.st_size;
902 }
903 ntfs_log_verbose("New file size: %lld\n", (long long)new_size);
904
905 in = fopen(opts.src_file, "r");
906 if (!in) {
907 ntfs_log_perror("ERROR: Couldn't open source file");
908 goto umount;
909 }
910
911 if (opts.inode) {
912 s64 inode_num;
913 char *s;
914
915 inode_num = strtoll(opts.dest_file, &s, 0);
916 if (*s) {
917 ntfs_log_error("ERROR: Couldn't parse inode number.\n");
918 goto close_src;
919 }
920 out = ntfs_inode_open(vol, inode_num);
921 } else {
922 #ifdef HAVE_WINDOWS_H
923 unix_name = ntfs_utils_unix_path(opts.dest_file);
924 if (unix_name) {
925 out = ntfs_pathname_to_inode(vol, NULL, unix_name);
926 } else
927 out = (ntfs_inode*)NULL;
928 #else
929 out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file);
930 #endif
931 }
932 if (!out) {
933 /* Copy the file if the dest_file's parent dir can be opened. */
934 char *parent_dirname;
935 char *filename;
936 ntfs_inode *dir_ni;
937 ntfs_inode *ni;
938 char *dirname_last_whack;
939
940 #ifdef HAVE_WINDOWS_H
941 filename = basename(unix_name);
942 parent_dirname = strdup(unix_name);
943 #else
944 filename = basename(opts.dest_file);
945 parent_dirname = strdup(opts.dest_file);
946 #endif
947 if (!parent_dirname) {
948 ntfs_log_perror("strdup() failed");
949 goto close_src;
950 }
951 dirname_last_whack = strrchr(parent_dirname, '/');
952 if (dirname_last_whack) {
953 if (dirname_last_whack == parent_dirname)
954 dirname_last_whack[1] = 0;
955 else
956 *dirname_last_whack = 0;
957 dir_ni = ntfs_pathname_to_inode(vol, NULL,
958 parent_dirname);
959 } else {
960 ntfs_log_verbose("Target path does not contain '/'. "
961 "Using root directory as parent.\n");
962 dir_ni = ntfs_inode_open(vol, FILE_root);
963 }
964 if (dir_ni) {
965 if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
966 /* Remove the last '/' for estetic reasons. */
967 dirname_last_whack[0] = 0;
968 ntfs_log_error("The file '%s' already exists "
969 "and is not a directory. "
970 "Aborting.\n", parent_dirname);
971 free(parent_dirname);
972 ntfs_inode_close(dir_ni);
973 goto close_src;
974 }
975 ntfs_log_verbose("Creating a new file '%s' under '%s'"
976 "\n", filename, parent_dirname);
977 ni = ntfs_new_file(dir_ni, filename);
978 ntfs_inode_close(dir_ni);
979 if (!ni) {
980 ntfs_log_perror("Failed to create '%s' under "
981 "'%s'", filename,
982 parent_dirname);
983 free(parent_dirname);
984 goto close_src;
985 }
986 out = ni;
987 } else {
988 ntfs_log_perror("ERROR: Couldn't open '%s'",
989 parent_dirname);
990 free(parent_dirname);
991 goto close_src;
992 }
993 free(parent_dirname);
994 }
995 /* The destination is a directory. */
996 if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) {
997 char *filename;
998 char *overwrite_filename;
999 int overwrite_filename_len;
1000 ntfs_inode *ni;
1001 ntfs_inode *dir_ni;
1002 int filename_len;
1003 int dest_dirname_len;
1004
1005 filename = basename(opts.src_file);
1006 dir_ni = out;
1007 filename_len = strlen(filename);
1008 dest_dirname_len = strlen(opts.dest_file);
1009 overwrite_filename_len = filename_len+dest_dirname_len + 2;
1010 overwrite_filename = malloc(overwrite_filename_len);
1011 if (!overwrite_filename) {
1012 ntfs_log_perror("ERROR: Failed to allocate %i bytes "
1013 "memory for the overwrite filename",
1014 overwrite_filename_len);
1015 ntfs_inode_close(out);
1016 goto close_src;
1017 }
1018 #ifdef HAVE_WINDOWS_H
1019 strcpy(overwrite_filename, unix_name);
1020 #else
1021 strcpy(overwrite_filename, opts.dest_file);
1022 #endif
1023 if (overwrite_filename[dest_dirname_len - 1] != '/') {
1024 strcat(overwrite_filename, "/");
1025 }
1026 strcat(overwrite_filename, filename);
1027 ni = ntfs_pathname_to_inode(vol, dir_ni, overwrite_filename);
1028 /* Does a file with the same name exist in the dest dir? */
1029 if (ni) {
1030 ntfs_log_verbose("Destination path has a file with "
1031 "the same name\nOverwriting the file "
1032 "'%s'\n", overwrite_filename);
1033 ntfs_inode_close(out);
1034 out = ni;
1035 } else {
1036 ntfs_log_verbose("Creating a new file '%s' under "
1037 "'%s'\n", filename, opts.dest_file);
1038 ni = ntfs_new_file(dir_ni, filename);
1039 ntfs_inode_close(dir_ni);
1040 if (!ni) {
1041 ntfs_log_perror("ERROR: Failed to create the "
1042 "destination file under '%s'",
1043 opts.dest_file);
1044 free(overwrite_filename);
1045 goto close_src;
1046 }
1047 out = ni;
1048 }
1049 free(overwrite_filename);
1050 }
1051
1052 attr_name = ntfs_str2ucs(opts.attr_name, &attr_name_len);
1053 if (!attr_name) {
1054 ntfs_log_perror("ERROR: Failed to parse attribute name '%s'",
1055 opts.attr_name);
1056 goto close_dst;
1057 }
1058
1059 na = ntfs_attr_open(out, opts.attribute, attr_name, attr_name_len);
1060 if (!na) {
1061 if (errno != ENOENT) {
1062 ntfs_log_perror("ERROR: Couldn't open attribute");
1063 goto close_dst;
1064 }
1065 /* Requested attribute isn't present, add it. */
1066 if (ntfs_attr_add(out, opts.attribute, attr_name,
1067 attr_name_len, NULL, 0)) {
1068 ntfs_log_perror("ERROR: Couldn't add attribute");
1069 goto close_dst;
1070 }
1071 na = ntfs_attr_open(out, opts.attribute, attr_name,
1072 attr_name_len);
1073 if (!na) {
1074 ntfs_log_perror("ERROR: Couldn't open just added "
1075 "attribute");
1076 goto close_dst;
1077 }
1078 }
1079
1080 ntfs_log_verbose("Old file size: %lld\n", (long long)na->data_size);
1081 if (opts.minfragments && NAttrCompressed(na)) {
1082 ntfs_log_info("Warning : Cannot avoid fragmentation"
1083 " of a compressed attribute\n");
1084 opts.minfragments = 0;
1085 }
1086 if (na->data_size && opts.minfragments) {
1087 if (ntfs_attr_truncate(na, 0)) {
1088 ntfs_log_perror(
1089 "ERROR: Couldn't truncate existing attribute");
1090 goto close_attr;
1091 }
1092 }
1093 if (na->data_size != new_size) {
1094 if (opts.minfragments) {
1095 /*
1096 * Do a standard truncate() to check whether the
1097 * attribute has to be made non-resident.
1098 * If still resident, preallocation is not needed.
1099 */
1100 if (ntfs_attr_truncate(na, new_size)) {
1101 ntfs_log_perror(
1102 "ERROR: Couldn't resize attribute");
1103 goto close_attr;
1104 }
1105 if (NAttrNonResident(na)
1106 && preallocate(na, new_size)) {
1107 ntfs_log_perror(
1108 "ERROR: Couldn't preallocate attribute");
1109 goto close_attr;
1110 }
1111 } else {
1112 if (ntfs_attr_truncate_solid(na, new_size)) {
1113 ntfs_log_perror(
1114 "ERROR: Couldn't resize attribute");
1115 goto close_attr;
1116 }
1117 }
1118 }
1119
1120 buf = malloc(NTFS_BUF_SIZE);
1121 if (!buf) {
1122 ntfs_log_perror("ERROR: malloc failed");
1123 goto close_attr;
1124 }
1125
1126 ntfs_log_verbose("Starting write.\n");
1127 offset = 0;
1128 while (!feof(in)) {
1129 if (caught_terminate) {
1130 ntfs_log_error("SIGTERM or SIGINT received. "
1131 "Aborting write.\n");
1132 break;
1133 }
1134 br = fread(buf, 1, NTFS_BUF_SIZE, in);
1135 if (!br) {
1136 if (!feof(in)) ntfs_log_perror("ERROR: fread failed");
1137 break;
1138 }
1139 bw = ntfs_attr_pwrite(na, offset, br, buf);
1140 if (bw != br) {
1141 ntfs_log_perror("ERROR: ntfs_attr_pwrite failed");
1142 break;
1143 }
1144 offset += bw;
1145 }
1146 if ((na->data_flags & ATTR_COMPRESSION_MASK)
1147 && ntfs_attr_pclose(na))
1148 ntfs_log_perror("ERROR: ntfs_attr_pclose failed");
1149 ntfs_log_verbose("Syncing.\n");
1150 result = 0;
1151 free(buf);
1152 close_attr:
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_sle64(change_time);
1159 ntfs_inode_update_times(out, 0);
1160 } else {
1161 ntfs_log_error("Failed to get the time stamp.\n");
1162 }
1163 }
1164 close_dst:
1165 while (ntfs_inode_close(out) && !opts.noaction) {
1166 if (errno != EBUSY) {
1167 ntfs_log_error("Sync failed. Run chkdsk.\n");
1168 break;
1169 }
1170 ntfs_log_error("Device busy. Will retry sync in 3 seconds.\n");
1171 sleep(3);
1172 }
1173 close_src:
1174 fclose(in);
1175 umount:
1176 ntfs_umount(vol, FALSE);
1177 ntfs_log_verbose("Done.\n");
1178 return result;
1179 }
1180