static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num, ext2_ino_t dir, unsigned long idx, ext2_ino_t *ino) { errcode_t retval; struct ext2_inode inode; retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino); if (retval) return retval; memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFREG | (0666 & ~fs->umask); inode.i_links_count = 1; inode.i_uid = uid & 0xFFFF; ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff); inode.i_gid = gid & 0xFFFF; ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff); retval = ext2fs_write_new_inode(fs, *ino, &inode); if (retval) return retval; ext2fs_inode_alloc_stats2(fs, *ino, +1, 0); if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS)) inode.i_flags |= EXT4_EXTENTS_FL; retval = ext2fs_fallocate(fs, EXT2_FALLOCATE_FORCE_INIT | EXT2_FALLOCATE_ZERO_BLOCKS, *ino, &inode, goal, 0, num); if (retval) return retval; retval = ext2fs_inode_size_set(fs, &inode, num * fs->blocksize); if (retval) return retval; retval = ext2fs_write_inode(fs, *ino, &inode); if (retval) goto errout; if (idx_digits) sprintf(fn_numbuf, "%0*lu", idx_digits, idx); else if (num_files > 1) sprintf(fn_numbuf, "%lu", idx); retry: retval = ext2fs_link(fs, dir, fn_buf, *ino, EXT2_FT_REG_FILE); if (retval == EXT2_ET_DIR_NO_SPACE) { retval = ext2fs_expand_dir(fs, dir); if (retval) goto errout; goto retry; } errout: return retval; }
static errcode_t create_directory(ext2_filsys fs, char *dir, ext2_ino_t *ret_ino) { struct ext2_inode inode; ext2_ino_t ino = EXT2_ROOT_INO; ext2_ino_t newdir; errcode_t retval = 0; char *fn, *cp, *next; fn = malloc(strlen(dir) + 1); if (fn == NULL) return ENOMEM; strcpy(fn, dir); cp = fn; while(1) { next = strchr(cp, '/'); if (next) *next++ = 0; if (*cp) { retval = ext2fs_new_inode(fs, ino, LINUX_S_IFDIR, NULL, &newdir); if (retval) goto errout; retval = ext2fs_mkdir(fs, ino, newdir, cp); if (retval) goto errout; ino = newdir; retval = ext2fs_read_inode(fs, ino, &inode); if (retval) goto errout; inode.i_uid = uid & 0xFFFF; ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff); inode.i_gid = gid & 0xFFFF; ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff); retval = ext2fs_write_inode(fs, ino, &inode); if (retval) goto errout; } if (next == NULL || *next == '\0') break; cp = next; } errout: free(fn); if (retval == 0) *ret_ino = ino; return retval; }
static ext2_ino_t ext2CreateFile(ext2_vd *vd, ext2_inode_t * parent, int type, const char * name) { errcode_t retval = -1; ext2_ino_t newfile = 0; ext2_ino_t existing; if(ext2fs_namei_follow(vd->fs, vd->root, parent->ino, name, &existing) == 0) { errno = EEXIST; return 0; } retval = ext2fs_new_inode(vd->fs, parent->ino, type, 0, &newfile); if (retval) { errno = EFAULT; return 0; } while((retval = ext2fs_link(vd->fs, parent->ino, name, newfile, EXT2_FT_REG_FILE)) == EXT2_ET_DIR_NO_SPACE) { if (ext2fs_expand_dir(vd->fs, parent->ino) != EXT2_ET_OK) { errno = EMLINK; return 0; } } if (retval != EXT2_ET_OK) { errno = EMLINK; return 0; } ext2fs_inode_alloc_stats2(vd->fs, newfile, +1, 0); struct ext2_inode inode; memset(&inode, 0, sizeof(inode)); inode.i_mode = type; inode.i_atime = inode.i_ctime = inode.i_mtime = time(0); inode.i_links_count = 1; inode.i_size = 0; inode.i_uid = parent->ni.i_uid; inode.i_gid = parent->ni.i_gid; if (ext2fs_write_new_inode(vd->fs, newfile, &inode) != 0) return 0; return newfile; }
static ext2_ino_t ext2CreateMkDir(ext2_vd *vd, ext2_inode_t * parent, int type, const char * name) { ext2_ino_t newentry = 0; ext2_ino_t existing; if(ext2fs_namei_follow(vd->fs, vd->root, parent->ino, name, &existing) == 0){ errno = EEXIST; return 0; } errcode_t err = ext2fs_new_inode(vd->fs, parent->ino, type, 0, &newentry); if(err != EXT2_ET_OK) { errno = EFAULT; return 0; } while((err = ext2fs_mkdir(vd->fs, parent->ino, newentry, name)) == EXT2_ET_DIR_NO_SPACE) { if(ext2fs_expand_dir(vd->fs, parent->ino) != EXT2_ET_OK) { errno = EMLINK; return 0; } } if(err != EXT2_ET_OK) { errno = EMLINK; return 0; } struct ext2_inode inode; if(ext2fs_read_inode(vd->fs, newentry, &inode) == EXT2_ET_OK) { inode.i_mode = type; inode.i_uid = parent->ni.i_uid; inode.i_gid = parent->ni.i_gid; ext2fs_write_new_inode(vd->fs, newentry, &inode); } return newentry; }
errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name) { errcode_t retval; struct ext2_inode parent_inode, inode; ext2_ino_t ino = inum; ext2_ino_t scratch_ino; blk_t blk; char *block = 0; char *ext2bp_block = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino); if (retval) goto cleanup; } /* * Allocate a data block for the directory */ retval = ext2fs_new_block(fs, 0, 0, &blk); printf("Using block %lu for the dir\n", blk); if (retval) goto cleanup; printf("Writing the dir info into the buffer\n"); /* * Create a scratch template for the directory */ /* Vijay: Offset the block address by the backpointer information */ retval = ext2fs_new_dir_block(fs, ino, parent, &block); //ext2bp_block = block + EXT2BP_HEADER_SIZE; //retval = ext2fs_new_dir_block(fs, ino, parent, &ext2bp_block); if (retval) goto cleanup; /* * Get the parent's inode, if necessary */ if (parent != ino) { retval = ext2fs_read_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } else memset(&parent_inode, 0, sizeof(parent_inode)); /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); inode.i_uid = inode.i_gid = 0; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; inode.i_links_count = 2; inode.i_size = fs->blocksize; /* Vijay: Adding backlink to the inode - Modifying position 0 * since this is a new inode - It will not have any other links * pointing to it. First, we need to reset all the backlinks. */ printf("Vijay: Adding the backlink to %s\n", name); int i; for(i=0; i < EXT2_N_LINKS; i++) inode.i_backlinks[i] = 0; inode.i_backlinks[0] = parent; printf("Going to write the dir block\n"); /* * Write out the inode and inode data block */ retval = ext2fs_write_dir_block(fs, blk, block); if (retval) goto cleanup; retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; printf("Link the directory into the filesystem hierarchy\n"); /* * Link the directory into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_DIR_EXISTS; name = 0; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); printf("Linking done: %lu\n", retval); if (retval) goto cleanup; } /* * Update parent inode's counts */ if (parent != ino) { parent_inode.i_links_count++; retval = ext2fs_write_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } /* * Update accounting.... */ ext2fs_block_alloc_stats(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); cleanup: if (block) ext2fs_free_mem(&block); return retval; }
static errcode_t file_test(ext2_filsys fs) { struct ext2_inode inode; ext2_ino_t newfile; errcode_t retval; size_t size; char *buf = 0, *cmpbuf = 0; int i; /* create a new file */ retval = ext2fs_new_inode(fs, 2, 010755, 0, &newfile); if (retval) { com_err("file_test", retval, "while allocaing a new inode"); return 1; } memset(&inode, 0, sizeof(inode)); inode.i_flags |= EXT4_INLINE_DATA_FL; inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; inode.i_mode = LINUX_S_IFREG; retval = ext2fs_write_new_inode(fs, newfile, &inode); if (retval) { com_err("file_test", retval, "while writting a new inode"); return 1; } retval = ext2fs_inline_data_init(fs, newfile); if (retval) { com_err("file_test", retval, "while init 'system.data'"); return 1; } retval = ext2fs_inline_data_size(fs, newfile, &size); if (retval) { com_err("file_test", retval, "while getting size"); return 1; } if (size != EXT4_MIN_INLINE_DATA_SIZE) { fprintf(stderr, "tst_inline_data: size of inline data is wrong\n"); return 1; } ext2fs_get_mem(BUFF_SIZE, &buf); memset(buf, 'a', BUFF_SIZE); retval = ext2fs_inline_data_set(fs, newfile, 0, buf, BUFF_SIZE); if (retval) { com_err("file_test", retval, "while setting inline data %s", buf); goto err; } ext2fs_get_mem(BUFF_SIZE, &cmpbuf); retval = ext2fs_inline_data_get(fs, newfile, 0, cmpbuf, &size); if (retval) { com_err("file_test", retval, "while getting inline data"); goto err; } if (size != BUFF_SIZE) { fprintf(stderr, "tst_inline_data: size %lu != buflen %u\n", size, BUFF_SIZE); retval = 1; goto err; } if (memcmp(buf, cmpbuf, BUFF_SIZE)) { fprintf(stderr, "tst_inline_data: buf != cmpbuf\n"); retval = 1; goto err; } retval = ext2fs_punch(fs, newfile, 0, 0, 0, ~0ULL); if (retval) { com_err("file_test", retval, "while truncating inode"); goto err; } /* reload inode and check isize */ ext2fs_read_inode(fs, newfile, &inode); if (inode.i_size != 0) { fprintf(stderr, "tst_inline_data: i_size should be 0\n"); retval = 1; } err: if (cmpbuf) ext2fs_free_mem(&cmpbuf); if (buf) ext2fs_free_mem(&buf); return retval; }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (retval && !fix) return 0; if (!retval) { if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Now let's create the actual data block for the inode */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode) { pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }
errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, const char *name, char *target) { ext2_extent_handle_t handle; errcode_t retval; struct ext2_inode inode; ext2_ino_t scratch_ino; blk64_t blk; int fastlink; unsigned int target_len; char *block_buf = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* The Linux kernel doesn't allow for links longer than a block */ target_len = strlen(target); if (target_len > fs->blocksize) { retval = EXT2_ET_INVALID_ARGUMENT; goto cleanup; } /* * Allocate a data block for slow links */ fastlink = (target_len < sizeof(inode.i_block)); if (!fastlink) { retval = ext2fs_new_block2(fs, 0, 0, &blk); if (retval) goto cleanup; retval = ext2fs_get_mem(fs->blocksize, &block_buf); if (retval) goto cleanup; } /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFLNK | 0755, 0, &ino); if (retval) goto cleanup; } /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFLNK | 0777; inode.i_uid = inode.i_gid = 0; ext2fs_iblk_set(fs, &inode, fastlink ? 0 : 1); inode.i_links_count = 1; inode.i_size = target_len; /* The time fields are set by ext2fs_write_new_inode() */ if (fastlink) { /* Fast symlinks, target stored in inode */ strcpy((char *)&inode.i_block, target); } else { /* Slow symlinks, target stored in the first block */ memset(block_buf, 0, fs->blocksize); strcpy(block_buf, target); if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { /* * The extent bmap is setup after the inode and block * have been written out below. */ inode.i_flags |= EXT4_EXTENTS_FL; } } /* * Write out the inode and inode data block. The inode generation * number is assigned by write_new_inode, which means that the * operations using ino must come after it. */ retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; if (!fastlink) { retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL, &blk); if (retval) goto cleanup; retval = io_channel_write_blk64(fs->io, blk, 1, block_buf); if (retval) goto cleanup; } /* * Link the symlink into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_FILE_EXISTS; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_SYMLINK); if (retval) goto cleanup; } /* * Update accounting.... */ if (!fastlink) ext2fs_block_alloc_stats2(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 0); cleanup: if (block_buf) ext2fs_free_mem(&block_buf); return retval; }
static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num, ext2_ino_t dir, unsigned long idx, ext2_ino_t *ino) { errcode_t retval; blk64_t lblk, bend = 0; __u64 size; blk64_t left; blk64_t count = 0; struct ext2_inode inode; ext2_extent_handle_t handle; retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino); if (retval) return retval; memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFREG | (0666 & ~fs->umask); inode.i_links_count = 1; inode.i_uid = uid & 0xFFFF; ext2fs_set_i_uid_high(inode, (uid >> 16) & 0xffff); inode.i_gid = gid & 0xFFFF; ext2fs_set_i_gid_high(inode, (gid >> 16) & 0xffff); retval = ext2fs_write_new_inode(fs, *ino, &inode); if (retval) return retval; ext2fs_inode_alloc_stats2(fs, *ino, +1, 0); retval = ext2fs_extent_open2(fs, *ino, &inode, &handle); if (retval) return retval; /* * We don't use ext2fs_fallocate() here because hugefiles are * designed to be physically contiguous (if the block group * descriptors are configured to be in a single block at the * beginning of the file system, by using the * packed_meta_blocks layout), with the extent tree blocks * allocated near the beginning of the file system. */ lblk = 0; left = num ? num : 1; while (left) { blk64_t pblk, end; blk64_t n = left; retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map, goal, ext2fs_blocks_count(fs->super) - 1, &end); if (retval) goto errout; goal = end; retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, goal, ext2fs_blocks_count(fs->super) - 1, &bend); if (retval == ENOENT) { bend = ext2fs_blocks_count(fs->super); if (num == 0) left = 0; } if (!num || bend - goal < left) n = bend - goal; pblk = goal; if (num) left -= n; goal += n; count += n; ext2fs_block_alloc_stats_range(fs, pblk, n, +1); if (zero_hugefile) { blk64_t ret_blk; retval = ext2fs_zero_blocks2(fs, pblk, n, &ret_blk, NULL); if (retval) com_err(program_name, retval, _("while zeroing block %llu " "for hugefile"), ret_blk); } while (n) { blk64_t l = n; struct ext2fs_extent newextent; if (l > EXT_INIT_MAX_LEN) l = EXT_INIT_MAX_LEN; newextent.e_len = l; newextent.e_pblk = pblk; newextent.e_lblk = lblk; newextent.e_flags = 0; retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &newextent); if (retval) return retval; pblk += l; lblk += l; n -= l; } } retval = ext2fs_read_inode(fs, *ino, &inode); if (retval) goto errout; retval = ext2fs_iblk_add_blocks(fs, &inode, count / EXT2FS_CLUSTER_RATIO(fs)); if (retval) goto errout; size = (__u64) count * fs->blocksize; retval = ext2fs_inode_size_set(fs, &inode, size); if (retval) goto errout; retval = ext2fs_write_new_inode(fs, *ino, &inode); if (retval) goto errout; if (idx_digits) sprintf(fn_numbuf, "%0*lu", idx_digits, idx); else if (num_files > 1) sprintf(fn_numbuf, "%lu", idx); retry: retval = ext2fs_link(fs, dir, fn_buf, *ino, EXT2_FT_REG_FILE); if (retval == EXT2_ET_DIR_NO_SPACE) { retval = ext2fs_expand_dir(fs, dir); if (retval) goto errout; goto retry; } if (retval) goto errout; errout: if (handle) ext2fs_extent_free(handle); return retval; }
int do_create (ext2_filsys e2fs, const char *path, mode_t mode, dev_t dev, const char *fastsymlink) { int rt; time_t tm; errcode_t rc; char *p_path; char *r_path; ext2_ino_t ino; struct ext2_inode inode; ext2_ino_t n_ino; struct fuse_context *ctx; debugf("enter"); debugf("path = %s, mode: 0%o", path, mode); rt=do_check_split(path, &p_path, &r_path); debugf("parent: %s, child: %s", p_path, r_path); rt = do_readinode(e2fs, p_path, &ino, &inode); if (rt) { debugf("do_readinode(%s, &ino, &inode); failed", p_path); free_split(p_path, r_path); return rt; } rc = ext2fs_new_inode(e2fs, ino, mode, 0, &n_ino); if (rc) { debugf("ext2fs_new_inode(ep.fs, ino, mode, 0, &n_ino); failed"); return -ENOMEM; } do { debugf("calling ext2fs_link(e2fs, %d, %s, %d, %d);", ino, r_path, n_ino, do_modetoext2lag(mode)); rc = ext2fs_link(e2fs, ino, r_path, n_ino, do_modetoext2lag(mode)); if (rc == EXT2_ET_DIR_NO_SPACE) { debugf("calling ext2fs_expand_dir(e2fs, &d)", ino); if (ext2fs_expand_dir(e2fs, ino)) { debugf("error while expanding directory %s (%d)", p_path, ino); free_split(p_path, r_path); return -ENOSPC; } } } while (rc == EXT2_ET_DIR_NO_SPACE); if (rc) { debugf("ext2fs_link(e2fs, %d, %s, %d, %d); failed", ino, r_path, n_ino, do_modetoext2lag(mode)); free_split(p_path, r_path); return -EIO; } if (ext2fs_test_inode_bitmap(e2fs->inode_map, n_ino)) { debugf("inode already set"); } ext2fs_inode_alloc_stats2(e2fs, n_ino, +1, 0); memset(&inode, 0, sizeof(inode)); tm = e2fs->now ? e2fs->now : time(NULL); inode.i_mode = mode; inode.i_atime = inode.i_ctime = inode.i_mtime = tm; inode.i_links_count = 1; inode.i_size = 0; ctx = fuse_get_context(); if (ctx) { inode.i_uid = ctx->uid; inode.i_gid = ctx->gid; } if (S_ISCHR(mode) || S_ISBLK(mode)) { if (old_valid_dev(dev)) inode.i_block[0]= ext2fs_cpu_to_le32(old_encode_dev(dev)); else inode.i_block[1]= ext2fs_cpu_to_le32(new_encode_dev(dev)); } if (S_ISLNK(mode) && fastsymlink != NULL) { inode.i_size = strlen(fastsymlink); strncpy((char *)&(inode.i_block[0]),fastsymlink, (EXT2_N_BLOCKS * sizeof(inode.i_block[0]))); } rc = ext2fs_write_new_inode(e2fs, n_ino, &inode); if (rc) { debugf("ext2fs_write_new_inode(e2fs, n_ino, &inode);"); free_split(p_path, r_path); return -EIO; } /* update parent dir */ rt = do_readinode(e2fs, p_path, &ino, &inode); if (rt) { debugf("do_readinode(%s, &ino, &inode); dailed", p_path); free_split(p_path, r_path); return -EIO; } inode.i_ctime = inode.i_mtime = tm; rc = ext2fs_write_inode(e2fs, ino, &inode); if (rc) { debugf("ext2fs_write_inode(e2fs, ino, &inode); failed"); free_split(p_path, r_path); return -EIO; } free_split(p_path, r_path); debugf("leave"); return 0; }
errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name) { errcode_t retval; struct ext2_inode parent_inode, inode; ext2_ino_t ino = inum; ext2_ino_t scratch_ino; blk_t blk; char *block = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino); if (retval) goto cleanup; } /* * Allocate a data block for the directory */ retval = ext2fs_new_block(fs, 0, 0, &blk); if (retval) goto cleanup; /* * Create a scratch template for the directory */ retval = ext2fs_new_dir_block(fs, ino, parent, &block); if (retval) goto cleanup; /* * Get the parent's inode, if necessary */ if (parent != ino) { retval = ext2fs_read_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } else memset(&parent_inode, 0, sizeof(parent_inode)); /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); inode.i_uid = inode.i_gid = 0; inode.i_blocks = fs->blocksize / 512; inode.i_block[0] = blk; inode.i_links_count = 2; inode.i_ctime = inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(NULL); inode.i_size = fs->blocksize; /* * Write out the inode and inode data block */ retval = ext2fs_write_dir_block(fs, blk, block); if (retval) goto cleanup; retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; /* * Link the directory into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_DIR_EXISTS; name = 0; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); if (retval) goto cleanup; } /* * Update parent inode's counts */ if (parent != ino) { parent_inode.i_links_count++; retval = ext2fs_write_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } /* * Update accounting.... */ ext2fs_block_alloc_stats(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); cleanup: if (block) ext2fs_free_mem(&block); return retval; }
static ext2_ino_t ext2CreateSymlink(ext2_vd *vd, const char *path, const char * targetdir, const char * name, mode_t type) { ext2_inode_t *target_ni = NULL; ext2_ino_t newentry = 0; ext2_ino_t ino = 0; // Check if it does exist target_ni = ext2OpenEntry(vd, targetdir); if (!target_ni) goto cleanup; int err = ext2fs_new_inode(vd->fs, target_ni->ino, type, 0, &ino); if (err) { errno = EFAULT; goto cleanup; } while((err = ext2fs_link(vd->fs, target_ni->ino, name, ino, EXT2_FT_SYMLINK)) == EXT2_ET_DIR_NO_SPACE) { if (ext2fs_expand_dir(vd->fs, target_ni->ino) != EXT2_ET_OK) { errno = EMLINK; goto cleanup; } } if(err != EXT2_ET_OK) { errno = EMLINK; return 0; } ext2fs_inode_alloc_stats2(vd->fs, ino, +1, 0); struct ext2_inode inode; memset(&inode, 0, sizeof(inode)); inode.i_mode = type; inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL); inode.i_links_count = 1; inode.i_size = strlen(path); //initial size of file inode.i_uid = target_ni->ni.i_uid; inode.i_gid = target_ni->ni.i_gid; if (strlen(path) <= sizeof(inode.i_block)) { /* fast symlink */ strncpy((char *)&(inode.i_block[0]),path,sizeof(inode.i_blocks)); } else { /* slow symlink */ char * buffer = mem_alloc(vd->fs->blocksize); if (buffer) { blk_t blk; strncpy(buffer, path, vd->fs->blocksize); err = ext2fs_new_block(vd->fs, 0, 0, &blk); if (!err) { inode.i_block[0] = blk; inode.i_blocks = vd->fs->blocksize / 512; vd->fs->io->manager->write_blk(vd->fs->io, blk, 1, buffer); ext2fs_block_alloc_stats(vd->fs, blk, +1); } mem_free(buffer); } } if(ext2fs_write_new_inode(vd->fs, ino, &inode) != 0) newentry = ino; cleanup: if(target_ni) ext2CloseEntry(vd, target_ni); return newentry; }
errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name) { ext2_extent_handle_t handle; errcode_t retval; struct ext2_inode parent_inode, inode; ext2_ino_t ino = inum; ext2_ino_t scratch_ino; blk64_t blk; char *block = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* * Allocate an inode, if necessary */ if (!ino) { retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino); if (retval) goto cleanup; } /* * Allocate a data block for the directory */ retval = ext2fs_new_block2(fs, 0, 0, &blk); if (retval) goto cleanup; /* * Create a scratch template for the directory */ retval = ext2fs_new_dir_block(fs, ino, parent, &block); if (retval) goto cleanup; /* * Get the parent's inode, if necessary */ if (parent != ino) { retval = ext2fs_read_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } else memset(&parent_inode, 0, sizeof(parent_inode)); /* * Create the inode structure.... */ memset(&inode, 0, sizeof(struct ext2_inode)); inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); inode.i_uid = inode.i_gid = 0; ext2fs_iblk_set(fs, &inode, 1); if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) inode.i_flags |= EXT4_EXTENTS_FL; else inode.i_block[0] = blk; inode.i_links_count = 2; inode.i_size = fs->blocksize; /* * Write out the inode and inode data block */ retval = ext2fs_write_dir_block(fs, blk, block); if (retval) goto cleanup; retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { retval = ext2fs_extent_open2(fs, ino, &inode, &handle); if (retval) goto cleanup; retval = ext2fs_extent_set_bmap(handle, 0, blk, 0); ext2fs_extent_free(handle); if (retval) goto cleanup; } /* * Link the directory into the filesystem hierarchy */ if (name) { retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { retval = EXT2_ET_DIR_EXISTS; name = 0; goto cleanup; } if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); if (retval) goto cleanup; } /* * Update parent inode's counts */ if (parent != ino) { parent_inode.i_links_count++; retval = ext2fs_write_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } /* * Update accounting.... */ ext2fs_block_alloc_stats2(fs, blk, +1); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); cleanup: if (block) ext2fs_free_mem(&block); return retval; }
/* Copy the native file to the fs */ errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src, const char *dest, ext2_ino_t root) { int fd; struct stat statbuf; ext2_ino_t newfile; errcode_t retval; struct ext2_inode inode; int bufsize = IO_BUFSIZE; int make_holes = 0; fd = ext2fs_open_file(src, O_RDONLY, 0); if (fd < 0) { com_err(src, errno, 0); return errno; } if (fstat(fd, &statbuf) < 0) { com_err(src, errno, 0); close(fd); return errno; } retval = ext2fs_namei(fs, root, cwd, dest, &newfile); if (retval == 0) { close(fd); return EXT2_ET_FILE_EXISTS; } retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile); if (retval) { com_err(__func__, retval, 0); close(fd); return retval; } #ifdef DEBUGFS printf("Allocated inode: %u\n", newfile); #endif retval = ext2fs_link(fs, cwd, dest, newfile, EXT2_FT_REG_FILE); if (retval == EXT2_ET_DIR_NO_SPACE) { retval = ext2fs_expand_dir(fs, cwd); if (retval) { com_err(__func__, retval, "while expanding directory"); close(fd); return retval; } retval = ext2fs_link(fs, cwd, dest, newfile, EXT2_FT_REG_FILE); } if (retval) { com_err(dest, retval, 0); close(fd); return errno; } if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile)) com_err(__func__, 0, "Warning: inode already set"); ext2fs_inode_alloc_stats2(fs, newfile, +1, 0); memset(&inode, 0, sizeof(inode)); inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG; inode.i_atime = inode.i_ctime = inode.i_mtime = fs->now ? fs->now : time(0); inode.i_links_count = 1; retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size); if (retval) { com_err(dest, retval, 0); close(fd); return retval; } if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_INLINE_DATA)) { inode.i_flags |= EXT4_INLINE_DATA_FL; } else if (fs->super->s_feature_incompat & 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; } retval = ext2fs_write_new_inode(fs, newfile, &inode); if (retval) { com_err(__func__, retval, "while creating inode %u", newfile); close(fd); return retval; } if (inode.i_flags & EXT4_INLINE_DATA_FL) { retval = ext2fs_inline_data_init(fs, newfile); if (retval) { com_err("copy_file", retval, 0); close(fd); return retval; } } if (LINUX_S_ISREG(inode.i_mode)) { if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) { make_holes = 1; /* * Use I/O blocksize as buffer size when * copying sparse files. */ bufsize = statbuf.st_blksize; } retval = copy_file(fs, fd, newfile, bufsize, make_holes); if (retval) com_err("copy_file", retval, 0); } close(fd); return retval; }
/* Make a special files (block and character devices), fifo's, and sockets */ errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name, struct stat *st) { ext2_ino_t ino; errcode_t retval; struct ext2_inode inode; unsigned long devmajor, devminor, mode; int filetype; switch(st->st_mode & S_IFMT) { case S_IFCHR: mode = LINUX_S_IFCHR; filetype = EXT2_FT_CHRDEV; break; case S_IFBLK: mode = LINUX_S_IFBLK; filetype = EXT2_FT_BLKDEV; break; case S_IFIFO: mode = LINUX_S_IFIFO; filetype = EXT2_FT_FIFO; break; case S_IFSOCK: mode = LINUX_S_IFSOCK; filetype = EXT2_FT_SOCK; break; default: return EXT2_ET_INVALID_ARGUMENT; } if (!(fs->flags & EXT2_FLAG_RW)) { com_err(__func__, 0, "Filesystem opened read/only"); return EROFS; } retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino); if (retval) { com_err(__func__, retval, 0); return retval; } #ifdef DEBUGFS printf("Allocated inode: %u\n", ino); #endif retval = ext2fs_link(fs, cwd, name, ino, filetype); if (retval == EXT2_ET_DIR_NO_SPACE) { retval = ext2fs_expand_dir(fs, cwd); if (retval) { com_err(__func__, retval, "while expanding directory"); return retval; } retval = ext2fs_link(fs, cwd, name, ino, filetype); } if (retval) { com_err(name, retval, 0); return retval; } if (ext2fs_test_inode_bitmap2(fs->inode_map, ino)) com_err(__func__, 0, "Warning: inode already set"); ext2fs_inode_alloc_stats2(fs, ino, +1, 0); memset(&inode, 0, sizeof(inode)); inode.i_mode = mode; inode.i_atime = inode.i_ctime = inode.i_mtime = fs->now ? fs->now : time(0); if (filetype != S_IFIFO) { devmajor = major(st->st_rdev); devminor = minor(st->st_rdev); if ((devmajor < 256) && (devminor < 256)) { inode.i_block[0] = devmajor * 256 + devminor; inode.i_block[1] = 0; } else { inode.i_block[0] = 0; inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) | ((devminor & ~0xff) << 12); } } inode.i_links_count = 1; retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) com_err(__func__, retval, "while creating inode %u", ino); return retval; }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; int will_rehash, flags; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO); if (will_rehash) { flags = ctx->fs->flags; ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; } retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (will_rehash) ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); if (retval && !fix) return 0; if (!retval) { /* Lost+found shouldn't have inline data */ retval = ext2fs_read_inode(fs, ino, &inode); if (fix && retval) return 0; if (fix && (inode.i_flags & EXT4_INLINE_DATA_FL)) { if (!fix_problem(ctx, PR_3_LPF_INLINE_DATA, &pctx)) return 0; goto unlink; } if (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) { if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx)) return 0; goto unlink; } if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; unlink: /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); /* * If the old lost+found was a directory, we've just * disconnected it from the directory tree, which * means we need to restart the directory tree scan. * The simplest way to do this is restart the whole * e2fsck operation. */ if (LINUX_S_ISDIR(inode.i_mode)) ctx->flags |= E2F_FLAG_RESTART; } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ if (ctx->lnf_repair_block) { blk = ctx->lnf_repair_block; ctx->lnf_repair_block = 0; goto skip_new_block; } retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); skip_new_block: ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval == EXT2_ET_INODE_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Now let's create the actual data block for the inode. * Due to metadata_csum, the directory block MUST be written * after the inode is written to disk! */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) { pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO); if (pctx.errcode) goto link_error; pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); } if (pctx.errcode) { link_error: pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }