mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-22 12:35:14 +00:00
Implement basic chmod() syscall and /bin/chmod helper.
Only raw octal modes are supported right now. This patch also changes mode_t from 32-bit to 16-bit to match the on-disk type used by Ext2FS. I also ran into EPERM being errno=0 which was confusing, so I inserted an ESUCCESS in its place.
This commit is contained in:
parent
ad53f6afd3
commit
c30e2c8d44
Notes:
sideshowbarker
2024-07-19 15:55:24 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/c30e2c8d440
22 changed files with 156 additions and 4 deletions
|
@ -66,6 +66,47 @@ ALWAYS_INLINE int printNumber(PutChFunc putch, char*& bufptr, dword number, bool
|
|||
return fieldWidth;
|
||||
}
|
||||
|
||||
template<typename PutChFunc>
|
||||
ALWAYS_INLINE int print_octal_number(PutChFunc putch, char*& bufptr, dword number, bool leftPad, bool zeroPad, dword fieldWidth)
|
||||
{
|
||||
dword divisor = 134217728;
|
||||
char ch;
|
||||
char padding = 1;
|
||||
char buf[32];
|
||||
char* p = buf;
|
||||
|
||||
for (;;) {
|
||||
ch = '0' + (number / divisor);
|
||||
number %= divisor;
|
||||
if (ch != '0')
|
||||
padding = 0;
|
||||
if (!padding || divisor == 1)
|
||||
*(p++) = ch;
|
||||
if (divisor == 1)
|
||||
break;
|
||||
divisor /= 8;
|
||||
}
|
||||
|
||||
size_t numlen = p - buf;
|
||||
if (!fieldWidth || fieldWidth < numlen)
|
||||
fieldWidth = numlen;
|
||||
if (!leftPad) {
|
||||
for (unsigned i = 0; i < fieldWidth - numlen; ++i) {
|
||||
putch(bufptr, zeroPad ? '0' : ' ');
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < numlen; ++i) {
|
||||
putch(bufptr, buf[i]);
|
||||
}
|
||||
if (leftPad) {
|
||||
for (unsigned i = 0; i < fieldWidth - numlen; ++i) {
|
||||
putch(bufptr, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
return fieldWidth;
|
||||
}
|
||||
|
||||
template<typename PutChFunc>
|
||||
ALWAYS_INLINE int printString(PutChFunc putch, char*& bufptr, const char* str, bool leftPad, dword fieldWidth)
|
||||
{
|
||||
|
@ -145,6 +186,10 @@ one_more:
|
|||
ret += printNumber(putch, bufptr, va_arg(ap, dword), leftPad, zeroPad, fieldWidth);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
ret += print_octal_number(putch, bufptr, va_arg(ap, dword), leftPad, zeroPad, fieldWidth);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
ret += printHex(putch, bufptr, va_arg(ap, dword), 8);
|
||||
break;
|
||||
|
|
|
@ -1292,3 +1292,13 @@ size_t Ext2FSInode::directory_entry_count() const
|
|||
LOCKER(m_lock);
|
||||
return m_lookup_cache.size();
|
||||
}
|
||||
|
||||
bool Ext2FSInode::chmod(mode_t mode, int& error)
|
||||
{
|
||||
error = 0;
|
||||
if (m_raw_inode.i_mode == mode)
|
||||
return true;
|
||||
m_raw_inode.i_mode = mode;
|
||||
set_metadata_dirty(true);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ private:
|
|||
virtual int increment_link_count() override;
|
||||
virtual int decrement_link_count() override;
|
||||
virtual size_t directory_entry_count() const override;
|
||||
virtual bool chmod(mode_t, int& error) override;
|
||||
|
||||
void populate_lookup_cache() const;
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
bool is_symlink() const { return metadata().isSymbolicLink(); }
|
||||
bool is_directory() const { return metadata().isDirectory(); }
|
||||
bool is_character_device() const { return metadata().isCharacterDevice(); }
|
||||
mode_t mode() const { return metadata().mode; }
|
||||
|
||||
InodeIdentifier identifier() const { return { fsid(), index() }; }
|
||||
virtual InodeMetadata metadata() const = 0;
|
||||
|
@ -89,6 +90,7 @@ public:
|
|||
virtual bool remove_child(const String& name, int& error) = 0;
|
||||
virtual RetainPtr<Inode> parent() const = 0;
|
||||
virtual size_t directory_entry_count() const = 0;
|
||||
virtual bool chmod(mode_t, int& error) = 0;
|
||||
|
||||
bool is_metadata_dirty() const { return m_metadata_dirty; }
|
||||
|
||||
|
|
|
@ -2120,3 +2120,13 @@ int Process::sys$read_tsc(dword* lsw, dword* msw)
|
|||
read_tsc(*lsw, *msw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$chmod(const char* pathname, mode_t mode)
|
||||
{
|
||||
if (!validate_read_str(pathname))
|
||||
return -EFAULT;
|
||||
int error;
|
||||
if (!VFS::the().chmod(String(pathname), mode, *cwd_inode(), error))
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -196,6 +196,7 @@ public:
|
|||
int sys$unlink(const char* pathname);
|
||||
int sys$rmdir(const char* pathname);
|
||||
int sys$read_tsc(dword* lsw, dword* msw);
|
||||
int sys$chmod(const char* pathname, mode_t);
|
||||
|
||||
int gui$create_window(const GUI_WindowParameters*);
|
||||
int gui$destroy_window(int window_id);
|
||||
|
|
|
@ -312,3 +312,9 @@ size_t SynthFSInode::directory_entry_count() const
|
|||
// NOTE: The 2 is for '.' and '..'
|
||||
return m_children.size() + 2;
|
||||
}
|
||||
|
||||
bool SynthFSInode::chmod(mode_t, int& error)
|
||||
{
|
||||
error = -EPERM;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ private:
|
|||
virtual bool remove_child(const String& name, int& error) override;
|
||||
virtual RetainPtr<Inode> parent() const override;
|
||||
virtual size_t directory_entry_count() const override;
|
||||
virtual bool chmod(mode_t, int& error) override;
|
||||
|
||||
SynthFS& fs();
|
||||
const SynthFS& fs() const;
|
||||
|
|
|
@ -221,6 +221,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
return current->gui$set_global_cursor_tracking_enabled((int)arg1, (bool)arg2);
|
||||
case Syscall::SC_rmdir:
|
||||
return current->sys$rmdir((const char*)arg1);
|
||||
case Syscall::SC_chmod:
|
||||
return current->sys$chmod((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;
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
__ENUMERATE_SYSCALL(gui_notify_paint_finished) \
|
||||
__ENUMERATE_SYSCALL(gui_set_global_cursor_tracking_enabled) \
|
||||
__ENUMERATE_SYSCALL(rmdir) \
|
||||
__ENUMERATE_SYSCALL(chmod) \
|
||||
|
||||
|
||||
#ifdef SERENITY
|
||||
|
|
|
@ -214,7 +214,7 @@ struct winsize {
|
|||
|
||||
typedef dword dev_t;
|
||||
typedef dword ino_t;
|
||||
typedef dword mode_t;
|
||||
typedef word mode_t;
|
||||
typedef dword nlink_t;
|
||||
typedef dword uid_t;
|
||||
typedef dword gid_t;
|
||||
|
|
|
@ -228,6 +228,37 @@ bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& erro
|
|||
return false;
|
||||
}
|
||||
|
||||
bool VFS::chmod(const String& path, mode_t mode, Inode& base, int& error)
|
||||
{
|
||||
error = -EWHYTHO;
|
||||
// FIXME: This won't work nicely across mount boundaries.
|
||||
FileSystemPath p(path);
|
||||
if (!p.is_valid()) {
|
||||
error = -EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
InodeIdentifier parent_dir;
|
||||
auto inode_id = resolve_path(path, base.identifier(), error, 0, &parent_dir);
|
||||
if (!inode_id.is_valid()) {
|
||||
error = -ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto inode = get_inode(inode_id);
|
||||
|
||||
// FIXME: Permission checks.
|
||||
|
||||
// Only change the permission bits.
|
||||
mode = (inode->mode() & ~04777) | (mode & 04777);
|
||||
|
||||
kprintf("VFS::chmod(): %u:%u mode %o\n", inode_id.fsid(), inode_id.index(), mode);
|
||||
if (!inode->chmod(mode, error))
|
||||
return false;
|
||||
error = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFS::unlink(const String& path, Inode& base, int& error)
|
||||
{
|
||||
error = -EWHYTHO;
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
|
||||
bool unlink(const String& path, Inode& base, int& error);
|
||||
bool rmdir(const String& path, Inode& base, int& error);
|
||||
bool chmod(const String& path, mode_t, Inode& base, int& error);
|
||||
|
||||
void register_character_device(CharacterDevice&);
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ cp -v ../Userland/guitest2 mnt/bin/guitest2
|
|||
cp -v ../Userland/sysctl mnt/bin/sysctl
|
||||
cp -v ../Terminal/Terminal mnt/bin/Terminal
|
||||
cp -v ../Userland/dmesg mnt/bin/dmesg
|
||||
cp -v ../Userland/chmod mnt/bin/chmod
|
||||
sh sync-local.sh
|
||||
cp -v kernel.map mnt/
|
||||
ln -s dir_a mnt/dir_cur
|
||||
|
|
|
@ -37,7 +37,7 @@ typedef dword ino_t;
|
|||
typedef signed_dword off_t;
|
||||
|
||||
typedef dword dev_t;
|
||||
typedef dword mode_t;
|
||||
typedef word mode_t;
|
||||
typedef dword nlink_t;
|
||||
typedef dword blksize_t;
|
||||
typedef dword blkcnt_t;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#define __ENUMERATE_ALL_ERRORS \
|
||||
__ERROR(ESUCCESS, "Success (not an error)") \
|
||||
__ERROR(EPERM, "Operation not permitted") \
|
||||
__ERROR(ENOENT, "No such file or directory") \
|
||||
__ERROR(ESRCH, "No such process") \
|
||||
|
|
|
@ -15,5 +15,11 @@ int mkdir(const char* pathname, mode_t mode)
|
|||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int chmod(const char* pathname, mode_t mode)
|
||||
{
|
||||
int rc = syscall(SC_chmod, pathname, mode);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ typedef uint32_t ino_t;
|
|||
typedef int32_t off_t;
|
||||
|
||||
typedef uint32_t dev_t;
|
||||
typedef uint32_t mode_t;
|
||||
typedef uint16_t mode_t;
|
||||
typedef uint32_t nlink_t;
|
||||
typedef uint32_t blksize_t;
|
||||
typedef uint32_t blkcnt_t;
|
||||
|
|
|
@ -97,7 +97,7 @@ int open(const char* path, int options, ...)
|
|||
{
|
||||
va_list ap;
|
||||
va_start(ap, options);
|
||||
int rc = syscall(SC_open, path, options, va_arg(ap, mode_t));
|
||||
int rc = syscall(SC_open, path, options, (mode_t)va_arg(ap, unsigned));
|
||||
va_end(ap);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
|
@ -28,3 +28,4 @@ rm
|
|||
cp
|
||||
rmdir
|
||||
dmesg
|
||||
chmod
|
||||
|
|
|
@ -25,6 +25,7 @@ OBJS = \
|
|||
cp.o \
|
||||
rmdir.o \
|
||||
dmesg.o \
|
||||
chmod.o \
|
||||
rm.o
|
||||
|
||||
APPS = \
|
||||
|
@ -55,6 +56,7 @@ APPS = \
|
|||
cp \
|
||||
rmdir \
|
||||
dmesg \
|
||||
chmod \
|
||||
rm
|
||||
|
||||
ARCH_FLAGS =
|
||||
|
@ -159,6 +161,9 @@ rm: rm.o
|
|||
rmdir: rmdir.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||
|
||||
chmod: chmod.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
|
|
27
Userland/chmod.cpp
Normal file
27
Userland/chmod.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
printf("usage: chmod <octal-mode> <path>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mode_t mode;
|
||||
int rc = sscanf(argv[1], "%o", &mode);
|
||||
if (rc != 1) {
|
||||
perror("sscanf");
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = chmod(argv[2], mode);
|
||||
if (rc < 0) {
|
||||
perror("chmod");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue