summaryrefslogtreecommitdiffstats
path: root/write.c
diff options
context:
space:
mode:
Diffstat (limited to 'write.c')
-rw-r--r--write.c377
1 files changed, 377 insertions, 0 deletions
diff --git a/write.c b/write.c
new file mode 100644
index 0000000..5f74332
--- /dev/null
+++ b/write.c
@@ -0,0 +1,377 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/write.c,v 0.5 2004/04/07 01:12:30 ksheff Exp $ */
+/*
+ * write.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>
+ */
+
+static char rcsid[] = "$Id: write.c,v 0.5 2004/04/07 01:12:30 ksheff Exp $";
+
+#ifndef WRITE_C
+#define WRITE_C
+#endif
+
+/* Description */
+/* This file contains the functions used to write a file to an ext2fs
+ * filesystem.
+ *
+ */
+/*
+ * $Log: write.c,v $
+ * Revision 0.5 2004/04/07 01:12:30 ksheff
+ * Modified to use a default file stat specified by the user.
+ *
+ * Revision 0.4 2002/07/08 11:16:11 ksheff
+ * Additional error messages after perror().
+ *
+ * Revision 0.3 2002/06/26 11:12:48 ksheff
+ * Modified to call update_progress() so that the user can know the state of
+ * the file copy operation. The put_file function also calls ext2fs_flush()
+ * before exiting now.
+ *
+ * Revision 0.2 2002/03/07 07:15:40 ksheff
+ * Added parameter to put_file so that the original file's owner, group,
+ * permission bits, access, modification, and creation times would be used.
+ *
+ * Revision 0.1 2002/02/27 04:49:32 ksheff
+ * initial revision
+ *
+ */
+
+/* Headers */
+
+#include "e2tools.h"
+
+/* External Prototypes */
+
+extern void init_progress(char *file, struct stat *sbuf);
+extern void update_progress(unsigned long num_bytes);
+extern void finish_progress();
+
+/* Local Prototypes */
+
+long
+put_file(ext2_filsys fs, ext2_ino_t cwd, char *infile, char *outfile,
+ ext2_ino_t *outfile_ino, int keep, struct stat *def_stat);
+
+static long
+store_data(ext2_filsys fs, int fd, ext2_ino_t newfile, off_t *file_size);
+
+/* Name: put_file()
+ *
+ * Description:
+ *
+ * This function copies a file from disk or stdin to the current directory
+ *
+ * Algorithm:
+ *
+ * Check input parameters
+ * If the input file is NULL
+ * Get the file descriptor for stdin
+ * Initialize a file stat structure
+ * Otherwise
+ * Open the input file
+ * Get the file stat structure for the file
+ * Get a new inode for the file
+ * Link the inode to the currect directory
+ * If this fails because there isn't enough room in the directory
+ * Expand the directory and try again
+ * Set the file statistics for the current inode
+ * If the file is a regular file
+ * Copy it to the current inode
+ * Close the input file
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * ext2_ino_t cwd; The current working directory
+ * char *infile; The name of the input file
+ * char *outfile; The name of the output file
+ * int keep; Flag indicating to use the input file's stat info
+ * struct stat *def_stat; The default file stat information
+ *
+ * Return Values:
+ *
+ * 0 - the file was copied successfully
+ * any other value indicates an error
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/17/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 02/27/02 K.Sheffield Added parameter to pass back to caller the
+ * inode number of the output file.
+ * 03/05/02 K.Sheffield Fixed a bug with reading from stdin
+ * 03/06/02 K.Sheffield Added time/owner/group keep flag
+ * 06/26/02 K.Sheffield Flush file system added at the end
+ * 07/08/02 K.Sheffield Additional error messages after perror()
+ * 04/06/04 K.Sheffield Added a default file stat parameter
+ */
+long
+put_file(ext2_filsys fs, ext2_ino_t cwd, char *infile, char *outfile,
+ ext2_ino_t *outfile_ino, int keep, struct stat *def_stat)
+{
+ int fd;
+ struct stat statbuf;
+ ext2_ino_t newfile;
+ long retval;
+ struct ext2_inode inode;
+ mode_t cur_umask;
+
+ if (fs == NULL || outfile == NULL)
+ {
+ fputs("Invalid input parameter. Exiting put_file() with -1\n",
+ stderr);
+ return (-1);
+ }
+
+ if (infile == NULL)
+ {
+ fd = fileno(stdin);
+ memset(&statbuf, 0, sizeof(statbuf));
+ }
+ else
+ {
+ if (0 > (fd = open(infile, O_RDONLY)))
+ {
+ perror(infile);
+ fprintf(stderr, "Error opening input file: %s\n", infile);
+ return(-1);
+ }
+ if (0 > fstat(fd, &statbuf))
+ {
+ perror(infile);
+ fprintf(stderr, "Error stat()'ing input file: %s\n", infile);
+ close(fd);
+ return(-1);
+ }
+ }
+
+ if (keep == 0 || infile == NULL)
+ {
+ statbuf.st_atime = statbuf.st_ctime = statbuf.st_mtime = time(NULL);
+ umask(cur_umask = umask(0)); /* get the current umask */
+ if (def_stat != NULL)
+ {
+ statbuf.st_mode = S_IFREG |
+ ((def_stat->st_mode == 0) ? (0666 & ~cur_umask):def_stat->st_mode);
+ statbuf.st_uid = def_stat->st_uid;
+ statbuf.st_gid = def_stat->st_gid;
+ }
+ else
+ {
+ statbuf.st_mode = S_IFREG | (0666 & ~cur_umask);
+ statbuf.st_uid = getuid();
+ statbuf.st_gid = getgid();
+ }
+ }
+
+ if ((retval = ext2fs_namei(fs, cwd, cwd, outfile, &newfile)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ close(fd);
+ return(retval);
+ }
+
+ }
+ /* file name exists, let's see if is a directory */
+ else if ((retval = ext2fs_check_directory(fs, newfile)))
+ {
+ if (retval != EXT2_ET_NO_DIRECTORY ||
+ (retval = rm_file(fs, cwd, outfile, newfile)))
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ close(fd);
+ return(retval);
+ }
+ }
+ else
+ {
+ /* if we get here, then it's an existing directory */
+ fprintf(stderr, "%s is a directory!\n", outfile);
+ return(1);
+ }
+
+ /* ok, create a new inode and directory entry */
+ if ((retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ close(fd);
+ return retval;
+ }
+
+ if ((retval = ext2fs_link(fs, cwd, outfile, newfile, EXT2_FT_REG_FILE)))
+ {
+ /* 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, outfile, newfile,
+ EXT2_FT_REG_FILE);
+ }
+ if (retval)
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ close(fd);
+ return retval;
+ }
+ }
+ ext2fs_inode_alloc_stats(fs, newfile, +1);
+ memset(&inode, 0, sizeof(inode));
+ inode.i_mode = host_mode_xlate(statbuf.st_mode);
+ inode.i_atime = statbuf.st_atime;
+ inode.i_ctime = statbuf.st_ctime;
+ inode.i_mtime = statbuf.st_mtime;
+ inode.i_links_count = 1;
+ inode.i_size = statbuf.st_size;
+ inode.i_uid = statbuf.st_uid;
+ inode.i_gid = statbuf.st_gid;
+
+ if ((retval = write_inode(fs, newfile, &inode)))
+ {
+ close(fd);
+ return (retval);
+ }
+
+ if (LINUX_S_ISREG(inode.i_mode) &&
+ (retval = store_data(fs, fd, newfile, &statbuf.st_size)))
+ {
+ close(fd);
+#ifndef DEBUG
+ rm_file(fs, cwd, outfile, newfile);
+
+#endif
+ return(retval);
+ }
+
+ close(fd);
+
+ /* if we were reading from standard input, figure out the size of
+ * the file and save it.
+ */
+
+ if (infile == NULL)
+ {
+ if ((retval = read_inode(fs, newfile, &inode)))
+ return(retval);
+
+ inode.i_size = statbuf.st_size;
+
+ if ((retval = write_inode(fs, newfile, &inode)))
+ return(retval);
+ }
+
+ /* save the files inode number for later use */
+ if (outfile_ino != NULL)
+ *outfile_ino = newfile;
+
+ return(ext2fs_flush(fs));
+
+} /* end of put_file */
+
+/* Name: store_data()
+ *
+ * Description:
+ *
+ * This function stores the contents of a file descriptor into the current ext2
+ * file system
+ *
+ * Algorithm:
+ *
+ * Open a new file in the ext2 file system
+ * While data can be read from the input file descriptor
+ * Write the data to the file on the ext2 filesystem
+ * Close the file
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * int fd; Input file descriptor
+ * ext2_ino_t newfile; Inode number of the new file
+ * off_t *file_size; The size of the file written
+ *
+ * Return Values:
+ *
+ * 0 - file copied successfully
+ * otherwise the error code of what went wrong
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/18/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 06/26/02 K.Sheffield Added a call to update_progress()
+ */
+static long
+store_data(ext2_filsys fs, int fd, ext2_ino_t newfile, off_t *file_size)
+{
+ ext2_file_t outfile;
+ long retval;
+ int bytes_read;
+ unsigned int bytes_written;
+ char buf[8192];
+ char *ptr;
+ off_t total = 0;
+
+ if ((retval = ext2fs_file_open(fs, newfile, EXT2_FILE_WRITE, &outfile)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ ext2fs_file_close(outfile);
+ *file_size = 0;
+ return retval;
+ }
+
+ while (0 < (bytes_read = read(fd, buf, sizeof(buf))))
+ {
+ ptr = buf;
+ while (bytes_read > 0)
+ {
+ if ((retval = ext2fs_file_write(outfile, ptr, bytes_read,
+ &bytes_written)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ ext2fs_file_close(outfile);
+ *file_size = total;
+ return retval;
+ }
+ bytes_read -= bytes_written;
+ total += bytes_written;
+ ptr += bytes_written;
+ }
+ update_progress((unsigned long) total);
+ }
+
+ if (bytes_read < 0)
+ {
+ perror("store_data");
+ retval = errno;
+ }
+ else
+ retval = 0;
+
+ finish_progress();
+
+ ext2fs_file_close(outfile);
+ *file_size = total;
+ return retval;
+
+} /* end of store_data */
+