mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 12:35:14 +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:
parent
a47f33bed3
commit
f70136a324
Notes:
sideshowbarker
2024-07-19 15:59:09 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/f70136a3245
9 changed files with 108 additions and 39 deletions
|
@ -124,7 +124,7 @@ void init_ksyms()
|
|||
void load_ksyms()
|
||||
{
|
||||
int error;
|
||||
auto descriptor = VFS::the().open("/kernel.map", error);
|
||||
auto descriptor = VFS::the().open("/kernel.map", error, 0, 0);
|
||||
if (!descriptor) {
|
||||
kprintf("Failed to open /kernel.map\n");
|
||||
} else {
|
||||
|
|
|
@ -289,7 +289,7 @@ int Process::do_exec(const String& path, Vector<String>&& arguments, Vector<Stri
|
|||
return -ENOENT;
|
||||
|
||||
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) {
|
||||
ASSERT(error != 0);
|
||||
return error;
|
||||
|
@ -1117,7 +1117,7 @@ int Process::sys$utime(const char* pathname, const Unix::utimbuf* buf)
|
|||
return -EFAULT;
|
||||
String path(pathname);
|
||||
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)
|
||||
return error;
|
||||
auto& inode = *descriptor->inode();
|
||||
|
@ -1206,7 +1206,7 @@ int Process::sys$lstat(const char* path, Unix::stat* statbuf)
|
|||
if (!validate_write_typed(statbuf))
|
||||
return -EFAULT;
|
||||
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)
|
||||
return error;
|
||||
descriptor->stat(statbuf);
|
||||
|
@ -1218,7 +1218,7 @@ int Process::sys$stat(const char* path, Unix::stat* statbuf)
|
|||
if (!validate_write_typed(statbuf))
|
||||
return -EFAULT;
|
||||
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)
|
||||
return error;
|
||||
descriptor->stat(statbuf);
|
||||
|
@ -1233,7 +1233,7 @@ int Process::sys$readlink(const char* path, char* buffer, size_t size)
|
|||
return -EFAULT;
|
||||
|
||||
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)
|
||||
return error;
|
||||
|
||||
|
@ -1255,7 +1255,7 @@ int Process::sys$chdir(const char* path)
|
|||
if (!validate_read_str(path))
|
||||
return -EFAULT;
|
||||
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)
|
||||
return error;
|
||||
if (!descriptor->is_directory())
|
||||
|
@ -1288,7 +1288,7 @@ size_t Process::number_of_open_file_descriptors() const
|
|||
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
|
||||
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;
|
||||
int error = -EWHYTHO;
|
||||
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)
|
||||
return error;
|
||||
if (options & O_DIRECTORY && !descriptor->is_directory())
|
||||
|
|
|
@ -140,7 +140,7 @@ public:
|
|||
pid_t sys$getpid();
|
||||
pid_t sys$getppid();
|
||||
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);
|
||||
ssize_t sys$read(int fd, void* outbuf, size_t nread);
|
||||
ssize_t sys$write(int fd, const void*, size_t);
|
||||
|
|
|
@ -73,7 +73,7 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
case Syscall::SC_getcwd:
|
||||
return current->sys$getcwd((char*)arg1, (size_t)arg2);
|
||||
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:
|
||||
return current->sys$write((int)arg1, (const void*)arg2, (size_t)arg3);
|
||||
case Syscall::SC_close:
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <Kernel/Syscall.h>
|
||||
|
||||
extern "C" {
|
||||
|
@ -91,7 +92,7 @@ int open(const char* path, int options, ...)
|
|||
{
|
||||
va_list ap;
|
||||
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);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <utime.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.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)
|
||||
{
|
||||
|
@ -8,9 +28,22 @@ int main(int argc, char** argv)
|
|||
fprintf(stderr, "usage: touch <path>\n");
|
||||
return 1;
|
||||
}
|
||||
int rc = utime(argv[1], nullptr);
|
||||
if (rc < 0)
|
||||
perror("utime");
|
||||
if (file_exists(argv[1])) {
|
||||
int rc = utime(argv[1], nullptr);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 });
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
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 { };
|
||||
}
|
||||
|
||||
// FIXME: Implement a scan that finds consecutive blocks if possible.
|
||||
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) {
|
||||
if (!bitmap.get(i)) {
|
||||
blocks.append(firstBlockInBitmap + i);
|
||||
blocks.append(first_block_in_bitmap + i);
|
||||
if (blocks.size() == count)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
dbgprintf("Ext2FS: allocateBlock found these blocks:\n");
|
||||
dbgprintf("Ext2FS: allocate_block found these blocks:\n");
|
||||
for (auto& bi : blocks) {
|
||||
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)
|
||||
{
|
||||
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());
|
||||
|
||||
|
@ -651,11 +658,11 @@ unsigned Ext2FS::allocate_inode(unsigned preferredGroup, unsigned expectedSize)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
traverse_inode_bitmap(groupIndex, [&firstFreeInodeInGroup] (unsigned firstInodeInBitmap, const Bitmap& bitmap) {
|
||||
|
@ -669,7 +676,7 @@ unsigned Ext2FS::allocate_inode(unsigned preferredGroup, unsigned expectedSize)
|
|||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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!
|
||||
auto inode_id = allocate_inode(0, 0);
|
||||
if (!inode_id) {
|
||||
kprintf("Ext2FS: createInode: allocate_inode failed\n");
|
||||
kprintf("Ext2FS: create_inode: allocate_inode failed\n");
|
||||
error = -ENOSPC;
|
||||
return { };
|
||||
}
|
||||
|
||||
auto blocks = allocate_blocks(group_index_from_inode(inode_id), ceilDiv(size, blockSize()));
|
||||
if (blocks.is_empty()) {
|
||||
kprintf("Ext2FS: createInode: allocate_blocks failed\n");
|
||||
auto needed_blocks = ceilDiv(size, blockSize());
|
||||
auto blocks = allocate_blocks(group_index_from_inode(inode_id), needed_blocks);
|
||||
if (blocks.size() != needed_blocks) {
|
||||
kprintf("Ext2FS: create_inode: allocate_blocks failed\n");
|
||||
error = -ENOSPC;
|
||||
return { };
|
||||
}
|
||||
|
|
|
@ -136,12 +136,15 @@ RetainPtr<FileDescriptor> VFS::open(RetainPtr<CharacterDevice>&& device, int& er
|
|||
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 = get_inode(inode_id);
|
||||
if (!inode)
|
||||
if (!inode) {
|
||||
if (options & O_CREAT)
|
||||
return create(path, error, options, mode, base);
|
||||
return nullptr;
|
||||
}
|
||||
auto metadata = inode->metadata();
|
||||
if (metadata.isCharacterDevice()) {
|
||||
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));
|
||||
}
|
||||
|
||||
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) path;
|
||||
(void) base;
|
||||
m_root_inode->fs().create_inode(m_root_inode->fs().root_inode(), "empty", 0100644, 0, error);
|
||||
return nullptr;
|
||||
(void) options;
|
||||
error = -EWHYTHO;
|
||||
// FIXME: This won't work nicely across mount boundaries.
|
||||
FileSystemPath p(path);
|
||||
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)
|
||||
|
|
|
@ -64,8 +64,8 @@ public:
|
|||
bool mount(RetainPtr<FS>&&, const String& path);
|
||||
|
||||
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> create(const String& path, InodeIdentifier base, int& error);
|
||||
RetainPtr<FileDescriptor> open(const String& path, int& error, int options, mode_t mode, InodeIdentifier base = InodeIdentifier());
|
||||
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 touch(const String&path);
|
||||
|
|
Loading…
Add table
Reference in a new issue