summaryrefslogtreecommitdiffstats
path: root/ln.c
diff options
context:
space:
mode:
Diffstat (limited to 'ln.c')
-rw-r--r--ln.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/ln.c b/ln.c
new file mode 100644
index 0000000..e5bda69
--- /dev/null
+++ b/ln.c
@@ -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 */
+