• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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