Inode *Ext2Inode::Mknod(const std::string name, mode_t mode) { anvil_syslog(0, "Ext2Inode::Mknod %o\n", mode); // Call the Filesystem to find an unused inode in the inode bitmap Ext2filesystem *pfs = static_cast<Ext2filesystem *>(m_fs); ino_t inum = pfs->AllocInode(true); struct ext2_inode *ext2inode = pfs->inodeGet(inum); ext2inode->i_links_count = 1; ext2inode->i_mode = mode; ext2inode->i_ctime = ext2inode->i_atime = ext2inode->i_mtime = time(NULL); //pfs->inodePut(inum); if (S_ISDIR(mode)) { // We're creating a directory anvil_syslog(0, "We're creating a directory\n"); Ext2Inode *child = new Ext2Inode((Ext2filesystem *)m_fs, inum); child->Read(); // If we are creating a directory, increase the link count on 'this' // inode because the .. entry we are about to make actually points to // 'this' inode struct ext2_inode *thisext2inode = pfs->inodeGet(m_ino); ++thisext2inode->i_links_count; pfs->inodePut(m_ino); // And the . entry will point to itself so increase that by one as well ++ext2inode->i_links_count; uint32_t blk_no = pfs->AllocBlock(); anvil_syslog(0, "Block %u allocated\n", blk_no); //ext2inode = pfs->inodeGet(inum); ext2inode->i_block[0] = blk_no; ext2inode->i_size = pfs->m_block_size; ext2inode->i_blocks = pfs->m_block_size / 512; //pfs->inodePut(inum); // struct ext2_direntry *d = (struct ext2_direntry *)pfs->GetBlock(blk_no); Page *p = child->GetPage(0); struct ext2_direntry *d = (struct ext2_direntry *)p->GetAddr(); d->d_inode = inum; d->d_reclen = 12; d->d_namelen = 1; d->d_type = 0; memcpy(d + 1, ".\0\0\0", 4); d = (ext2_direntry *)((char *)d + d->d_reclen); d->d_inode = m_ino; d->d_reclen = 1024 - 12; d->d_namelen = 2; d->d_type = 0; memcpy(d + 1, "..\0\0", 4); p->set_dirty(0xff); p->flush(); } else { } pfs->inodePut(inum); anvil_syslog(0, "Inode %d allocated\n", inum); // Now we search the directory to see if we can find it Inode *new_child = (Ext2Inode *)SearchDirAndAct(name.c_str(), Inode::action::create, inum); return new_child; }
Inode *Ext2Inode::SearchDirAndAct(const char *lookup_name, enum Inode::action action, ino_t inum) { //anvil_syslog(0, "Ext2Inode::SearchDir %s dirsize=%d\n", lookup_name, m_size); Ext2Inode *inode = nullptr; // Now search the pages that hold the directory off_t offset_of_page = 0; off_t offset_of_space = 0; off_t offs = 0; uint32_t remains = m_size; // If we are creating work out how much space we need off_t needed_space; if (action == Inode::action::create) { needed_space = (8 + strlen(lookup_name) + 3) & ~0x3; anvil_syslog(0, "Ext2Inode::SearchDir space needed = %d\n", needed_space); } while (1) { Page *p = GetPage(offs); char *addr = p->GetAddr(); struct ext2_direntry *item = (struct ext2_direntry *)addr; // Figure out how much of this page is used struct ext2_direntry *end = (struct ext2_direntry *)(addr + (remains > __PAGESIZE ? __PAGESIZE : remains)); while (item < end) { char found_name[1024]; memcpy(found_name, item+1, item->d_namelen); found_name[item->d_namelen] = 0; //anvil_syslog(0, "found_name: %.20s - ", found_name); int space = item->d_reclen - item->d_namelen - 8; if (action == Inode::action::create && offset_of_page == 0 && needed_space <= space) { offset_of_page = offs; offset_of_space = (char *)item - addr; } //anvil_syslog(0, "inode=%d reclen=%d namelen=%d type=%d SPACE=%d\n", item->d_inode, item->d_reclen, item->d_namelen, item->d_type, space); if (!namecmp(found_name, lookup_name)) { // It's a match inode = new Ext2Inode((Ext2filesystem *)m_fs, item->d_inode); inode->Read(); //anvil_syslog(0, "Returning inode %016lx\n", inode); return inode; } item = (ext2_direntry *)((char *)item + item->d_reclen); //anvil_syslog(0, "item=%016lx end=%016lx\n", item, end); } offs += __PAGESIZE; if (offs > m_size) break; } if (action == Inode::action::create) { if (offset_of_page == 0) { // Todo: create a new page } Page *p = GetPage(offset_of_page); char *addr = p->GetAddr(); struct ext2_direntry *item = (struct ext2_direntry *)addr; item = (ext2_direntry *)((char *)item + offset_of_space); off_t space = item->d_reclen - item->d_namelen - 8; off_t actual_space_needed = (8 + item->d_namelen + 3) & ~0x3; anvil_syslog(0, "CREATING: space_needed=%d\n", needed_space); anvil_syslog(0, "CREATING: inode=%d reclen=%d namelen=%d type=%d SPACE=%d\n", item->d_inode, item->d_reclen, item->d_namelen, item->d_type, space); anvil_syslog(0, "inode=%d reclen=%d namelen=%d type=%d\n", item->d_inode, item->d_reclen, item->d_namelen, item->d_type); struct ext2_direntry *new_item = (struct ext2_direntry *)((char *)item + actual_space_needed); new_item->d_inode = inum; new_item->d_namelen = strlen(lookup_name); memcpy(new_item+1, lookup_name, new_item->d_namelen); new_item->d_reclen = item->d_reclen - actual_space_needed; new_item->d_type = 0; // change it item->d_reclen = actual_space_needed; anvil_syslog(0, "inode=%d reclen=%d namelen=%d type=%d\n", item->d_inode, item->d_reclen, item->d_namelen, item->d_type); anvil_syslog(0, "inode=%d reclen=%d namelen=%d type=%d\n", new_item->d_inode, new_item->d_reclen, new_item->d_namelen, new_item->d_type); p->set_dirty(0xff); p->flush(); inode = new Ext2Inode((Ext2filesystem *)m_fs, new_item->d_inode); inode->Read(); anvil_syslog(0, "Returning inode %016lx\n", inode); return inode; } //anvil_syslog(0, "Returning null\n"); return NULL; }