static errcode_t get_file(ext2_filsys fs, const char * filename, struct mem_file *ret_file) { errcode_t retval; char *buf; ext2_file_t e2_file = NULL; unsigned int got; struct ext2_inode inode; ext2_ino_t ino; ret_file->buf = 0; ret_file->size = 0; ret_file->ptr = 0; retval = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename, &ino); if (retval) return retval; retval = ext2fs_read_inode(fs, ino, &inode); if (retval) return retval; if (inode.i_size_high || (inode.i_size > 65536)) return EFBIG; buf = malloc(inode.i_size + 1); if (!buf) return ENOMEM; memset(buf, 0, inode.i_size+1); retval = ext2fs_file_open(fs, ino, 0, &e2_file); if (retval) goto errout; retval = ext2fs_file_read(e2_file, buf, inode.i_size, &got); if (retval) goto errout; retval = ext2fs_file_close(e2_file); if (retval) goto errout; ret_file->buf = buf; ret_file->size = (int) got; return 0; errout: free(buf); if (e2_file) ext2fs_file_close(e2_file); return retval; }
void ext2CloseFile (ext2_file_state *file) { // Sanity check if (!file || !file->vd) return; ext2fs_file_close(file->fd); // Sync the file (and its attributes) to disc if(file->write) ext2UpdateTimes(file->vd, file->ni, EXT2_UPDATE_ACTIME); if (file->read) ext2UpdateTimes(file->vd, file->ni, EXT2_UPDATE_ATIME); ext2Sync(file->vd, file->ni); // Close the file (if open) if (file->ni) ext2CloseEntry(file->vd, file->ni); // Reset the file state file->ni = NULL; file->fd = NULL; file->flags = 0; file->read = false; file->write = false; file->append = false; return; }
int ext2lib_close(fsi_file_t *file) { ext2_file_t *f = fsip_file_data(file); ext2fs_file_close(*f); free(f); return (0); }
errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) { int retval = 0, i; dict_t *dict; ext2_filsys fs; struct quota_handle *h = NULL; int fmt = QFMT_VFS_V1; if (!qctx) return 0; fs = qctx->fs; retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); if (retval) { log_err("Unable to allocate quota handle", ""); goto out; } ext2fs_read_bitmaps(fs); for (i = 0; i < MAXQUOTAS; i++) { if ((qtype != -1) && (i != qtype)) continue; dict = qctx->quota_dict[i]; if (!dict) continue; retval = quota_file_create(h, fs, i, fmt); if (retval < 0) { log_err("Cannot initialize io on quotafile", ""); continue; } write_dquots(dict, h); retval = quota_file_close(h); if (retval < 0) { log_err("Cannot finish IO on new quotafile: %s", strerror(errno)); if (h->qh_qf.e2_file) ext2fs_file_close(h->qh_qf.e2_file); quota_inode_truncate(fs, h->qh_qf.ino); continue; } /* Set quota inode numbers in superblock. */ quota_set_sb_inum(fs, h->qh_qf.ino, i); ext2fs_mark_super_dirty(fs); ext2fs_mark_bb_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } ext2fs_write_bitmaps(fs); out: if (h) ext2fs_free_mem(&h); return retval; }
errcode_t write_quota_inode(quota_ctx_t qctx, int qtype) { int retval, i; unsigned long qf_inums[MAXQUOTAS]; struct dquot *dquot; dict_t *dict; ext2_filsys fs; struct quota_handle *h; int fmt = QFMT_VFS_V1; if (!qctx) return; fs = qctx->fs; h = smalloc(sizeof(struct quota_handle)); ext2fs_read_bitmaps(fs); for (i = 0; i < MAXQUOTAS; i++) { if ((qtype != -1) && (i != qtype)) continue; dict = qctx->quota_dict[i]; if (!dict) continue; retval = new_io(h, fs, i, fmt); if (retval < 0) { log_err("Cannot initialize io on quotafile", ""); continue; } write_dquots(dict, h); retval = end_io(h); if (retval < 0) { log_err("Cannot finish IO on new quotafile: %s", strerror(errno)); if (h->qh_qf.e2_file) ext2fs_file_close(h->qh_qf.e2_file); truncate_quota_inode(fs, h->qh_qf.ino); continue; } /* Set quota inode numbers in superblock. */ set_sb_quota_inum(fs, h->qh_qf.ino, i); ext2fs_mark_super_dirty(fs); ext2fs_mark_bb_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } ext2fs_write_bitmaps(fs); out: free(h); return retval; }
static void rdump_symlink(ext2_ino_t ino, struct ext2_inode *inode, const char *fullname) { ext2_file_t e2_file; char *buf; errcode_t retval; buf = malloc(inode->i_size + 1); if (!buf) { com_err("rdump", errno, "while allocating for symlink"); goto errout; } /* Apparently, this is the right way to detect and handle fast * symlinks; see do_stat() in debugfs.c. */ if (inode->i_blocks == 0) strcpy(buf, (char *) inode->i_block); else { unsigned bytes = inode->i_size; char *p = buf; retval = ext2fs_file_open(current_fs, ino, 0, &e2_file); if (retval) { com_err("rdump", retval, "while opening symlink"); goto errout; } for (;;) { unsigned int got; retval = ext2fs_file_read(e2_file, p, bytes, &got); if (retval) { com_err("rdump", retval, "while reading symlink"); goto errout; } bytes -= got; p += got; if (got == 0 || bytes == 0) break; } buf[inode->i_size] = 0; retval = ext2fs_file_close(e2_file); if (retval) com_err("rdump", retval, "while closing symlink"); } if (symlink(buf, fullname) == -1) { com_err("rdump", errno, "while creating symlink %s -> %s", buf, fullname); goto errout; } errout: free(buf); }
static void dump_file(const char *cmdname, ext2_ino_t ino, int fd, int preserve, char *outname) { errcode_t retval; struct ext2_inode inode; char *buf = 0; ext2_file_t e2_file; int nbytes; unsigned int got, blocksize = current_fs->blocksize; if (debugfs_read_inode(ino, &inode, cmdname)) return; retval = ext2fs_file_open(current_fs, ino, 0, &e2_file); if (retval) { com_err(cmdname, retval, "while opening ext2 file"); return; } retval = ext2fs_get_mem(blocksize, &buf); if (retval) { com_err(cmdname, retval, "while allocating memory"); return; } while (1) { retval = ext2fs_file_read(e2_file, buf, blocksize, &got); if (retval) com_err(cmdname, retval, "while reading ext2 file"); if (got == 0) break; nbytes = write(fd, buf, got); if ((unsigned) nbytes != got) com_err(cmdname, errno, "while writing file"); } if (buf) ext2fs_free_mem(&buf); retval = ext2fs_file_close(e2_file); if (retval) { com_err(cmdname, retval, "while closing ext2 file"); return; } if (preserve) fix_perms("dump_file", &inode, fd, outname); else if (fd != 1) close(fd); return; }
static errcode_t inode_close(io_channel channel) { struct inode_private_data *data; errcode_t retval = 0; EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); data = (struct inode_private_data *) channel->private_data; EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL); if (--channel->refcount > 0) return 0; retval = ext2fs_file_close(data->file); ext2fs_free_mem(&channel->private_data); if (channel->name) ext2fs_free_mem(&channel->name); ext2fs_free_mem(&channel); return retval; }
static errcode_t ext2fs_inline_data_file_expand(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, char *buf, size_t size) { ext2_file_t e2_file; errcode_t retval; /* Update inode */ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS)) { int i; struct ext3_extent_header *eh; eh = (struct ext3_extent_header *) &inode->i_block[0]; eh->eh_depth = 0; eh->eh_entries = 0; eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC); i = (sizeof(inode->i_block) - sizeof(*eh)) / sizeof(struct ext3_extent); eh->eh_max = ext2fs_cpu_to_le16(i); inode->i_flags |= EXT4_EXTENTS_FL; } inode->i_flags &= ~EXT4_INLINE_DATA_FL; inode->i_size = 0; retval = ext2fs_write_inode(fs, ino, inode); if (retval) return retval; /* Write out the block buffer */ retval = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file); if (retval) return retval; retval = ext2fs_file_write(e2_file, buf, size, 0); ext2fs_file_close(e2_file); return retval; }
static void print_inline_journal_information(ext2_filsys fs) { journal_superblock_t *jsb; struct ext2_inode inode; ext2_file_t journal_file; errcode_t retval; ino_t ino = fs->super->s_journal_inum; char buf[1024]; __u32 *mask_ptr, mask, m; int i, j, size, printed = 0; if (fs->flags & EXT2_FLAG_IMAGE_FILE) return; retval = ext2fs_read_inode(fs, ino, &inode); if (retval) { com_err(program_name, retval, "%s", _("while reading journal inode")); exit(1); } retval = ext2fs_file_open2(fs, ino, &inode, 0, &journal_file); if (retval) { com_err(program_name, retval, "%s", _("while opening journal inode")); exit(1); } retval = ext2fs_file_read(journal_file, buf, sizeof(buf), 0); if (retval) { com_err(program_name, retval, "%s", _("while reading journal super block")); exit(1); } ext2fs_file_close(journal_file); jsb = (journal_superblock_t *) buf; if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) { fprintf(stderr, "%s", _("Journal superblock magic number invalid!\n")); exit(1); } printf("%s", _("Journal features: ")); for (i=0, mask_ptr=&jsb->s_feature_compat; i <3; i++,mask_ptr++) { mask = be32_to_cpu(*mask_ptr); for (j=0,m=1; j < 32; j++, m<<=1) { if (mask & m) { printf(" %s", e2p_jrnl_feature2string(i, m)); printed++; } } } if (printed == 0) printf(" (none)"); printf("\n"); fputs(_("Journal size: "), stdout); if ((fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && (inode.i_flags & EXT4_HUGE_FILE_FL)) size = inode.i_blocks / (fs->blocksize / 1024); else size = inode.i_blocks >> 1; if (size < 8192) printf("%uk\n", size); else printf("%uM\n", size >> 10); printf(_("Journal length: %u\n" "Journal sequence: 0x%08x\n" "Journal start: %u\n"), (unsigned int)ntohl(jsb->s_maxlen), (unsigned int)ntohl(jsb->s_sequence), (unsigned int)ntohl(jsb->s_start)); if (jsb->s_feature_compat & ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM)) printf(_("Journal checksum type: crc32\n")); if (jsb->s_feature_incompat & ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2)) printf(_("Journal checksum type: %s\n" "Journal checksum: 0x%08x\n"), journal_checksum_type_str(jsb->s_checksum_type), ext2fs_be32_to_cpu(jsb->s_checksum)); if (jsb->s_errno != 0) printf(_("Journal errno: %d\n"), (int) ntohl(jsb->s_errno)); }
void do_logdump(int argc, char **argv) { int c; int retval; char *out_fn; FILE *out_file; char *inode_spec = NULL; char *journal_fn = NULL; int journal_fd = 0; int use_sb = 0; ext2_ino_t journal_inum; struct ext2_inode journal_inode; ext2_file_t journal_file; char *tmp; struct journal_source journal_source; struct ext2_super_block *es = NULL; journal_source.where = 0; journal_source.fd = 0; journal_source.file = 0; dump_all = 0; dump_contents = 0; dump_descriptors = 1; block_to_dump = ANY_BLOCK; bitmap_to_dump = -1; inode_block_to_dump = ANY_BLOCK; inode_to_dump = -1; reset_getopt(); while ((c = getopt (argc, argv, "ab:ci:f:s")) != EOF) { switch (c) { case 'a': dump_all++; break; case 'b': block_to_dump = strtoul(optarg, &tmp, 0); if (*tmp) { com_err(argv[0], 0, "Bad block number - %s", optarg); return; } dump_descriptors = 0; break; case 'c': dump_contents++; break; case 'f': journal_fn = optarg; break; case 'i': inode_spec = optarg; dump_descriptors = 0; break; case 's': use_sb++; break; default: goto print_usage; } } if (optind != argc && optind != argc-1) { goto print_usage; } if (current_fs) es = current_fs->super; if (inode_spec) { int inode_group, group_offset, inodes_per_block; if (check_fs_open(argv[0])) return; inode_to_dump = string_to_inode(inode_spec); if (!inode_to_dump) return; inode_group = ((inode_to_dump - 1) / es->s_inodes_per_group); group_offset = ((inode_to_dump - 1) % es->s_inodes_per_group); inodes_per_block = (current_fs->blocksize / sizeof(struct ext2_inode)); inode_block_to_dump = current_fs->group_desc[inode_group].bg_inode_table + (group_offset / inodes_per_block); inode_offset_to_dump = ((group_offset % inodes_per_block) * sizeof(struct ext2_inode)); printf("Inode %u is at group %u, block %u, offset %u\n", inode_to_dump, inode_group, inode_block_to_dump, inode_offset_to_dump); } if (optind == argc) { out_file = stdout; } else { out_fn = argv[optind]; out_file = fopen(out_fn, "w"); if (!out_file < 0) { com_err(argv[0], errno, "while opening %s for logdump", out_fn); return; } } if (block_to_dump != ANY_BLOCK && current_fs != NULL) { group_to_dump = ((block_to_dump - es->s_first_data_block) / es->s_blocks_per_group); bitmap_to_dump = current_fs->group_desc[group_to_dump].bg_block_bitmap; } if (!journal_fn && check_fs_open(argv[0])) return; if (journal_fn) { /* Set up to read journal from a regular file somewhere */ journal_fd = open(journal_fn, O_RDONLY, 0); if (journal_fd < 0) { com_err(argv[0], errno, "while opening %s for logdump", journal_fn); return; } journal_source.where = JOURNAL_IS_EXTERNAL; journal_source.fd = journal_fd; } else if ((journal_inum = es->s_journal_inum)) { if (use_sb) { if (es->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS) { com_err(argv[0], 0, "no journal backup in super block\n"); return; } memset(&journal_inode, 0, sizeof(struct ext2_inode)); memcpy(&journal_inode.i_block[0], es->s_jnl_blocks, EXT2_N_BLOCKS*4); journal_inode.i_size = es->s_jnl_blocks[16]; journal_inode.i_links_count = 1; journal_inode.i_mode = LINUX_S_IFREG | 0600; } else { if (debugfs_read_inode(journal_inum, &journal_inode, argv[0])) return; } retval = ext2fs_file_open2(current_fs, journal_inum, &journal_inode, 0, &journal_file); if (retval) { com_err(argv[0], retval, "while opening ext2 file"); return; } journal_source.where = JOURNAL_IS_INTERNAL; journal_source.file = journal_file; } else { char uuid[37]; uuid_unparse(es->s_journal_uuid, uuid); journal_fn = blkid_get_devname(NULL, "UUID", uuid); if (!journal_fn) journal_fn = blkid_devno_to_devname(es->s_journal_dev); if (!journal_fn) { com_err(argv[0], 0, "filesystem has no journal"); return; } journal_fd = open(journal_fn, O_RDONLY, 0); if (journal_fd < 0) { com_err(argv[0], errno, "while opening %s for logdump", journal_fn); free(journal_fn); return; } fprintf(out_file, "Using external journal found at %s\n", journal_fn); free(journal_fn); journal_source.where = JOURNAL_IS_EXTERNAL; journal_source.fd = journal_fd; } dump_journal(argv[0], out_file, &journal_source); if (journal_source.where == JOURNAL_IS_INTERNAL) ext2fs_file_close(journal_file); else close(journal_fd); if (out_file != stdout) fclose(out_file); return; print_usage: fprintf(stderr, "%s: Usage: logdump [-ac] [-b<block>] [-i<inode>]\n\t" "[-f<journal_file>] [output_file]\n", argv[0]); }
/* Name: tail() * * Description: * * This function displays the last lines at the end of a file in an ext2 * file system. * * Algorithm: * * Get the directory and basename of the file * Determine the inode number for the file * Open the file for reading * Skip to the last block in the file * While we have not found the last num_lines of newline characters * Skip backwards in the file one block and read it * Display the contents of the block from that point on. * Display the rest of the file if not contained in the block * Save the current location of the file. * If we are following the file as it grows * While forever * Sleep * Re-read the inode for the file * If the size has changed * Display the file from the saved point on * Save the current location of the file. * * * Global Variables: * * None * * Arguments: * * ext2_filsys *fs; Our filesystem * ext2_ino_t root; The root directory inode number * char *input; The name of the input file to tail * int num_lines; The number of lines to display * int follow; Flag indicating if the we should follow any * new contents to the file. * int sleep_int; The number of seconds to sleep between checking * for new lines * char *cur_filesys * * Return Values: * * 0 - the last number of lines was displayed correctly. * an error occurred. * * Author: Keith W. Sheffield * Date: 08/07/2002 * * Modification History: * * MM/DD/YY Name Description */ static long tail(ext2_filsys *fs_ptr, ext2_ino_t root, char *input, int num_lines, int follow, int sleep_int, char *cur_filesys) { ext2_filsys fs = *fs_ptr; ext2_ino_t cwd; ext2_ino_t tail_ino; ext2_ino_t t_tail_ino; char *tail_dir; char *tail_name; long retval; char buf[BLK_SIZE]; unsigned int bytes_to_read; unsigned int bytes_read; char *ptr; struct ext2_inode inode; ext2_file_t tail_fd; ext2_off_t offset; ext2_off_t cur_pos; if (get_file_parts(fs, root, input, &cwd, &tail_dir, &tail_name)) { ext2fs_close(fs); return(-1); } /* get the inode number for the source file */ if ((retval = ext2fs_namei(fs, cwd, cwd, tail_name, &tail_ino))) { fprintf(stderr, "%s: file %s\n",error_message(retval), tail_name); return(retval); } /* open the file */ if ((retval = ext2fs_file_open(fs, tail_ino, 0, &tail_fd))) { fputs(error_message(retval), stderr); return retval; } /* get the length of the file and determine where to start reading */ inode.i_size = offset = ext2fs_file_get_size(tail_fd); bytes_to_read = offset % BLK_SIZE; if (bytes_to_read == 0) bytes_to_read = BLK_SIZE; offset -= bytes_to_read; if (((int32_t)offset) < 0) offset = 0; do { /* seek to the start of the last block in the file */ if ((retval = ext2fs_file_lseek(tail_fd, offset, EXT2_SEEK_SET, NULL))) { fputs(error_message(retval), stderr); return retval; } /* read the last block in the file */ if ((retval = ext2fs_file_read(tail_fd, buf, bytes_to_read, &bytes_read))) { fputs(error_message(retval), stderr); return retval; } if (bytes_to_read != bytes_read) { fputs("error reading file\n", stderr); return(-1); } ptr = buf + bytes_read - 1; while (bytes_to_read--) { if (*ptr == '\n' && num_lines-- == 0) { /* if the newline wasn't the last character in the buffer, then * print what's remaining. */ if (bytes_to_read != bytes_read - 1) { ptr++; if (0 > write(1, ptr, bytes_read - bytes_to_read - 1)) { perror("writing bytes to stdout"); return -1; } } offset = 0; /* make sure we break out of the main loop */ break; } ptr--; } offset -= (offset < BLK_SIZE) ? offset : BLK_SIZE; bytes_to_read = BLK_SIZE; } while (offset > 0); /* if we are here and have any lines left, we hit the beginning, so * dump the rest of what's in memory out. */ if (num_lines > 0) { if (0 > write(1, buf, bytes_read)) { perror("writing bytes to stdout"); return -1; } } /* retreive the current position in the file */ if ((retval = ext2fs_file_lseek(tail_fd, 0, EXT2_SEEK_CUR, &cur_pos))) { fputs(error_message(retval), stderr); return retval; } /* ok, if we are before the end of the file, then dump the rest of it */ if (cur_pos < inode.i_size) { if ((retval = read_to_eof(tail_fd, 1, cur_pos, &cur_pos))) { return retval; } } if ((retval = ext2fs_file_close(tail_fd))) { fputs(error_message(retval), stderr); return retval; } if (follow) { while(1) { sleep(sleep_int); /* I don't know how to force a re-read of the file system info yet, * so, just close the file system and reopen it. */ ext2fs_close(fs); if ((retval = open_filesystem(cur_filesys, &fs, &root, 0))) { *fs_ptr = NULL; fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys); return retval; } *fs_ptr = fs; /* if we are following the name, find the directory and file name * again. */ if (follow == FOLLOW_NAME) { cwd = root; if (tail_dir != NULL && *tail_dir != '\0' && strcmp(tail_dir, ",") != 0 && (retval = change_cwd(fs, root, &cwd, tail_dir))) { fprintf(stderr, "Error changing to directory %s\n", tail_dir); return(retval); } /* get the inode number for the source file */ if ((retval = ext2fs_namei(fs, cwd, cwd, tail_name, &t_tail_ino))) { fprintf(stderr, "%s: file %s\n",error_message(retval), tail_name); return(retval); } /* if we are dealing with a new file, then start from the * beginning. */ if (t_tail_ino != tail_ino) { tail_ino = t_tail_ino; cur_pos = 0; } } if ((retval = ext2fs_read_inode(fs, tail_ino, &inode))) { fputs(error_message(retval), stderr); return retval; } if (inode.i_size > cur_pos) { if ((retval = retrieve_data(fs, tail_ino, 1, NULL, 0, cur_pos, &cur_pos))) { fputs(error_message(retval), stderr); return retval; } } else if (inode.i_size < cur_pos) { /* the file was truncated, so bail */ return(0); } } } return(0); }
errcode_t quota_write_inode(quota_ctx_t qctx, unsigned int qtype_bits) { int retval = 0; enum quota_type qtype; dict_t *dict; ext2_filsys fs; struct quota_handle *h = NULL; int fmt = QFMT_VFS_V1; if (!qctx) return 0; fs = qctx->fs; retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); if (retval) { log_debug("Unable to allocate quota handle: %s", error_message(retval)); goto out; } retval = ext2fs_read_bitmaps(fs); if (retval) { log_debug("Couldn't read bitmaps: %s", error_message(retval)); goto out; } for (qtype = 0; qtype < MAXQUOTAS; qtype++) { if (((1 << qtype) & qtype_bits) == 0) continue; dict = qctx->quota_dict[qtype]; if (!dict) continue; retval = quota_file_create(h, fs, qtype, fmt); if (retval) { log_debug("Cannot initialize io on quotafile: %s", error_message(retval)); goto out; } write_dquots(dict, h); retval = quota_file_close(qctx, h); if (retval) { log_debug("Cannot finish IO on new quotafile: %s", strerror(errno)); if (h->qh_qf.e2_file) ext2fs_file_close(h->qh_qf.e2_file); (void) quota_inode_truncate(fs, h->qh_qf.ino); goto out; } /* Set quota inode numbers in superblock. */ quota_set_sb_inum(fs, h->qh_qf.ino, qtype); ext2fs_mark_super_dirty(fs); ext2fs_mark_bb_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } retval = ext2fs_write_bitmaps(fs); if (retval) { log_debug("Couldn't write bitmaps: %s", error_message(retval)); goto out; } out: if (h) ext2fs_free_mem(&h); return retval; }
static errcode_t copy_file(ext2_filsys fs, int fd, ext2_ino_t newfile, int bufsize, int make_holes) { ext2_file_t e2_file; errcode_t retval, close_ret; int got; unsigned int written; char *buf; char *ptr; char *zero_buf; int cmp; retval = ext2fs_file_open(fs, newfile, EXT2_FILE_WRITE, &e2_file); if (retval) return retval; retval = ext2fs_get_mem(bufsize, &buf); if (retval) { com_err("copy_file", retval, "can't allocate buffer\n"); goto out_close; } /* This is used for checking whether the whole block is zero */ retval = ext2fs_get_memzero(bufsize, &zero_buf); if (retval) { com_err("copy_file", retval, "can't allocate zero buffer\n"); goto out_free_buf; } while (1) { got = read(fd, buf, bufsize); if (got == 0) break; if (got < 0) { retval = errno; goto fail; } ptr = buf; /* Sparse copy */ if (make_holes) { /* Check whether all is zero */ cmp = memcmp(ptr, zero_buf, got); if (cmp == 0) { /* The whole block is zero, make a hole */ retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL); if (retval) goto fail; got = 0; } } /* Normal copy */ while (got > 0) { retval = ext2fs_file_write(e2_file, ptr, got, &written); if (retval) goto fail; got -= written; ptr += written; } } fail: ext2fs_free_mem(&zero_buf); out_free_buf: ext2fs_free_mem(&buf); out_close: close_ret = ext2fs_file_close(e2_file); if (retval == 0) retval = close_ret; return retval; }
static int ext2_copy(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_info_t *file) { int error=0; FILE *f_out; const struct ext2_dir_struct *ls = (const struct ext2_dir_struct *)dir_data->private_dir_data; char *new_file; f_out=fopen_local(&new_file, dir_data->local_dir, dir_data->current_directory); 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; if (ext2fs_read_inode(ls->current_fs, file->st_ino, &inode)!=0) { free(new_file); fclose(f_out); return -1; } retval = ext2fs_file_open(ls->current_fs, file->st_ino, 0, &e2_file); if (retval) { log_error("Error while opening ext2 file %s\n", dir_data->current_directory); free(new_file); fclose(f_out); return -2; } while (1) { int nbytes; unsigned int got; 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->td_atime, file->td_mtime); (void)set_mode(new_file, file->st_mode); } free(new_file); return error; }