blob: 3f15dafacfd854887c0d4a9d1022d31af316a841 [file] [log] [blame]
// Copyright 2015 Google Inc. 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.
// File system Input/Output
#ifndef STARBOARD_FILE_H_
#define STARBOARD_FILE_H_
#include "starboard/export.h"
#include "starboard/log.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;
// kSbFile(Open|Create)(Only|Always|Truncated) are mutually exclusive. You
// should specify exactly one of the five (possibly combining with other flags)
// when opening or creating a file.
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, // May create a new file.
kSbFileCreateAlways = 1 << 3, // May overwrite an old file.
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,
// Put new entries here and increment kSbFileErrorMax.
kSbFileErrorMax = -16,
} 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|. |out_created|, if provided, will be set to true if a new file was
// created (or an old one truncated to zero length to simulate a new file, which
// can happen with kSbFileCreateAlways), and false otherwise. |out_error| can
// be NULL. If creation failed, it will return kSbFileInvalid. The read/write
// position is at the beginning of the file.
//
// It only guarantees the correct behavior when |path| points to a file. If
// |path| points to directory, the behavior is undefined.
SB_EXPORT SbFile SbFileOpen(const char* path,
int flags,
bool* out_created,
SbFileError* out_error);
// Closes |file|. Returns whether the close was successful.
SB_EXPORT bool SbFileClose(SbFile file);
// Changes current read/write position in |file| to |offset| relative to the
// origin defined by |whence|. Returns the resultant current read/write position
// in the file (relative to the start) or -1 in case of error. May not support
// seeking past the end of the file on some platforms.
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. Returns the number of bytes read, or
// -1 on error. Note that this function does NOT make a best effort to read all
// data on all platforms, it just reads however many bytes are quickly
// available. Can be run in a loop to make it a best-effort read.
SB_EXPORT int SbFileRead(SbFile file, char* data, int size);
// Writes the given buffer into |file| at the file's current position,
// overwritting any data that was previously there. Returns the number of bytes
// written, or -1 on error. Note that this function does NOT make a best effort
// to write all data, it writes however many bytes can be written quickly. It
// should be run in a loop to ensure all data is written.
SB_EXPORT int SbFileWrite(SbFile file, const char* data, int size);
// Truncates the given |file| to the given |length|. If length is greater than
// the current size of the file, the file is extended with zeros. Negative
// |length| will do nothing and return false.
SB_EXPORT bool SbFileTruncate(SbFile file, int64_t length);
// Flushes the write buffer to |file|. Data written via SbFileWrite isn't
// necessarily comitted right away until the file is flushed or closed.
SB_EXPORT bool SbFileFlush(SbFile file);
// Places some information about |file|, an open SbFile, in |out_info|. Returns
// |true| if successful. If unsuccessful, |out_info| is untouched.
SB_EXPORT bool SbFileGetInfo(SbFile file, SbFileInfo* out_info);
// Places information about the file or directory at |path|, which must be
// absolute, into |out_info|. Returns |true| if successful. If unsuccessful,
// |out_info| is untouched.
SB_EXPORT bool SbFileGetPathInfo(const char* path, SbFileInfo* out_info);
// Deletes the regular file, symlink, or empty directory at |path|, which must
// be absolute. Used mainly to clean up after unit tests. May fail on some
// platforms if the file in question is being held open.
SB_EXPORT bool SbFileDelete(const char* path);
// Returns whether a file or directory exists at |path|, which must be absolute.
SB_EXPORT bool SbFileExists(const char* path);
// Returns whether SbFileOpen() with the given |flags| is allowed for |path|,
// which must be absolute.
SB_EXPORT bool SbFileCanOpen(const char* path, int flags);
// Converts an ISO fopen() mode string into flags that can be equivalently
// passed into SbFileOpen().
SB_EXPORT int SbFileModeStringToFlags(const char* mode);
// Reads the given number of bytes (or until EOF is reached). Returns the number
// of bytes read, or -1 on error. Note that this function makes a best effort to
// read all data on all platforms, so it is not intended for stream oriented
// files but instead for cases when the normal expectation is that actually
// |size| bytes are read unless there is an error.
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 (bytes_read <= 0) {
break;
}
bytes_read += rv;
} while (bytes_read < size);
return bytes_read ? bytes_read : rv;
}
// Writes the given buffer into the file, overwritting any data that was
// previously there. Returns the number of bytes written, or -1 on error. Note
// that this function makes a best effort to write all data on all platforms.
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 (bytes_written <= 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;
static bool success = GetInfo(&file_info);
return (success ? file_info.size : -1);
}
private:
SbFile file_;
};
} // namespace starboard
#endif // ifdef __cplusplus
#endif // STARBOARD_FILE_H_