int build_jindex(struct gfs2_sbd *sdp) { struct gfs2_inode *jindex; unsigned int j; int ret; jindex = createi(sdp->master_dir, "jindex", S_IFDIR | 0700, GFS2_DIF_SYSTEM); if (jindex == NULL) { return errno; } sdp->md.journal = malloc(sdp->md.journals * sizeof(struct gfs2_inode *)); for (j = 0; j < sdp->md.journals; j++) { ret = build_journal(sdp, j, jindex); if (ret) return ret; inode_put(&sdp->md.journal[j]); } if (cfg_debug) { printf("\nJindex:\n"); gfs2_dinode_print(&jindex->i_di); } free(sdp->md.journal); inode_put(&jindex); return 0; }
/* * Removes a directory entry. */ PUBLIC int sys_unlink(const char *path) { int ret; /* Return value. */ struct inode *dir; /* Working directory. */ const char *filename; /* Working file name. */ char *pathname; /* Path name. */ pathname = getname(path); dir = inode_dname(pathname, &filename); /* Failed to get directory. */ if (dir == NULL) { putname(pathname); return (-ENOENT); } /* No write permissions on directory. */ if (!permission(dir->mode, dir->uid, dir->gid, curr_proc, MAY_WRITE, 0)) { inode_put(dir); putname(pathname); return (-EPERM); } ret = dir_remove(dir, filename); inode_put(dir); putname(pathname); return (ret); }
/** * Write a jindex file given a list of journal inums. * master: Inode of the master directory * jnls: List of inum structures relating to previously created journals. * nmemb: The number of entries in the list (number of journals). * Returns 0 on success or non-zero on error with errno set. */ int lgfs2_build_jindex(struct gfs2_inode *master, struct gfs2_inum *jnls, size_t nmemb) { char fname[GFS2_FNAMESIZE + 1]; struct gfs2_inode *jindex; unsigned j; int ret; if (nmemb == 0 || jnls == NULL) { errno = EINVAL; return 1; } jindex = createi(master, "jindex", S_IFDIR | 0700, GFS2_DIF_SYSTEM); if (jindex == NULL) return 1; fname[GFS2_FNAMESIZE] = '\0'; for (j = 0; j < nmemb; j++) { snprintf(fname, GFS2_FNAMESIZE, "journal%u", j); ret = dir_add(jindex, fname, strlen(fname), &jnls[j], IF2DT(S_IFREG | 0600)); if (ret) { inode_put(&jindex); return 1; } } if (cfg_debug) { printf("\nJindex:\n"); gfs2_dinode_print(&jindex->i_di); } inode_put(&jindex); return 0; }
/* * Removes an entry from a directory. */ PUBLIC int dir_remove(struct inode *dinode, const char *filename) { struct buffer *buf; /* Block buffer. */ struct d_dirent *d; /* Directory entry. */ struct inode *file; /* File inode. */ d = dirent_search(dinode, filename, &buf, 0); /* Not found. */ if (d == NULL) return (-ENOENT); /* Cannot remove '.' */ if (d->d_ino == dinode->num) { brelse(buf); return (-EBUSY); } file = inode_get(dinode->dev, d->d_ino); /* Failed to get file's inode. */ if (file == NULL) { brelse(buf); return (-ENOENT); } /* Unlinking directory. */ if (S_ISDIR(file->mode)) { /* Not allowed. */ if (!IS_SUPERUSER(curr_proc)) { inode_put(file); brelse(buf); return (-EPERM); } /* Directory not empty. */ if (dinode->size) { inode_put(file); brelse(buf); return (-EBUSY); } } /* Remove directory entry. */ d->d_ino = INODE_NULL; buf->flags |= BUFFER_DIRTY; inode_touch(dinode); file->nlinks--; inode_touch(file); inode_put(file); brelse(buf); return (0); }
/** * Look up and return the inode for a path name. * If nameiparent is true, return the inode for the parent and copy the final * path element into name, which must have room for DIRSIZ bytes. * Returns 0 in the case of error. */ static struct inode* namex(char *path, bool nameiparent, char *name) { struct inode *ip; struct inode *next; // If path is a full path, get the pointer to the root inode. Otherwise get // the inode corresponding to the current working directory. if(*path == '/'){ ip = inode_get(ROOTDEV, ROOTINO); } else { ip = inode_dup((struct inode*) tcb_get_cwd(get_curid())); } while((path = skipelem(path, name)) != 0){ inode_lock(ip); if(ip -> type != T_DIR) { return 0; } if(nameiparent && *path == 0) { inode_unlock(ip); return ip; } next = dir_lookup(ip, name, 0); inode_unlockput(ip); ip = next; } if(nameiparent){ inode_put(ip); return 0; } return ip; }
int build_quota(struct gfs2_sbd *sdp) { struct gfs2_inode *ip; struct gfs2_quota qu; char buf[sizeof(struct gfs2_quota)]; int count; ip = createi(sdp->master_dir, "quota", S_IFREG | 0600, GFS2_DIF_SYSTEM | GFS2_DIF_JDATA); if (ip == NULL) { return errno; } ip->i_di.di_payload_format = GFS2_FORMAT_QU; bmodified(ip->i_bh); memset(&qu, 0, sizeof(struct gfs2_quota)); qu.qu_value = 1; gfs2_quota_out(&qu, buf); count = gfs2_writei(ip, buf, ip->i_di.di_size, sizeof(struct gfs2_quota)); if (count != sizeof(struct gfs2_quota)) return -1; count = gfs2_writei(ip, buf, ip->i_di.di_size, sizeof(struct gfs2_quota)); if (count != sizeof(struct gfs2_quota)) return -1; if (cfg_debug) { printf("\nRoot quota:\n"); gfs2_quota_print(&qu); } inode_put(&ip); return 0; }
int build_per_node(struct gfs2_sbd *sdp) { struct gfs2_inode *per_node; unsigned int j; int err; per_node = createi(sdp->master_dir, "per_node", S_IFDIR | 0700, GFS2_DIF_SYSTEM); if (per_node == NULL) { return errno; } for (j = 0; j < sdp->md.journals; j++) { err = build_inum_range(per_node, j); if (err) { return err; } err = build_statfs_change(per_node, j); if (err) { return err; } err = build_quota_change(per_node, j); if (err) { return err; } } if (cfg_debug) { printf("\nper_node:\n"); gfs2_dinode_print(&per_node->i_di); } inode_put(&per_node); return 0; }
/** * find_journal_block - figure out where a journal starts, given the name * Returns: journal block number, changes j_size to the journal size */ uint64_t find_journal_block(const char *journal, uint64_t *j_size) { int journal_num; uint64_t jindex_block, jblock = 0; int amtread; struct gfs2_buffer_head *jindex_bh, *j_bh; char jbuf[sbd.bsize]; journal_num = atoi(journal + 7); if (journal_num < 0) return 0; /* Figure out the block of the jindex file */ if (sbd.gfs1) jindex_block = sbd1->sb_jindex_di.no_addr; else jindex_block = masterblock("jindex"); /* read in the block */ jindex_bh = bread(&sbd, jindex_block); /* get the dinode data from it. */ gfs2_dinode_in(&di, jindex_bh); /* parse disk inode to struct*/ if (!sbd.gfs1) do_dinode_extended(&di, jindex_bh); /* parse dir. */ if (sbd.gfs1) { struct gfs2_inode *jiinode; struct gfs_jindex ji; jiinode = lgfs2_inode_get(&sbd, jindex_bh); if (jiinode == NULL) return 0; amtread = gfs2_readi(jiinode, (void *)&jbuf, journal_num * sizeof(struct gfs_jindex), sizeof(struct gfs_jindex)); if (amtread) { gfs_jindex_in(&ji, jbuf); jblock = ji.ji_addr; *j_size = ji.ji_nsegment * 0x10; } inode_put(&jiinode); } else { struct gfs2_dinode jdi; if (journal_num > indirect->ii[0].dirents - 2) return 0; jblock = indirect->ii[0].dirent[journal_num + 2].block; j_bh = bread(&sbd, jblock); gfs2_dinode_in(&jdi, j_bh);/* parse dinode to struct */ *j_size = jdi.di_size; brelse(j_bh); } brelse(jindex_bh); return jblock; }
/* * Changes working directory. */ PUBLIC int sys_chroot(const char *path) { struct inode *inode; inode = inode_name(path); /* Failed to get inode. */ if (inode == NULL) return (curr_proc->errno); /* Not a directory. */ if (!S_ISDIR(inode->mode)) { inode_put(inode); return (-ENOTDIR); } inode_put(curr_proc->root); curr_proc->root = inode; inode_unlock(inode); return (0); }
int build_statfs(struct gfs2_sbd *sdp) { struct gfs2_inode *ip; ip = createi(sdp->master_dir, "statfs", S_IFREG | 0600, GFS2_DIF_SYSTEM | GFS2_DIF_JDATA); if (ip == NULL) { return errno; } if (cfg_debug) { printf("\nStatFS Inode:\n"); gfs2_dinode_print(&ip->i_di); } inode_put(&ip); return 0; }
int build_quota_change(struct gfs2_inode *per_node, unsigned int j) { struct gfs2_sbd *sdp = per_node->i_sbd; struct gfs2_meta_header mh; char name[256]; struct gfs2_inode *ip; unsigned int blocks = sdp->qcsize << (20 - sdp->sd_sb.sb_bsize_shift); unsigned int x; unsigned int hgt; struct gfs2_buffer_head *bh; memset(&mh, 0, sizeof(struct gfs2_meta_header)); mh.mh_magic = GFS2_MAGIC; mh.mh_type = GFS2_METATYPE_QC; mh.mh_format = GFS2_FORMAT_QC; sprintf(name, "quota_change%u", j); ip = createi(per_node, name, S_IFREG | 0600, GFS2_DIF_SYSTEM); if (ip == NULL) { return errno; } hgt = calc_tree_height(ip, (blocks + 1) * sdp->bsize); build_height(ip, hgt); for (x = 0; x < blocks; x++) { bh = get_file_buf(ip, x, FALSE); if (!bh) return -1; memset(bh->b_data, 0, sdp->bsize); gfs2_meta_header_out(&mh, bh->b_data); bmodified(bh); brelse(bh); } if (cfg_debug) { printf("\nQuota Change %u:\n", j); gfs2_dinode_print(&ip->i_di); } inode_put(&ip); return 0; }
/* * Closes a file. */ PUBLIC void do_close(int fd) { struct inode *i; /* Inode. */ struct file *f; /* File. */ f = curr_proc->ofiles[fd]; /* Not opened. */ if (f == NULL) return; curr_proc->close &= ~(1 << fd); curr_proc->ofiles[fd] = NULL; if (--f->count) return; inode_lock(i = f->inode); inode_put(i); }
int build_rindex(struct gfs2_sbd *sdp) { struct gfs2_inode *ip; struct osi_node *n, *next = NULL; struct rgrp_tree *rl; char buf[sizeof(struct gfs2_rindex)]; int count; ip = createi(sdp->master_dir, "rindex", S_IFREG | 0600, GFS2_DIF_SYSTEM | GFS2_DIF_JDATA); if (ip == NULL) { return errno; } ip->i_di.di_payload_format = GFS2_FORMAT_RI; bmodified(ip->i_bh); for (n = osi_first(&sdp->rgtree); n; n = next) { next = osi_next(n); rl = (struct rgrp_tree *)n; gfs2_rindex_out(&rl->ri, buf); count = gfs2_writei(ip, buf, ip->i_di.di_size, sizeof(struct gfs2_rindex)); if (count != sizeof(struct gfs2_rindex)) return -1; } memset(buf, 0, sizeof(struct gfs2_rindex)); count = __gfs2_writei(ip, buf, ip->i_di.di_size, sizeof(struct gfs2_rindex), 0); if (count != sizeof(struct gfs2_rindex)) return -1; if (cfg_debug) { printf("\nResource Index:\n"); gfs2_dinode_print(&ip->i_di); } inode_put(&ip); return 0; }
int build_statfs_change(struct gfs2_inode *per_node, unsigned int j) { char name[256]; struct gfs2_inode *ip; sprintf(name, "statfs_change%u", j); ip = createi(per_node, name, S_IFREG | 0600, GFS2_DIF_SYSTEM | GFS2_DIF_JDATA); if (ip == NULL) { return errno; } ip->i_di.di_size = sizeof(struct gfs2_statfs_change); gfs2_dinode_out(&ip->i_di, ip->i_bh->b_data); bmodified(ip->i_bh); if (cfg_debug) { printf("\nStatFS Change %u:\n", j); gfs2_dinode_print(&ip->i_di); } inode_put(&ip); return 0; }
int op_getattr(const char *path, struct stat *stbuf) { struct ext4_inode raw_inode; struct inode *inode; int ret = 0; uint64_t size; DEBUG("getattr(%s)", path); memset(stbuf, 0, sizeof(struct stat)); ret = inode_get_by_path(path, &raw_inode); if (ret < 0) { return ret; } inode = inode_get(0, &raw_inode); if (!inode) return -ENOMEM; size = inode_get_size(inode); inode_put(inode); DEBUG("getattr done"); stbuf->st_mode = raw_inode.i_mode; stbuf->st_nlink = raw_inode.i_links_count; stbuf->st_size = size; stbuf->st_blocks = raw_inode.i_blocks_lo; stbuf->st_uid = raw_inode.i_uid; stbuf->st_gid = raw_inode.i_gid; stbuf->st_atime = raw_inode.i_atime; stbuf->st_mtime = raw_inode.i_mtime; stbuf->st_ctime = raw_inode.i_ctime; return 0; }
/** * Close file f. (Decrement ref count, close when reaches 0.) */ void file_close(struct file *f) { struct file ff; spinlock_acquire(&ftable.lock); if(f->ref < 1) KERN_PANIC("file_close"); if(--f->ref > 0){ spinlock_release(&ftable.lock); return; } ff = *f; f->ref = 0; f->type = FD_NONE; spinlock_release(&ftable.lock); if(ff.type == FD_INODE){ begin_trans(); inode_put(ff.ip); commit_trans(); } }
/** * dump_journal - dump a journal file's contents. * @journal: name of the journal to dump * @tblk: block number to trace in the journals * * This function dumps the contents of a journal. If a trace block is specified * then only information printed is: (1) log descriptors that reference that * block, (2) metadata in the journal that references the block, or (3) * rgrp bitmaps that reference that block's allocation bit status. */ void dump_journal(const char *journal, int tblk) { struct gfs2_buffer_head *j_bh = NULL, dummy_bh; uint64_t jblock, j_size, jb, abs_block, saveblk, wrappt = 0; int start_line, journal_num; struct gfs2_inode *j_inode = NULL; int ld_blocks = 0, offset_from_ld = 0; uint64_t tblk_off = 0, bblk_off = 0, bitblk = 0; uint64_t highest_seq = 0; char *jbuf = NULL; struct rgrp_tree *rgd = NULL; uint64_t abs_ld = 0; start_line = line; lines_per_row[dmode] = 1; journal_num = atoi(journal + 7); print_gfs2("Dumping journal #%d.", journal_num); if (tblk) { dmode = HEX_MODE; print_gfs2(" Tracing block 0x%llx", (unsigned long long)tblk); } eol(0); jblock = find_journal_block(journal, &j_size); if (!jblock) return; if (!sbd.gfs1) { j_bh = bread(&sbd, jblock); j_inode = lgfs2_inode_get(&sbd, j_bh); if (j_inode == NULL) { fprintf(stderr, "Out of memory\n"); exit(-1); } jbuf = malloc(sbd.bsize); if (jbuf == NULL) { fprintf(stderr, "Out of memory\n"); exit(-1); } } if (tblk) { uint64_t wp; rgd = gfs2_blk2rgrpd(&sbd, tblk); if (!rgd) { print_gfs2("Can't locate the rgrp for block 0x%x", tblk); eol(0); } else { uint64_t o; int bmap = 0; print_gfs2("rgd: 0x%llx for 0x%x, ", rgd->ri.ri_addr, rgd->ri.ri_length); o = tblk - rgd->ri.ri_data0; if (o >= (rgd->bits->bi_start + rgd->bits->bi_len) * GFS2_NBBY) o += (sizeof(struct gfs2_rgrp) - sizeof(struct gfs2_meta_header)) * GFS2_NBBY; bmap = o / sbd.sd_blocks_per_bitmap; bitblk = rgd->ri.ri_addr + bmap; print_gfs2("bitmap: %d, bitblk: 0x%llx", bmap, (unsigned long long)bitblk); eol(0); } wrappt = find_wrap_pt(j_inode, jbuf, jblock, j_size); wp = wrappt / (sbd.gfs1 ? 1 : sbd.bsize); print_gfs2("Starting at journal wrap block: 0x%llx " "(j + 0x%llx)", (unsigned long long)jblock + wp, (unsigned long long)wp); eol(0); } for (jb = 0; jb < j_size; jb += (sbd.gfs1 ? 1 : sbd.bsize)) { int is_pertinent = 1; uint32_t block_type = 0; if (sbd.gfs1) { if (j_bh) brelse(j_bh); abs_block = jblock + ((jb + wrappt) % j_size); j_bh = bread(&sbd, abs_block); dummy_bh.b_data = j_bh->b_data; } else { int error = fsck_readi(j_inode, (void *)jbuf, ((jb + wrappt) % j_size), sbd.bsize, &abs_block); if (!error) /* end of file */ break; dummy_bh.b_data = jbuf; } offset_from_ld++; block_type = get_block_type(&dummy_bh, NULL); if (block_type == GFS2_METATYPE_LD) { ld_blocks = process_ld(abs_block, wrappt, j_size, jb, &dummy_bh, tblk, &tblk_off, bitblk, rgd, &is_pertinent, &bblk_off); offset_from_ld = 0; abs_ld = abs_block; } else if (!tblk && block_type == GFS2_METATYPE_LH) { struct gfs2_log_header lh; struct gfs_log_header lh1; if (sbd.gfs1) { gfs_log_header_in(&lh1, &dummy_bh); check_journal_wrap(lh1.lh_sequence, &highest_seq); print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log header: " "Flags:%x, Seq: 0x%llx, 1st: 0x%llx, " "tail: 0x%llx, last: 0x%llx", abs_block, jb + wrappt, lh1.lh_flags, lh1.lh_sequence, lh1.lh_first, lh1.lh_tail, lh1.lh_last_dump); } else { gfs2_log_header_in(&lh, &dummy_bh); check_journal_wrap(lh.lh_sequence, &highest_seq); print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log header: Seq" ": 0x%llx, tail: 0x%x, blk: 0x%x%s", abs_block, ((jb + wrappt) % j_size) / sbd.bsize, lh.lh_sequence, lh.lh_tail, lh.lh_blkno, lh.lh_flags == GFS2_LOG_HEAD_UNMOUNT ? " [UNMOUNTED]" : ""); } eol(0); } else if ((ld_blocks > 0) && (sbd.gfs1 || block_type == GFS2_METATYPE_LB)) { print_gfs2("0x%"PRIx64" (j+%4"PRIx64"): Log descriptor" " continuation block", abs_block, ((jb + wrappt) % j_size) / sbd.bsize); eol(0); print_gfs2(" "); ld_blocks -= print_ld_blks((uint64_t *)dummy_bh.b_data + (sbd.gfs1 ? 0 : sizeof(struct gfs2_meta_header)), (dummy_bh.b_data + sbd.bsize), start_line, tblk, &tblk_off, 0, rgd, 0, 1, NULL, 0); } else if (block_type == 0) { continue; } /* Check if this metadata block references the block we're trying to trace. */ if (details || (tblk && ((is_pertinent && ((tblk_off && offset_from_ld == tblk_off) || (bblk_off && offset_from_ld == bblk_off))) || meta_has_ref(abs_block, tblk)))) { uint64_t ref_blk = 0; saveblk = block; block = abs_block; if (tblk && !details) { ref_blk = get_ldref(abs_ld, offset_from_ld); display(0, 1, tblk, ref_blk); } else { display(0, 0, 0, 0); } block = saveblk; } } inode_put(&j_inode); brelse(j_bh); blockhist = -1; /* So we don't print anything else */ free(jbuf); if (!termlines) fflush(stdout); }
/* * Executes a program. */ PUBLIC int sys_execve(const char *filename, const char **argv, const char **envp) { int i; /* Loop index. */ struct inode *inode; /* File inode. */ struct region *reg; /* Process region. */ addr_t entry; /* Program entry point. */ addr_t sp; /* User stack pointer. */ char *name; /* File name. */ char stack[ARG_MAX]; /* Stack size. */ /* Get file name. */ if ((name = getname(filename)) == NULL) return (curr_proc->errno); /* Build arguments before freeing user memory. */ kmemset(stack, 0, ARG_MAX); if (!(sp = buildargs(stack, ARG_MAX, argv, envp))) { putname(name); return (curr_proc->errno); } /* Get file's inode. */ if ((inode = inode_name(name)) == NULL) { putname(name); return (curr_proc->errno); } /* Not a regular file. */ if (!S_ISREG(inode->mode)) { putname(name); inode_put(inode); return (-EACCES); } /* Not allowed. */ if (!permission(inode->mode, inode->uid, inode->gid, curr_proc, MAY_EXEC, 0)) { putname(name); inode_put(inode); return (-EACCES); } /* Close file descriptors. */ for (i = 0; i < OPEN_MAX; i++) { if (curr_proc->close & (1 << i)) do_close(i); } /* Detach process memory regions. */ for (i = 0; i < NR_PREGIONS; i++) detachreg(curr_proc, &curr_proc->pregs[i]); /* Reset signal handlers. */ curr_proc->restorer = NULL; for (i = 0; i < NR_SIGNALS; i++) { if (curr_proc->handlers[i] != SIG_DFL) { if (curr_proc->handlers[i] != SIG_IGN) curr_proc->handlers[i] = SIG_DFL; } } /* Load executable. */ if (!(entry = load_elf32(inode))) goto die0; /* Attach stack region. */ if ((reg = allocreg(S_IRUSR | S_IWUSR, PAGE_SIZE, REGION_DOWNWARDS)) == NULL) goto die0; if (attachreg(curr_proc, STACK(curr_proc), USTACK_ADDR - 1, reg)) goto die1; unlockreg(reg); /* Attach heap region. */ if ((reg = allocreg(S_IRUSR | S_IWUSR, PAGE_SIZE, REGION_UPWARDS)) == NULL) goto die0; if (attachreg(curr_proc, HEAP(curr_proc), UHEAP_ADDR, reg)) goto die1; unlockreg(reg); inode_put(inode); putname(name); kmemcpy((void *)(USTACK_ADDR - ARG_MAX), stack, ARG_MAX); user_mode(entry, sp); /* Will not return. */ return (0); die1: unlockreg(reg); freereg(reg); die0: inode_put(inode); putname(name); die(((SIGSEGV & 0xff) << 16) | (1 << 9)); return (-1); }