1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 05:08:13 +00:00

Kernel: Support open() with O_CREAT.

It's now possible to create zero-length files! :^)
Also hook up the new functionality in /bin/touch.
This commit is contained in:
Andreas Kling 2019-01-22 00:58:13 +01:00
parent a47f33bed3
commit f70136a324
9 changed files with 108 additions and 39 deletions

View file

@ -124,7 +124,7 @@ void init_ksyms()
void load_ksyms() void load_ksyms()
{ {
int error; int error;
auto descriptor = VFS::the().open("/kernel.map", error); auto descriptor = VFS::the().open("/kernel.map", error, 0, 0);
if (!descriptor) { if (!descriptor) {
kprintf("Failed to open /kernel.map\n"); kprintf("Failed to open /kernel.map\n");
} else { } else {

View file

@ -289,7 +289,7 @@ int Process::do_exec(const String& path, Vector<String>&& arguments, Vector<Stri
return -ENOENT; return -ENOENT;
int error; int error;
auto descriptor = VFS::the().open(path, error, 0, m_cwd ? m_cwd->identifier() : InodeIdentifier()); auto descriptor = VFS::the().open(path, error, 0, 0, m_cwd ? m_cwd->identifier() : InodeIdentifier());
if (!descriptor) { if (!descriptor) {
ASSERT(error != 0); ASSERT(error != 0);
return error; return error;
@ -1117,7 +1117,7 @@ int Process::sys$utime(const char* pathname, const Unix::utimbuf* buf)
return -EFAULT; return -EFAULT;
String path(pathname); String path(pathname);
int error; int error;
auto descriptor = VFS::the().open(move(path), error, 0, cwd_inode()->identifier()); auto descriptor = VFS::the().open(move(path), error, 0, 0, cwd_inode()->identifier());
if (!descriptor) if (!descriptor)
return error; return error;
auto& inode = *descriptor->inode(); auto& inode = *descriptor->inode();
@ -1206,7 +1206,7 @@ int Process::sys$lstat(const char* path, Unix::stat* statbuf)
if (!validate_write_typed(statbuf)) if (!validate_write_typed(statbuf))
return -EFAULT; return -EFAULT;
int error; int error;
auto descriptor = VFS::the().open(move(path), error, O_NOFOLLOW_NOERROR, cwd_inode()->identifier()); auto descriptor = VFS::the().open(move(path), error, O_NOFOLLOW_NOERROR, 0, cwd_inode()->identifier());
if (!descriptor) if (!descriptor)
return error; return error;
descriptor->stat(statbuf); descriptor->stat(statbuf);
@ -1218,7 +1218,7 @@ int Process::sys$stat(const char* path, Unix::stat* statbuf)
if (!validate_write_typed(statbuf)) if (!validate_write_typed(statbuf))
return -EFAULT; return -EFAULT;
int error; int error;
auto descriptor = VFS::the().open(move(path), error, 0, cwd_inode()->identifier()); auto descriptor = VFS::the().open(move(path), error, 0, 0, cwd_inode()->identifier());
if (!descriptor) if (!descriptor)
return error; return error;
descriptor->stat(statbuf); descriptor->stat(statbuf);
@ -1233,7 +1233,7 @@ int Process::sys$readlink(const char* path, char* buffer, size_t size)
return -EFAULT; return -EFAULT;
int error; int error;
auto descriptor = VFS::the().open(path, error, O_RDONLY | O_NOFOLLOW_NOERROR, cwd_inode()->identifier()); auto descriptor = VFS::the().open(path, error, O_RDONLY | O_NOFOLLOW_NOERROR, 0, cwd_inode()->identifier());
if (!descriptor) if (!descriptor)
return error; return error;
@ -1255,7 +1255,7 @@ int Process::sys$chdir(const char* path)
if (!validate_read_str(path)) if (!validate_read_str(path))
return -EFAULT; return -EFAULT;
int error; int error;
auto descriptor = VFS::the().open(path, error, 0, cwd_inode()->identifier()); auto descriptor = VFS::the().open(path, error, 0, 0, cwd_inode()->identifier());
if (!descriptor) if (!descriptor)
return error; return error;
if (!descriptor->is_directory()) if (!descriptor->is_directory())
@ -1288,7 +1288,7 @@ size_t Process::number_of_open_file_descriptors() const
return count; return count;
} }
int Process::sys$open(const char* path, int options) int Process::sys$open(const char* path, int options, mode_t mode)
{ {
#ifdef DEBUG_IO #ifdef DEBUG_IO
dbgprintf("%s(%u) sys$open(\"%s\")\n", name().characters(), pid(), path); dbgprintf("%s(%u) sys$open(\"%s\")\n", name().characters(), pid(), path);
@ -1299,7 +1299,7 @@ int Process::sys$open(const char* path, int options)
return -EMFILE; return -EMFILE;
int error = -EWHYTHO; int error = -EWHYTHO;
ASSERT(cwd_inode()); ASSERT(cwd_inode());
auto descriptor = VFS::the().open(path, error, options, cwd_inode()->identifier()); auto descriptor = VFS::the().open(path, error, options, mode, cwd_inode()->identifier());
if (!descriptor) if (!descriptor)
return error; return error;
if (options & O_DIRECTORY && !descriptor->is_directory()) if (options & O_DIRECTORY && !descriptor->is_directory())

View file

@ -140,7 +140,7 @@ public:
pid_t sys$getpid(); pid_t sys$getpid();
pid_t sys$getppid(); pid_t sys$getppid();
mode_t sys$umask(mode_t); mode_t sys$umask(mode_t);
int sys$open(const char* path, int options); int sys$open(const char* path, int options, mode_t mode = 0);
int sys$close(int fd); int sys$close(int fd);
ssize_t sys$read(int fd, void* outbuf, size_t nread); ssize_t sys$read(int fd, void* outbuf, size_t nread);
ssize_t sys$write(int fd, const void*, size_t); ssize_t sys$write(int fd, const void*, size_t);

View file

@ -73,7 +73,7 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
case Syscall::SC_getcwd: case Syscall::SC_getcwd:
return current->sys$getcwd((char*)arg1, (size_t)arg2); return current->sys$getcwd((char*)arg1, (size_t)arg2);
case Syscall::SC_open: case Syscall::SC_open:
return current->sys$open((const char*)arg1, (int)arg2); return current->sys$open((const char*)arg1, (int)arg2, (mode_t)arg3);
case Syscall::SC_write: case Syscall::SC_write:
return current->sys$write((int)arg1, (const void*)arg2, (size_t)arg3); return current->sys$write((int)arg1, (const void*)arg2, (size_t)arg3);
case Syscall::SC_close: case Syscall::SC_close:

View file

@ -7,6 +7,7 @@
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/types.h>
#include <Kernel/Syscall.h> #include <Kernel/Syscall.h>
extern "C" { extern "C" {
@ -91,7 +92,7 @@ int open(const char* path, int options, ...)
{ {
va_list ap; va_list ap;
va_start(ap, options); va_start(ap, options);
int rc = syscall(SC_open, path, options, ap); int rc = syscall(SC_open, path, options, va_arg(ap, mode_t));
va_end(ap); va_end(ap);
__RETURN_WITH_ERRNO(rc, rc, -1); __RETURN_WITH_ERRNO(rc, rc, -1);
} }

View file

@ -1,6 +1,26 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#include <utime.h> #include <utime.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
static bool file_exists(const char* path)
{
struct stat st;
int rc = stat(path, &st);
if (rc < 0) {
if (errno == ENOENT)
return false;
}
if (rc == 0) {
return true;
}
perror("stat");
exit(1);
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
@ -8,9 +28,22 @@ int main(int argc, char** argv)
fprintf(stderr, "usage: touch <path>\n"); fprintf(stderr, "usage: touch <path>\n");
return 1; return 1;
} }
int rc = utime(argv[1], nullptr); if (file_exists(argv[1])) {
if (rc < 0) int rc = utime(argv[1], nullptr);
perror("utime"); if (rc < 0)
perror("utime");
} else {
int fd = open(argv[1], O_CREAT, 0010644);
if (fd < 0) {
perror("open");
return 1;
}
int rc = close(fd);
if (rc < 0) {
perror("close");
return 1;
}
}
return 0; return 0;
} }

View file

@ -435,7 +435,12 @@ bool Ext2FSInode::add_child(InodeIdentifier child_id, const String& name, byte f
} }
entries.append({ name.characters(), name.length(), child_id, file_type }); entries.append({ name.characters(), name.length(), child_id, file_type });
return fs().write_directory_inode(index(), move(entries)); bool success = fs().write_directory_inode(index(), move(entries));
if (success) {
LOCKER(m_lock);
m_lookup_cache.set(name, child_id.index());
}
return success;
} }
bool Ext2FS::write_directory_inode(unsigned directoryInode, Vector<DirectoryEntry>&& entries) bool Ext2FS::write_directory_inode(unsigned directoryInode, Vector<DirectoryEntry>&& entries)
@ -598,27 +603,29 @@ bool Ext2FS::write_ext2_inode(unsigned inode, const ext2_inode& e2inode)
Vector<Ext2FS::BlockIndex> Ext2FS::allocate_blocks(unsigned group, unsigned count) Vector<Ext2FS::BlockIndex> Ext2FS::allocate_blocks(unsigned group, unsigned count)
{ {
dbgprintf("Ext2FS: allocateBlocks(group: %u, count: %u)\n", group, count); dbgprintf("Ext2FS: allocate_blocks(group: %u, count: %u)\n", group, count);
if (count == 0)
return { };
auto& bgd = group_descriptor(group); auto& bgd = group_descriptor(group);
if (bgd.bg_free_blocks_count < count) { if (bgd.bg_free_blocks_count < 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); kprintf("Ext2FS: allocate_blocks can't allocate out of group %u, wanted %u but only %u available\n", group, count, bgd.bg_free_blocks_count);
return { }; return { };
} }
// FIXME: Implement a scan that finds consecutive blocks if possible. // FIXME: Implement a scan that finds consecutive blocks if possible.
Vector<BlockIndex> blocks; Vector<BlockIndex> blocks;
traverse_block_bitmap(group, [&blocks, count] (unsigned firstBlockInBitmap, const Bitmap& bitmap) { traverse_block_bitmap(group, [&blocks, count] (unsigned first_block_in_bitmap, const Bitmap& bitmap) {
for (unsigned i = 0; i < bitmap.size(); ++i) { for (unsigned i = 0; i < bitmap.size(); ++i) {
if (!bitmap.get(i)) { if (!bitmap.get(i)) {
blocks.append(firstBlockInBitmap + i); blocks.append(first_block_in_bitmap + i);
if (blocks.size() == count) if (blocks.size() == count)
return false; return false;
} }
} }
return true; return true;
}); });
dbgprintf("Ext2FS: allocateBlock found these blocks:\n"); dbgprintf("Ext2FS: allocate_block found these blocks:\n");
for (auto& bi : blocks) { for (auto& bi : blocks) {
dbgprintf(" > %u\n", bi); dbgprintf(" > %u\n", bi);
} }
@ -628,7 +635,7 @@ Vector<Ext2FS::BlockIndex> Ext2FS::allocate_blocks(unsigned group, unsigned coun
unsigned Ext2FS::allocate_inode(unsigned preferredGroup, unsigned expectedSize) unsigned Ext2FS::allocate_inode(unsigned preferredGroup, unsigned expectedSize)
{ {
dbgprintf("Ext2FS: allocateInode(preferredGroup: %u, expectedSize: %u)\n", preferredGroup, expectedSize); dbgprintf("Ext2FS: allocate_inode(preferredGroup: %u, expectedSize: %u)\n", preferredGroup, expectedSize);
unsigned neededBlocks = ceilDiv(expectedSize, blockSize()); unsigned neededBlocks = ceilDiv(expectedSize, blockSize());
@ -651,11 +658,11 @@ unsigned Ext2FS::allocate_inode(unsigned preferredGroup, unsigned expectedSize)
} }
if (!groupIndex) { if (!groupIndex) {
kprintf("Ext2FS: allocateInode: no suitable group found for new inode with %u blocks needed :(\n", neededBlocks); kprintf("Ext2FS: allocate_inode: no suitable group found for new inode with %u blocks needed :(\n", neededBlocks);
return 0; return 0;
} }
dbgprintf("Ext2FS: allocateInode: found suitable group [%u] for new inode with %u blocks needed :^)\n", groupIndex, neededBlocks); dbgprintf("Ext2FS: allocate_inode: found suitable group [%u] for new inode with %u blocks needed :^)\n", groupIndex, neededBlocks);
unsigned firstFreeInodeInGroup = 0; unsigned firstFreeInodeInGroup = 0;
traverse_inode_bitmap(groupIndex, [&firstFreeInodeInGroup] (unsigned firstInodeInBitmap, const Bitmap& bitmap) { traverse_inode_bitmap(groupIndex, [&firstFreeInodeInGroup] (unsigned firstInodeInBitmap, const Bitmap& bitmap) {
@ -669,7 +676,7 @@ unsigned Ext2FS::allocate_inode(unsigned preferredGroup, unsigned expectedSize)
}); });
if (!firstFreeInodeInGroup) { if (!firstFreeInodeInGroup) {
kprintf("Ext2FS: firstFreeInodeInGroup returned no inode, despite bgd claiming there are inodes :(\n"); kprintf("Ext2FS: first_free_inode_in_group returned no inode, despite bgd claiming there are inodes :(\n");
return 0; return 0;
} }
@ -841,14 +848,15 @@ RetainPtr<Inode> Ext2FS::create_inode(InodeIdentifier parent_id, const String& n
// NOTE: This doesn't commit the inode allocation just yet! // NOTE: This doesn't commit the inode allocation just yet!
auto inode_id = allocate_inode(0, 0); auto inode_id = allocate_inode(0, 0);
if (!inode_id) { if (!inode_id) {
kprintf("Ext2FS: createInode: allocate_inode failed\n"); kprintf("Ext2FS: create_inode: allocate_inode failed\n");
error = -ENOSPC; error = -ENOSPC;
return { }; return { };
} }
auto blocks = allocate_blocks(group_index_from_inode(inode_id), ceilDiv(size, blockSize())); auto needed_blocks = ceilDiv(size, blockSize());
if (blocks.is_empty()) { auto blocks = allocate_blocks(group_index_from_inode(inode_id), needed_blocks);
kprintf("Ext2FS: createInode: allocate_blocks failed\n"); if (blocks.size() != needed_blocks) {
kprintf("Ext2FS: create_inode: allocate_blocks failed\n");
error = -ENOSPC; error = -ENOSPC;
return { }; return { };
} }

View file

@ -136,12 +136,15 @@ RetainPtr<FileDescriptor> VFS::open(RetainPtr<CharacterDevice>&& device, int& er
return FileDescriptor::create(move(device)); return FileDescriptor::create(move(device));
} }
RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options, InodeIdentifier base) RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options, mode_t mode, InodeIdentifier base)
{ {
auto inode_id = resolve_path(path, base, error, options); auto inode_id = resolve_path(path, base, error, options);
auto inode = get_inode(inode_id); auto inode = get_inode(inode_id);
if (!inode) if (!inode) {
if (options & O_CREAT)
return create(path, error, options, mode, base);
return nullptr; return nullptr;
}
auto metadata = inode->metadata(); auto metadata = inode->metadata();
if (metadata.isCharacterDevice()) { if (metadata.isCharacterDevice()) {
auto it = m_character_devices.find(encodedDevice(metadata.majorDevice, metadata.minorDevice)); auto it = m_character_devices.find(encodedDevice(metadata.majorDevice, metadata.minorDevice));
@ -154,13 +157,37 @@ RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options,
return FileDescriptor::create(move(inode)); return FileDescriptor::create(move(inode));
} }
RetainPtr<FileDescriptor> VFS::create(const String& path, InodeIdentifier base, int& error) RetainPtr<FileDescriptor> VFS::create(const String& path, int& error, int options, mode_t mode, InodeIdentifier base)
{ {
// FIXME: Do the real thing, not just this fake thing! (void) options;
(void) path; error = -EWHYTHO;
(void) base; // FIXME: This won't work nicely across mount boundaries.
m_root_inode->fs().create_inode(m_root_inode->fs().root_inode(), "empty", 0100644, 0, error); FileSystemPath p(path);
return nullptr; if (!p.is_valid()) {
error = -EINVAL;
return nullptr;
}
InodeIdentifier parent_dir;
auto existing_dir = resolve_path(path, base, error, 0, &parent_dir);
if (existing_dir.is_valid()) {
error = -EEXIST;
return nullptr;
}
if (!parent_dir.is_valid()) {
error = -ENOENT;
return nullptr;
}
if (error != -ENOENT) {
return nullptr;
}
dbgprintf("VFS::create_file: '%s' in %u:%u\n", p.basename().characters(), parent_dir.fsid(), parent_dir.index());
auto new_file = base.fs()->create_inode(base.fs()->root_inode(), p.basename(), mode, 0, error);
if (!new_file)
return nullptr;
error = 0;
return FileDescriptor::create(move(new_file));
} }
bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error) bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error)

View file

@ -64,8 +64,8 @@ public:
bool mount(RetainPtr<FS>&&, const String& path); bool mount(RetainPtr<FS>&&, const String& path);
RetainPtr<FileDescriptor> open(RetainPtr<CharacterDevice>&&, int& error, int options); RetainPtr<FileDescriptor> open(RetainPtr<CharacterDevice>&&, int& error, int options);
RetainPtr<FileDescriptor> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier()); RetainPtr<FileDescriptor> open(const String& path, int& error, int options, mode_t mode, InodeIdentifier base = InodeIdentifier());
RetainPtr<FileDescriptor> create(const String& path, InodeIdentifier base, int& error); RetainPtr<FileDescriptor> create(const String& path, int& error, int options, mode_t mode, InodeIdentifier base);
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error); bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
bool touch(const String&path); bool touch(const String&path);