#define FUSE_USE_VERSION 26 #include #include #include #include #include #include #include #include #include "block_device.h" #include "raw_blockfs_util.h" block_device *bd; void *blockbuf; static int raw_block_getattr(const char *path, struct stat *stbuf) { // Notes: see 'man 2 stat' for stbuf doc memset(stbuf, 0, sizeof(struct stat)); int is_dir; int k = parse_path(path, bd->n_block, &is_dir); if (k < 0) return -ENOENT; else if(is_dir) { // This is a directory, // Make mode mode 555 (ugo+rx), so everyone can read (writing not allowed) stbuf->st_mode = S_IFDIR | 0555; // two links, one for '.', one for parent dir stbuf->st_nlink = 2; } else { // This is a block file // Make mode 666 (ugo+rw) so anyone can read/write stbuf->st_mode = S_IFREG | 0666; stbuf->st_nlink = 1; // one for parent dir stbuf->st_size = bd->block_size; } return 0; } static int raw_block_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { (void) offset; // just here to keep warnings about unused params away (void) fi; int is_dir; int k = parse_path(path, bd->n_block, &is_dir); if (k < 0 || !is_dir) return -ENOENT; filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); char entname[2]; // entry name is a single char 0-9 entname[1]='\0';// null terminated string int i; for (i = 0;i <= k; i++){ entname[0] = '0' + i; // write the char name in filler(buf, entname, NULL, 0); } return 0; } static int raw_block_open(const char *path, struct fuse_file_info *fi) { int is_dir; int k = parse_path(path, bd->n_block, &is_dir); if (k < 0 || is_dir) return -ENOENT; // Stash the block number into the file handle field. // This is field provided by the API for user convenience. // Further file operations (e.g. read and write) can use // this instead of manipulating path. fi->fh = k; return 0; } char pbuf[1024]; static int raw_block_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int k = fi->fh; // Use stashed block number int rc = bd_read(bd, k, blockbuf); if (rc < 0) return -EIO;// I/O error if (offset < bd->block_size) { if ( (offset + size) > bd->block_size) size = bd->block_size - offset; memcpy(buf, blockbuf + offset, size); } else { size = 0; } return size; } static int raw_block_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int k = fi->fh; // read the block in int rc = bd_read(bd, k, blockbuf); if (rc < 0) return -EIO;// I/O error if (offset+size > bd->block_size) return -EFBIG; // File exceeds max size memcpy(blockbuf + offset, buf, size); // write block back out rc = bd_write(bd, k, blockbuf); if (rc < 0) return -EIO;// I/O error return size; } static int raw_block_truncate(const char *path, off_t size) { int is_dir; int k = parse_path(path, bd->n_block, &is_dir); if (k < 0 || is_dir) return -ENOENT; if ( size > bd->block_size) return -EFBIG; // Too big return 0; // Pretend any other truncation 'just works' } static struct fuse_operations raw_block_oper = { .getattr = raw_block_getattr, .readdir = raw_block_readdir, .open = raw_block_open, .read = raw_block_read, .write = raw_block_write, .truncate = raw_block_truncate }; void usage(){ printf("usage: \n"); exit(1); }; int main(int argc, char *argv[]) { if (argc != 3) usage(); // Grab out the block device path first. char *path = argv[1]; bd = bd_open(path); if (!bd){ printf("Unable to open block device %s", path); perror("bd_open"); } blockbuf = malloc_block(bd); char *fuse_argv[100]; int fuse_argc = argc-1; fuse_argv[0] = argv[0]; int i; for (i = 2; i < argc; i++){ fuse_argv[i-1] = argv[i]; } int rc = fuse_main(fuse_argc, fuse_argv, &raw_block_oper, NULL); bd_close(bd); return rc; }