/* $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 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 */