diff options
Diffstat (limited to 'ln.c')
-rw-r--r-- | ln.c | 388 |
1 files changed, 388 insertions, 0 deletions
@@ -0,0 +1,388 @@ +/* $Header: /home/ksheff/src/e2tools/RCS/ln.c,v 0.3 2002/06/30 05:54:02 ksheff Exp $ */ +/* + * ln.c + * + * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed + * under the terms of the GNU Public License. + * + */ + +#ifndef LN_C +#define LN_C +#endif + +/* Description */ +/* + * Module to create links + * + */ +/* + * $Log: ln.c,v $ + * Revision 0.3 2002/06/30 05:54:02 ksheff + * Modified create_hard_link() to check file type before linking to current + * directory. This was not being done before and it was causing problems if a + * non regular file was renamed. + * + * Revision 0.2 2002/03/21 09:04:40 ksheff + * Split the mv operation into its own module. + * + * Revision 0.1 2002/03/07 07:23:41 ksheff + * initial revision. + * + */ + +/* Feature Test Switches */ +/* Headers */ +#include "e2tools.h" + +/* Macros */ +#define USAGE "Usage: e2ln [-vfs] source destination\n" + +/* Local Prototypes */ +long +do_ln(int argc, char *argv[]); + +long +create_hard_link(ext2_filsys fs, ext2_ino_t cwd, ext2_ino_t new_file_ino, + char *newfile, int ln_flags); + +/* Name: do_ln() + * + * Description: + * + * This function reads the command line arguments and creates a link + * in an ext2fs file system + * + * Algorithm: + * + * Read any command line switches + * Get the source file specification + * Open the file system + * Get the directory and basename of the source file + * Determine the inode number for the source file + * If the destination file is not given or if it's a . + * use the current directory and the basename of the source file + * Otherwise + * Get the directory and basename of the destination file + * Create the link + * + * Global Variables: + * + * None + * + * Arguments: + * + * int argc; The number of arguments + * char *argv[]; The command line arguments + * + * Return Values: + * + * 0 - the link was created successfully + * an error occurred. + * + * Author: Keith W. Sheffield + * Date: 03/05/2002 + * + * Modification History: + * + * MM/DD/YY Name Description + * 03/06/02 K. Sheffield Modified to perform file moves + * 03/20/02 K. Sheffield Moved the mv operation to a separate file + */ +long +do_ln(int argc, char *argv[]) +{ + int verbose=0; + int force=0; + int symlink=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; + long retval; + int c; + +#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': + symlink = 1; + break; + default: + errcnt++; + break; + } + } + + if (errcnt || argc == optind) + { + fputs(USAGE, stderr); + return(1); + } + + if (symlink) + { + fputs("Not implemented yet\n", stderr); + return(1); + } + + cur_filesys = argv[optind++]; + if (NULL == (src_dir = strchr(cur_filesys, ':'))) + { + fprintf(stderr, "Invalid file specification: %s\n", cur_filesys); + return(1); + } + *src_dir++ = '\0'; + + if (*src_dir == '\0') + { + fputs(USAGE, stderr); + return(1); + } + + if ((retval = open_filesystem(cur_filesys, &fs, &root, 1))) + { + fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys); + return retval; + } + + /* 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); + } + + /* get the destination directory */ + destd = root; + if (argc == optind || strcmp(dest_dir = argv[optind], ".") == 0) + dest_name = src_name; + else + { + if (get_file_parts(fs, root, dest_dir, &destd, &dest_dir, + &dest_name)) + { + ext2fs_close(fs); + return(-1); + } + } + + /* now create the link */ + if ((retval = create_hard_link(fs, destd, source_file, dest_name, force))) + { + fprintf(stderr, "Error linking %s/%s as %s/%s\n", + ((src_dir == NULL) ? "." : src_dir), src_name, + ((dest_dir == NULL) ? "." : dest_dir), dest_name); + ext2fs_close(fs); + return(1); + } + + if (verbose) + fprintf(stderr, "linked %s/%s as %s/%s\n", + ((src_dir == NULL) ? "." : src_dir), src_name, + ((dest_dir == NULL) ? "." : dest_dir), dest_name); + + ext2fs_close(fs); + return(0); + +} /* end of do_ln */ + +/* Name: create_hard_link() + * + * Description: + * + * This function creates a hard link to an existing file + * + * Algorithm: + * + * Check input parameters + * Check to see if the new file name already exists + * Make sure the new file is not an existing directory + * If the file exists, remove it if the del_current flag is set + * Add the new file name and it's inode to the current directory. + * Get the inode structure for the current inode number + * update the number of links + * Write the inode structure back out to the file system. + * + * Global Variables: + * + * None. + * + * Arguments: + * + * ext2_filsys fs; The current file system + * ext2_ino_t cwd; The current working directory + * ext2_ino_t new_file_ino; The inode number of the new file + * char *newfile; The name of the new file + * int ln_flags; Flags affecting hard_link action + * + * Return Values: + * + * 0 - the new file link was created successfully + * any other value indicates an error + * + * Author: Keith W. Sheffield + * Date: 03/05/2002 + * + * Modification History: + * + * MM/DD/YY Name Description + * 06/30/02 K.Sheffield Directory link flag is now based on the + * type of file being linked. This was + * causing problems if a directory was + * renamed. + */ +long +create_hard_link(ext2_filsys fs, ext2_ino_t cwd, ext2_ino_t new_file_ino, + char *newfile, int ln_flags) +{ + ext2_ino_t curr_ino; + struct ext2_inode inode; + long retval; + int dir_flag; + + if (fs == NULL || newfile == NULL) + { + fputs("Invalid input parameter. Exiting create_hard_link() with -1\n", + stderr); + return (-1); + } + + /* check to see if the file name already exists in the current directory */ + if ((retval = ext2fs_namei(fs, cwd, cwd, newfile, &curr_ino))) + { + if (retval != EXT2_ET_FILE_NOT_FOUND) + { + fprintf(stderr, "%s\n",error_message(retval)); + return(retval); + } + + } + /* file name exists, let's see if is a directory */ + else if ((retval = ext2fs_check_directory(fs, curr_ino))) + { + if (retval != EXT2_ET_NO_DIRECTORY) + { + fprintf(stderr, "%s\n",error_message(retval)); + return(retval); + } + + /* delete the existing file if needed */ + if ((ln_flags & E2T_FORCE) && + (curr_ino != new_file_ino)) + { + if ((retval = rm_file(fs, cwd, newfile, curr_ino))) + { + fprintf(stderr, "%s\n",error_message(retval)); + return(retval); + } + } + else + { + fprintf(stderr, "ln: %s: File exists\n", newfile); + return(1); + } + } + else + { + /* if we get here, then it's an existing directory */ + fprintf(stderr, "%s is a directory!\n", newfile); + return(1); + } + + /* read the inode associated with the file */ + if ((retval = read_inode(fs, new_file_ino, &inode))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return (retval); + } + + /* determine how to link into the directory based on the type of file */ + switch(inode.i_mode & LINUX_S_IFMT) + { + case LINUX_S_IFREG: + dir_flag = EXT2_FT_REG_FILE; + break; + case LINUX_S_IFLNK: + dir_flag = EXT2_FT_SYMLINK; + break; + case LINUX_S_IFDIR: + dir_flag = EXT2_FT_DIR; + break; + case LINUX_S_IFSOCK: + dir_flag = EXT2_FT_SOCK; + break; + case LINUX_S_IFBLK: + dir_flag = EXT2_FT_BLKDEV; + break; + case LINUX_S_IFCHR: + dir_flag = EXT2_FT_CHRDEV; + break; + case LINUX_S_IFIFO: + dir_flag = EXT2_FT_FIFO; + break; + default: + dir_flag = EXT2_FT_UNKNOWN; + break; + } + + + if ((retval = ext2fs_link(fs, cwd, newfile, new_file_ino, dir_flag))) + { + /* check to see if we ran out of space in the directory */ + if (retval == EXT2_ET_DIR_NO_SPACE) + { + /* try resizing the directory and try again */ + if (0 == (retval = ext2fs_expand_dir(fs, cwd))) + retval = ext2fs_link(fs, cwd, newfile, new_file_ino, dir_flag); + } + if (retval) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + } + + + /* update the inode stat information */ + if ((ln_flags & E2T_DO_MV) == 0) + { + inode.i_links_count++; + if ((retval = write_inode(fs, new_file_ino, &inode))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return (retval); + } + } + + return(0); + +} /* end of create_hard_link */ + |