From 4f2949ac4c466b3243a5c2db0eaf87c58c40a8cb Mon Sep 17 00:00:00 2001 From: Christophe Grenier Date: Tue, 27 May 2008 00:17:02 +0200 Subject: [PATCH] support for file copy from ext2/ext3 --- src/dir.c | 51 +++++++++++++++++++++++++++++++++ src/dir.h | 1 + src/ext2_dir.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 128 insertions(+), 1 deletion(-) diff --git a/src/dir.c b/src/dir.c index 7cc8323b..251931d4 100644 --- a/src/dir.c +++ b/src/dir.c @@ -731,3 +731,54 @@ int filesort(const struct td_list_head *a, const struct td_list_head *b) /* Files and directories are sorted by name */ return strcmp(file_a->name,file_b->name); } + +/* + * The mode_xlate function translates a linux mode into a native-OS mode_t. + */ + +static struct { + unsigned int lmask; + mode_t mask; +} mode_table[] = { + { LINUX_S_IRUSR, S_IRUSR }, + { LINUX_S_IWUSR, S_IWUSR }, + { LINUX_S_IXUSR, S_IXUSR }, + { LINUX_S_IRGRP, S_IRGRP }, + { LINUX_S_IWGRP, S_IWGRP }, + { LINUX_S_IXGRP, S_IXGRP }, + { LINUX_S_IROTH, S_IROTH }, + { LINUX_S_IWOTH, S_IWOTH }, + { LINUX_S_IXOTH, S_IXOTH }, + { 0, 0 } +}; + +static mode_t mode_xlate(unsigned int lmode) +{ + mode_t mode = 0; + int i; + + for (i=0; mode_table[i].lmask; i++) { + if (lmode & mode_table[i].lmask) + mode |= mode_table[i].mask; + } + return mode; +} + +/** + * set_mode - Set the file's date and time + * @pathname: Path and name of the file to alter + * @mode: Mode using LINUX values + * + * Give a file a particular mode. + * + * Return: 1 Success, set the file's mode + * 0 Error, failed to change the file's mode + */ +int set_mode(const char *pathname, unsigned int mode) +{ +#if defined(HAVE_CHMOD) && ! ( defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) || defined(__OS2__)) + return chmod(pathname, mode_xlate(mode)); +#else + return 0; +#endif +} diff --git a/src/dir.h b/src/dir.h index 08d77be5..f9c58acd 100644 --- a/src/dir.h +++ b/src/dir.h @@ -74,6 +74,7 @@ int dir_whole_partition_log(disk_t *disk_car, const partition_t *partition, dir_ void mode_string (const unsigned int mode, char *str); FILE *create_file(const char *filename); int set_date(const char *pathname, time_t actime, time_t modtime); +int set_mode(const char *pathname, unsigned int mode); #define LINUX_S_IFMT 00170000 #define LINUX_S_IFSOCK 0140000 diff --git a/src/ext2_dir.c b/src/ext2_dir.c index 22bef022..a7470939 100644 --- a/src/ext2_dir.c +++ b/src/ext2_dir.c @@ -27,6 +27,9 @@ #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_ERRNO_H +#include +#endif #ifdef HAVE_SYS_STAT_H #include #endif @@ -66,6 +69,7 @@ static errcode_t my_flush(io_channel channel); static io_channel alloc_io_channel(disk_t *disk_car,my_data_t *my_data); static void dir_partition_ext2_close(dir_data_t *dir_data); +static int ext2_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_data_t *file); static struct struct_io_manager my_struct_manager = { magic: EXT2_ET_MAGIC_IO_MANAGER, @@ -293,7 +297,7 @@ int dir_partition_ext2_init(disk_t *disk_car, const partition_t *partition, dir_ dir_data->verbose=verbose; dir_data->capabilities=0; dir_data->get_dir=ext2_dir; - dir_data->copy_file=NULL; + dir_data->copy_file=ext2_copy; dir_data->close=&dir_partition_ext2_close; dir_data->local_dir=NULL; dir_data->private_dir_data=ls; @@ -303,6 +307,77 @@ int dir_partition_ext2_init(disk_t *disk_car, const partition_t *partition, dir_ #endif } +static int ext2_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_data_t *file) +{ + int error=0; + FILE *f_out; + struct ext2_dir_struct *ls = (struct ext2_dir_struct *)dir_data->private_dir_data; + char *new_file; + { + int l1=strlen(dir_data->local_dir); + int l2=strlen(dir_data->current_directory); + new_file=MALLOC(l1+l2+1); + l1=filename_convert(new_file, dir_data->local_dir, l1+1); + filename_convert(new_file+l1, dir_data->current_directory, l2+1); + } + f_out=create_file(new_file); + if(!f_out) + { + log_critical("Can't create file %s: %s\n", new_file, strerror(errno)); + free(new_file); + return -4; + } + { + errcode_t retval; + struct ext2_inode inode; + char buffer[8192]; + ext2_file_t e2_file; + int nbytes; + unsigned int got; + + if (ext2fs_read_inode(ls->current_fs, file->filestat.st_ino, &inode)!=0) + { + free(new_file); + return -1; + } + + retval = ext2fs_file_open(ls->current_fs, file->filestat.st_ino, 0, &e2_file); + if (retval) { + log_error("Error while opening ext2 file %s\n", dir_data->current_directory); + free(new_file); + return -2; + } + while (1) + { + retval = ext2fs_file_read(e2_file, buffer, sizeof(buffer), &got); + if (retval) + { + log_error("Error while reading ext2 file %s\n", dir_data->current_directory); + error=-3; + } + if (got == 0) + break; + nbytes = fwrite(buffer, 1, got, f_out); + if ((unsigned) nbytes != got) + { + log_error("Error while writing file %s\n", new_file); + error=-5; + } + } + retval = ext2fs_file_close(e2_file); + if (retval) + { + log_error("Error while closing ext2 file\n"); + error=-6; + } + fclose(f_out); + set_date(new_file, file->filestat.st_atime, file->filestat.st_mtime); + set_mode(new_file, file->filestat.st_mode); + } + free(new_file); + return error; +} + const char*td_ext2fs_version(void) { const char *ext2fs_version="none";