mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include <AK/LexicalPath.h>
 | |
| #include <AK/Platform.h>
 | |
| #include <AK/ScopeGuard.h>
 | |
| #include <LibCore/DeprecatedFile.h>
 | |
| #include <LibCore/DirIterator.h>
 | |
| #include <LibCore/System.h>
 | |
| #include <LibFileSystem/FileSystem.h>
 | |
| #include <errno.h>
 | |
| #include <fcntl.h>
 | |
| #include <libgen.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <sys/stat.h>
 | |
| #include <unistd.h>
 | |
| #include <utime.h>
 | |
| 
 | |
| #ifdef AK_OS_SERENITY
 | |
| #    include <serenity.h>
 | |
| #endif
 | |
| 
 | |
| namespace Core {
 | |
| 
 | |
| ErrorOr<NonnullRefPtr<DeprecatedFile>> DeprecatedFile::open(DeprecatedString filename, OpenMode mode, mode_t permissions)
 | |
| {
 | |
|     auto file = DeprecatedFile::construct(move(filename));
 | |
|     if (!file->open_impl(mode, permissions))
 | |
|         return Error::from_errno(file->error());
 | |
|     return file;
 | |
| }
 | |
| 
 | |
| DeprecatedFile::DeprecatedFile(DeprecatedString filename, Object* parent)
 | |
|     : IODevice(parent)
 | |
|     , m_filename(move(filename))
 | |
| {
 | |
| }
 | |
| 
 | |
| DeprecatedFile::~DeprecatedFile()
 | |
| {
 | |
|     if (m_should_close_file_descriptor == ShouldCloseFileDescriptor::Yes && mode() != OpenMode::NotOpen)
 | |
|         close();
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::open(int fd, OpenMode mode, ShouldCloseFileDescriptor should_close)
 | |
| {
 | |
|     set_fd(fd);
 | |
|     set_mode(mode);
 | |
|     m_should_close_file_descriptor = should_close;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::open(OpenMode mode)
 | |
| {
 | |
|     return open_impl(mode, 0666);
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::open_impl(OpenMode mode, mode_t permissions)
 | |
| {
 | |
|     VERIFY(!m_filename.is_null());
 | |
|     int flags = 0;
 | |
|     if (has_flag(mode, OpenMode::ReadOnly) && has_flag(mode, OpenMode::WriteOnly)) {
 | |
|         flags |= O_RDWR | O_CREAT;
 | |
|     } else if (has_flag(mode, OpenMode::ReadOnly)) {
 | |
|         flags |= O_RDONLY;
 | |
|     } else if (has_flag(mode, OpenMode::WriteOnly)) {
 | |
|         flags |= O_WRONLY | O_CREAT;
 | |
|         bool should_truncate = !(has_flag(mode, OpenMode::Append) || has_flag(mode, OpenMode::MustBeNew));
 | |
|         if (should_truncate)
 | |
|             flags |= O_TRUNC;
 | |
|     }
 | |
|     if (has_flag(mode, OpenMode::Append))
 | |
|         flags |= O_APPEND;
 | |
|     if (has_flag(mode, OpenMode::Truncate))
 | |
|         flags |= O_TRUNC;
 | |
|     if (has_flag(mode, OpenMode::MustBeNew))
 | |
|         flags |= O_EXCL;
 | |
|     if (!has_flag(mode, OpenMode::KeepOnExec))
 | |
|         flags |= O_CLOEXEC;
 | |
|     int fd = ::open(m_filename.characters(), flags, permissions);
 | |
|     if (fd < 0) {
 | |
|         set_error(errno);
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     set_fd(fd);
 | |
|     set_mode(mode);
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| int DeprecatedFile::leak_fd()
 | |
| {
 | |
|     m_should_close_file_descriptor = ShouldCloseFileDescriptor::No;
 | |
|     return fd();
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::is_device() const
 | |
| {
 | |
|     struct stat st;
 | |
|     if (fstat(fd(), &st) < 0)
 | |
|         return false;
 | |
|     return S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode);
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::is_block_device() const
 | |
| {
 | |
|     struct stat stat;
 | |
|     if (fstat(fd(), &stat) < 0)
 | |
|         return false;
 | |
|     return S_ISBLK(stat.st_mode);
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::is_char_device() const
 | |
| {
 | |
|     struct stat stat;
 | |
|     if (fstat(fd(), &stat) < 0)
 | |
|         return false;
 | |
|     return S_ISCHR(stat.st_mode);
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::is_directory() const
 | |
| {
 | |
|     struct stat st;
 | |
|     if (fstat(fd(), &st) < 0)
 | |
|         return false;
 | |
|     return S_ISDIR(st.st_mode);
 | |
| }
 | |
| 
 | |
| bool DeprecatedFile::is_link() const
 | |
| {
 | |
|     struct stat stat;
 | |
|     if (fstat(fd(), &stat) < 0)
 | |
|         return false;
 | |
|     return S_ISLNK(stat.st_mode);
 | |
| }
 | |
| 
 | |
| DeprecatedString DeprecatedFile::real_path_for(DeprecatedString const& filename)
 | |
| {
 | |
|     if (filename.is_null())
 | |
|         return {};
 | |
|     auto* path = realpath(filename.characters(), nullptr);
 | |
|     DeprecatedString real_path(path);
 | |
|     free(path);
 | |
|     return real_path;
 | |
| }
 | |
| 
 | |
| DeprecatedString DeprecatedFile::current_working_directory()
 | |
| {
 | |
|     char* cwd = getcwd(nullptr, 0);
 | |
|     if (!cwd) {
 | |
|         perror("getcwd");
 | |
|         return {};
 | |
|     }
 | |
| 
 | |
|     auto cwd_as_string = DeprecatedString(cwd);
 | |
|     free(cwd);
 | |
| 
 | |
|     return cwd_as_string;
 | |
| }
 | |
| 
 | |
| DeprecatedString DeprecatedFile::absolute_path(DeprecatedString const& path)
 | |
| {
 | |
|     if (!Core::System::stat(path).is_error())
 | |
|         return DeprecatedFile::real_path_for(path);
 | |
| 
 | |
|     if (path.starts_with("/"sv))
 | |
|         return LexicalPath::canonicalized_path(path);
 | |
| 
 | |
|     auto working_directory = DeprecatedFile::current_working_directory();
 | |
|     auto full_path = LexicalPath::join(working_directory, path);
 | |
| 
 | |
|     return LexicalPath::canonicalized_path(full_path.string());
 | |
| }
 | |
| 
 | |
| Optional<DeprecatedString> DeprecatedFile::resolve_executable_from_environment(StringView filename)
 | |
| {
 | |
|     if (filename.is_empty())
 | |
|         return {};
 | |
| 
 | |
|     // Paths that aren't just a file name generally count as already resolved.
 | |
|     if (filename.contains('/')) {
 | |
|         if (access(DeprecatedString { filename }.characters(), X_OK) != 0)
 | |
|             return {};
 | |
| 
 | |
|         return filename;
 | |
|     }
 | |
| 
 | |
|     auto const* path_str = getenv("PATH");
 | |
|     StringView path;
 | |
|     if (path_str)
 | |
|         path = { path_str, strlen(path_str) };
 | |
|     if (path.is_empty())
 | |
|         path = DEFAULT_PATH_SV;
 | |
| 
 | |
|     auto directories = path.split_view(':');
 | |
| 
 | |
|     for (auto directory : directories) {
 | |
|         auto file = DeprecatedString::formatted("{}/{}", directory, filename);
 | |
| 
 | |
|         if (access(file.characters(), X_OK) == 0)
 | |
|             return file;
 | |
|     }
 | |
| 
 | |
|     return {};
 | |
| };
 | |
| 
 | |
| }
 | 
