errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf) { struct mmp_struct *mmp_cmp; errcode_t retval = 0; if ((mmp_blk <= fs->super->s_first_data_block) || (mmp_blk >= fs->super->s_blocks_count)) return EXT2_ET_MMP_BAD_BLOCK; /* ext2fs_open() reserves fd0,1,2 to avoid stdio collision, so checking * mmp_fd <= 0 is OK to validate that the fd is valid. This opens its * own fd to read the MMP block to ensure that it is using O_DIRECT, * regardless of how the io_manager is doing reads, to avoid caching of * the MMP block by the io_manager or the VM. It needs to be fresh. */ if (fs->mmp_fd <= 0) { /* fs->mmp_fd = open(fs->device_name, O_RDWR | O_DIRECT); if (fs->mmp_fd < 0) { retval = EXT2_ET_MMP_OPEN_DIRECT; goto out; } */ } if (fs->mmp_cmp == NULL) { int align = ext2fs_get_dio_alignment(fs->mmp_fd); retval = ext2fs_get_memalign(fs->blocksize, align, &fs->mmp_cmp); if (retval) return retval; } if (ext2fs_llseek(fs->mmp_fd, mmp_blk * fs->blocksize, SEEK_SET) != mmp_blk * fs->blocksize) { retval = EXT2_ET_LLSEEK_FAILED; goto out; } if (read(fs->mmp_fd, fs->mmp_cmp, fs->blocksize) != fs->blocksize) { retval = EXT2_ET_SHORT_READ; goto out; } mmp_cmp = fs->mmp_cmp; #ifdef WORDS_BIGENDIAN ext2fs_swap_mmp(mmp_cmp); #endif if (buf != NULL && buf != fs->mmp_cmp) memcpy(buf, fs->mmp_cmp, fs->blocksize); if (mmp_cmp->mmp_magic != EXT4_MMP_MAGIC) { retval = EXT2_ET_MMP_MAGIC_INVALID; goto out; } out: return retval; }
int main(int argc, char **argv) { int lsectsize, psectsize; int retval; int fd; if (argc < 2) { fprintf(stderr, "Usage: %s device\n", argv[0]); exit(1); } retval = ext2fs_get_device_sectsize(argv[1], &lsectsize); if (retval) { com_err(argv[0], retval, "while calling ext2fs_get_device_sectsize"); exit(1); } retval = ext2fs_get_device_phys_sectsize(argv[1], &psectsize); if (retval) { com_err(argv[0], retval, "while calling ext2fs_get_device_phys_sectsize"); exit(1); } printf("Device %s has logical/physical sector size of %d/%d.\n", argv[1], lsectsize, psectsize); fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); exit(1); } printf("The device's DIO alignment is %d\n", ext2fs_get_dio_alignment(fd)); close(fd); exit(0); }
static errcode_t unix_open(const char *name, int flags, io_channel *channel) { io_channel io = NULL; struct unix_private_data *data = NULL; errcode_t retval; int open_flags, zeroes = 0; int f_nocache = 0; ext2fs_struct_stat st; #ifdef __linux__ struct utsname ut; #endif if (name == 0) return EXT2_ET_BAD_DEVICE_NAME; retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io); if (retval) goto cleanup; memset(io, 0, sizeof(struct struct_io_channel)); io->magic = EXT2_ET_MAGIC_IO_CHANNEL; retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data); if (retval) goto cleanup; io->manager = unix_io_manager; retval = ext2fs_get_mem(strlen(name)+1, &io->name); if (retval) goto cleanup; strcpy(io->name, name); io->private_data = data; io->block_size = 1024; io->read_error = 0; io->write_error = 0; io->refcount = 1; memset(data, 0, sizeof(struct unix_private_data)); data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; data->io_stats.num_fields = 2; open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY; if (flags & IO_FLAG_EXCLUSIVE) open_flags |= O_EXCL; #if defined(O_DIRECT) if (flags & IO_FLAG_DIRECT_IO) { open_flags |= O_DIRECT; io->align = ext2fs_get_dio_alignment(data->dev); } #elif defined(F_NOCACHE) if (flags & IO_FLAG_DIRECT_IO) { f_nocache = F_NOCACHE; io->align = 4096; } #endif data->flags = flags; data->dev = ext2fs_open_file(io->name, open_flags, 0); if (data->dev < 0) { retval = errno; goto cleanup; } if (f_nocache) { if (fcntl(data->dev, f_nocache, 1) < 0) { retval = errno; goto cleanup; } } /* * If the device is really a block device, then set the * appropriate flag, otherwise we can set DISCARD_ZEROES flag * because we are going to use punch hole instead of discard * and if it succeed, subsequent read from sparse area returns * zero. */ if (ext2fs_stat(io->name, &st) == 0) { if (S_ISBLK(st.st_mode)) io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE; else io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; } #ifdef BLKDISCARDZEROES ioctl(data->dev, BLKDISCARDZEROES, &zeroes); if (zeroes) io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; #endif #if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) /* * Some operating systems require that the buffers be aligned, * regardless of O_DIRECT */ if (!io->align) io->align = 512; #endif if ((retval = alloc_cache(io, data))) goto cleanup; #ifdef BLKROGET if (flags & IO_FLAG_RW) { int error; int readonly = 0; /* Is the block device actually writable? */ error = ioctl(data->dev, BLKROGET, &readonly); if (!error && readonly) { close(data->dev); retval = EPERM; goto cleanup; } } #endif #ifdef __linux__ #undef RLIM_INFINITY #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4))) #define RLIM_INFINITY ((unsigned long)(~0UL>>1)) #else #define RLIM_INFINITY (~0UL) #endif /* * Work around a bug in 2.4.10-2.4.18 kernels where writes to * block devices are wrongly getting hit by the filesize * limit. This workaround isn't perfect, since it won't work * if glibc wasn't built against 2.2 header files. (Sigh.) * */ if ((flags & IO_FLAG_RW) && (uname(&ut) == 0) && ((ut.release[0] == '2') && (ut.release[1] == '.') && (ut.release[2] == '4') && (ut.release[3] == '.') && (ut.release[4] == '1') && (ut.release[5] >= '0') && (ut.release[5] < '8')) && (ext2fs_stat(io->name, &st) == 0) && (S_ISBLK(st.st_mode))) { struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY; setrlimit(RLIMIT_FSIZE, &rlim); getrlimit(RLIMIT_FSIZE, &rlim); if (((unsigned long) rlim.rlim_cur) < ((unsigned long) rlim.rlim_max)) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_FSIZE, &rlim); } } #endif *channel = io; return 0; cleanup: if (data) { free_cache(data); ext2fs_free_mem(&data); } if (io) ext2fs_free_mem(&io); return retval; }
errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest) { ext2_filsys fs; errcode_t retval; EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS); retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); if (retval) return retval; *fs = *src; fs->device_name = 0; fs->super = 0; fs->orig_super = 0; fs->group_desc = 0; fs->inode_map = 0; fs->block_map = 0; fs->badblocks = 0; fs->dblist = 0; fs->mmp_buf = 0; fs->mmp_cmp = 0; fs->mmp_fd = -1; io_channel_bumpcount(fs->io); if (fs->icache) fs->icache->refcount++; retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name); if (retval) goto errout; strcpy(fs->device_name, src->device_name); retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super); if (retval) goto errout; memcpy(fs->super, src->super, SUPERBLOCK_SIZE); retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super); if (retval) goto errout; memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE); retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, &fs->group_desc); if (retval) goto errout; memcpy(fs->group_desc, src->group_desc, (size_t) fs->desc_blocks * fs->blocksize); if (src->inode_map) { retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map); if (retval) goto errout; } if (src->block_map) { retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map); if (retval) goto errout; } if (src->badblocks) { retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks); if (retval) goto errout; } if (src->dblist) { retval = ext2fs_copy_dblist(src->dblist, &fs->dblist); if (retval) goto errout; } if (src->mmp_buf) { retval = ext2fs_get_mem(src->blocksize, &fs->mmp_buf); if (retval) goto errout; memcpy(fs->mmp_buf, src->mmp_buf, src->blocksize); } if (src->mmp_fd >= 0) { fs->mmp_fd = dup(src->mmp_fd); if (fs->mmp_fd < 0) { retval = EXT2_ET_MMP_OPEN_DIRECT; goto errout; } } if (src->mmp_cmp) { int align = ext2fs_get_dio_alignment(src->mmp_fd); retval = ext2fs_get_memalign(src->blocksize, align, &fs->mmp_cmp); if (retval) goto errout; memcpy(fs->mmp_cmp, src->mmp_cmp, src->blocksize); } *dest = fs; return 0; errout: ext2fs_free(fs); return retval; }