summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-01-22 00:58:13 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-01-22 00:58:56 +0100
commitf70136a32455e59ef4adf9f35031a22c7027c8f6 (patch)
treed27e39389f28cc867bd19afef273517cbbd96cd5
parenta47f33bed3c5b7860dca30a185c1e83c5a8f058b (diff)
downloadserenity-f70136a32455e59ef4adf9f35031a22c7027c8f6.zip
Kernel: Support open() with O_CREAT.
It's now possible to create zero-length files! :^) Also hook up the new functionality in /bin/touch.
-rw-r--r--Kernel/KSyms.cpp2
-rw-r--r--Kernel/Process.cpp16
-rw-r--r--Kernel/Process.h2
-rw-r--r--Kernel/Syscall.cpp2
-rw-r--r--LibC/unistd.cpp3
-rw-r--r--Userland/touch.cpp39
-rw-r--r--VirtualFileSystem/Ext2FileSystem.cpp36
-rw-r--r--VirtualFileSystem/VirtualFileSystem.cpp43
-rw-r--r--VirtualFileSystem/VirtualFileSystem.h4
9 files changed, 108 insertions, 39 deletions
diff --git a/Kernel/KSyms.cpp b/Kernel/KSyms.cpp
index 4168e8a43c..4a89206fee 100644
--- a/Kernel/KSyms.cpp
+++ b/Kernel/KSyms.cpp
@@ -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 {
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 71d5a7f0a1..df38358ee0 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -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())
diff --git a/Kernel/Process.h b/Kernel/Process.h
index 858a3f0988..c4a57402ac 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -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);
diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp
index 9a551b2a37..3e8d5ba9a6 100644
--- a/Kernel/Syscall.cpp
+++ b/Kernel/Syscall.cpp
@@ -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:
diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp
index d039c1daef..0e10e7811b 100644
--- a/LibC/unistd.cpp
+++ b/LibC/unistd.cpp
@@ -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);
}
diff --git a/Userland/touch.cpp b/Userland/touch.cpp
index 6d857198f6..3d0dcb58bf 100644
--- a/Userland/touch.cpp
+++ b/Userland/touch.cpp
@@ -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;
}
diff --git a/VirtualFileSystem/Ext2FileSystem.cpp b/VirtualFileSystem/Ext2FileSystem.cpp
index 106b1058dd..71b20b8dd3 100644
--- a/VirtualFileSystem/Ext2FileSystem.cpp
+++ b/VirtualFileSystem/Ext2FileSystem.cpp
@@ -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 { };
}
diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp
index 957c39421c..f6e3484d04 100644
--- a/VirtualFileSystem/VirtualFileSystem.cpp
+++ b/VirtualFileSystem/VirtualFileSystem.cpp
@@ -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)
diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h
index 4472eb5e34..543d9bd4d4 100644
--- a/VirtualFileSystem/VirtualFileSystem.h
+++ b/VirtualFileSystem/VirtualFileSystem.h
@@ -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);