blob: 11f7494d00480228c6bcbbabf24592e2b3248220 [file] [log] [blame]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Module Overview: Starboard File module
//
// Defines file system input/output functions.
#ifndef STARBOARD_FILE_H_
#define STARBOARD_FILE_H_
#include "starboard/export.h"
#include "starboard/time.h"
#include "starboard/types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Private structure representing an open file.
typedef struct SbFilePrivate SbFilePrivate;
// A handle to an open file.
typedef SbFilePrivate* SbFile;
// Flags that define how a file is used in the application. These flags should
// be or'd together when passed to SbFileOpen to open or create a file.
//
// The following five flags are mutually exclusive. You must specify exactly one
// of them:
// - |kSbFileOpenAlways|
// - |kSbFileOpenOnly|
// - |kSbFileOpenTruncated|
// - |kSbFileCreateAlways|
// - |kSbFileCreateOnly|
//
// In addition, one or more of the following flags must be specified:
// - |kSbFileRead|
// - |kSbFileWrite|
//
// The |kSbFileAsync| flag is optional.
typedef enum SbFileFlags {
kSbFileOpenOnly = 1 << 0, // Opens a file, only if it exists.
kSbFileCreateOnly = 1 << 1, // Creates a new file, only if it
// does not already exist.
kSbFileOpenAlways = 1 << 2, // Opens an existing file at the specified
// path or creates a new file at that path.
kSbFileCreateAlways = 1 << 3, // Creates a new file at the specified path
// or overwrites an existing file at that
// path.
kSbFileOpenTruncated = 1 << 4, // Opens a file and truncates it to zero,
// only if it exists.
kSbFileRead = 1 << 5,
kSbFileWrite = 1 << 6,
kSbFileAsync = 1 << 7, // May allow asynchronous I/O on some
// platforms, meaning that calls to
// Read or Write will only return the
// data that is readily available.
} SbFileFlags;
// kSbFileErrorAccessDenied is returned when a call fails because of a
// filesystem restriction. kSbFileErrorSecurity is returned when a security
// policy doesn't allow the operation to be executed.
typedef enum SbFileError {
kSbFileOk = 0,
kSbFileErrorFailed = -1,
kSbFileErrorInUse = -2,
kSbFileErrorExists = -3,
kSbFileErrorNotFound = -4,
kSbFileErrorAccessDenied = -5,
kSbFileErrorTooManyOpened = -6,
kSbFileErrorNoMemory = -7,
kSbFileErrorNoSpace = -8,
kSbFileErrorNotADirectory = -9,
kSbFileErrorInvalidOperation = -10,
kSbFileErrorSecurity = -11,
kSbFileErrorAbort = -12,
kSbFileErrorNotAFile = -13,
kSbFileErrorNotEmpty = -14,
kSbFileErrorInvalidUrl = -15,
#if SB_API_VERSION >= 11
kSbFileErrorIO = -16,
kSbFileErrorMax = -17,
#else
// Put new entries here and increment kSbFileErrorMax.
kSbFileErrorMax = -16,
#endif
} SbFileError;
// This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
typedef enum SbFileWhence {
kSbFileFromBegin = 0,
kSbFileFromCurrent = 1,
kSbFileFromEnd = 2,
} SbFileWhence;
// Used to hold information about a file.
typedef struct SbFileInfo {
// The size of the file in bytes. Undefined when is_directory is true.
int64_t size;
// Whether the file corresponds to a directory.
bool is_directory;
// Whether the file corresponds to a symbolic link.
bool is_symbolic_link;
// The last modified time of a file.
SbTime last_modified;
// The last accessed time of a file.
SbTime last_accessed;
// The creation time of a file.
SbTime creation_time;
} SbFileInfo;
// Well-defined value for an invalid file handle.
#define kSbFileInvalid (SbFile) NULL
// Returns whether the given file handle is valid.
static SB_C_INLINE bool SbFileIsValid(SbFile file) {
return file != kSbFileInvalid;
}
// Opens the file at |path|, which must be absolute, creating it if specified by
// |flags|. The read/write position is at the beginning of the file.
//
// Note that this function only guarantees the correct behavior when |path|
// points to a file. The behavior is undefined if |path| points to a directory.
//
// |path|: The absolute path of the file to be opened.
// |flags|: |SbFileFlags| that determine how the file is used in the
// application. Among other things, |flags| can indicate whether the
// application should create |path| if |path| does not already exist.
// |out_created|: Starboard sets this value to |true| if a new file is created
// or if an old file is truncated to zero length to simulate a new file,
// which can happen if the |kSbFileCreateAlways| flag is set. Otherwise,
// Starboard sets this value to |false|.
// |out_error|: If |path| cannot be created, this is set to |kSbFileInvalid|.
// Otherwise, it is |NULL|.
SB_EXPORT SbFile SbFileOpen(const char* path,
int flags,
bool* out_created,
SbFileError* out_error);
// Closes |file|. The return value indicates whether the file was closed
// successfully.
//
// |file|: The absolute path of the file to be closed.
SB_EXPORT bool SbFileClose(SbFile file);
#if SB_API_VERSION >= SB_FILE_ATOMIC_REPLACE_VERSION
// Replaces the content of the file at |path| with |data|. Returns whether the
// contents of the file were replaced. The replacement of the content is an
// atomic operation. The file will either have all of the data, or none.
//
// |path|: The path to the file whose contents should be replaced.
// |data|: The data to replace the file contents with.
// |data_size|: The amount of |data|, in bytes, to be written to the file.
SB_EXPORT bool SbFileAtomicReplace(const char* path,
const char* data,
int64_t data_size);
#endif // SB_API_VERSION >= SB_FILE_ATOMIC_REPLACE_VERSION
// Changes the current read/write position in |file|. The return value
// identifies the resultant current read/write position in the file (relative
// to the start) or |-1| in case of an error. This function might not support
// seeking past the end of the file on some platforms.
//
// |file|: The SbFile in which the read/write position will be changed.
// |whence|: The starting read/write position. The position is modified relative
// to this value.
// |offset|: The amount that the read/write position is changed, relative to
// |whence|.
SB_EXPORT int64_t SbFileSeek(SbFile file, SbFileWhence whence, int64_t offset);
// Reads |size| bytes (or until EOF is reached) from |file| into |data|,
// starting at the file's current position.
//
// The return value specifies the number of bytes read or |-1| if there was
// an error. Note that this function does NOT make a best effort to read all
// data on all platforms; rather, it just reads however many bytes are quickly
// available. However, this function can be run in a loop to make it a
// best-effort read.
//
// |file|: The SbFile from which to read data.
// |data|: The variable to which data is read.
// |size|: The amount of data (in bytes) to read.
SB_EXPORT int SbFileRead(SbFile file, char* data, int size);
// Writes the given buffer into |file| at the file's current position,
// overwriting any data that was previously there.
//
// The return value identifies the number of bytes written, or |-1| on error.
// Note that this function does NOT make a best effort to write all data;
// rather, it writes however many bytes can be written quickly. Generally, this
// means that it writes however many bytes as possible without blocking on IO.
// Run this function in a loop to ensure that all data is written.
//
// |file|: The SbFile to which data will be written.
// |data|: The data to be written.
// |size|: The amount of data (in bytes) to write.
SB_EXPORT int SbFileWrite(SbFile file, const char* data, int size);
// Truncates the given |file| to the given |length|. The return value indicates
// whether the file was truncated successfully.
//
// |file|: The file to be truncated.
// |length|: The expected length of the file after it is truncated. If |length|
// is greater than the current size of the file, then the file is extended
// with zeros. If |length| is negative, then the function is a no-op and
// returns |false|.
SB_EXPORT bool SbFileTruncate(SbFile file, int64_t length);
// Flushes the write buffer to |file|. Data written via SbFileWrite is not
// necessarily committed until the SbFile is flushed or closed.
//
// |file|: The SbFile to which the write buffer is flushed.
SB_EXPORT bool SbFileFlush(SbFile file);
// Retrieves information about |file|. The return value indicates whether the
// file information was retrieved successfully.
//
// |file|: The SbFile for which information is retrieved.
// |out_info|: The variable into which the retrieved data is placed. This
// variable is not touched if the operation is not successful.
SB_EXPORT bool SbFileGetInfo(SbFile file, SbFileInfo* out_info);
// Retrieves information about the file at |path|. The return value indicates
// whether the file information was retrieved successfully.
//
// |file|: The absolute path of the file for which information is retrieved.
// |out_info|: The variable into which the retrieved data is placed. This
// variable is not touched if the operation is not successful.
SB_EXPORT bool SbFileGetPathInfo(const char* path, SbFileInfo* out_info);
// Deletes the regular file, symlink, or empty directory at |path|. This
// function is used primarily to clean up after unit tests. On some platforms,
// this function fails if the file in question is being held open.
//
// |path|: The absolute path fo the file, symlink, or directory to be deleted.
SB_EXPORT bool SbFileDelete(const char* path);
// Indicates whether a file or directory exists at |path|.
//
// |path|: The absolute path of the file or directory being checked.
SB_EXPORT bool SbFileExists(const char* path);
// Indicates whether SbFileOpen() with the given |flags| is allowed for |path|.
//
// |path|: The absolute path to be checked.
// |flags|: The flags that are being evaluated for the given |path|.
SB_EXPORT bool SbFileCanOpen(const char* path, int flags);
// Converts an ISO |fopen()| mode string into flags that can be equivalently
// passed into SbFileOpen().
//
// |mode|: The mode string to be converted into flags.
SB_EXPORT int SbFileModeStringToFlags(const char* mode);
// Reads |size| bytes (or until EOF is reached) from |file| into |data|,
// starting at the file's current position.
//
// The return value specifies the number of bytes read or |-1| if there was
// an error. Note that, unlike |SbFileRead|, this function does make a best
// effort to read all data on all platforms. As such, it is not intended for
// stream-oriented files but instead for cases when the normal expectation is
// that |size| bytes can be read unless there is an error.
//
// |file|: The SbFile from which to read data.
// |data|: The variable to which data is read.
// |size|: The amount of data (in bytes) to read.
static inline int SbFileReadAll(SbFile file, char* data, int size) {
if (!SbFileIsValid(file) || size < 0) {
return -1;
}
int bytes_read = 0;
int rv;
do {
rv = SbFileRead(file, data + bytes_read, size - bytes_read);
if (rv <= 0) {
break;
}
bytes_read += rv;
} while (bytes_read < size);
return bytes_read ? bytes_read : rv;
}
// Writes the given buffer into |file|, starting at the beginning of the file,
// and overwriting any data that was previously there. Unlike SbFileWrite, this
// function does make a best effort to write all data on all platforms.
//
// The return value identifies the number of bytes written, or |-1| on error.
//
// |file|: The file to which data will be written.
// |data|: The data to be written.
// |size|: The amount of data (in bytes) to write.
static inline int SbFileWriteAll(SbFile file, const char* data, int size) {
if (!SbFileIsValid(file) || size < 0) {
return -1;
}
int bytes_written = 0;
int rv;
do {
rv = SbFileWrite(file, data + bytes_written, size - bytes_written);
if (rv <= 0) {
break;
}
bytes_written += rv;
} while (bytes_written < size);
return bytes_written ? bytes_written : rv;
}
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
namespace starboard {
// A class that opens an SbFile in its constructor and closes it in its
// destructor, so the file is open for the lifetime of the object. Member
// functions call the corresponding SbFile function.
class ScopedFile {
public:
ScopedFile(const char* path,
int flags,
bool* out_created,
SbFileError* out_error)
: file_(kSbFileInvalid) {
file_ = SbFileOpen(path, flags, out_created, out_error);
}
ScopedFile(const char* path, int flags, bool* out_created)
: file_(kSbFileInvalid) {
file_ = SbFileOpen(path, flags, out_created, NULL);
}
ScopedFile(const char* path, int flags) : file_(kSbFileInvalid) {
file_ = SbFileOpen(path, flags, NULL, NULL);
}
~ScopedFile() { SbFileClose(file_); }
SbFile file() const { return file_; }
bool IsValid() const { return SbFileIsValid(file_); }
int64_t Seek(SbFileWhence whence, int64_t offset) const {
return SbFileSeek(file_, whence, offset);
}
int Read(char* data, int size) const { return SbFileRead(file_, data, size); }
int ReadAll(char* data, int size) const {
return SbFileReadAll(file_, data, size);
}
int Write(const char* data, int size) const {
return SbFileWrite(file_, data, size);
}
int WriteAll(const char* data, int size) const {
return SbFileWriteAll(file_, data, size);
}
bool Truncate(int64_t length) const { return SbFileTruncate(file_, length); }
bool Flush() const { return SbFileFlush(file_); }
bool GetInfo(SbFileInfo* out_info) const {
return SbFileGetInfo(file_, out_info);
}
int64_t GetSize() const {
SbFileInfo file_info;
bool success = GetInfo(&file_info);
return (success ? file_info.size : -1);
}
// disallow copy and move operations
ScopedFile(const ScopedFile&) = delete;
ScopedFile& operator=(const ScopedFile&) = delete;
private:
SbFile file_;
};
} // namespace starboard
#endif // ifdef __cplusplus
#endif // STARBOARD_FILE_H_