~ubuntu-branches/ubuntu/lucid/linux-ntfs/lucid

« back to all changes in this revision

Viewing changes to ntfsprogs/ntfscp.c

  • Committer: Bazaar Package Importer
  • Author(s): David Martínez Moreno
  • Date: 2005-11-08 20:20:23 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20051108202023-dpn4lutm8o0div8g
Tags: 1.12.1-1
* New upstream release (closes: #332930):
  - Fixed lots of memory leaks in the tools.
  - ntfsmount now uses the new API, and it has several fixes.
  - Support journals which have been modified by chkdsk.
  - New API for creating hard links, index handling, high-level creation and
    deletion of files and directories.
  - New utility ntfscmp (make extra) which compares two NTFS volumes and
    tell the differences. It's used for development, debugging, testing, etc.
  - Added robustness to several tools.
  - ntfsclone: fix saving by sectors during --rescue.
  - ntfsmount: Add 'locale' option and change interface to 'ntfsmount device
    mount_point'.
  - Fixed problem with kernel 2.4 and mkntfs.
  - Change ALL utilities to display the libntfs version they are running on.
    This should make debugging easier in the case that people are running
    mismatched utilities/library.
* This new release fixes problems with libfuse 2.4.0 (closes: #336357).
* Fixed a lot of typos in the manpages, kindly submitted by A Costa. Thanks!
  (closes: #336143, #336144, #336145, #336147, #336148).
* Fixed a couple of typos by me.
* debian/control: The SONAME of libntfs was bumped. Created new package
  (libntfs8) and removed the old one.
* debian/copyright: Updated the FSF postal address.
* Added debian/ntfsprogs.links in order to ship mkfs.ntfs and
  mount.ntfs-fuse.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/**
2
2
 * ntfscp - Part of the Linux-NTFS project.
3
3
 *
4
 
 * Copyright (c) 2004 Yura Pakhuchiy
 
4
 * Copyright (c) 2004-2005 Yura Pakhuchiy
 
5
 * Copyright (c) 2005 Anton Altaparmakov
5
6
 *
6
7
 * This utility will overwrite files on ntfs volume
7
8
 *
23
24
 
24
25
#include "config.h"
25
26
 
 
27
#ifdef HAVE_STDIO_H
26
28
#include <stdio.h>
 
29
#endif
 
30
#ifdef HAVE_GETOPT_H
27
31
#include <getopt.h>
 
32
#endif
 
33
#ifdef HAVE_STDLIB_H
28
34
#include <stdlib.h>
 
35
#endif
 
36
#ifdef HAVE_STRING_H
29
37
#include <string.h>
 
38
#endif
 
39
#include <signal.h>
 
40
#ifdef HAVE_SYS_STAT_H
30
41
#include <sys/stat.h>
 
42
#endif
 
43
#ifdef HAVE_UNISTD_H
 
44
#include <unistd.h>
 
45
#endif
31
46
 
32
47
#include "types.h"
33
48
#include "attrib.h"
34
49
#include "utils.h"
35
50
#include "volume.h"
 
51
#include "dir.h"
36
52
#include "debug.h"
 
53
#include "version.h"
37
54
 
38
55
struct options {
39
56
        char            *device;        /* Device/File to work with */
40
57
        char            *src_file;      /* Source file */
41
58
        char            *dest_file;     /* Destination file */
 
59
        char            *attr_name;     /* Write to attribute with this name. */
42
60
        int              force;         /* Override common sense */
43
61
        int              quiet;         /* Less output */
44
62
        int              verbose;       /* Extra output */
45
63
        int              noaction;      /* Do not write to disk */
 
64
        ATTR_TYPES       attribute;     /* Write to this attribute. */
 
65
        int              inode;         /* Treat dest_file as inode number. */
46
66
};
47
67
 
48
68
static const char *EXEC_NAME = "ntfscp";
49
69
static struct options opts;
 
70
volatile sig_atomic_t caught_terminate = 0;
50
71
 
51
72
GEN_PRINTF (Eprintf, stderr, NULL,          FALSE)
52
73
GEN_PRINTF (Vprintf, stderr, &opts.verbose, TRUE)
62
83
 */
63
84
static void version (void)
64
85
{
65
 
        Printf ("\n%s v%s - Overwrite files on NTFS volume.\n\n",
66
 
                EXEC_NAME, VERSION);
67
 
        Printf ("Copyright (c) 2004 Yura Pakhuchiy\n");
 
86
        Printf("\n%s v%s (libntfs %s) - Overwrite files on NTFS volume.\n\n",
 
87
                EXEC_NAME, VERSION, ntfs_libntfs_version());
 
88
        Printf ("Copyright (c) 2004-2005 Yura Pakhuchiy\n");
68
89
        Printf ("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
69
90
}
70
91
 
78
99
static void usage (void)
79
100
{
80
101
        Printf ("\nUsage: %s [options] device src_file dest_file\n\n"
 
102
                "    -a  --attribute num   Write to this attribute\n"
 
103
                "    -i  --inode           Treat dest_file as inode number\n"
81
104
                "    -f  --force           Use less caution\n"
82
105
                "    -h  --help            Print this help\n"
 
106
                "    -N  --attr-name name  Write to attribute with this name\n"
83
107
                "    -n  --no-action       Do not write to disk\n"
84
108
                "    -q  --quiet           Less output\n"
85
109
                "    -V  --version         Version information\n"
99
123
 */
100
124
static int parse_options (int argc, char **argv)
101
125
{
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   }
111
138
        };
112
139
 
 
140
        char *s;
113
141
        char c = -1;
114
142
        int err  = 0;
115
143
        int ver  = 0;
116
144
        int help = 0;
117
 
        
118
 
        opts.device = 0;
119
 
        opts.src_file = 0;
120
 
        opts.dest_file = 0;
 
145
        s64 attr;
 
146
 
 
147
        opts.device = NULL;
 
148
        opts.src_file = NULL;
 
149
        opts.dest_file = NULL;
 
150
        opts.attr_name = NULL;
 
151
        opts.inode = 0;
 
152
        opts.attribute = AT_DATA;
121
153
 
122
154
        opterr = 0; /* We'll handle the errors, thank you. */
123
155
 
124
 
        while ((c = getopt_long (argc, argv, sopt, lopt, NULL)) != (char)-1) {
 
156
        while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != (char) -1) {
125
157
                switch (c) {
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];
133
165
                        } else {
134
 
                                Eprintf("You must specify exactly two files.\n");
135
 
                                err++;
136
 
                        }
 
166
                                Eprintf("You must specify exactly 2 files.\n");
 
167
                                err++;
 
168
                        }
 
169
                        break;
 
170
                case 'a':
 
171
                        if (opts.attribute != AT_DATA) {
 
172
                                Eprintf("You can specify only 1 attribute.\n");
 
173
                                err++;
 
174
                                break;
 
175
                        }
 
176
 
 
177
                        attr = strtol(optarg, &s, 0);
 
178
                        if (*s) {
 
179
                                Eprintf("Couldn't parse attribute.\n");
 
180
                                err++;
 
181
                        } else
 
182
                                opts.attribute = (ATTR_TYPES)attr;
 
183
                        break;
 
184
                case 'i':
 
185
                        opts.inode++;
137
186
                        break;
138
187
                case 'f':
139
188
                        opts.force++;
142
191
                case '?':
143
192
                        help++;
144
193
                        break;
 
194
                case 'N':
 
195
                        if (opts.attr_name) {
 
196
                                Eprintf("You can specify only one attribute "
 
197
                                                "name.\n");
 
198
                                err++;
 
199
                        } else
 
200
                                opts.attr_name = argv[optind - 1];
 
201
                        break;
145
202
                case 'n':
146
203
                        opts.noaction++;
147
204
                        break;
155
212
                        opts.verbose++;
156
213
                        break;
157
214
                default:
158
 
                        Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
 
215
                        Eprintf("Unknown option '%s'.\n", argv[optind - 1]);
159
216
                        err++;
160
217
                        break;
161
218
                }
165
222
                opts.quiet = 0;
166
223
        } else {
167
224
                if (!opts.device) {
168
 
                        Eprintf ("You must specify a device.\n");
 
225
                        Eprintf("You must specify a device.\n");
169
226
                        err++;
170
227
                } else if (!opts.src_file) {
171
 
                        Eprintf ("You must specify a source file.\n");
 
228
                        Eprintf("You must specify a source file.\n");
172
229
                        err++;
173
230
                } else if (!opts.dest_file) {
174
 
                        Eprintf ("You must specify a destination file.\n");
 
231
                        Eprintf("You must specify a destination file.\n");
175
232
                        err++;
176
233
                }
177
234
 
191
248
}
192
249
 
193
250
/**
 
251
 * signal_handler - Handle SIGINT and SIGTERM: abort write, sync and exit.
 
252
 */
 
253
static void signal_handler(int arg __attribute__((unused)))
 
254
{
 
255
        caught_terminate++;
 
256
}
 
257
 
 
258
/**
194
259
 * main - Begin here
195
260
 *
196
261
 * Start from here.
204
269
        ntfs_volume *vol;
205
270
        ntfs_inode *out;
206
271
        ntfs_attr *na;
207
 
        ntfs_attr_search_ctx *ctx;
208
 
        FILE_NAME_ATTR *fna;
209
272
        int flags = 0;
210
273
        int result = 1;
211
274
        s64 new_size;
212
 
        int need_logfile_reset = 0;
213
275
        u64 offset;
214
276
        char *buf;
215
277
        s64 br, bw;
 
278
        ntfschar *attr_name;
 
279
        int attr_name_len = 0;
216
280
 
217
 
        if (!parse_options (argc, argv))
 
281
        if (!parse_options(argc, argv))
218
282
                return 1;
219
283
 
220
284
        utils_set_locale();
221
 
        
 
285
 
 
286
        /* Set SIGINT handler. */
 
287
        if (signal(SIGINT, signal_handler) == SIG_ERR) {
 
288
                perror("Failed to set SIGINT handler");
 
289
                return 1;
 
290
        }
 
291
        /* Set SIGTERM handler. */
 
292
        if (signal(SIGTERM, signal_handler) == SIG_ERR) {
 
293
                perror("Failed to set SIGTERM handler");
 
294
                return 1;
 
295
        }
 
296
 
222
297
        if (opts.noaction)
223
298
                flags = MS_RDONLY;
224
299
 
225
 
        vol = utils_mount_volume (opts.device, flags, opts.force);
 
300
        vol = utils_mount_volume(opts.device, flags, opts.force);
226
301
        if (!vol) {
227
 
                perror("ERROR: couldn't mount volume");
 
302
                perror("ERROR: couldn't mount volume");
228
303
                return 1;
229
304
        }
230
 
        
 
305
 
231
306
        if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force))
232
307
                goto umount;
233
308
 
234
309
        {
235
 
        struct stat fst;
236
 
        if (stat (opts.src_file, &fst) == -1) {
237
 
                perror ("ERROR: Couldn't stat source file\n");
238
 
                goto umount;
239
 
        }
240
 
        new_size = fst.st_size;
241
 
        }
242
 
        Vprintf ("New file size: %lld\n", new_size);
 
310
                struct stat fst;
 
311
                if (stat (opts.src_file, &fst) == -1) {
 
312
                        perror("ERROR: Couldn't stat source file");
 
313
                        goto umount;
 
314
                }
 
315
                new_size = fst.st_size;
 
316
        }
 
317
        Vprintf("New file size: %lld\n", new_size);
243
318
 
244
 
        in = fopen (opts.src_file, "r");
 
319
        in = fopen(opts.src_file, "r");
245
320
        if (!in) {
246
 
                perror ("ERROR: Couldn't open source file");
 
321
                perror("ERROR: Couldn't open source file");
247
322
                goto umount;
248
323
        }
249
324
 
250
 
        out = utils_pathname_to_inode (vol, NULL, opts.dest_file);
 
325
        if (opts.inode) {
 
326
                s64 inode_num;
 
327
                char *s;
 
328
 
 
329
                inode_num = strtoll(opts.dest_file, &s, 0);
 
330
                if (*s) {
 
331
                        Eprintf("ERROR: Couldn't parse inode number.\n");
 
332
                        goto close_src;
 
333
                }
 
334
                out = ntfs_inode_open(vol, inode_num);
 
335
        } else
 
336
                out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file);
251
337
        if (!out) {
252
 
                perror ("ERROR: Couldn't open destination file");
 
338
                perror("ERROR: Couldn't open destination file");
253
339
                goto close_src;
254
340
        }
255
 
        
256
 
        na = ntfs_attr_open (out, AT_DATA, 0, 0);
 
341
        if ((le16_to_cpu(out->mrec->flags) & MFT_RECORD_IS_DIRECTORY) &&
 
342
                        !opts.inode){
 
343
                /*
 
344
                 * @out is directory and it was specified by pathname, add
 
345
                 * filename to path and reopen inode.
 
346
                 */
 
347
                char *filename, *new_dest_file;
 
348
 
 
349
                /*
 
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.
 
353
                 */
 
354
                filename = strrchr(opts.src_file, '/');
 
355
                if (filename)
 
356
                        filename++;
 
357
                else
 
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");
 
364
                        goto close_dst;
 
365
                }
 
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);
 
371
                free(new_dest_file);
 
372
                if (!out) {
 
373
                        perror("ERROR: Failed to open destination file");
 
374
                        goto close_src;
 
375
                }
 
376
        }
 
377
 
 
378
        if (opts.attr_name) {
 
379
                attr_name = NULL;
 
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");
 
383
                        goto close_dst;
 
384
                }
 
385
        } else
 
386
                attr_name = AT_UNNAMED;
 
387
        na = ntfs_attr_open(out, opts.attribute, attr_name, attr_name_len);
257
388
        if (!na) {
258
 
                perror ("ERROR: Couldn't open $DATA attribute");
259
 
                goto close_dst;
 
389
                if (errno != ENOENT) {
 
390
                        perror("ERROR: Couldn't open attribute");
 
391
                        goto close_dst;
 
392
                }
 
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");
 
397
                        goto close_dst;
 
398
                }
 
399
                na = ntfs_attr_open(out, opts.attribute, attr_name,
 
400
                                attr_name_len);
 
401
                if (!na) {
 
402
                        perror("ERROR: Couldn't open just added attribute");
 
403
                        goto close_dst;
 
404
                }
260
405
        }
261
 
        
262
 
        Vprintf ("Old file size: %lld\n", na->data_size);
 
406
        if (attr_name != AT_UNNAMED)
 
407
                free(attr_name);
 
408
 
 
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");
266
 
                        goto close_attr;
267
 
                }
268
 
                need_logfile_reset = 1;
269
 
                
270
 
                /* Update $FILE_NAME(0x30) attribute for new file size. */
271
 
                ctx = ntfs_attr_get_search_ctx(out, NULL);
272
 
                if (!ctx) {
273
 
                        perror("ERROR: Couldn't get search context");
274
 
                        goto close_attr;
275
 
                }
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);
279
 
                        goto close_attr;
280
 
                }
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);
286
 
                } else {
287
 
                        fna->allocated_size = 0;
288
 
                        fna->data_size = 0;
289
 
                }
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");
 
413
                        goto close_attr;
 
414
                }
292
415
        }
293
416
 
294
 
        buf = malloc (NTFS_BUF_SIZE);
 
417
        buf = malloc(NTFS_BUF_SIZE);
295
418
        if (!buf) {
296
 
                perror ("ERROR: malloc failed");
 
419
                perror("ERROR: malloc failed");
297
420
                goto close_attr;
298
421
        }
299
422
 
 
423
        Vprintf("Starting write.\n");
300
424
        offset = 0;
301
 
        while (!feof (in)) {
302
 
                br = fread (buf, 1, NTFS_BUF_SIZE, in);
 
425
        while (!feof(in)) {
 
426
                if (caught_terminate) {
 
427
                        printf("SIGTERM or SIGINT received. Aborting write.\n");
 
428
                        break;
 
429
                }
 
430
                br = fread(buf, 1, NTFS_BUF_SIZE, in);
303
431
                if (!br) {
304
 
                        if (!feof (in)) perror ("ERROR: fread failed");
 
432
                        if (!feof(in)) perror("ERROR: fread failed");
305
433
                        break;
306
434
                }
307
 
                
308
 
                bw = ntfs_attr_pwrite (na, offset, br, buf);
 
435
                bw = ntfs_attr_pwrite(na, offset, br, buf);
309
436
                if (bw != br) {
310
 
                        perror ("ERROR: ntfs_attr_pwrite failed");
 
437
                        perror("ERROR: ntfs_attr_pwrite failed");
311
438
                        break;
312
439
                }
313
440
                offset += bw;
314
441
        }
315
 
        need_logfile_reset = 1;
316
 
 
317
 
        free (buf);
 
442
        Vprintf("Syncing.\n");
 
443
        result = 0;
 
444
        free(buf);
318
445
close_attr:
319
 
        ntfs_attr_close (na);
 
446
        ntfs_attr_close(na);
320
447
close_dst:
321
 
        ntfs_inode_close (out);
322
 
 
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");
 
451
                        break;
 
452
                }
 
453
                Eprintf("Device busy. Will retry sync after 3 seconds.\n");
 
454
                sleep(3);
326
455
        }
327
 
 
328
456
close_src:
329
 
        fclose (in);
 
457
        fclose(in);
330
458
umount:
331
 
        ntfs_umount (vol, FALSE);
332
 
 
 
459
        ntfs_umount(vol, FALSE);
 
460
        Vprintf("Done.\n");
333
461
        return result;
334
462
}