blob: a6da0ab4887253921a3e7a802f8c5db947116c02 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CRAZY_LINKER_SYSTEM_H
#define CRAZY_LINKER_SYSTEM_H
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include "crazy_linker_macros.h"
#include "crazy_linker_util.h" // for String
// System abstraction used by the crazy linker.
// This is used to make unit testing easier without using tons of
// dependency injection in the rest of the code base.
//
// In a nutshell: in a normal build, this will wrap normal open() / read()
// calls. During unit testing, everything is mocked, see
// crazy_linker_system_mock.cpp
namespace crazy {
enum FileOpenMode {
FILE_OPEN_READ_ONLY = 0,
FILE_OPEN_READ_WRITE,
FILE_OPEN_WRITE
};
// Scoping wrapper for a platform file descriptor.
// The descriptor is closed on destruction, unless Release() is called.
//
// IMPORTANT NOTE: The purpose of this file is only to provide a way to mock
// the file system during unit testing. There are simple cases where it is
// better to use direct syscalls (e.g. Ashmem region file descriptors require
// specific opening a non-mockable location (/dev/ashmem) as well as ioctl()
// calls not covered here).
class FileDescriptor {
public:
using HandleType = int;
static constexpr HandleType kEmptyFD = -1;
constexpr FileDescriptor() = default;
FileDescriptor(const char* path) : fd_(DoOpenReadOnly(path)) {}
~FileDescriptor() { Close(); }
CRAZY_DISALLOW_COPY_OPERATIONS(FileDescriptor)
// Move operations are allowed.
FileDescriptor(FileDescriptor&& other) noexcept : fd_(other.fd_) {
other.fd_ = kEmptyFD;
}
FileDescriptor& operator=(FileDescriptor&& other) noexcept;
// Returns true if the descriptor is valid.
bool IsOk() const { return fd_ != kEmptyFD; }
// Return the value of the platform file descriptor.
HandleType Get() const { return fd_; }
// Close the current descriptor, and try to open a file read-only.
// Return true on success, false/errno on failure.
bool OpenReadOnly(const char* path) {
Close();
fd_ = DoOpenReadOnly(path);
return IsOk();
}
// Close the current descriptor, then try to open a file read-write.
// Return true on success, false/errno on failure.
bool OpenReadWrite(const char* path) {
Close();
fd_ = DoOpenReadWrite(path);
return IsOk();
}
// Try to read |buffer_size| bytes into |buffer|. On success, return the
// number of bytes that were read, or 0 for EOF, or -1/errno for I/O
// error.
ssize_t Read(void* buffer, size_t buffer_size);
// Try to read exactly |buffer_size| bytes into |buffer|. Return true
// on success, false/errno on failure.
bool ReadFull(void* buffer, size_t buffer_size) {
ssize_t ret = Read(buffer, buffer_size);
return (ret >= 0 && static_cast<size_t>(ret) == buffer_size);
}
// Seek to a specific offset of the file. Return |offset| on success, or
// -1/errno on error.
off_t SeekTo(off_t offset);
// Map the file into memory. Parameters must match the ::mmap() system call.
// Return a new memory address on success, or nullptr on failure.
void* Map(void* address,
size_t length,
int prot_flags,
int flags,
off_t offset);
// Return the size in bytes of the corresponding file, or -1/errno if the
// descriptor is invalid.
int64_t GetFileSize() const;
// Close the file descriptor if needed.
void Close() {
if (fd_ != kEmptyFD) {
DoClose(fd_);
fd_ = kEmptyFD;
}
}
// Release ownership of the file descriptor. The caller becomes responsible
// for closing the returned handle.
HandleType Release() {
HandleType ret = fd_;
fd_ = kEmptyFD;
return ret;
}
protected:
explicit FileDescriptor(HandleType handle) : fd_(handle) {}
static int DoOpenReadOnly(const char* path);
static int DoOpenReadWrite(const char* path);
static void DoClose(int fd);
HandleType fd_ = kEmptyFD;
};
// Returns true iff a given file path exists.
bool PathExists(const char* path_name);
// Returns true iff a given path is a regular file (or link to a regular
// file).
bool PathIsFile(const char* path_name);
// Returns the current directory, as a string.
String GetCurrentDirectory();
// Convert |path| into a String, and appends a trailing directory separator
// if there isn't already one. NOTE: As a special case, if the input is empty,
// then "./" will be returned.
String MakeDirectoryPath(const char* path);
String MakeDirectoryPath(const char* path, size_t path_len);
// Convert |path| into an absolute path if necessary, always returns a new
// String instance as well.
String MakeAbsolutePathFrom(const char* path);
// Same, but for the [path..path + path_len) input string.
String MakeAbsolutePathFrom(const char* path, size_t path_len);
// Returns the value of a given environment variable.
const char* GetEnv(const char* var_name);
// Returns true iff |lib_path| corresponds to the path of a system library,
// which should always be loaded through the system linker, and not the
// crazy one. Note that |lib_path| must be an absolute path, not a relative
// one.
bool IsSystemLibraryPath(const char* lib_path);
} // namespace crazy
#endif // CRAZY_LINKER_SYSTEM_H