1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 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 */
|