407 lines
13 KiB
C++
407 lines
13 KiB
C++
#include "ext2_dentry.h"
|
|
#include "ext2_file.h"
|
|
#include "delog/delog.h"
|
|
#include "mm/buf.h"
|
|
#include "stat.h"
|
|
#include <cstring>
|
|
#include <ctime>
|
|
|
|
using namespace EXT2;
|
|
EXT2_DEntry::EXT2_DEntry(EXT2_FS* fs1, VFS::DEntry* parent1,
|
|
_u32 inode_n1, _u8 type1, const std::string& name1) {
|
|
fs = fs1;
|
|
ext2_fs = fs1;
|
|
parent = parent1;
|
|
if (parent == nullptr)
|
|
parent = this;
|
|
inode = nullptr;
|
|
ext2_inode = nullptr;
|
|
inode_n = inode_n1;
|
|
type=type1;
|
|
name = std::string(name1);
|
|
sync = 1;
|
|
}
|
|
#include <iostream>
|
|
void EXT2_DEntry::load_children() {
|
|
_error(type != VFS::Directory);
|
|
|
|
if (ext2_inode != nullptr && children.size() != 0)
|
|
return ;
|
|
inflate();
|
|
_log_info("load children");
|
|
|
|
_error(ext2_inode == nullptr);
|
|
//_si(ext2_inode->size);
|
|
|
|
Dev::BlockDevice* dev = ext2_fs->dev;
|
|
MM::Buf buf(ext2_fs->block_size);
|
|
|
|
DirEntry *temp_str = new DirEntry();
|
|
for (auto x: children)
|
|
delete x;
|
|
children.clear();
|
|
// for (_u32 i = 0; i < ext2_inode->i->blocks; i++) {
|
|
_sp(*ext2_inode);
|
|
ext2_inode->print();
|
|
_u32 all_length = 0;
|
|
for (int i: *ext2_inode) {
|
|
_u32 data_block_pos = ext2_fs->block_to_pos(i);
|
|
dev->read(buf, data_block_pos, ext2_fs->block_size);
|
|
// _sa(buf.data, ext2_fs->block_size);
|
|
_u32 s_pos = 0;
|
|
// _u32 next_length = 12;
|
|
while (all_length < ext2_inode->size) {
|
|
// _sa(buf.data + s_pos, 20);
|
|
memmove(temp_str, buf.data + s_pos, sizeof(DirEntry));
|
|
if (temp_str->rec_len == 0)
|
|
break;
|
|
// if (temp_str->inode == parent->inode_n) {
|
|
// children.push_back(parent);
|
|
// } else if (temp_str->inode == inode_n) {
|
|
// children.push_back(this);
|
|
// } else {
|
|
EXT2_DEntry *sub = new EXT2_DEntry(ext2_fs, this,
|
|
temp_str->inode, temp_str->file_type,
|
|
std::string((char*)temp_str->name, temp_str->name_len));
|
|
// if (temp_str->inode == parent->inode_n) {
|
|
// sub->inode = parent->inode;
|
|
// sub->sync = 0;
|
|
// } else if (temp_str->inode == inode_n) {
|
|
// sub->inode = inode;
|
|
// sub->sync = 0;
|
|
// }
|
|
_si(temp_str->rec_len);
|
|
children.push_back(sub);
|
|
//}
|
|
// std::cout << sub->name << " " << sub->inode_n << std::endl;
|
|
s_pos += temp_str->rec_len;
|
|
all_length += temp_str->rec_len;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EXT2_DEntry::inflate() {
|
|
if (inode != nullptr && sync != 1)
|
|
return;
|
|
_log_info("inflate");
|
|
delete inode;
|
|
EXT2::Inode* disk_inode = new Inode();
|
|
MM::Buf buf(sizeof(Inode));
|
|
_u32 inode_pos = ext2_fs->inode_to_pos(inode_n);
|
|
_si(inode_pos);
|
|
fs->dev->read(buf, inode_pos, sizeof(Inode));
|
|
memcpy(disk_inode, buf.data, sizeof(Inode));
|
|
ext2_inode = new EXT2_Inode(ext2_fs, inode_n, disk_inode);
|
|
ext2_inode->print();
|
|
inode = ext2_inode;
|
|
// type = VFS::mode_to_type(inode->mode);
|
|
sync = 0;
|
|
}
|
|
|
|
static inline int cal_name_len(int s) {
|
|
if (s % 4 == 0)
|
|
return s;
|
|
return 4 - (s % 4) + s;
|
|
}
|
|
|
|
void EXT2_DEntry::write_children() {
|
|
_error(type != VFS::Directory);
|
|
DirEntry new_disk_entry[1];
|
|
EXT2_File parent_body(this, this->ext2_inode);
|
|
_u32 all_length = 0;
|
|
_u32 sub_item_cnt = 0;
|
|
for (VFS::DEntry* de: children) {
|
|
memset(new_disk_entry->name, 0, sizeof(new_disk_entry->name));
|
|
new_disk_entry->file_type = de->type;
|
|
new_disk_entry->inode = de->inode_n;
|
|
strcpy((char*)new_disk_entry->name, de->name.c_str());
|
|
new_disk_entry->name_len = strlen(de->name.c_str());
|
|
if (sub_item_cnt == children.size() - 1) {
|
|
// 最后一个项目充满整个块
|
|
new_disk_entry->rec_len = ext2_fs->block_size - all_length;
|
|
} else {
|
|
new_disk_entry->rec_len = 8 + cal_name_len(new_disk_entry->name_len);
|
|
}
|
|
sub_item_cnt++;
|
|
all_length += new_disk_entry->rec_len;
|
|
parent_body.write((char *)new_disk_entry, new_disk_entry->rec_len);
|
|
// new_disk_entry->name = de->name.c_str();
|
|
}
|
|
_d_end();
|
|
}
|
|
|
|
VFS::DEntry* EXT2_DEntry::mkdir(const std::string& new_name) {
|
|
_error(type != VFS::Directory);
|
|
EXT2_GD *new_dir_gd = nullptr;
|
|
_u32 new_i_n = ext2_fs->alloc_inode(&new_dir_gd);
|
|
new_dir_gd->get_gd()->used_dirs_count++;
|
|
_u32 new_b_n = ext2_fs->alloc_block();
|
|
// _dbg_log("分配节点");
|
|
// MM::Buf buf(1024);
|
|
// ext2_fs->dev->read(buf, ext2_fs->inode_to_pos(new_i_n - 1), 1024);
|
|
// _sa(buf.data, 1024);
|
|
// exit(0);
|
|
load_children();
|
|
|
|
// 构建新的Inode
|
|
EXT2::Inode *new_disk_i = new EXT2::Inode();
|
|
// _sp(*new_disk_i);
|
|
new_disk_i->mode = ext2_inode->mode;
|
|
new_disk_i->uid = ext2_inode->uid;
|
|
new_disk_i->size = ext2_fs->block_size;
|
|
new_disk_i->atime = time(0);
|
|
new_disk_i->mtime = time(0);
|
|
new_disk_i->ctime = time(0);
|
|
new_disk_i->gid = ext2_inode->gid;
|
|
new_disk_i->links_count = 2; // . 和父目录中的自己
|
|
new_disk_i->blocks = 2;
|
|
new_disk_i->flags = 0;
|
|
new_disk_i->block[0] = new_b_n;
|
|
EXT2_Inode *new_i = new EXT2_Inode(ext2_fs, new_i_n, new_disk_i);
|
|
new_i->write_inode(); // 新Inode写入磁盘
|
|
EXT2_DEntry *new_entry = new EXT2_DEntry(ext2_fs, this, new_i_n, VFS::Directory, new_name);
|
|
new_entry->ext2_inode = new_i;
|
|
// 加入到当前目录中
|
|
children.push_back(new_entry);
|
|
// 子目录的DirEntry写入父目录的文件体中
|
|
write_children();
|
|
// EXT2_File parent_body11(this, this->ext2_inode);
|
|
|
|
// 修改父目录的Inode
|
|
ext2_inode->nlink++; // 硬链接计数器加1
|
|
ext2_inode->write_inode();
|
|
|
|
DirEntry new_disk_entry[1];
|
|
// 在子目录的文件体中写入.和..
|
|
new_disk_entry->file_type = VFS::Directory;
|
|
EXT2_File child_body(new_entry, new_i);
|
|
new_disk_entry->inode = new_i_n;
|
|
new_disk_entry->rec_len = 12;
|
|
new_disk_entry->name_len = 1;
|
|
new_disk_entry->name[0] = '.';
|
|
new_disk_entry->name[1] = '\0';
|
|
child_body.write((char*)new_disk_entry, new_disk_entry->rec_len);
|
|
new_disk_entry->inode = this->inode_n;
|
|
new_disk_entry->name_len = 2;
|
|
new_disk_entry->rec_len = ext2_fs->block_size - 12;
|
|
new_disk_entry->name[1] = '.';
|
|
new_disk_entry->name[2] = '\0';
|
|
child_body.write((char*)new_disk_entry, new_disk_entry->rec_len);
|
|
// EXT2_File child_bod11y(new_entry, new_i);
|
|
|
|
// ext2_fs->sb->
|
|
ext2_fs->write_gdt();
|
|
ext2_fs->write_super();
|
|
return new_entry;
|
|
}
|
|
|
|
VFS::DEntry *EXT2_DEntry::create(const std::string& name) {
|
|
_error(type != VFS::Directory);
|
|
_pos();
|
|
inflate();
|
|
_u32 new_i_n = ext2_fs->alloc_inode();
|
|
_error(new_i_n == 0);
|
|
EXT2::Inode *new_disk_i = new EXT2::Inode();
|
|
// _sp(*new_disk_i);
|
|
new_disk_i->mode = S_IFREG | S_IRUSR | S_IWUSR | S_IROTH | S_IRGRP;
|
|
new_disk_i->uid = ext2_inode->uid;
|
|
new_disk_i->size = 0;
|
|
new_disk_i->atime = time(0);
|
|
new_disk_i->mtime = time(0);
|
|
new_disk_i->ctime = time(0);
|
|
new_disk_i->gid = ext2_inode->gid;
|
|
new_disk_i->links_count = 1; // 父目录中的自己
|
|
new_disk_i->blocks = 0;
|
|
new_disk_i->flags = 0;
|
|
EXT2_Inode *new_i = new EXT2_Inode(ext2_fs, new_i_n, new_disk_i);
|
|
new_i->write_inode(); // 新Inode写入磁盘
|
|
EXT2_DEntry *new_entry = new EXT2_DEntry(ext2_fs, this, new_i_n, VFS::RegularFile, name);
|
|
new_entry->ext2_inode = new_i;
|
|
new_entry->inode = new_i;
|
|
load_children();
|
|
children.push_back(new_entry);
|
|
write_children();
|
|
|
|
ext2_fs->write_gdt();
|
|
ext2_fs->write_super();
|
|
return new_entry;
|
|
}
|
|
|
|
VFS::File *EXT2_DEntry::get_file() {
|
|
if (type==VFS::SymbolLink)
|
|
return follow()->open();
|
|
return new EXT2_File(this);
|
|
}
|
|
|
|
void EXT2_DEntry::unlink(VFS::DEntry *d) {
|
|
_dbg_log("unlink sub current %d, del %d.", inode_n, d->inode_n);
|
|
_error(type != VFS::Directory);
|
|
load_children();
|
|
if (d->type == VFS::Directory) {
|
|
ext2_inode->nlink--; // 降低自己的引用链接
|
|
ext2_inode->write_inode();
|
|
ext2_fs->gdt_list[d->inode_n / ext2_fs->sb->inodes_per_group]->get_gd()->used_dirs_count--;
|
|
ext2_fs->write_gdt();
|
|
}
|
|
d->unlink(); // 删除子项目
|
|
children.remove(d);
|
|
delete d;
|
|
write_children();
|
|
_dbg_log("unlink sub current %d, del %d. finish", inode_n, d->inode_n);
|
|
}
|
|
|
|
|
|
void EXT2_DEntry::unlink() {
|
|
inflate();
|
|
_dbg_log("ulink %d ref cnt: %d type: %d.", inode_n, ext2_inode->nlink, type);
|
|
if (ext2_inode->nlink == 0)
|
|
return;
|
|
|
|
ext2_inode->nlink--;
|
|
// 硬引用计数减一,当引用计数为0时彻底删除文件,目录可以等于1
|
|
if (ext2_inode->nlink == 0 || (type==VFS::Directory && ext2_inode->nlink == 1)) {
|
|
_pos();
|
|
ext2_inode->i->dtime = time(0);
|
|
EXT2_File f(this);
|
|
f.resize(0);
|
|
// if (type==VFS::Directory)
|
|
// ext2_inode->i->size = 1024;
|
|
ext2_inode->nlink = 0;
|
|
ext2_fs->release_inode(inode_n);
|
|
ext2_fs->write_gdt();
|
|
ext2_fs->write_super();
|
|
}
|
|
ext2_inode->write_inode();
|
|
_dbg_log("ulink %d ref cnt: %d type: %d. finish", inode_n, ext2_inode->nlink, type);
|
|
}
|
|
|
|
void EXT2_DEntry::unlink_children() {
|
|
_dbg_log("unlink chlidren current %d, del", inode_n);
|
|
_error(type != VFS::Directory);
|
|
load_children();
|
|
_pos();
|
|
for (auto d: children) {
|
|
if (d->inode_n == inode_n || d->inode_n == parent->inode_n)
|
|
continue;
|
|
if (d->type == VFS::Directory) {
|
|
ext2_inode->nlink--; // 降低自己的引用链接
|
|
ext2_fs->gdt_list[d->inode_n / ext2_fs->sb->inodes_per_group]->get_gd()->used_dirs_count--;
|
|
d->unlink_children();
|
|
}
|
|
d->unlink(); // 删除子项目
|
|
delete d;
|
|
}
|
|
children.clear();
|
|
ext2_inode->write_inode();
|
|
ext2_fs->write_gdt();
|
|
write_children();
|
|
_dbg_log("unlink chlidren current %d. finish", inode_n);
|
|
}
|
|
|
|
VFS::DEntry *EXT2_DEntry::link(DEntry *tar, const std::string& s) {
|
|
if (tar->fs != fs) {
|
|
_log_info("[EXT2]: Hard Link must in the same file system.");
|
|
return nullptr;
|
|
}
|
|
if (type == VFS::Directory) {
|
|
_log_info("%s: hard link not allowed for directory", name.c_str());
|
|
return nullptr;
|
|
}
|
|
EXT2_DEntry *t = dynamic_cast<EXT2_DEntry*>(tar);
|
|
std::string ts;
|
|
if (s == "")
|
|
ts = t->name;
|
|
else
|
|
ts = s;
|
|
EXT2_DEntry *new_e = new EXT2_DEntry(ext2_fs, parent, inode_n, type, ts);
|
|
t->load_children();
|
|
t->children.push_back(new_e);
|
|
t->write_children();
|
|
inflate();
|
|
if (type == VFS::Directory) {
|
|
// 目录的硬链接比普通文件多一个
|
|
ext2_inode->nlink += 2;
|
|
// 目录的硬链接,组中目录数目加一
|
|
ext2_fs->gdt_list[inode_n / ext2_fs->sb->inodes_per_group]->get_gd()->used_dirs_count++;
|
|
ext2_fs->write_gdt();
|
|
} else
|
|
ext2_inode->nlink += 1;
|
|
ext2_inode->write_inode();
|
|
return new_e;
|
|
}
|
|
|
|
VFS::DEntry *EXT2_DEntry::move(DEntry *dir, const std::string& new_name) {
|
|
auto ans = link(dir, new_name); // 在dir中创建item的硬链接
|
|
parent->unlink(this); // 在父目录中删除自己
|
|
return ans;
|
|
}
|
|
|
|
bool EXT2_DEntry::empty() {
|
|
load_children();
|
|
return children.size() == 2;
|
|
}
|
|
|
|
VFS::DEntry* EXT2_DEntry::copy(DEntry *dir, const std::string& new_name) {
|
|
VFS::DEntry *new_entry = dir->create(new_name==""?this->name:new_name);
|
|
VFS::File *old_f = this->open();
|
|
VFS::File *new_f = new_entry->open();
|
|
char buf[old_f->size];
|
|
old_f->read(buf, old_f->size);
|
|
new_f->write(buf, old_f->size);
|
|
// dynamic_cast<EXT2_DEntry*>(new_entry)->ext2_inode->write_inode();
|
|
delete old_f;
|
|
delete new_f;
|
|
return new_entry;
|
|
}
|
|
|
|
VFS::DEntry *EXT2_DEntry::symlink(DEntry *file, const std::string& new_name) {
|
|
EXT2_DEntry *new_entry = static_cast<EXT2_DEntry*>(create(new_name==""?file->name:new_name));
|
|
_pos();
|
|
new_entry->inode->mode = S_IFLNK | S_IRWXG | S_IRWXO | S_IRWXU;
|
|
new_entry->type = VFS::SymbolLink;
|
|
_pos();
|
|
std::string path = file->printed_path();
|
|
if (path.size() <= 60) {
|
|
memmove(new_entry->ext2_inode->i->block, path.c_str(), path.size());
|
|
} else {
|
|
VFS::File *file = new_entry->open();
|
|
file->write(path.c_str(), path.size());
|
|
file->close();
|
|
}
|
|
new_entry->ext2_inode->size = path.size();
|
|
new_entry->inode->size = path.size();
|
|
new_entry->ext2_inode->write_inode();
|
|
write_children();
|
|
_d_end();
|
|
return new_entry;
|
|
}
|
|
|
|
VFS::DEntry *EXT2_DEntry::follow() {
|
|
_dbg_log("start");
|
|
inflate();
|
|
char buf[inode->size];
|
|
if (inode->size <= 60) {
|
|
memmove(buf, ext2_inode->i->block, inode->size);
|
|
} else {
|
|
VFS::File *f = open();
|
|
f->read(buf, inode->size);
|
|
f->close();
|
|
}
|
|
_ss(buf);
|
|
VFS::NameI *path = VFS::NameI::from_str(std::string(buf, inode->size));
|
|
VFS::DEntry *ans = parent->get_child(path);
|
|
delete path;
|
|
_d_end();
|
|
return ans;
|
|
}
|
|
|
|
|
|
EXT2_DEntry::~EXT2_DEntry() {
|
|
delete inode;
|
|
for (auto x: children) {
|
|
if (x->name != ".." && x->name != ".")
|
|
delete x;
|
|
}
|
|
}
|
|
|