mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 19:22:45 +00:00 
			
		
		
		
	Implement utime() along with a naive /bin/touch.
This synchronous approach to inodes is silly, obviously. I need to rework it so that the in-memory CoreInode object is the canonical inode, and then we just need a sync() that flushes pending changes to disk.
This commit is contained in:
		
							parent
							
								
									e03d341615
								
							
						
					
					
						commit
						038d8641f9
					
				
					 22 changed files with 122 additions and 22 deletions
				
			
		|  | @ -1079,6 +1079,30 @@ int Process::sys$close(int fd) | ||||||
|     return rc; |     return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int Process::sys$utime(const char* pathname, const Unix::utimbuf* buf) | ||||||
|  | { | ||||||
|  |     if (!validate_read_str(pathname)) | ||||||
|  |         return -EFAULT; | ||||||
|  |     if (buf && !validate_read_typed(buf)) | ||||||
|  |         return -EFAULT; | ||||||
|  |     String path(pathname); | ||||||
|  |     int error; | ||||||
|  |     auto descriptor = VFS::the().open(move(path), error, 0, cwd_inode()->identifier()); | ||||||
|  |     if (!descriptor) | ||||||
|  |         return error; | ||||||
|  |     Unix::time_t atime; | ||||||
|  |     Unix::time_t mtime; | ||||||
|  |     if (buf) { | ||||||
|  |         atime = buf->actime; | ||||||
|  |         mtime = buf->modtime; | ||||||
|  |     } else { | ||||||
|  |         auto now = RTC::now(); | ||||||
|  |         mtime = now; | ||||||
|  |         atime = now; | ||||||
|  |     } | ||||||
|  |     return descriptor->set_atime_and_mtime(atime, mtime); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int Process::sys$access(const char* pathname, int mode) | int Process::sys$access(const char* pathname, int mode) | ||||||
| { | { | ||||||
|     (void) mode; |     (void) mode; | ||||||
|  |  | ||||||
|  | @ -173,6 +173,7 @@ public: | ||||||
|     int sys$ioctl(int fd, unsigned request, unsigned arg); |     int sys$ioctl(int fd, unsigned request, unsigned arg); | ||||||
|     int sys$mkdir(const char* pathname, mode_t mode); |     int sys$mkdir(const char* pathname, mode_t mode); | ||||||
|     Unix::clock_t sys$times(Unix::tms*); |     Unix::clock_t sys$times(Unix::tms*); | ||||||
|  |     int sys$utime(const char* pathname, const struct Unix::utimbuf*); | ||||||
| 
 | 
 | ||||||
|     static void initialize(); |     static void initialize(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -177,6 +177,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2, | ||||||
|         return current->sys$mkdir((const char*)arg1, (mode_t)arg2); |         return current->sys$mkdir((const char*)arg1, (mode_t)arg2); | ||||||
|     case Syscall::SC_times: |     case Syscall::SC_times: | ||||||
|         return current->sys$times((Unix::tms*)arg1); |         return current->sys$times((Unix::tms*)arg1); | ||||||
|  |     case Syscall::SC_utime: | ||||||
|  |         return current->sys$utime((const char*)arg1, (const Unix::utimbuf*)arg2); | ||||||
|     default: |     default: | ||||||
|         kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); |         kprintf("<%u> int0x80: Unknown function %u requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3); | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
|  | @ -64,6 +64,7 @@ | ||||||
|     __ENUMERATE_SYSCALL(ioctl) \ |     __ENUMERATE_SYSCALL(ioctl) \ | ||||||
|     __ENUMERATE_SYSCALL(mkdir) \ |     __ENUMERATE_SYSCALL(mkdir) \ | ||||||
|     __ENUMERATE_SYSCALL(times) \ |     __ENUMERATE_SYSCALL(times) \ | ||||||
|  |     __ENUMERATE_SYSCALL(utime) \ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define DO_SYSCALL_A0(function) Syscall::invoke((dword)(function)) | #define DO_SYSCALL_A0(function) Syscall::invoke((dword)(function)) | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ cp -v ../Userland/kill mnt/bin/kill | ||||||
| cp -v ../Userland/tty mnt/bin/tty | cp -v ../Userland/tty mnt/bin/tty | ||||||
| cp -v ../Userland/strsignal mnt/bin/strsignal | cp -v ../Userland/strsignal mnt/bin/strsignal | ||||||
| cp -v ../Userland/mkdir mnt/bin/mkdir | cp -v ../Userland/mkdir mnt/bin/mkdir | ||||||
|  | cp -v ../Userland/touch mnt/bin/touch | ||||||
| sh sync-local.sh | sh sync-local.sh | ||||||
| cp -v kernel.map mnt/ | cp -v kernel.map mnt/ | ||||||
| ln -s dir_a mnt/dir_cur | ln -s dir_a mnt/dir_cur | ||||||
|  |  | ||||||
|  | @ -32,6 +32,7 @@ LIBC_OBJS = \ | ||||||
|        qsort.o \
 |        qsort.o \
 | ||||||
|        ioctl.o \
 |        ioctl.o \
 | ||||||
|        math.o \
 |        math.o \
 | ||||||
|  |        utime.o \
 | ||||||
|        entry.o |        entry.o | ||||||
| 
 | 
 | ||||||
| OBJS = $(AK_OBJS) $(LIBC_OBJS) | OBJS = $(AK_OBJS) $(LIBC_OBJS) | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								LibC/utime.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								LibC/utime.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | #include <utime.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <Kernel/Syscall.h> | ||||||
|  | 
 | ||||||
|  | extern "C" { | ||||||
|  | 
 | ||||||
|  | int utime(const char* pathname, const struct utimbuf* buf) | ||||||
|  | { | ||||||
|  |     int rc = Syscall::invoke(Syscall::SC_utime, (dword)pathname, (dword)buf); | ||||||
|  |     __RETURN_WITH_ERRNO(rc, rc, -1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										10
									
								
								LibC/utime.h
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								LibC/utime.h
									
										
									
									
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <sys/cdefs.h> | ||||||
|  | 
 | ||||||
|  | __BEGIN_DECLS | ||||||
|  | 
 | ||||||
|  | int utime(const char* pathname, const struct utimbuf*); | ||||||
|  | 
 | ||||||
|  | __END_DECLS | ||||||
|  | 
 | ||||||
							
								
								
									
										1
									
								
								Userland/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								Userland/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -21,3 +21,4 @@ ft2 | ||||||
| strsignal | strsignal | ||||||
| fgrep | fgrep | ||||||
| mkdir | mkdir | ||||||
|  | touch | ||||||
|  |  | ||||||
|  | @ -19,7 +19,8 @@ OBJS = \ | ||||||
|        strsignal.o \
 |        strsignal.o \
 | ||||||
|        fgrep.o \
 |        fgrep.o \
 | ||||||
|        tty.o \
 |        tty.o \
 | ||||||
|        mkdir.o |        mkdir.o \
 | ||||||
|  |        touch.o | ||||||
| 
 | 
 | ||||||
| APPS = \
 | APPS = \
 | ||||||
|        id \
 |        id \
 | ||||||
|  | @ -42,7 +43,8 @@ APPS = \ | ||||||
|        strsignal \
 |        strsignal \
 | ||||||
|        fgrep \
 |        fgrep \
 | ||||||
|        tty \
 |        tty \
 | ||||||
|        mkdir |        mkdir \
 | ||||||
|  |        touch | ||||||
| 
 | 
 | ||||||
| ARCH_FLAGS = | ARCH_FLAGS = | ||||||
| STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc | STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc | ||||||
|  | @ -125,6 +127,9 @@ strsignal: strsignal.o | ||||||
| mkdir: mkdir.o | mkdir: mkdir.o | ||||||
| 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | ||||||
| 
 | 
 | ||||||
|  | touch: touch.o | ||||||
|  | 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a | ||||||
|  | 
 | ||||||
| .cpp.o: | .cpp.o: | ||||||
| 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< | 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -152,6 +152,8 @@ int do_dir(const char* path) | ||||||
| 
 | 
 | ||||||
|         printf(" %10u  ", st.st_size); |         printf(" %10u  ", st.st_size); | ||||||
| 
 | 
 | ||||||
|  |         printf(" %10u  ", st.st_mtime); | ||||||
|  | 
 | ||||||
|         print_name(st, de->d_name, pathbuf); |         print_name(st, de->d_name, pathbuf); | ||||||
| 
 | 
 | ||||||
|         printf("\n"); |         printf("\n"); | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								Userland/touch.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Userland/touch.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <utime.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | 
 | ||||||
|  | int main(int argc, char** argv) | ||||||
|  | { | ||||||
|  |     if (argc != 2) { | ||||||
|  |         fprintf(stderr, "usage: touch <path>\n"); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  |     int rc = utime(argv[1], nullptr); | ||||||
|  |     if (rc < 0) | ||||||
|  |         perror("utime"); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @ -716,16 +716,18 @@ bool Ext2FS::modify_link_count(InodeIndex inode, int delta) | ||||||
|     return write_ext2_inode(inode, *e2inode); |     return write_ext2_inode(inode, *e2inode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Ext2FS::set_mtime(InodeIdentifier inode, dword timestamp) | int Ext2FS::set_atime_and_mtime(InodeIdentifier inode, dword atime, dword mtime) | ||||||
| { | { | ||||||
|     ASSERT(inode.fsid() == id()); |     ASSERT(inode.fsid() == id()); | ||||||
| 
 | 
 | ||||||
|     auto e2inode = lookup_ext2_inode(inode.index()); |     auto e2inode = lookup_ext2_inode(inode.index()); | ||||||
|     if (!e2inode) |     if (!e2inode) | ||||||
|         return false; |         return -EIO; | ||||||
| 
 | 
 | ||||||
|     kprintf("changing inode %u mtime from %u to %u\n", inode.index(), e2inode->i_mtime, timestamp); |     dbgprintf("changing inode %u atime from %u to %u\n", inode.index(), e2inode->i_atime, atime); | ||||||
|     e2inode->i_mtime = timestamp; |     dbgprintf("changing inode %u mtime from %u to %u\n", inode.index(), e2inode->i_mtime, mtime); | ||||||
|  |     e2inode->i_mtime = mtime; | ||||||
|  |     e2inode->i_atime = atime; | ||||||
| 
 | 
 | ||||||
|     return write_ext2_inode(inode.index(), *e2inode); |     return write_ext2_inode(inode.index(), *e2inode); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -72,7 +72,7 @@ private: | ||||||
|     virtual InodeIdentifier root_inode() const override; |     virtual InodeIdentifier root_inode() const override; | ||||||
|     virtual bool write_inode(InodeIdentifier, const ByteBuffer&) override; |     virtual bool write_inode(InodeIdentifier, const ByteBuffer&) override; | ||||||
|     virtual InodeMetadata inode_metadata(InodeIdentifier) const override; |     virtual InodeMetadata inode_metadata(InodeIdentifier) const override; | ||||||
|     virtual bool set_mtime(InodeIdentifier, dword timestamp) override; |     virtual int set_atime_and_mtime(InodeIdentifier, dword atime, dword mtime) override; | ||||||
|     virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override; |     virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override; | ||||||
|     virtual ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, size_t count, byte* buffer, FileDescriptor*) const override; |     virtual ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, size_t count, byte* buffer, FileDescriptor*) const override; | ||||||
|     virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override; |     virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override; | ||||||
|  |  | ||||||
|  | @ -288,3 +288,17 @@ FileDescriptor::FileDescriptor(FIFO& fifo, FIFO::Direction direction) | ||||||
| { | { | ||||||
|     m_fifo->open(direction); |     m_fifo->open(direction); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int FileDescriptor::set_atime_and_mtime(time_t atime, time_t mtime) | ||||||
|  | { | ||||||
|  |     if (!m_vnode || !m_vnode->core_inode()) | ||||||
|  |         return -EBADF; | ||||||
|  |     return m_vnode->core_inode()->set_atime_and_mtime(atime, mtime); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int FileDescriptor::set_ctime(time_t ctime) | ||||||
|  | { | ||||||
|  |     (void) ctime; | ||||||
|  |     // FIXME: Implement.
 | ||||||
|  |     ASSERT_NOT_REACHED(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -64,13 +64,15 @@ public: | ||||||
| 
 | 
 | ||||||
|     ByteBuffer& generator_cache() { return m_generator_cache; } |     ByteBuffer& generator_cache() { return m_generator_cache; } | ||||||
| 
 | 
 | ||||||
|  |     int set_atime_and_mtime(time_t, time_t); | ||||||
|  |     int set_ctime(time_t); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     friend class VFS; |     friend class VFS; | ||||||
|     explicit FileDescriptor(RetainPtr<Vnode>&&); |     explicit FileDescriptor(RetainPtr<Vnode>&&); | ||||||
|     FileDescriptor(FIFO&, FIFO::Direction); |     FileDescriptor(FIFO&, FIFO::Direction); | ||||||
| 
 | 
 | ||||||
|     RetainPtr<Vnode> m_vnode; |     RetainPtr<Vnode> m_vnode; | ||||||
|     RetainPtr<CoreInode> m_inode; |  | ||||||
| 
 | 
 | ||||||
|     Unix::off_t m_current_offset { 0 }; |     Unix::off_t m_current_offset { 0 }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -127,3 +127,8 @@ FS::DirectoryEntry::DirectoryEntry(const char* n, size_t nl, InodeIdentifier i, | ||||||
| CoreInode::~CoreInode() | CoreInode::~CoreInode() | ||||||
| { | { | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int CoreInode::set_atime_and_mtime(Unix::time_t atime, Unix::time_t mtime) | ||||||
|  | { | ||||||
|  |     return fs().set_atime_and_mtime(identifier(), atime, mtime); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -44,7 +44,7 @@ public: | ||||||
|         byte fileType { 0 }; |         byte fileType { 0 }; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     virtual bool set_mtime(InodeIdentifier, dword timestamp) = 0; |     virtual int set_atime_and_mtime(InodeIdentifier, dword atime, dword mtime) = 0; | ||||||
|     virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) = 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 create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -85,6 +85,8 @@ public: | ||||||
|     virtual InodeIdentifier lookup(const String& name) = 0; |     virtual InodeIdentifier lookup(const String& name) = 0; | ||||||
|     virtual String reverse_lookup(InodeIdentifier) = 0; |     virtual String reverse_lookup(InodeIdentifier) = 0; | ||||||
| 
 | 
 | ||||||
|  |     int set_atime_and_mtime(Unix::time_t atime, Unix::time_t mtime); | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|     CoreInode(FS& fs, unsigned index) |     CoreInode(FS& fs, unsigned index) | ||||||
|         : m_fs(fs) |         : m_fs(fs) | ||||||
|  |  | ||||||
|  | @ -146,11 +146,12 @@ InodeMetadata SynthFS::inode_metadata(InodeIdentifier inode) const | ||||||
|     return (*it).value->m_metadata; |     return (*it).value->m_metadata; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool SynthFS::set_mtime(InodeIdentifier, dword timestamp) | int SynthFS::set_atime_and_mtime(InodeIdentifier, dword atime, dword mtime) | ||||||
| { | { | ||||||
|     (void) timestamp; |     (void) atime; | ||||||
|  |     (void) mtime; | ||||||
|     kprintf("FIXME: Implement SyntheticFileSystem::setModificationTime().\n"); |     kprintf("FIXME: Implement SyntheticFileSystem::setModificationTime().\n"); | ||||||
|     return false; |     return -ENOTIMPL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| InodeIdentifier SynthFS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size, int& error) | InodeIdentifier SynthFS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size, int& error) | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ public: | ||||||
|     virtual InodeIdentifier root_inode() const override; |     virtual InodeIdentifier root_inode() const override; | ||||||
|     virtual bool write_inode(InodeIdentifier, const ByteBuffer&) override; |     virtual bool write_inode(InodeIdentifier, const ByteBuffer&) override; | ||||||
|     virtual InodeMetadata inode_metadata(InodeIdentifier) const override; |     virtual InodeMetadata inode_metadata(InodeIdentifier) const override; | ||||||
|     virtual bool set_mtime(InodeIdentifier, dword timestamp) override; |     virtual int set_atime_and_mtime(InodeIdentifier, dword atime, dword mtime) override; | ||||||
|     virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override; |     virtual InodeIdentifier create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override; | ||||||
|     virtual ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, size_t count, byte* buffer, FileDescriptor*) const override; |     virtual ssize_t read_inode_bytes(InodeIdentifier, Unix::off_t offset, size_t count, byte* buffer, FileDescriptor*) const override; | ||||||
|     virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override; |     virtual InodeIdentifier create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override; | ||||||
|  |  | ||||||
|  | @ -264,6 +264,11 @@ typedef signed_qword off_t; | ||||||
| typedef ::time_t time_t; | typedef ::time_t time_t; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | struct utimbuf { | ||||||
|  |     time_t actime; | ||||||
|  |     time_t modtime; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| typedef dword blksize_t; | typedef dword blksize_t; | ||||||
| typedef dword blkcnt_t; | typedef dword blkcnt_t; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -252,15 +252,6 @@ void VFS::traverse_directory_inode(CoreInode& dir_inode, Function<bool(const FS: | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool VFS::touch(const String& path) |  | ||||||
| { |  | ||||||
|     int error; |  | ||||||
|     auto inode = resolve_path(path, root_inode_id(), error); |  | ||||||
|     if (!inode.is_valid()) |  | ||||||
|         return false; |  | ||||||
|     return inode.fs()->set_mtime(inode, ktime(nullptr)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| RetainPtr<FileDescriptor> VFS::open(CharacterDevice& device, int options) | RetainPtr<FileDescriptor> VFS::open(CharacterDevice& device, int options) | ||||||
| { | { | ||||||
|     // FIXME: Respect options.
 |     // FIXME: Respect options.
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling