diff --git a/ntfsprogs/ntfscp.c b/ntfsprogs/ntfscp.c index 90c754a3..c96024b2 100644 --- a/ntfsprogs/ntfscp.c +++ b/ntfsprogs/ntfscp.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004-2006 Yura Pakhuchiy * Copyright (c) 2005 Anton Altaparmakov + * Copyright (c) 2006 Hil Liao * * This utility will overwrite files on NTFS volume. * @@ -43,6 +44,9 @@ #ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_LIBGEN_H +#include +#endif #include "types.h" #include "attrib.h" @@ -270,6 +274,34 @@ static void signal_handler(int arg __attribute__((unused))) caught_terminate++; } +/** + * Create a regular file under the given directory inode + * + * It is a wrapper function to ntfs_create(...) + * + * Return: the created file inode + */ +static ntfs_inode *ntfs_new_file(ntfs_inode *dir_ni, + const char *filename) +{ + ntfschar *ufilename; + /* inode to the file that is being created */ + ntfs_inode *ni; + int ufilename_len; + + /* ntfs_mbstoucs(...) will allocate memory for ufilename if it's NULL */ + ufilename = NULL; + ufilename_len = ntfs_mbstoucs(filename, &ufilename, 0); + if (ufilename_len == -1) { + ntfs_log_perror("ERROR: Failed to convert '%s' to unicode", + filename); + return NULL; + } + ni = ntfs_create(dir_ni, ufilename, ufilename_len, S_IFREG); + free(ufilename); + return ni; +} + /** * main - Begin here * @@ -352,26 +384,116 @@ int main(int argc, char *argv[]) } else out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file); if (!out) { - ntfs_log_perror("ERROR: Couldn't open destination file"); - goto close_src; - } - if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) { - /* - * @out is directory and it was specified by pathname, add - * filename to path and try once again. - */ + /* copy the file if the dest_file's parent dir can be opened */ + char *parent_dirname; char *filename; - ntfs_inode *out_tmp; + ntfs_inode *dir_ni; + ntfs_inode *ni; + int dest_path_len; + char *dirname_last_whack; - filename = basename(opts.src_file); - out_tmp = ntfs_pathname_to_inode(vol, out, filename); - ntfs_inode_close(out); - out = out_tmp; - if (!out) { - ntfs_log_perror("ERROR: Failed to open destination " - "file"); + filename = basename(opts.dest_file); + dest_path_len = strlen(opts.dest_file); + parent_dirname = strdup(opts.dest_file); + if (!parent_dirname) { + ntfs_log_perror("strdup() failed"); goto close_src; } + dirname_last_whack = strrchr(parent_dirname, '/'); + if (dirname_last_whack) { + dirname_last_whack[1] = '\0'; + dir_ni = ntfs_pathname_to_inode(vol, NULL, + parent_dirname); + } else { + ntfs_log_verbose("Target path does not contain '/'. " + "Using root directory as parent.\n"); + dir_ni = ntfs_inode_open(vol, FILE_root); + } + if (dir_ni) { + if (!(dir_ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) { + /* Remove the last '/' for estetic reasons. */ + dirname_last_whack[0] = '\0'; + ntfs_log_error("The file '%s' already exists " + "and is not a directory. " + "Aborting.\n", parent_dirname); + free(parent_dirname); + ntfs_inode_close(dir_ni); + goto close_src; + } + ntfs_log_verbose("Creating a new file '%s' under '%s'" + "\n", filename, parent_dirname); + ni = ntfs_new_file(dir_ni, filename); + ntfs_inode_close(dir_ni); + if (!ni) { + ntfs_log_perror("Failed to create '%s' under " + "'%s'", filename, + parent_dirname); + free(parent_dirname); + goto close_src; + } + out = ni; + } else { + ntfs_log_perror("ERROR: Couldn't open '%s'", + parent_dirname); + free(parent_dirname); + goto close_src; + } + free(parent_dirname); + } + /* the destination file is a path */ + if ((out->mrec->flags & MFT_RECORD_IS_DIRECTORY) && !opts.inode) { + char *filename; + char *overwrite_filename; + int overwrite_filename_len; + /* inode to the file that is being created */ + ntfs_inode *ni; + /* inode to the directory to create the file */ + ntfs_inode *dir_ni; + int filename_len; + int dest_dirname_len; + + filename = basename(opts.src_file); + dir_ni = out; + filename_len = strlen(filename); + dest_dirname_len = strlen(opts.dest_file); + overwrite_filename_len = filename_len+dest_dirname_len+2; + overwrite_filename = malloc(overwrite_filename_len); + if (!overwrite_filename) { + ntfs_log_perror("ERROR: Failed to allocate %i bytes " + "memory for the overwrite filename", + overwrite_filename_len); + ntfs_inode_close(out); + goto close_src; + } + strcpy(overwrite_filename, opts.dest_file); + /* add '/' in the end of dest_dirname if there is not one there */ + if (opts.dest_file[dest_dirname_len-1] != '/') { + strcat(overwrite_filename, "/"); + } + strcat(overwrite_filename, filename); + ni = ntfs_pathname_to_inode(vol, NULL, overwrite_filename); + /* Does a file with the same name exist in the dest dir? */ + if (ni) { + ntfs_log_verbose("Destination path has a file with " + "the same name\nOverwriting the file " + "'%s'\n", overwrite_filename); + ntfs_inode_close(out); + out = ni; + } else { + ntfs_log_verbose("Creating a new file '%s' under '%s'\n", + filename, opts.dest_file); + ni = ntfs_new_file(dir_ni, filename); + ntfs_inode_close(dir_ni); + if (!ni) { + ntfs_log_perror("ERROR: Failed to create the " + "destination file under '%s'", + opts.dest_file); + free(overwrite_filename); + goto close_src; + } + out = ni; + } + free(overwrite_filename); } attr_name = ntfs_str2ucs(opts.attr_name, &attr_name_len);