395 lines
12 KiB
C++
395 lines
12 KiB
C++
#include "MinixFSInode.h"
|
|
#ifndef EXE2MINIXFS
|
|
#include "kstring.h"
|
|
#endif
|
|
#include <assert.h>
|
|
#include "MinixFSSuperblock.h"
|
|
#include "MinixFSFile.h"
|
|
#include "Dentry.h"
|
|
|
|
MinixFSInode::MinixFSInode(Superblock *super_block, uint32 inode_type) :
|
|
Inode(super_block, inode_type),
|
|
i_zones_(0),
|
|
i_num_(0),
|
|
children_loaded_(false)
|
|
{
|
|
debug(M_INODE, "Simple Constructor\n");
|
|
}
|
|
|
|
MinixFSInode::MinixFSInode(Superblock *super_block, uint16 i_mode, uint32 i_size, uint16 i_nlinks, uint32* i_zones,
|
|
uint32 i_num) :
|
|
Inode(super_block, 0), i_zones_(new MinixFSZone((MinixFSSuperblock*) super_block, i_zones)), i_num_(i_num),
|
|
children_loaded_(false)
|
|
{
|
|
i_size_ = i_size;
|
|
i_nlink_ = i_nlinks;
|
|
i_state_ = I_UNUSED;
|
|
if (i_mode & 0x8000)
|
|
{
|
|
i_type_ = I_FILE;
|
|
}
|
|
else if (i_mode & 0x4000)
|
|
{
|
|
i_type_ = I_DIR;
|
|
}
|
|
else
|
|
{
|
|
debug(M_INODE, "i_mode = %x\n", i_mode);
|
|
assert(false);
|
|
}
|
|
// (hard/sym link/...) not handled!
|
|
|
|
debug(M_INODE, "Constructor: size: %d\tnlink: %d\tnum zones: %d\tmode: %x\n", i_size_, numLinks(),
|
|
i_zones_->getNumZones(), i_mode);
|
|
}
|
|
|
|
MinixFSInode::~MinixFSInode()
|
|
{
|
|
debug(M_INODE, "Destructor\n");
|
|
delete i_zones_;
|
|
}
|
|
|
|
int32 MinixFSInode::readData(uint32 offset, uint32 size, char *buffer)
|
|
{
|
|
assert(buffer);
|
|
debug(M_INODE, "readData: offset: %d, size; %d,i_size_: %d\n", offset, size, i_size_);
|
|
if ((size + offset) > i_size_)
|
|
{
|
|
if (i_size_ <= offset)
|
|
return 0;
|
|
else
|
|
size = i_size_ - offset;
|
|
}
|
|
uint32 start_zone = offset / ZONE_SIZE;
|
|
uint32 zone_offset = offset % ZONE_SIZE;
|
|
uint32 num_zones = (zone_offset + size) / ZONE_SIZE + 1;
|
|
char rbuffer[ZONE_SIZE];
|
|
|
|
uint32 index = 0;
|
|
debug(M_INODE, "readData: zone: %d, zone_offset %d, num_zones: %d\n", start_zone, zone_offset, num_zones);
|
|
for (uint32 zone = start_zone; zone < start_zone + num_zones; zone++)
|
|
{
|
|
memset(rbuffer, 0, sizeof(rbuffer));
|
|
((MinixFSSuperblock *) superblock_)->readZone(i_zones_->getZone(zone), rbuffer);
|
|
uint32 count = size - index;
|
|
uint32 zone_diff = ZONE_SIZE - zone_offset;
|
|
count = count < zone_diff ? count : zone_diff;
|
|
memcpy(buffer + index, rbuffer + zone_offset, count);
|
|
index += count;
|
|
zone_offset = 0;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
int32 MinixFSInode::writeData(uint32 offset, uint32 size, const char *buffer)
|
|
{
|
|
debug(M_INODE, "MinixFSInode writeData> offset: %d, size: %d, i_size_: %d\n", offset, size, i_size_);
|
|
uint32 zone = offset / ZONE_SIZE;
|
|
uint32 num_zones = (offset % ZONE_SIZE + size) / ZONE_SIZE + 1;
|
|
uint32 last_used_zone = i_size_ / ZONE_SIZE;
|
|
uint32 last_zone = last_used_zone;
|
|
if ((size + offset) > i_size_)
|
|
{
|
|
uint32 num_new_zones = (size + offset - i_size_) / ZONE_SIZE + 1;
|
|
for (uint32 new_zones = 0; new_zones < num_new_zones; new_zones++, last_zone++)
|
|
{
|
|
MinixFSSuperblock* sb = (MinixFSSuperblock*) superblock_;
|
|
debug(M_INODE, "writeData: allocating new Zone\n");
|
|
uint16 new_zone = sb->allocateZone();
|
|
i_zones_->setZone(i_zones_->getNumZones(), new_zone);
|
|
}
|
|
}
|
|
if (offset > i_size_)
|
|
{
|
|
debug(M_INODE, "writeData: have to clean memory\n");
|
|
uint32 zone_size_offset = i_size_ % ZONE_SIZE;
|
|
char fill_buffer[ZONE_SIZE];
|
|
memset(fill_buffer, 0, sizeof(fill_buffer));
|
|
if (zone_size_offset)
|
|
{
|
|
readData(i_size_ - zone_size_offset, zone_size_offset, fill_buffer);
|
|
((MinixFSSuperblock *) superblock_)->writeZone(last_used_zone, fill_buffer);
|
|
}
|
|
++last_used_zone;
|
|
for (; last_used_zone <= offset / ZONE_SIZE; last_used_zone++)
|
|
{
|
|
memset(fill_buffer, 0, sizeof(fill_buffer));
|
|
((MinixFSSuperblock *) superblock_)->writeZone(last_used_zone, fill_buffer);
|
|
}
|
|
--last_used_zone;
|
|
i_size_ = offset;
|
|
}
|
|
uint32 zone_offset = offset % ZONE_SIZE;
|
|
char* wbuffer_array = new char[num_zones * ZONE_SIZE];
|
|
char* wbuffer = wbuffer_array;
|
|
memset((void*) wbuffer, 0, num_zones * ZONE_SIZE);
|
|
debug(M_INODE, "writeData: reading data at the beginning of zone: offset-zone_offset: %d,zone_offset: %d\n",
|
|
offset - zone_offset, zone_offset);
|
|
readData(offset - zone_offset, num_zones * ZONE_SIZE, wbuffer);
|
|
for (uint32 index = 0, pos = zone_offset; index < size; pos++, index++)
|
|
{
|
|
wbuffer[pos] = buffer[index];
|
|
}
|
|
for (uint32 zone_index = 0; zone_index < num_zones; zone_index++)
|
|
{
|
|
debug(M_INODE, "writeData: writing zone_index: %d, i_zones_->getZone(zone) : %d\n", zone_index,
|
|
i_zones_->getZone(zone));
|
|
((MinixFSSuperblock *) superblock_)->writeZone(i_zones_->getZone(zone_index + zone), wbuffer);
|
|
wbuffer += ZONE_SIZE;
|
|
}
|
|
if (i_size_ < offset + size)
|
|
{
|
|
i_size_ = offset + size;
|
|
}
|
|
delete[] wbuffer_array;
|
|
return size;
|
|
}
|
|
|
|
int32 MinixFSInode::mknod(Dentry *dentry)
|
|
{
|
|
Inode::mknod(dentry);
|
|
debug(M_INODE, "mknod: dentry: %p, i_type_: %x\n", dentry, i_type_);
|
|
|
|
((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(0, i_num_, dentry->getName());
|
|
return 0;
|
|
}
|
|
|
|
int32 MinixFSInode::mkfile(Dentry *dentry)
|
|
{
|
|
Inode::mkfile(dentry);
|
|
debug(M_INODE, "mkfile: dentry: %p (%s)\n", dentry, dentry->getName());
|
|
|
|
((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(0, i_num_, dentry->getName());
|
|
return 0;
|
|
}
|
|
|
|
int32 MinixFSInode::mkdir(Dentry *dentry)
|
|
{
|
|
Inode::mkdir(dentry);
|
|
debug(M_INODE, "mkdir: dentry: %p (%s)\n", dentry, dentry->getName());
|
|
|
|
MinixFSInode* parent_inode = ((MinixFSInode *) dentry->getParent()->getInode());
|
|
assert(parent_inode->getType() == I_DIR);
|
|
|
|
parent_inode->writeDentry(0, i_num_, dentry->getName());
|
|
// link count already increased once in Inode::mkdir(dentry);
|
|
|
|
writeDentry(0, i_num_, ".");
|
|
incLinkCount();
|
|
|
|
writeDentry(0, parent_inode->i_num_, "..");
|
|
parent_inode->incLinkCount();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32 MinixFSInode::findDentry(uint32 i_num)
|
|
{
|
|
debug(M_INODE, "findDentry: i_num: %d\n", i_num);
|
|
char dbuffer[ZONE_SIZE];
|
|
for (uint32 zone = 0; zone < i_zones_->getNumZones(); zone++)
|
|
{
|
|
((MinixFSSuperblock *) superblock_)->readZone(i_zones_->getZone(zone), dbuffer);
|
|
for (uint32 curr_dentry = 0; curr_dentry < BLOCK_SIZE; curr_dentry += INODE_SIZE)
|
|
{
|
|
uint16 inode_index = *(uint16*) (dbuffer + curr_dentry);
|
|
if (inode_index == i_num)
|
|
{
|
|
debug(M_INODE, "findDentry: found pos: %d\n", (zone * ZONE_SIZE + curr_dentry));
|
|
return (zone * ZONE_SIZE + curr_dentry);
|
|
}
|
|
}
|
|
}
|
|
debug(M_INODE, "findDentry: i_num: %d not found\n", i_num);
|
|
return -1;
|
|
}
|
|
|
|
void MinixFSInode::writeDentry(uint32 dest_i_num, uint32 src_i_num, const char* name)
|
|
{
|
|
debug(M_INODE, "writeDentry: dest_i_num : %d, src_i_num : %d, name : %s\n", dest_i_num, src_i_num, name);
|
|
assert(name);
|
|
int32 dentry_pos = findDentry(dest_i_num);
|
|
if (dentry_pos < 0 && dest_i_num == 0)
|
|
{
|
|
i_zones_->addZone(((MinixFSSuperblock *) superblock_)->allocateZone());
|
|
dentry_pos = (i_zones_->getNumZones() - 1) * ZONE_SIZE;
|
|
}
|
|
char dbuffer[ZONE_SIZE];
|
|
uint32 zone = i_zones_->getZone(dentry_pos / ZONE_SIZE);
|
|
((MinixFSSuperblock *) superblock_)->readZone(zone, dbuffer);
|
|
*(uint16*) (dbuffer + (dentry_pos % ZONE_SIZE)) = src_i_num;
|
|
strncpy(dbuffer + dentry_pos % ZONE_SIZE + INODE_BYTES, name, MAX_NAME_LENGTH);
|
|
((MinixFSSuperblock *) superblock_)->writeZone(zone, dbuffer);
|
|
|
|
if (dest_i_num == 0 && i_size_ < (uint32) dentry_pos + INODE_SIZE)
|
|
i_size_ += INODE_SIZE;
|
|
|
|
}
|
|
|
|
File* MinixFSInode::open(Dentry* dentry, uint32 flag)
|
|
{
|
|
debug(M_INODE, "Open file, flag: %x\n", flag);
|
|
assert(ustl::find(i_dentrys_.begin(), i_dentrys_.end(), dentry) != i_dentrys_.end());
|
|
File* file = (File*) (new MinixFSFile(this, dentry, flag));
|
|
i_files_.push_back(file);
|
|
getSuperblock()->fileOpened(file);
|
|
return file;
|
|
}
|
|
|
|
|
|
int32 MinixFSInode::link(Dentry* dentry)
|
|
{
|
|
int32 link_status = Inode::link(dentry);
|
|
if(link_status)
|
|
{
|
|
return link_status;
|
|
}
|
|
|
|
((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(0, i_num_, dentry->getName());
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32 MinixFSInode::unlink(Dentry* dentry)
|
|
{
|
|
int32 unlink_status = Inode::unlink(dentry);
|
|
if(unlink_status)
|
|
{
|
|
return unlink_status;
|
|
}
|
|
|
|
((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(i_num_, 0, "");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32 MinixFSInode::rmdir(Dentry* dentry)
|
|
{
|
|
assert(dentry && (dentry->getInode() == this));
|
|
assert(dentry->getParent() && (dentry->getParent()->getInode()));
|
|
assert(getType() == I_DIR);
|
|
|
|
debug(M_INODE, "rmdir %s for inode %p\n", dentry->getName(), this);
|
|
|
|
MinixFSInode* parent_inode = static_cast<MinixFSInode*>(dentry->getParent()->getInode());
|
|
|
|
//the "." and ".." dentries will be deleted in some inode-dtor
|
|
//("." in this inodes-dtor, ".." in the parent-dentry-inodes-dtor)
|
|
for (Dentry* child : dentry->d_child_)
|
|
{
|
|
if (strcmp(child->getName(), ".") != 0 && strcmp(child->getName(), "..") != 0)
|
|
{
|
|
//if directory contains other entries than "." or ".."
|
|
//-> directory not empty
|
|
debug(M_INODE, "Error: Cannot remove non-empty directory\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
writeDentry(i_num_, 0, ""); //this was the "."-entry
|
|
decLinkCount();
|
|
|
|
writeDentry(parent_inode->i_num_, 0, ""); //this was ".."
|
|
parent_inode->decLinkCount();
|
|
|
|
parent_inode->writeDentry(i_num_, 0, "");
|
|
decLinkCount();
|
|
|
|
assert(i_nlink_ == 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Dentry* MinixFSInode::lookup(const char* name)
|
|
{
|
|
if(i_type_ != I_DIR)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
assert(i_dentrys_.size() >= 1);
|
|
|
|
debug(M_INODE, "lookup: name: %s this->i_dentry_->getName(): %s \n", name, i_dentrys_.front()->getName());
|
|
if (name == 0)
|
|
{
|
|
// ERROR_DNE
|
|
return 0;
|
|
}
|
|
|
|
Dentry* dentry_update = 0;
|
|
|
|
dentry_update = i_dentrys_.front()->checkName(name);
|
|
if (dentry_update == 0)
|
|
{
|
|
// ERROR_NNE
|
|
return (Dentry*) 0;
|
|
}
|
|
else
|
|
{
|
|
debug(M_INODE, "lookup: dentry_update->getName(): %s\n", dentry_update->getName());
|
|
if (((MinixFSInode *) dentry_update->getInode())->i_type_ == I_DIR)
|
|
{
|
|
((MinixFSInode *) dentry_update->getInode())->loadChildren();
|
|
}
|
|
return dentry_update;
|
|
}
|
|
}
|
|
|
|
void MinixFSInode::loadChildren()
|
|
{
|
|
if (children_loaded_)
|
|
{
|
|
debug(M_INODE, "loadChildren: Children allready loaded\n");
|
|
return;
|
|
}
|
|
char dbuffer[ZONE_SIZE];
|
|
for (uint32 zone = 0; zone < i_zones_->getNumZones(); zone++)
|
|
{
|
|
((MinixFSSuperblock *) superblock_)->readZone(i_zones_->getZone(zone), dbuffer);
|
|
for (uint32 curr_dentry = 0; curr_dentry < BLOCK_SIZE; curr_dentry += INODE_SIZE)
|
|
{
|
|
uint16 inode_index = *(uint16*) (dbuffer + curr_dentry);
|
|
if (inode_index)
|
|
{
|
|
debug(M_INODE, "loadChildren: loading child %d\n", inode_index);
|
|
bool is_already_loaded = false;
|
|
|
|
MinixFSInode* inode = ((MinixFSSuperblock *) superblock_)->getInode(inode_index, is_already_loaded);
|
|
|
|
if (!inode)
|
|
{
|
|
kprintfd("MinixFSInode::loadChildren: inode nr. %d not set in bitmap, but occurs in directory-entry; "
|
|
"maybe filesystem was not properly unmounted last time\n",
|
|
inode_index);
|
|
char ch = 0;
|
|
writeDentry(inode_index, 0, &ch);
|
|
continue;
|
|
}
|
|
|
|
char name[MAX_NAME_LENGTH + 1];
|
|
strncpy(name, dbuffer + curr_dentry + INODE_BYTES, MAX_NAME_LENGTH);
|
|
|
|
name[MAX_NAME_LENGTH] = 0;
|
|
|
|
debug(M_INODE, "loadChildren: dentry name: %s\n", name);
|
|
assert(i_dentrys_.size() >= 1);
|
|
Dentry *new_dentry = new Dentry(inode, i_dentrys_.front(), name);
|
|
inode->i_dentrys_.push_back(new_dentry);
|
|
|
|
if (!is_already_loaded)
|
|
{
|
|
((MinixFSSuperblock *) superblock_)->all_inodes_add_inode(inode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
children_loaded_ = true;
|
|
}
|
|
|
|
int32 MinixFSInode::flush()
|
|
{
|
|
superblock_->writeInode(this);
|
|
debug(M_INODE, "flush: flushed\n");
|
|
return 0;
|
|
}
|