diff options
author | Hans Ulrich Niedermann <hun@n-dimensional.de> | 2007-12-14 16:08:25 +0100 |
---|---|---|
committer | Hans Ulrich Niedermann <hun@n-dimensional.de> | 2007-12-14 16:08:25 +0100 |
commit | 6749719af90afe9544db14bdd8e2742926f1439c (patch) | |
tree | 9bb8edef05f9625be2ccd9bce5cb245af63effc4 /mkdir.c | |
download | e2tools-6749719af90afe9544db14bdd8e2742926f1439c.tar.gz e2tools-6749719af90afe9544db14bdd8e2742926f1439c.tar.xz e2tools-6749719af90afe9544db14bdd8e2742926f1439c.zip |
Diffstat (limited to 'mkdir.c')
-rw-r--r-- | mkdir.c | 587 |
1 files changed, 587 insertions, 0 deletions
@@ -0,0 +1,587 @@ +/* $Header: /home/ksheff/src/e2tools/RCS/mkdir.c,v 0.8 2004/04/07 03:19:32 ksheff Exp $ */ +/* + * mkdir.c + * + * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed + * under the terms of the GNU Public License. + * + * Derived from debugfs.c Copyright (C) 1993 Theodore Ts'o <tytso@mit.edu> + * and modified by Robert Sanders <gt8134b@prism.gatech.edu> + * as well as portions of the ext2fs library (C) 1993-1995 Theodore Ts'o + */ + +#ifndef MKDIR_C +#define MKDIR_C +#endif + +/* Description */ +/* + * This file contains the functions used to create a directory in an ext2fs + * filesystem. + * + */ +/* + * $Log: mkdir.c,v $ + * Revision 0.8 2004/04/07 03:19:32 ksheff + * Modified to always apply the default user and group information. + * + * Revision 0.7 2004/04/07 02:55:44 ksheff + * Updated usage string. + * + * Revision 0.6 2002/07/09 02:15:23 ksheff + * Fixed a error reporting bug that was not displaying the full file name. + * + * Revision 0.5 2002/04/10 09:30:28 ksheff + * Added the ability to set the mode, owner, group, etc. for a directory. + * + * Revision 0.4 2002/03/05 13:42:12 ksheff + * Fixed minor indentation. + * + * Revision 0.3 2002/03/05 12:14:10 ksheff + * Removed setting optind for SCO. + * + * Revision 0.2 2002/02/27 05:34:43 ksheff + * Added the function e2mkdir which is run by a user to create directories in + * an ext2fs filesystem. + * + * Revision 0.1 2002/02/27 04:48:30 ksheff + * initial revision + * + */ + +/* Headers */ +#include "e2tools.h" + +/* Local Prototypes */ +long +e2mkdir(int argc, char *argv[]); + +long +create_dir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd, + char *dirname, struct stat *def_stat); +long +create_subdir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd, + char *dirname, struct stat *def_stat); +/* Name: e2mkdir() + * + * Description: + * + * This function extracts the command line parameters and creates + * directories based on user input + * + * Algorithm: + * + * Extract any command line switches + * Sort the remaining arguments + * For each argument + * Open a new filesystem if needed + * Create the directory + * + * Global Variables: + * + * None + * + * Arguments: + * + * int argc; The number of arguments + * char *argv[]; the command line arguments + * + * Return Values: + * + * 0 - the directories were created successfully + * otherwise, an error code is returned + * + * Author: Keith W. Sheffield + * Date: 02/26/2002 + * + * Modification History: + * + * MM/DD/YY Name Description + * 03/05/02 K. Sheffield Removed setting optind for SCO + * 04/10/02 K.Sheffield Added a default directory permission + * 04/06/04 K.Sheffield Modified to apply the default user and + * group. + */ +long +e2mkdir(int argc, char *argv[]) +{ + int verbose=0; + int num_files; + int errcnt=0; + char *last_filesys = NULL; + char *cur_filesys = NULL; + ext2_filsys fs = NULL; + ext2_ino_t root; + ext2_ino_t cwd; + char **cur_opt; + char *filespec; + int i; + char *ptr; + int c; + long retval; + struct stat def_stat; + + init_stat_buf(&def_stat); + def_stat.st_ino = 1; + +#ifdef HAVE_OPTRESET + optreset = 1; /* Makes BSD getopt happy */ +#endif + while ((c = getopt(argc, argv, "G:O:P:v")) != EOF) + { + switch (c) + { + case 'v': + verbose = 1; + break; + case 'G': + def_stat.st_gid = atoi(optarg); + break; + case 'O': + def_stat.st_uid = atoi(optarg); + break; + case 'P': + def_stat.st_mode = strtol(optarg, NULL, 8); + break; + default: + errcnt++; + break; + } + } + + if (errcnt || argc == optind) + { + fputs("Usage: e2mkdir [-G gid][-O uid][-P mode][-v] filesystem:directory...\n", stderr); + return(1); + } + + num_files = argc - optind; + + cur_opt = argv + optind; + if (num_files > 1 ) + qsort(cur_opt, num_files, sizeof(char *), my_strcmp); + + for(i=0;i<num_files;i++) + { + filespec = *cur_opt++; + + /* dealing with a filesystem or a regular file */ + if (NULL != (ptr = strchr(filespec, ':'))) + { + /* separate the filesystem name from the file name */ + *ptr++ = '\0'; + cur_filesys = filespec; + filespec = ptr; + + /* check to see if the filesystem has changed */ + if (last_filesys == NULL || + strcmp(last_filesys, cur_filesys) != 0) + { + if (last_filesys != NULL && + (retval = ext2fs_close(fs))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + + if ((retval = open_filesystem(cur_filesys, &fs, &root, 1))) + { + fprintf(stderr, "%s\n", error_message(retval)); + fprintf(stderr, "Error opening fileystem %s\n", + cur_filesys); + return retval; + } + cwd = root; + last_filesys = cur_filesys; + } /* end of filesystem change? */ + if ((retval = create_dir(fs, root, &cwd, filespec, &def_stat))) + { + fprintf(stderr, "Error creating %s:%s\n", cur_filesys, filespec); + return(-1); + } + cwd = root; /* reset the current directory */ + if (verbose) + printf("Created directory %s:%s\n", cur_filesys, filespec); + } + else if (verbose) + { + printf("%s is not a valid e2fs filesystem specification. skipping\n", + filespec); + } + } + if (fs != NULL && + (retval = ext2fs_close(fs))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + return(0); + +} /* end of e2mkdir */ + +/* Name: create_dir() + * + * Description: + * + * This function will create a directory in the given ext2fs file system. + * It will re-create all the parent directories if necessary (similar + * to mkdir -p). The current working directory is then set to this new + * directory. + * + * Algorithm: + * + * Check the input parameters + * Check to see if the directory name contains a / + * If it exists + * Break the entire path into specific directory names + * For each section of the path + * Check to see if the name exists in the current directory + * If it doesn't + * Call create_subdir for that section of the path + * Otherwise + * If it is a symbolic link, follow it + * Read the inode structure for the current section of the path + * If it is not a directory + * Print an error message and return an error. + * Otherwise + * Call create_subdir for that section of the path + * + * Global Variables: + * + * None. + * + * Arguments: + * + * ext2_filsys fs; The current file system + * ext2_ino_t root; The inode number of the root directory + * ext2_ino_t *cwd; Pointer to the inode number of the current + * directory + * char *dirname; The directory to create + * struct stat *def_stat; Default directory status, owner, group, etc. + * + * Return Values: + * + * 0 - the directory was created successfully + * error code of what went wrong + * + * Author: Keith W. Sheffield + * Date: 02/18/2002 + * + * Modification History: + * + * MM/DD/YY Name Description + * 04/10/02 K.Sheffield Added a default directory permission + * 07/08/02 K.Sheffield Fixed bugs in error reporting + */ +long +create_dir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd, + char *dirname, struct stat *def_stat) +{ + char *ptr; /* working pointer to /'s */ + ext2_ino_t parent; /* the parent directory inode number*/ + ext2_ino_t child; /* the inode number of the new directory */ + struct ext2_inode inode; /* inode of file/directory dirname */ + char *name; /* basename of the new directory */ + long retval; /* function return value */ + char *buf; + int len; + char c; + char *dname; /* name of the sub directory */ + + /* make sure we have valid parameters */ + if (fs == NULL || cwd == NULL || dirname == NULL || *dirname == '\0') + { + fputs("create_dir: invalid parameter\n", stderr); + return(-1); + } + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* check to see if there are any sub directories or absolute paths given + */ + if (NULL != (ptr = strchr(dirname, '/'))) + { + + dname = dirname; + /* if the directory name starts with / the starting parent directory + * is the root directory. + */ + if (*dirname == '/') + { + parent = root; + dname++; + } + else + parent = *cwd; + + /* allocate memory for the lookups */ + if ((retval = ext2fs_get_mem(fs->blocksize, (void **) &buf))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + + c = *dname; + ptr = dname; + while (c != '\0') + { + len = 0; + /* skip ahead to the next / character */ + while ((c = *ptr) != '/' && c != '\0') + { + len++; + ptr++; + } + + if (c == '/') + *ptr++ = '\0'; + + /* multiple /'s in a row or trailing / */ + if (len == 0) + { + /* restore /'s */ + if (dname > dirname) + *--dname = '/'; + + dname = ptr; + continue; + } + + /* check to see if this file is in the parent directory */ + if ((retval = ext2fs_lookup(fs, parent, dname, len, buf, &child))) + { + if (retval == EXT2_ET_FILE_NOT_FOUND) + { + /* ok, it's not there, so just create it */ + if ((retval = create_subdir(fs, root, &parent, dname, + def_stat))) + { + fprintf(stderr, + "create_dir: error creating directory %s/%s:%d\n", + dirname, dname, retval); + ext2fs_free_mem((void **) &buf); + return(retval); + } + } + else + { + fprintf(stderr, "%s\n", error_message(retval)); + ext2fs_free_mem((void **) &buf); + return retval; + } + } + else + { + /* ok, so the name exists...follow it if it's a symlink + * otherwise, it's a directory so set the parent directory to + * the child inode number + */ + if ((retval = ext2fs_follow_link(fs, root, parent, child, + &parent))) + { + fprintf(stderr, "%s\n", error_message(retval)); + ext2fs_free_mem((void **) &buf); + return retval; + } + + /* now check to see if it's a directory */ + if ((retval = ext2fs_read_inode(fs, parent, &inode))) + { + fprintf(stderr, "%s\n", error_message(retval)); + ext2fs_free_mem((void **) &buf); + return retval; + } + + /* not a directory? something's wrong */ + if (!LINUX_S_ISDIR(inode.i_mode)) + { + fprintf(stderr, "create_dir: %s/%s is not a directory: %o\n", + dirname, dname, inode.i_mode); + ext2fs_free_mem((void **) &buf); + return(-1); + } + } + + /* restore /'s */ + if (dname > dirname) + *--dname = '/'; + dname = ptr; + } + ext2fs_free_mem((void **) &buf); + *cwd = parent; + } + else + { + if ((retval = create_subdir(fs, root, cwd, dirname, def_stat))) + { + fprintf(stderr, + "create_dir: error creating directory %s:%d\n", + dirname, retval); + return(retval); + } + } + return(0); +} /* end of create_dir */ + +/* Name: create_subdir() + * + * Description: + * + * This function will create a sub directory in the given ext2fs file system. + * The current working directory is then set to this new directory. + * + * Algorithm: + * + * Find a new inode number to use + * Create the directory + * + * Global Variables: + * + * None. + * + * Arguments: + * + * ext2_filsys fs; The current file system + * ext2_ino_t root; The inode number of the root directory + * ext2_ino_t *cwd; Pointer to the inode number of the current + * or parent directory + * char *dirname; The directory to create + * struct stat *def_stat; Default directory status, owner, group, etc. + * + * Return Values: + * + * 0 - the directory was created successfully + * error code of what went wrong + * + * Author: Keith W. Sheffield + * Date: 02/18/2002 + * + * Modification History: + * + * MM/DD/YY Name Description + * 04/10/02 K.Sheffield Added a default directory permission + * + */ +long create_subdir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd, + char *dirname, struct stat *def_stat) +{ + ext2_ino_t parent; /* the parent directory inode number*/ + ext2_ino_t child; /* the inode number of the new directory */ + long retval; /* function return value */ + struct ext2_inode inode; + + parent = *cwd; + + if ((retval = ext2fs_namei(fs, root, parent, dirname, &child))) + { + 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, child))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return(retval); + } + else + { + /* if we get here, then it's an existing directory */ + *cwd = child; + return(0); + } + + /* ok, the directory doesn't exist + /* get a new inode number */ + if ((retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &child))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + + /* now create the directory */ + if ((retval = ext2fs_mkdir(fs, parent, child, dirname))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + + *cwd = child; + if (def_stat != NULL && def_stat->st_ino != 0) + { + if ((retval = read_inode(fs, child, &inode))) + return(retval); + + if (def_stat->st_mode != 0) + inode.i_mode = LINUX_S_IFDIR | host_mode_xlate(def_stat->st_mode); + + inode.i_uid = def_stat->st_uid; + inode.i_gid = def_stat->st_gid; + inode.i_atime = def_stat->st_atime; + inode.i_ctime = def_stat->st_ctime; + inode.i_mtime = def_stat->st_mtime; + + if ((retval = write_inode(fs, child, &inode))) + return(retval); + } + + return(0); +} /* end of create_subdir */ + +/* Name: change_cwd() + * + * Description: + * + * This function changes the current working directory + * + * Algorithm: + * + * Look up the inode number for the input string + * check to see if it's a directory + * Assign it as the current working directory if it is. + * + * Global Variables: + * + * None + * + * Arguments: + * + * ext2_filsys fs; The current filesystem + * ext_ino_t root; The root directory + * ext_ino_t *cwd; The current working directory + * char *dirname; The name of the directory we want to change to + * + * Return Values: + * + * 0 - changed to the directory successfully + * the error code of what went wrong + * + * Author: Keith W Sheffield + * Date: 02/21/2002 + * + * Modification History: + * + * MM/DD/YY Name Description + * + */ +long +change_cwd(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd, char *dirname) +{ + ext2_ino_t inode; + long retval; + + if ((retval = ext2fs_namei(fs, root, *cwd, dirname, &inode))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + else if ((retval = ext2fs_check_directory(fs, inode))) + { + fprintf(stderr, "%s\n", error_message(retval)); + return retval; + } + *cwd = inode; + return(0); +} /* end of change_cwd */ |