Finally hook up the mkdir code to a syscall.

Added a /bin/mkdir that makes directories. How very neat :^)
There are various limitations because of missing functionality.
This commit is contained in:
Andreas Kling 2018-11-18 14:57:41 +01:00
parent 303577df16
commit de4604ac95
26 changed files with 238 additions and 132 deletions

View file

@ -30,15 +30,32 @@ bool FileSystemPath::canonicalize(bool resolveSymbolicLinks)
canonicalParts.append(part);
}
if (canonicalParts.isEmpty()) {
m_string = "/";
m_string = m_basename = m_dirname = "/";
return true;
}
StringBuilder builder;
for (auto& cpart : canonicalParts) {
builder.append('/');
builder.append(move(cpart));
m_basename = canonicalParts.last();
if (canonicalParts.size() == 1) {
m_dirname = "/";
} else {
StringBuilder builder;
for (size_t i = 0; i < canonicalParts.size() - 1; ++i) {
auto& cpart = canonicalParts[i];
builder.append('/');
builder.append(cpart);
}
m_dirname = builder.build();
}
{
StringBuilder builder;
for (auto& cpart : canonicalParts) {
builder.append('/');
builder.append(move(cpart));
}
m_string = builder.build();
}
m_string = builder.build();
return true;
}

View file

@ -12,10 +12,15 @@ public:
bool isValid() const { return m_isValid; }
String string() const { return m_string; }
String basename() const { return m_basename; }
String dirname() const { return m_dirname; }
private:
bool canonicalize(bool resolveSymbolicLinks = false);
String m_string;
String m_dirname;
String m_basename;
bool m_isValid { false };
};

View file

@ -7,6 +7,11 @@ void StringBuilder::append(String&& str)
m_strings.append(move(str));
}
void StringBuilder::append(const String& str)
{
m_strings.append(str);
}
void StringBuilder::append(char ch)
{
m_strings.append(StringImpl::create(&ch, 1));

View file

@ -10,6 +10,7 @@ public:
StringBuilder() { }
~StringBuilder() { }
void append(const String&);
void append(String&&);
void append(char);

View file

@ -18,6 +18,7 @@
enum IDECommand : byte {
IDENTIFY_DRIVE = 0xEC,
READ_SECTORS = 0x21,
WRITE_SECTORS = 0x30,
};
enum IDEStatus : byte {
@ -64,11 +65,8 @@ bool IDEDiskDevice::readBlock(unsigned index, byte* out) const
bool IDEDiskDevice::writeBlock(unsigned index, const byte* data)
{
(void) index;
(void) data;
kprintf("IDEDiskDevice: writeBlock not implemented()\n");
notImplemented();
return false;
write_sectors(index, 1, data);
return true;
}
#ifdef DISK_DEBUG
@ -221,3 +219,48 @@ bool IDEDiskDevice::read_sectors(dword start_sector, word count, byte* outbuf)
return true;
}
bool IDEDiskDevice::write_sectors(dword start_sector, word count, const byte* data)
{
LOCKER(m_lock);
dbgprintf("%s(%u): IDEDiskDevice::write_sectors request (%u sector(s) @ %u)\n",
current->name().characters(),
current->pid(),
count,
start_sector);
disableIRQ();
auto chs = lba_to_chs(start_sector);
while (IO::in8(IDE0_STATUS) & BUSY);
//dbgprintf("IDEDiskDevice: Writing %u sector(s) @ LBA %u (%u/%u/%u)\n", count, start_sector, chs.cylinder, chs.head, chs.sector);
IO::out8(0x1F2, count == 256 ? 0 : LSB(count));
IO::out8(0x1F3, chs.sector);
IO::out8(0x1F4, LSB(chs.cylinder));
IO::out8(0x1F5, MSB(chs.cylinder));
IO::out8(0x1F6, 0xA0 | chs.head); /* 0xB0 for 2nd device */
IO::out8(0x3F6, 0x08);
IO::out8(IDE0_COMMAND, WRITE_SECTORS);
while (!(IO::in8(IDE0_STATUS) & DRQ));
byte status = IO::in8(0x1f7);
if (status & DRQ) {
//dbgprintf("Sending %u bytes (status=%b), data=%p...\n", count * 512, status, data);
auto* data_as_words = (const word*)data;
for (dword i = 0; i < (count * 512) / 2; ++i) {
IO::out16(IDE0_DATA, data_as_words[i]);
}
}
m_interrupted = false;
enableIRQ();
wait_for_irq();
return true;
}

View file

@ -34,7 +34,8 @@ private:
void initialize();
bool wait_for_irq();
bool read_sectors(dword start_sector, word count, byte* outbuf);
bool read_sectors(dword start_sector, word count, byte* buffer);
bool write_sectors(dword start_sector, word count, const byte* data);
SpinLock m_lock;
word m_cylinders { 0 };

View file

@ -44,7 +44,8 @@ ELFLOADER_OBJS = \
AK_OBJS = \
../AK/String.o \
../AK/StringImpl.o \
../AK/StringBuilder.o
../AK/StringBuilder.o \
../AK/FileSystemPath.o
OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(ELFLOADER_OBJS)

View file

@ -1751,3 +1751,15 @@ int Process::sys$setgroups(size_t count, const gid_t* gids)
m_gids.set(gids[i]);
return 0;
}
int Process::sys$mkdir(const char* pathname, mode_t mode)
{
if (!validate_read_str(pathname))
return -EFAULT;
if (strlen(pathname) >= 255)
return -ENAMETOOLONG;
int error;
if (!VFS::the().mkdir(pathname, mode, cwd_inode()->identifier(), error))
return error;
return 0;
}

View file

@ -172,6 +172,7 @@ public:
int sys$access(const char* pathname, int mode);
int sys$fcntl(int fd, int cmd, dword extra_arg);
int sys$ioctl(int fd, unsigned request, unsigned arg);
int sys$mkdir(const char* pathname, mode_t mode);
static void initialize();

View file

@ -175,6 +175,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
return current->sys$ioctl((int)arg1, (unsigned)arg2, (unsigned)arg3);
case Syscall::SC_fstat:
return current->sys$fstat((int)arg1, (Unix::stat*)arg2);
case Syscall::SC_mkdir:
return current->sys$mkdir((const char*)arg1, (mode_t)arg2);
default:
kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
break;

View file

@ -63,6 +63,7 @@
__ENUMERATE_SYSCALL(access) \
__ENUMERATE_SYSCALL(fcntl) \
__ENUMERATE_SYSCALL(ioctl) \
__ENUMERATE_SYSCALL(mkdir) \
#define DO_SYSCALL_A0(function) Syscall::invoke((dword)(function))

View file

@ -29,6 +29,7 @@ cp -v ../Userland/mm mnt/bin/mm
cp -v ../Userland/kill mnt/bin/kill
cp -v ../Userland/tty mnt/bin/tty
cp -v ../Userland/strsignal mnt/bin/strsignal
cp -v ../Userland/mkdir mnt/bin/mkdir
sh sync-local.sh
cp -v kernel.map mnt/
umount mnt

View file

@ -41,6 +41,7 @@
__ERROR(ENOSYS, "No such syscall") \
__ERROR(ENOTIMPL, "Not implemented") \
__ERROR(EAFNOSUPPORT, "Address family not supported") \
__ERROR(EWHYTHO, "Failed without setting an error code (Bug!)") \
enum __errno_values {
#undef __ERROR

View file

@ -1,4 +1,5 @@
#include <sys/stat.h>
#include <errno.h>
#include <Kernel/Syscall.h>
extern "C" {
@ -8,5 +9,11 @@ mode_t umask(mode_t mask)
return Syscall::invoke(Syscall::SC_umask, (dword)mask);
}
int mkdir(const char* pathname, mode_t mode)
{
int rc = Syscall::invoke(Syscall::SC_mkdir, (dword)pathname, (dword)mode);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

View file

@ -7,5 +7,6 @@ __BEGIN_DECLS
mode_t umask(mode_t);
int chmod(const char* pathname, mode_t);
int mkdir(const char* pathname, mode_t);
__END_DECLS

1
Userland/.gitignore vendored
View file

@ -20,3 +20,4 @@ ft
ft2
strsignal
fgrep
mkdir

View file

@ -18,7 +18,8 @@ OBJS = \
ft2.o \
strsignal.o \
fgrep.o \
tty.o
tty.o \
mkdir.o
APPS = \
id \
@ -40,7 +41,8 @@ APPS = \
ft2 \
strsignal \
fgrep \
tty
tty \
mkdir
ARCH_FLAGS =
STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
@ -120,6 +122,9 @@ tty: tty.o
strsignal: strsignal.o
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
mkdir: mkdir.o
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
.cpp.o:
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<

21
Userland/mkdir.cpp Normal file
View file

@ -0,0 +1,21 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
if (argc != 2) {
printf("usage: mkdir <path>\n");
return 1;
}
int rc = mkdir(argv[1], 0755);
if (rc < 0) {
perror("mkdir");
return 1;
}
return 0;
}

View file

@ -11,31 +11,6 @@
//#define EXT2_DEBUG
class Ext2FS::CachedExt2InodeImpl : public Retainable<CachedExt2InodeImpl> {
public:
CachedExt2InodeImpl(OwnPtr<ext2_inode>&& e2i) : e2inode(move(e2i)) { }
~CachedExt2InodeImpl() { }
OwnPtr<ext2_inode> e2inode;
};
class Ext2FS::CachedExt2Inode {
public:
const ext2_inode* operator->() const { return ptr->e2inode.ptr(); }
const ext2_inode& operator*() const { return *ptr->e2inode; }
ext2_inode* operator->() { return ptr->e2inode.ptr(); }
ext2_inode& operator*() { return *ptr->e2inode; }
bool operator!() const { return !ptr; }
operator bool() const { return !!ptr; }
CachedExt2Inode() { }
explicit CachedExt2Inode(OwnPtr<ext2_inode>&& e2inode)
: ptr(adopt(*new CachedExt2InodeImpl(move(e2inode))))
{ }
explicit CachedExt2Inode(RetainPtr<CachedExt2InodeImpl> p)
: ptr(p)
{ }
RetainPtr<CachedExt2InodeImpl> ptr;
};
RetainPtr<Ext2FS> Ext2FS::create(RetainPtr<DiskDevice>&& device)
{
return adopt(*new Ext2FS(move(device)));
@ -187,16 +162,8 @@ ByteBuffer Ext2FS::readBlockContainingInode(unsigned inode, unsigned& blockIndex
return readBlock(blockIndex);
}
auto Ext2FS::lookupExt2Inode(unsigned inode) const -> CachedExt2Inode
OwnPtr<ext2_inode> Ext2FS::lookupExt2Inode(unsigned inode) const
{
{
LOCKER(m_inodeCacheLock);
auto it = m_inodeCache.find(inode);
if (it != m_inodeCache.end()) {
return CachedExt2Inode{ (*it).value };
}
}
unsigned blockIndex;
unsigned offset;
auto block = readBlockContainingInode(inode, blockIndex, offset);
@ -210,12 +177,7 @@ auto Ext2FS::lookupExt2Inode(unsigned inode) const -> CachedExt2Inode
dumpExt2Inode(*e2inode);
#endif
LOCKER(m_inodeCacheLock);
if (m_inodeCache.size() >= 128)
m_inodeCache.removeOneRandomly();
auto cachedInode = adopt(*new CachedExt2InodeImpl(OwnPtr<ext2_inode>(e2inode)));
m_inodeCache.set(inode, cachedInode.copyRef());
return CachedExt2Inode{ cachedInode };
return OwnPtr<ext2_inode>(e2inode);
}
InodeMetadata Ext2FS::inodeMetadata(InodeIdentifier inode) const
@ -528,7 +490,7 @@ bool Ext2FS::writeInode(InodeIdentifier inode, const ByteBuffer& data)
for (unsigned i = 0; i < list.size(); ++i) {
auto section = data.slice(i * blockSize(), blockSize());
kprintf("section = %p (%u)\n", section.pointer(), section.size());
//kprintf("section = %p (%u)\n", section.pointer(), section.size());
bool success = writeBlock(list[i], section);
ASSERT(success);
}
@ -587,14 +549,14 @@ bool Ext2FS::deprecated_enumerateDirectoryInode(InodeIdentifier inode, Function<
return true;
}
bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType)
bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType, int& error)
{
auto e2inodeForDirectory = lookupExt2Inode(directoryInode);
ASSERT(e2inodeForDirectory);
ASSERT(isDirectory(e2inodeForDirectory->i_mode));
//#ifdef EXT2_DEBUG
kprintf("ext2fs: Adding inode %u with name '%s' to directory %u\n", inode, name.characters(), directoryInode);
dbgprintf("Ext2FS: Adding inode %u with name '%s' to directory %u\n", inode, name.characters(), directoryInode);
//#endif
Vector<DirectoryEntry> entries;
@ -608,7 +570,8 @@ bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const
return true;
});
if (nameAlreadyExists) {
kprintf("ext2fs: Name '%s' already exists in directory inode %u\n", name.characters(), directoryInode);
kprintf("Ext2FS: Name '%s' already exists in directory inode %u\n", name.characters(), directoryInode);
error = -EEXIST;
return false;
}
@ -618,18 +581,18 @@ bool Ext2FS::addInodeToDirectory(unsigned directoryInode, unsigned inode, const
bool Ext2FS::writeDirectoryInode(unsigned directoryInode, Vector<DirectoryEntry>&& entries)
{
kprintf("ext2fs: New directory inode %u contents to write:\n", directoryInode);
dbgprintf("Ext2FS: New directory inode %u contents to write:\n", directoryInode);
unsigned directorySize = 0;
for (auto& entry : entries) {
kprintf(" - %08u %s\n", entry.inode.index(), entry.name);
//kprintf(" - %08u %s\n", entry.inode.index(), entry.name);
directorySize += EXT2_DIR_REC_LEN(entry.name_length);
}
unsigned blocksNeeded = ceilDiv(directorySize, blockSize());
unsigned occupiedSize = blocksNeeded * blockSize();
kprintf("ext2fs: directory size: %u (occupied: %u)\n", directorySize, occupiedSize);
dbgprintf("Ext2FS: directory size: %u (occupied: %u)\n", directorySize, occupiedSize);
auto directoryData = ByteBuffer::createUninitialized(occupiedSize);
@ -641,11 +604,11 @@ bool Ext2FS::writeDirectoryInode(unsigned directoryInode, Vector<DirectoryEntry>
if (i == entries.size() - 1)
recordLength += occupiedSize - directorySize;
kprintf("* inode: %u", entry.inode.index());
kprintf(", name_len: %u", word(entry.name_length));
kprintf(", rec_len: %u", word(recordLength));
kprintf(", file_type: %u", byte(entry.fileType));
kprintf(", name: %s\n", entry.name);
dbgprintf("* inode: %u", entry.inode.index());
dbgprintf(", name_len: %u", word(entry.name_length));
dbgprintf(", rec_len: %u", word(recordLength));
dbgprintf(", file_type: %u", byte(entry.fileType));
dbgprintf(", name: %s\n", entry.name);
stream << dword(entry.inode.index());
stream << word(recordLength);
@ -654,7 +617,7 @@ bool Ext2FS::writeDirectoryInode(unsigned directoryInode, Vector<DirectoryEntry>
stream << entry.name;
unsigned padding = recordLength - entry.name_length - 8;
kprintf(" *** pad %u bytes\n", padding);
//dbgprintf(" *** pad %u bytes\n", padding);
for (unsigned j = 0; j < padding; ++j) {
stream << byte(0);
}
@ -772,7 +735,7 @@ bool Ext2FS::modifyLinkCount(InodeIndex inode, int delta)
return false;
auto newLinkCount = e2inode->i_links_count + delta;
kprintf("changing inode %u link count from %u to %u\n", inode, e2inode->i_links_count, newLinkCount);
dbgprintf("Ext2FS: changing inode %u link count from %u to %u\n", inode, e2inode->i_links_count, newLinkCount);
e2inode->i_links_count = newLinkCount;
return writeExt2Inode(inode, *e2inode);
@ -799,6 +762,18 @@ bool Ext2FS::writeExt2Inode(unsigned inode, const ext2_inode& e2inode)
auto block = readBlockContainingInode(inode, blockIndex, offset);
if (!block)
return false;
{
LOCKER(m_inode_cache_lock);
auto it = m_inode_cache.find(inode);
if (it != m_inode_cache.end()) {
auto& cached_inode = *(*it).value;
LOCKER(cached_inode.m_lock);
cached_inode.m_raw_inode = e2inode;
cached_inode.populate_metadata();
if (cached_inode.is_directory())
cached_inode.m_lookup_cache.clear();
}
}
memcpy(reinterpret_cast<ext2_inode*>(block.offsetPointer(offset)), &e2inode, inodeSize());
writeBlock(blockIndex, block);
return true;
@ -813,11 +788,11 @@ bool Ext2FS::isDirectoryInode(unsigned inode) const
Vector<Ext2FS::BlockIndex> Ext2FS::allocateBlocks(unsigned group, unsigned count)
{
kprintf("ext2fs: allocateBlocks(group: %u, count: %u)\n", group, count);
dbgprintf("Ext2FS: allocateBlocks(group: %u, count: %u)\n", group, count);
auto& bgd = blockGroupDescriptor(group);
if (bgd.bg_free_blocks_count < count) {
kprintf("ext2fs: allocateBlocks can't allocate out of group %u, wanted %u but only %u available\n", group, count, bgd.bg_free_blocks_count);
kprintf("ExtFS: allocateBlocks can't allocate out of group %u, wanted %u but only %u available\n", group, count, bgd.bg_free_blocks_count);
return { };
}
@ -833,9 +808,9 @@ Vector<Ext2FS::BlockIndex> Ext2FS::allocateBlocks(unsigned group, unsigned count
}
return true;
});
kprintf("ext2fs: allocateBlock found these blocks:\n");
dbgprintf("Ext2FS: allocateBlock found these blocks:\n");
for (auto& bi : blocks) {
kprintf(" > %u\n", bi);
dbgprintf(" > %u\n", bi);
}
return blocks;
@ -843,11 +818,11 @@ Vector<Ext2FS::BlockIndex> Ext2FS::allocateBlocks(unsigned group, unsigned count
unsigned Ext2FS::allocateInode(unsigned preferredGroup, unsigned expectedSize)
{
kprintf("ext2fs: allocateInode(preferredGroup: %u, expectedSize: %u)\n", preferredGroup, expectedSize);
dbgprintf("Ext2FS: allocateInode(preferredGroup: %u, expectedSize: %u)\n", preferredGroup, expectedSize);
unsigned neededBlocks = ceilDiv(expectedSize, blockSize());
kprintf("ext2fs: minimum needed blocks: %u\n", neededBlocks);
dbgprintf("Ext2FS: minimum needed blocks: %u\n", neededBlocks);
unsigned groupIndex = 0;
@ -866,11 +841,11 @@ unsigned Ext2FS::allocateInode(unsigned preferredGroup, unsigned expectedSize)
}
if (!groupIndex) {
kprintf("ext2fs: allocateInode: no suitable group found for new inode with %u blocks needed :(\n", neededBlocks);
kprintf("Ext2FS: allocateInode: no suitable group found for new inode with %u blocks needed :(\n", neededBlocks);
return 0;
}
kprintf("ext2fs: allocateInode: found suitable group [%u] for new inode with %u blocks needed :^)\n", groupIndex, neededBlocks);
dbgprintf("Ext2FS: allocateInode: found suitable group [%u] for new inode with %u blocks needed :^)\n", groupIndex, neededBlocks);
unsigned firstFreeInodeInGroup = 0;
traverseInodeBitmap(groupIndex, [&firstFreeInodeInGroup] (unsigned firstInodeInBitmap, const Bitmap& bitmap) {
@ -884,12 +859,12 @@ unsigned Ext2FS::allocateInode(unsigned preferredGroup, unsigned expectedSize)
});
if (!firstFreeInodeInGroup) {
kprintf("ext2fs: firstFreeInodeInGroup returned no inode, despite bgd claiming there are inodes :(\n");
kprintf("Ext2FS: firstFreeInodeInGroup returned no inode, despite bgd claiming there are inodes :(\n");
return 0;
}
unsigned inode = firstFreeInodeInGroup;
kprintf("ext2fs: found suitable inode %u\n", inode);
dbgprintf("Ext2FS: found suitable inode %u\n", inode);
// FIXME: allocate blocks if needed!
@ -915,7 +890,7 @@ bool Ext2FS::setInodeAllocationState(unsigned inode, bool newState)
ASSERT(block);
auto bitmap = Bitmap::wrap(block.pointer(), block.size());
bool currentState = bitmap.get(bitIndex);
kprintf("ext2fs: setInodeAllocationState(%u) %u -> %u\n", inode, currentState, newState);
dbgprintf("ext2fs: setInodeAllocationState(%u) %u -> %u\n", inode, currentState, newState);
if (currentState == newState)
return true;
@ -925,7 +900,7 @@ bool Ext2FS::setInodeAllocationState(unsigned inode, bool newState)
// Update superblock
auto& sb = *reinterpret_cast<ext2_super_block*>(m_cachedSuperBlock.pointer());
kprintf("ext2fs: superblock free inode count %u -> %u\n", sb.s_free_inodes_count, sb.s_free_inodes_count - 1);
dbgprintf("Ext2FS: superblock free inode count %u -> %u\n", sb.s_free_inodes_count, sb.s_free_inodes_count - 1);
if (newState)
--sb.s_free_inodes_count;
else
@ -938,7 +913,7 @@ bool Ext2FS::setInodeAllocationState(unsigned inode, bool newState)
--mutableBGD.bg_free_inodes_count;
else
++mutableBGD.bg_free_inodes_count;
kprintf("ext2fs: group free inode count %u -> %u\n", bgd.bg_free_inodes_count, bgd.bg_free_inodes_count - 1);
dbgprintf("Ext2FS: group free inode count %u -> %u\n", bgd.bg_free_inodes_count, bgd.bg_free_inodes_count - 1);
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
@ -959,7 +934,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt
ASSERT(block);
auto bitmap = Bitmap::wrap(block.pointer(), block.size());
bool currentState = bitmap.get(bitIndex);
kprintf("ext2fs: setBlockAllocationState(%u) %u -> %u\n", bi, currentState, newState);
dbgprintf("Ext2FS: setBlockAllocationState(%u) %u -> %u\n", bi, currentState, newState);
if (currentState == newState)
return true;
@ -969,7 +944,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt
// Update superblock
auto& sb = *reinterpret_cast<ext2_super_block*>(m_cachedSuperBlock.pointer());
kprintf("ext2fs: superblock free block count %u -> %u\n", sb.s_free_blocks_count, sb.s_free_blocks_count - 1);
dbgprintf("Ext2FS: superblock free block count %u -> %u\n", sb.s_free_blocks_count, sb.s_free_blocks_count - 1);
if (newState)
--sb.s_free_blocks_count;
else
@ -982,7 +957,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt
--mutableBGD.bg_free_blocks_count;
else
++mutableBGD.bg_free_blocks_count;
kprintf("ext2fs: group free block count %u -> %u\n", bgd.bg_free_blocks_count, bgd.bg_free_blocks_count - 1);
dbgprintf("Ext2FS: group free block count %u -> %u\n", bgd.bg_free_blocks_count, bgd.bg_free_blocks_count - 1);
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
@ -991,7 +966,7 @@ bool Ext2FS::setBlockAllocationState(GroupIndex group, BlockIndex bi, bool newSt
return true;
}
InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t mode)
InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, int& error)
{
ASSERT(parentInode.fsid() == id());
ASSERT(isDirectoryInode(parentInode.index()));
@ -1003,11 +978,11 @@ InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const Stri
// NOTE: When creating a new directory, make the size 1 block.
// There's probably a better strategy here, but this works for now.
auto inode = create_inode(parentInode, name, mode, blockSize());
auto inode = create_inode(parentInode, name, mode, blockSize(), error);
if (!inode.isValid())
return { };
kprintf("ext2fs: makeDirectory: created new directory named '%s' with inode %u\n", name.characters(), inode.index());
dbgprintf("Ext2FS: create_directory: created new directory named '%s' with inode %u\n", name.characters(), inode.index());
Vector<DirectoryEntry> entries;
entries.append({ ".", inode, EXT2_FT_DIR });
@ -1021,34 +996,35 @@ InodeIdentifier Ext2FS::create_directory(InodeIdentifier parentInode, const Stri
auto& bgd = const_cast<ext2_group_desc&>(blockGroupDescriptor(groupIndexFromInode(inode.index())));
++bgd.bg_used_dirs_count;
kprintf("ext2fs: incremented bg_used_dirs_count %u -> %u\n", bgd.bg_used_dirs_count - 1, bgd.bg_used_dirs_count);
dbgprintf("Ext2FS: incremented bg_used_dirs_count %u -> %u\n", bgd.bg_used_dirs_count - 1, bgd.bg_used_dirs_count);
unsigned blocksToWrite = ceilDiv(m_blockGroupCount * (unsigned)sizeof(ext2_group_desc), blockSize());
unsigned firstBlockOfBGDT = blockSize() == 1024 ? 2 : 1;
writeBlocks(firstBlockOfBGDT, blocksToWrite, m_cachedBlockGroupDescriptorTable);
error = 0;
return inode;
}
InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size)
InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size, int& error)
{
ASSERT(parentInode.fsid() == id());
ASSERT(isDirectoryInode(parentInode.index()));
//#ifdef EXT2_DEBUG
kprintf("ext2fs: Adding inode '%s' (mode %o) to parent directory %u:\n", name.characters(), mode, parentInode.index());
//#endif
dbgprintf("Ext2FS: Adding inode '%s' (mode %o) to parent directory %u:\n", name.characters(), mode, parentInode.index());
// NOTE: This doesn't commit the inode allocation just yet!
auto inode = allocateInode(0, 0);
if (!inode) {
kprintf("ext2fs: createInode: allocateInode failed\n");
kprintf("Ext2FS: createInode: allocateInode failed\n");
error = -ENOSPC;
return { };
}
auto blocks = allocateBlocks(groupIndexFromInode(inode), ceilDiv(size, blockSize()));
if (blocks.isEmpty()) {
kprintf("ext2fs: createInode: allocateBlocks failed\n");
kprintf("Ext2FS: createInode: allocateBlocks failed\n");
error = -ENOSPC;
return { };
}
@ -1069,11 +1045,9 @@ InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String&
fileType = EXT2_FT_SYMLINK;
// Try adding it to the directory first, in case the name is already in use.
bool success = addInodeToDirectory(parentInode.index(), inode, name, fileType);
if (!success) {
kprintf("ext2fs: failed to add inode to directory :(\n");
bool success = addInodeToDirectory(parentInode.index(), inode, name, fileType, error);
if (!success)
return { };
}
// Looks like we're good, time to update the inode bitmap and group+global inode counters.
success = setInodeAllocationState(inode, true);
@ -1107,7 +1081,7 @@ InodeIdentifier Ext2FS::create_inode(InodeIdentifier parentInode, const String&
// FIXME: Implement writing out indirect blocks!
ASSERT(blocks.size() < EXT2_NDIR_BLOCKS);
kprintf("[XXX] writing %zu blocks to i_block array\n", min((size_t)EXT2_NDIR_BLOCKS, blocks.size()));
dbgprintf("Ext2FS: writing %zu blocks to i_block array\n", min((size_t)EXT2_NDIR_BLOCKS, blocks.size()));
for (unsigned i = 0; i < min((size_t)EXT2_NDIR_BLOCKS, blocks.size()); ++i) {
e2inode->i_block[i] = blocks[i];
}

View file

@ -51,9 +51,6 @@ private:
typedef unsigned BlockIndex;
typedef unsigned GroupIndex;
typedef unsigned InodeIndex;
class CachedExt2Inode;
class CachedExt2InodeImpl;
explicit Ext2FS(RetainPtr<DiskDevice>&&);
const ext2_super_block& superBlock() const;
@ -64,7 +61,7 @@ private:
unsigned blocksPerGroup() const;
unsigned inodeSize() const;
CachedExt2Inode lookupExt2Inode(unsigned) const;
OwnPtr<ext2_inode> lookupExt2Inode(unsigned) const;
bool writeExt2Inode(unsigned, const ext2_inode&);
ByteBuffer readBlockContainingInode(unsigned inode, unsigned& blockIndex, unsigned& offset) const;
@ -76,9 +73,9 @@ private:
virtual bool writeInode(InodeIdentifier, const ByteBuffer&) override;
virtual InodeMetadata inodeMetadata(InodeIdentifier) const override;
virtual bool set_mtime(InodeIdentifier, dword timestamp) override;
virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override;
virtual Unix::ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override;
virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override;
virtual InodeIdentifier find_parent_of_inode(InodeIdentifier) const override;
virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) const override;
@ -95,7 +92,7 @@ private:
template<typename F> void traverseInodeBitmap(unsigned groupIndex, F) const;
template<typename F> void traverseBlockBitmap(unsigned groupIndex, F) const;
bool addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType);
bool addInodeToDirectory(unsigned directoryInode, unsigned inode, const String& name, byte fileType, int& error);
bool writeDirectoryInode(unsigned directoryInode, Vector<DirectoryEntry>&&);
bool setInodeAllocationState(unsigned inode, bool);
bool setBlockAllocationState(GroupIndex, BlockIndex, bool);
@ -109,9 +106,6 @@ private:
mutable ByteBuffer m_cachedSuperBlock;
mutable ByteBuffer m_cachedBlockGroupDescriptorTable;
mutable SpinLock m_inodeCacheLock;
mutable HashMap<unsigned, RetainPtr<CachedExt2InodeImpl>> m_inodeCache;
mutable SpinLock m_inode_cache_lock;
mutable HashMap<BlockIndex, RetainPtr<Ext2FSInode>> m_inode_cache;
};

View file

@ -107,7 +107,7 @@ ByteBuffer FS::readEntireInode(InodeIdentifier inode, FileDescriptor* handle) co
}
FS::DirectoryEntry::DirectoryEntry(const char* n, InodeIdentifier i, byte ft)
: name_length(strlen(name))
: name_length(strlen(n))
, inode(i)
, fileType(ft)
{

View file

@ -45,8 +45,8 @@ public:
};
virtual bool set_mtime(InodeIdentifier, dword timestamp) = 0;
virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) = 0;
virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t) = 0;
virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) = 0;
virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) = 0;
virtual InodeIdentifier find_parent_of_inode(InodeIdentifier) const = 0;

View file

@ -1,5 +1,6 @@
#include "SyntheticFileSystem.h"
#include "FileDescriptor.h"
#include <LibC/errno_numbers.h>
#include <AK/StdLib.h>
#ifndef SERENITY
@ -152,13 +153,14 @@ bool SynthFS::set_mtime(InodeIdentifier, dword timestamp)
return false;
}
InodeIdentifier SynthFS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size)
InodeIdentifier SynthFS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size, int& error)
{
(void) parentInode;
(void) name;
(void) mode;
(void) size;
kprintf("FIXME: Implement SyntheticFileSystem::createDirectoryInode().\n");
(void) error;
kprintf("FIXME: Implement SyntheticFileSystem::create_inode().\n");
return { };
}
@ -205,11 +207,9 @@ Unix::ssize_t SynthFS::read_inode_bytes(InodeIdentifier inode, Unix::off_t offse
return nread;
}
InodeIdentifier SynthFS::create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t)
InodeIdentifier SynthFS::create_directory(InodeIdentifier, const String&, Unix::mode_t, int& error)
{
(void) parentInode;
(void) name;
kprintf("FIXME: Implement SyntheticFileSystem::makeDirectory().\n");
error = -EROFS;
return { };
}

View file

@ -17,9 +17,9 @@ public:
virtual bool writeInode(InodeIdentifier, const ByteBuffer&) override;
virtual InodeMetadata inodeMetadata(InodeIdentifier) const override;
virtual bool set_mtime(InodeIdentifier, dword timestamp) override;
virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override;
virtual Unix::ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override;
virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override;
virtual InodeIdentifier find_parent_of_inode(InodeIdentifier) const override;
virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) const override;

View file

@ -1,6 +1,7 @@
#include "VirtualFileSystem.h"
#include "FileDescriptor.h"
#include "FileSystem.h"
#include <AK/FileSystemPath.h>
#include <AK/StringBuilder.h>
#include <AK/kmalloc.h>
#include <AK/kstdio.h>
@ -419,22 +420,34 @@ RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options,
return FileDescriptor::create(move(vnode));
}
RetainPtr<FileDescriptor> VFS::create(const String& path, InodeIdentifier base)
RetainPtr<FileDescriptor> VFS::create(const String& path, InodeIdentifier base, int& error)
{
// FIXME: Do the real thing, not just this fake thing!
(void) path;
(void) base;
m_root_vnode->fileSystem()->create_inode(m_root_vnode->fileSystem()->rootInode(), "empty", 0100644, 0);
m_root_vnode->fileSystem()->create_inode(m_root_vnode->fileSystem()->rootInode(), "empty", 0100644, 0, error);
return nullptr;
}
RetainPtr<FileDescriptor> VFS::mkdir(const String& path, InodeIdentifier base)
bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error)
{
// FIXME: Do the real thing, not just this fake thing!
(void) path;
(void) base;
m_root_vnode->fileSystem()->create_directory(m_root_vnode->fileSystem()->rootInode(), "mydir", 0400755);
return nullptr;
error = EWHYTHO;
// FIXME: This won't work nicely across mount boundaries.
FileSystemPath p(path);
if (!p.isValid()) {
error = -EINVAL;
return false;
}
dbgprintf("VFS::mkdir: '%s' in '%s'\n", p.basename().characters(), p.dirname().characters());
auto parent_dir = resolve_path(p.dirname(), error, m_root_vnode->inode);
if (!parent_dir.isValid())
return false;
auto new_dir = base.fileSystem()->create_directory(parent_dir, p.basename(), mode, error);
if (new_dir.isValid()) {
error = 0;
return true;
}
return false;
}
InodeIdentifier VFS::resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error)

View file

@ -115,8 +115,8 @@ public:
RetainPtr<FileDescriptor> open(CharacterDevice&, int options);
RetainPtr<FileDescriptor> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier());
RetainPtr<FileDescriptor> create(const String& path, InodeIdentifier base = InodeIdentifier());
RetainPtr<FileDescriptor> mkdir(const String& path, InodeIdentifier base = InodeIdentifier());
RetainPtr<FileDescriptor> create(const String& path, InodeIdentifier base, int& error);
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
bool touch(const String&path);
@ -136,7 +136,6 @@ private:
bool is_vfs_root(InodeIdentifier) const;
void traverse_directory_inode(CoreInode&, Function<bool(const FS::DirectoryEntry&)>);
InodeIdentifier resolve_path(const String& path, int& error, CoreInode& base, int options = 0);
InodeIdentifier resolve_path(const String& path, int& error, InodeIdentifier base = InodeIdentifier(), int options = 0);
InodeIdentifier resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error);