100
124
static int parse_options (int argc, char **argv)
102
static const char *sopt = "-fh?nqVv";
126
static const char *sopt = "-a:ifh?N:nqVv";
103
127
static const struct option lopt[] = {
128
{ "attribute", required_argument, NULL, 'a' },
129
{ "inode", no_argument, NULL, 'i' },
104
130
{ "force", no_argument, NULL, 'f' },
105
131
{ "help", no_argument, NULL, 'h' },
132
{ "attr-name", required_argument, NULL, 'N' },
106
133
{ "no-action", no_argument, NULL, 'n' },
107
134
{ "quiet", no_argument, NULL, 'q' },
108
135
{ "version", no_argument, NULL, 'V' },
110
137
{ NULL, 0, NULL, 0 }
148
opts.src_file = NULL;
149
opts.dest_file = NULL;
150
opts.attr_name = NULL;
152
opts.attribute = AT_DATA;
122
154
opterr = 0; /* We'll handle the errors, thank you. */
124
while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != (char)-1) {
156
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != (char) -1) {
126
158
case 1: /* A non-option argument */
127
159
if (!opts.device) {
128
opts.device = argv[optind-1];
160
opts.device = argv[optind - 1];
129
161
} else if (!opts.src_file) {
130
opts.src_file = argv[optind-1];
162
opts.src_file = argv[optind - 1];
131
163
} else if (!opts.dest_file) {
132
opts.dest_file = argv[optind-1];
164
opts.dest_file = argv[optind - 1];
134
Eprintf("You must specify exactly two files.\n");
166
Eprintf("You must specify exactly 2 files.\n");
171
if (opts.attribute != AT_DATA) {
172
Eprintf("You can specify only 1 attribute.\n");
177
attr = strtol(optarg, &s, 0);
179
Eprintf("Couldn't parse attribute.\n");
182
opts.attribute = (ATTR_TYPES)attr;
204
269
ntfs_volume *vol;
207
ntfs_attr_search_ctx *ctx;
212
int need_logfile_reset = 0;
279
int attr_name_len = 0;
217
if (!parse_options (argc, argv))
281
if (!parse_options(argc, argv))
220
284
utils_set_locale();
286
/* Set SIGINT handler. */
287
if (signal(SIGINT, signal_handler) == SIG_ERR) {
288
perror("Failed to set SIGINT handler");
291
/* Set SIGTERM handler. */
292
if (signal(SIGTERM, signal_handler) == SIG_ERR) {
293
perror("Failed to set SIGTERM handler");
222
297
if (opts.noaction)
223
298
flags = MS_RDONLY;
225
vol = utils_mount_volume (opts.device, flags, opts.force);
300
vol = utils_mount_volume(opts.device, flags, opts.force);
227
perror("ERROR: couldn't mount volume");
302
perror("ERROR: couldn't mount volume");
231
306
if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force))
236
if (stat (opts.src_file, &fst) == -1) {
237
perror ("ERROR: Couldn't stat source file\n");
240
new_size = fst.st_size;
242
Vprintf ("New file size: %lld\n", new_size);
311
if (stat (opts.src_file, &fst) == -1) {
312
perror("ERROR: Couldn't stat source file");
315
new_size = fst.st_size;
317
Vprintf("New file size: %lld\n", new_size);
244
in = fopen (opts.src_file, "r");
319
in = fopen(opts.src_file, "r");
246
perror ("ERROR: Couldn't open source file");
321
perror("ERROR: Couldn't open source file");
250
out = utils_pathname_to_inode (vol, NULL, opts.dest_file);
329
inode_num = strtoll(opts.dest_file, &s, 0);
331
Eprintf("ERROR: Couldn't parse inode number.\n");
334
out = ntfs_inode_open(vol, inode_num);
336
out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file);
252
perror ("ERROR: Couldn't open destination file");
338
perror("ERROR: Couldn't open destination file");
256
na = ntfs_attr_open (out, AT_DATA, 0, 0);
341
if ((le16_to_cpu(out->mrec->flags) & MFT_RECORD_IS_DIRECTORY) &&
344
* @out is directory and it was specified by pathname, add
345
* filename to path and reopen inode.
347
char *filename, *new_dest_file;
350
* FIXME: There should exist more beautiful way to get filename.
351
* Not sure that it will work in windows, but I don't think that
352
* someone will use ntfscp under windows.
354
filename = strrchr(opts.src_file, '/');
358
filename = opts.src_file;
359
/* Add 2 bytes for '/' and null-terminator. */
360
new_dest_file = malloc(strlen(opts.dest_file) +
361
strlen(filename) + 2);
362
if (!new_dest_file) {
363
perror("ERROR: malloc() failed");
366
strcpy(new_dest_file, opts.dest_file);
367
strcat(new_dest_file, "/");
368
strcat(new_dest_file, filename);
369
ntfs_inode_close(out);
370
out = ntfs_pathname_to_inode(vol, NULL, new_dest_file);
373
perror("ERROR: Failed to open destination file");
378
if (opts.attr_name) {
380
attr_name_len = ntfs_mbstoucs(opts.attr_name, &attr_name, 0);
381
if (attr_name_len == -1) {
382
perror("ERROR: Failed to parse attribute name");
386
attr_name = AT_UNNAMED;
387
na = ntfs_attr_open(out, opts.attribute, attr_name, attr_name_len);
258
perror ("ERROR: Couldn't open $DATA attribute");
389
if (errno != ENOENT) {
390
perror("ERROR: Couldn't open attribute");
393
/* Requested attribute isn't present, add it. */
394
if (ntfs_attr_add(out, opts.attribute, attr_name,
395
attr_name_len, NULL, 0)) {
396
perror("ERROR: Couldn't add attribute");
399
na = ntfs_attr_open(out, opts.attribute, attr_name,
402
perror("ERROR: Couldn't open just added attribute");
262
Vprintf ("Old file size: %lld\n", na->data_size);
406
if (attr_name != AT_UNNAMED)
409
Vprintf("Old file size: %lld\n", na->data_size);
263
410
if (na->data_size != new_size) {
264
if (ntfs_attr_truncate (na, new_size)) {
265
perror ("ERROR: Couldn't resize $DATA attribute");
268
need_logfile_reset = 1;
270
/* Update $FILE_NAME(0x30) attribute for new file size. */
271
ctx = ntfs_attr_get_search_ctx(out, NULL);
273
perror("ERROR: Couldn't get search context");
276
if (ntfs_attr_lookup(AT_FILE_NAME, 0, 0, 0, 0, NULL, 0, ctx)) {
277
perror("ERROR: Couldn't find $FILE_NAME attribute");
278
ntfs_attr_put_search_ctx(ctx);
281
fna = (FILE_NAME_ATTR *)((u8*)ctx->attr +
282
le16_to_cpu(ctx->attr->value_offset));
283
if (NAttrNonResident(na)) {
284
fna->allocated_size = scpu_to_le64(na->allocated_size);
285
fna->data_size = scpu_to_le64(na->data_size);
287
fna->allocated_size = 0;
290
ntfs_inode_mark_dirty(ctx->ntfs_ino);
291
ntfs_attr_put_search_ctx(ctx);
411
if (ntfs_attr_truncate(na, new_size)) {
412
perror("ERROR: Couldn't resize attribute");
294
buf = malloc (NTFS_BUF_SIZE);
417
buf = malloc(NTFS_BUF_SIZE);
296
perror ("ERROR: malloc failed");
419
perror("ERROR: malloc failed");
423
Vprintf("Starting write.\n");
302
br = fread (buf, 1, NTFS_BUF_SIZE, in);
426
if (caught_terminate) {
427
printf("SIGTERM or SIGINT received. Aborting write.\n");
430
br = fread(buf, 1, NTFS_BUF_SIZE, in);
304
if (!feof (in)) perror ("ERROR: fread failed");
432
if (!feof(in)) perror("ERROR: fread failed");
308
bw = ntfs_attr_pwrite (na, offset, br, buf);
435
bw = ntfs_attr_pwrite(na, offset, br, buf);
310
perror ("ERROR: ntfs_attr_pwrite failed");
437
perror("ERROR: ntfs_attr_pwrite failed");
315
need_logfile_reset = 1;
442
Vprintf("Syncing.\n");
319
ntfs_attr_close (na);
321
ntfs_inode_close (out);
323
if (need_logfile_reset) {
324
printf ("Resetting logfile.\n");
325
ntfs_logfile_reset (vol);
448
while (ntfs_inode_close(out)) {
449
if (errno != EBUSY) {
450
Eprintf("Sync failed. Run chkdsk.\n");
453
Eprintf("Device busy. Will retry sync after 3 seconds.\n");
331
ntfs_umount (vol, FALSE);
459
ntfs_umount(vol, FALSE);