summaryrefslogtreecommitdiffstats
path: root/mv.c
diff options
context:
space:
mode:
Diffstat (limited to 'mv.c')
-rw-r--r--mv.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/mv.c b/mv.c
new file mode 100644
index 0000000..a9ee0c6
--- /dev/null
+++ b/mv.c
@@ -0,0 +1,554 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/mv.c,v 0.1 2002/03/21 09:03:25 ksheff Exp $ */
+/*
+ * mv.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ */
+
+
+#ifndef MV_C
+#define MV_C
+#endif
+
+/* Description */
+/*
+ * Module to move/rename files
+ *
+ */
+/*
+ * $Log: mv.c,v $
+ * Revision 0.1 2002/03/21 09:03:25 ksheff
+ * initial revision.
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+#include "e2tools.h"
+
+/* Macros */
+#define USAGE "Usage: e2mv [-vfs] source1 [... sourceN] destination\n"
+
+/* Local Prototypes */
+static long
+do_swap(int force, int verbose, int curidx, int argc, char **argv);
+
+/* Name: do_mv()
+ *
+ * Description:
+ *
+ * This function reads the command line arguments and moves or renames files
+ * in an ext2fs file system
+ *
+ * Algorithm:
+ *
+ * Read any command line switches
+ * Get the first source file specification
+ * If we are performing a file swap, call do_swap()
+ * Open the file system
+ * Get the destination and determine if it is a directory
+ * If not, then get the destination's directory and basename
+ * Also check that the number of source files are no more than one
+ * For each source file
+ * Get the directory and basename of the source file
+ * Determine the inode number for the source file
+ * Create the link
+ * Unlink the original source file.
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * int argc; The number of arguments
+ * char *argv[]; The command line arguments
+ *
+ * Return Values:
+ *
+ * 0 - the file was move successfully
+ * an error occurred.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/20/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ */
+long
+do_mv(int argc, char *argv[])
+{
+ int verbose=0;
+ int force=0;
+ int swap_files=0;
+ int num_files;
+ int errcnt=0;
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t srcd;
+ ext2_ino_t destd;
+ ext2_ino_t source_file;
+ char *src_dir;
+ char *dest_dir;
+ char *src_name;
+ char *dest_name;
+ char *result_name;
+ long retval;
+ int c;
+ int curidx;
+
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt(argc, argv, "vfs")) != EOF)
+ {
+ switch (c)
+ {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'f':
+ force = E2T_FORCE;
+ break;
+ case 's':
+ swap_files = 1;
+ break;
+ default:
+ errcnt++;
+ break;
+ }
+ }
+
+ curidx = optind;
+
+ force |= E2T_DO_MV;
+
+ if (errcnt || argc < curidx+2)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ if (swap_files)
+ return(do_swap(force, verbose, curidx, argc, argv));
+
+ cur_filesys = argv[curidx++];
+ if (NULL == (src_dir = strchr(cur_filesys, ':')))
+ {
+ fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
+ return(1);
+ }
+ *src_dir++ = '\0';
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
+ {
+ fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys);
+ return retval;
+ }
+
+
+ /* get the destination directory */
+ dest_name = NULL;
+ if (strcmp(dest_dir = argv[argc-1], ".") != 0)
+ {
+ /* check to see if the file name already exists in the current
+ * directory and also see if it is a directory.
+ */
+ if ((retval = ext2fs_namei(fs, root, root, dest_dir, &destd)) ||
+ (retval = ext2fs_check_directory(fs, destd)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND &&
+ retval != EXT2_ET_NO_DIRECTORY)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ /* ok, so it's either not there or it's not a directory, so
+ * get the real destination directory and file name.
+ */
+ if (curidx+1 < argc)
+ {
+ fprintf(stderr, "%s must be a directory!\n", dest_dir);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if (get_file_parts(fs, root, dest_dir, &destd, &dest_dir,
+ &dest_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+ }
+ else /* we have a directory!!! */
+ dest_name = NULL;
+ }
+ else
+ {
+ destd = root;
+ dest_name = NULL;
+ }
+
+ do
+ {
+ /* move to the source directory */
+ if (get_file_parts(fs, root, src_dir, &srcd, &src_dir, &src_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the source file */
+ if ((retval = ext2fs_namei(fs, srcd, srcd, src_name, &source_file)))
+ {
+ fprintf(stderr, "%s: source file %s\n",error_message(retval),
+ src_name);
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ result_name = (dest_name) ? dest_name : src_name;
+
+ /* now create the link */
+ if ((retval = create_hard_link(fs, destd, source_file, result_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((src_dir == NULL) ? "." : src_dir), src_name,
+ ((dest_dir == NULL) ? "." : dest_dir), result_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, srcd, src_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", src_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if (verbose)
+ fprintf(stderr, "moved %s/%s as %s/%s\n",
+ ((src_dir == NULL) ? "." : src_dir), src_name,
+ ((dest_dir == NULL) ? "." : dest_dir), result_name);
+ src_dir = argv[curidx++];
+ }
+ while (curidx < argc);
+
+ ext2fs_close(fs);
+ return(0);
+
+} /* end of do_mv */
+
+/* Name: get_file_parts()
+ *
+ * Description:
+ *
+ * This function returns each of the following file 'parts': directory name,
+ * base name, inode number of the directory
+ *
+ * Algorithm:
+ *
+ * Use the root directory as the current working directory
+ * Find the last / in the full pathname
+ * If none are found, set the basename to the full pathname,
+ * and the directory to NULL
+ * Otherwise,
+ * Separate the basename from the directory
+ * Change the working directory
+ * Set the return pointers.
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; the filesystem being used
+ * ext2_ino_t root; the root directory of the filesystem
+ * char *pathname; the full pathname of the file
+ * ext2_ino_t *dir_ino; The inode number of the directory
+ * char **dir_name; the directory the file is in
+ * char **base_name; The basename of the file
+ *
+ * Return Values:
+ *
+ * 0 - retrieved the information ok
+ * otherwise the error code of what went wrong
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/21/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+long
+get_file_parts(ext2_filsys fs, ext2_ino_t root, char *pathname,
+ ext2_ino_t *dir_ino, char **dir_name, char **base_name)
+{
+ char *fname;
+ long retval;
+
+ /* move to the source directory */
+ *dir_name = pathname;
+ *dir_ino = root;
+ if (NULL == (fname = strrchr(pathname, '/')))
+ {
+ fname = pathname;
+ *dir_name = NULL;
+ }
+ else
+ {
+ *fname++ = '\0';
+ if ((*pathname != '\0' && strcmp(pathname, ".") != 0) &&
+ (retval = change_cwd(fs, root, dir_ino, pathname)))
+ {
+ fprintf(stderr, "Error changing to directory %s\n",
+ pathname);
+ return(retval);
+ }
+ }
+
+ *base_name = fname;
+ return(0);
+} /* end of get_file_parts */
+
+
+/* Name: do_swap()
+ *
+ * Description:
+ *
+ * This function swaps the names of two files and optionally assigns the
+ * first file a new name:
+ *
+ * file1 file2 file3
+ *
+ * After the operation, file1 will reference the file that was originally file2, and file3 will reference the what used to be file1.
+ *
+ * Algorithm:
+ *
+ * check input parameters
+ * Get the directory and inode numbers for the first two files
+ * If a third file exists
+ * Get the directory info for the file
+ * Rename the first file to the third
+ * Rename the 2nd file to the first
+ * Otherwise
+ * Remove the first file from its directory
+ * Rename the 2nd file to the first
+ * Add the first file back as the 2nd file.
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * int force; Flag indicating if existing files are to be removed
+ * int verbose; Flag to print lots of output
+ * int curidx; The current index in the command line args
+ * int argc; The total number of arguments
+ * char **argv; Pointer to an array of argument strings.
+ *
+ * Return Values:
+ *
+ * 0 - the operation was successful
+ * otherwise the error code of what went wrong.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/21/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+
+static long
+do_swap(int force, int verbose, int curidx, int argc, char **argv)
+{
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t file1_dirno;
+ ext2_ino_t file2_dirno;
+ ext2_ino_t file3_dirno;
+ ext2_ino_t file1_no;
+ ext2_ino_t file2_no;
+ char *file1_dir;
+ char *file2_dir;
+ char *file3_dir;
+ char *file1_name;
+ char *file2_name;
+ char *file3_name;
+ long retval;
+
+ if (curidx + 2 > argc)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ cur_filesys = argv[curidx++];
+ if (NULL == (file1_dir = strchr(cur_filesys, ':')))
+ {
+ fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
+ return(1);
+ }
+ *file1_dir++ = '\0';
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
+ {
+ fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys);
+ return retval;
+ }
+
+ /* move to the file 1 directory */
+ if (get_file_parts(fs, root, file1_dir, &file1_dirno, &file1_dir,
+ &file1_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the file 1 file */
+ if ((retval = ext2fs_namei(fs, file1_dirno, file1_dirno, file1_name,
+ &file1_no)))
+ {
+ fprintf(stderr, "%s: file 1 file %s\n",error_message(retval),
+ file1_name);
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+
+ /* move to the file 2 directory */
+ if (get_file_parts(fs, root, argv[curidx++], &file2_dirno, &file2_dir,
+ &file2_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the file 2 file */
+ if ((retval = ext2fs_namei(fs, file2_dirno, file2_dirno, file2_name,
+ &file2_no)))
+ {
+ fprintf(stderr, "%s: file 2 file %s\n",error_message(retval),
+ file2_name);
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if (curidx < argc)
+ {
+ /* move to the file 3 directory */
+ if (get_file_parts(fs, root, argv[curidx++], &file3_dirno, &file3_dir,
+ &file3_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* now move the first file to the 3rd */
+ if ((retval = create_hard_link(fs, file3_dirno, file1_no, file3_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file3_dir == NULL) ? "." : file3_dir), file3_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file1_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+
+ /* now move the 2nd file to the 1st */
+ if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name,
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file2_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if (verbose)
+ fprintf(stderr, "renamed file %s/%s as %s/%s\n"
+ "renamed file %s/%s as %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file3_dir == NULL) ? "." : file3_dir), file3_name,
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name,
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name);
+ }
+ else
+ {
+ /* now remove the first file */
+ if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file1_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ /* now move the 2nd file to the 1st */
+ if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name,
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file2_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if ((retval = create_hard_link(fs, file2_dirno, file1_no, file2_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if (verbose)
+ fprintf(stderr, "swapped files %s/%s <-> %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name);
+
+ }
+
+ ext2fs_close(fs);
+ return(0);
+
+} /* end of do_swap */