blob: c90c4387ecff5128a346a50718650691b2ba7f18 [file] [log] [blame]
// Copyright 2016 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
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
// User-based Storage API. This is a simple all-at-once BLOB storage and
// retrieval API that is intended for robust long-term, per-user storage. Some
// platforms have different mechanisms for this kind of storage, so this API
// exists to allow a client application to access this kind of storage.
// Only a single open record can exist for each user. Attempting to open a
// second record for a user will result in undefined behavior.
// These APIs are NOT expected to be thread-safe, so either call them from a
// single thread, or perform proper synchronization around all calls.
#include "starboard/export.h"
#include "starboard/types.h"
#include "starboard/user.h"
#ifdef __cplusplus
extern "C" {
// Private structure representing a single storage record.
typedef struct SbStorageRecordPrivate SbStorageRecordPrivate;
// A handle to an open storage record.
typedef SbStorageRecordPrivate* SbStorageRecord;
// Well-defined value for an invalid storage record handle.
#define kSbStorageInvalidRecord (SbStorageRecord) NULL
// Returns whether the given storage record handle is valid.
static SB_C_INLINE bool SbStorageIsValidRecord(SbStorageRecord record) {
return record != kSbStorageInvalidRecord;
// Opens the storage record for |user|, providing a handle to the opened
// record. |user| must be a valid SbUser, or kSbStorageInvalidRecord will be
// returned. Performs blocking I/O on the calling thread.
SB_EXPORT SbStorageRecord SbStorageOpenRecord(SbUser user);
// Closes |record|, synchronously ensuring all written data is flushed, and
// returning whether the operation was successful. Storage writes should be as
// atomic as possible, so either the record should be fully written, or it
// should delete the record (or, even better, leave it untouched). |record| will
// be invalidated after this point, and subsequent calls to |record| will
// fail. Performs blocking I/O on the calling thread.
SB_EXPORT bool SbStorageCloseRecord(SbStorageRecord record);
// Returns the size of |record|, or -1 on error. Performs blocking I/O on the
// calling thread.
SB_EXPORT int64_t SbStorageGetRecordSize(SbStorageRecord record);
// Reads up to |data_size| bytes from |record| into |out_data|, starting at the
// beginning of the record. Returns the number of actual bytes read, which must
// be <= |size|, or -1 on error. This function makes a best-effort and performs
// blocking I/O on the calling thread.
SB_EXPORT int64_t SbStorageReadRecord(SbStorageRecord record,
char* out_data,
int64_t data_size);
// Replaces the data in |record| with |size| bytes from |data|. This always
// deletes any previous data in that record. Returns whether the write
// succeeded. This function makes a best-effort and performs blocking I/O on the
// calling thread.
SB_EXPORT bool SbStorageWriteRecord(SbStorageRecord record,
const char* data,
int64_t data_size);
// Deletes |user|'s storage record, returning whether the record both existed
// and was successfully deleted. This must not be called while |user|'s storage
// record is open. This function performs blocking I/O on the calling thread.
SB_EXPORT bool SbStorageDeleteRecord(SbUser user);
#ifdef __cplusplus
} // extern "C"
#ifdef __cplusplus
namespace starboard {
// Inline scoped wrapper for SbStorageRecord.
class StorageRecord {
: user_(SbUserGetCurrent()), record_(kSbStorageInvalidRecord) {
if (SbUserIsValid(user_)) {
record_ = SbStorageOpenRecord(user_);
explicit StorageRecord(SbUser user)
: user_(user), record_(kSbStorageInvalidRecord) {
if (SbUserIsValid(user_)) {
record_ = SbStorageOpenRecord(user_);
~StorageRecord() { Close(); }
bool IsValid() { return SbStorageIsValidRecord(record_); }
int64_t GetSize() { return SbStorageGetRecordSize(record_); }
int64_t Read(char* out_data, int64_t data_size) {
return SbStorageReadRecord(record_, out_data, data_size);
bool Write(const char* data, int64_t data_size) {
return SbStorageWriteRecord(record_, data, data_size);
bool Close() {
if (SbStorageIsValidRecord(record_)) {
SbStorageRecord record = record_;
record_ = kSbStorageInvalidRecord;
return SbStorageCloseRecord(record);
return false;
bool Delete() {
return SbStorageDeleteRecord(user_);
SbUser user_;
SbStorageRecord record_;
} // namespace starboard