Harlequin RIP SDK

Implementation of the union device type. More...

#include "skinkit.h"
#include "devutils.h"
#include "kitdevs.h"
#include "file.h"
#include "paths.h"
#include "mem.h"
#include "sync.h"
#include "skindevs.h"
#include "hqmemcpy.h"
#include "hqmemcmp.h"
#include "hqmemset.h"
#include "murmurhash3.h"
#include "monevent.h"
#include "pserrors.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "swdevice.h"
#include "swoften.h"

Data Structures

struct  map_entry_t
 
struct  union_fd_t
 Structure to hold file-specific state. More...
 
struct  union_state_t
 Structure to hold device-specific state. More...
 

Macros

#define MAP_ADJACENCY   (64 / sizeof(map_entry_t))
 
#define INITIAL_MAP_SIZE   199
 Initial size of hash table. More...
 
#define MAP_SIZE_INCREMENT   197
 Hash table increment. More...
 
#define PERSISTENT_MAP_FILE   ".123456789!"
 Hidden filename that the persistent map is stored in. More...
 

Typedefs

typedef struct map_entry_t map_entry_t
 
typedef struct union_fd_t union_fd_t
 Structure to hold file-specific state.
 
typedef struct union_state_t union_state_t
 Structure to hold device-specific state.
 

Enumerations

enum  { FILE_UNKNOWN = -3 , FILE_DELETED = -2 , FILE_ON_WRITEDEV = -1 }
 

Functions

static union_fd_tcreateFileState (int32 openflags, uint8 *filename)
 Allocate a file state object. Should be released with releaseFileState().
 
static void releaseFileState (union_fd_t *fd)
 Release a file state object.
 
static uint8makeFileName (uint8 fullname[LONGESTFILENAME], devref_t *devref, uint8 *fname)
 Construct filename for a particular device reference.
 
static HqBool readPersistentMap (union_state_t *state)
 Read the persistent deletions map.
 
static HqBool writePersistentMap (union_state_t *state)
 Write the persistent deletions map.
 
static HqBool clearReadDevs (DEVICELIST *dev)
 Clear the readable base device list.
 
static HqBool clearWriteDev (DEVICELIST *dev)
 Clear the writable base device.
 
static HqBool union_clear_state (DEVICELIST *dev)
 Uninitialise a device state object.
 
static int32 union_device_init (DEVICELIST *dev)
 Union device initialisation.
 
static int32 union_spare (void)
 The following routines are simple stub routines for cases where the only functionality required is to set the appropriate error condition. Take care which is used in which circumstances.
 
static DEVICE_FILEDESCRIPTOR union_open_file (DEVICELIST *dev, uint8 *filename, int32 openflags)
 The file_open call for the union device type.
 
static int32 union_read_file (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, uint8 *buff, int32 len)
 Read from an open file descriptor.
 
static int32 union_write_file (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, uint8 *buff, int32 len)
 Write data to an open file descriptor.
 
static int32 union_abort_file (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor)
 The abort_file routine for the union device type.
 
static int32 union_close_file (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor)
 The close_file routine for the union device type.
 
static int32 union_seek_file (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, Hq32x2 *destination, int32 flags)
 The seek_file routine for the union device type.
 
static int32 union_bytes_file (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, Hq32x2 *bytes, int32 reason)
 The bytes_file routine for the union device type.
 
static int32 union_status_file (DEVICELIST *dev, uint8 *filename, STAT *statbuff)
 The status_file routine for the union device type.
 
static void * union_start_file_list (DEVICELIST *dev, uint8 *pattern)
 Prepare file listing. More...
 
static int32 union_next_file (DEVICELIST *dev, void **handle, uint8 *pattern, FILEENTRY *entry)
 union_next_file
 
static int32 union_end_file_list (DEVICELIST *dev, void *handle)
 union_end_file_list
 
static int32 union_rename_file (DEVICELIST *dev, uint8 *file1, uint8 *file2)
 The rename_file routine for the union device type.
 
static int32 union_delete_file (DEVICELIST *dev, uint8 *filename)
 The delete_file routine for the union device type.
 
static int32 union_set_param (DEVICELIST *dev, DEVICEPARAM *param)
 The set_param routine for the union device type. More...
 
static int32 union_start_param (DEVICELIST *dev)
 The start_param routine for the union device type. More...
 
static int32 devref_repsize (const devref_t *ref)
 Calculate size of (osPrefix) string to represent a device reference, excluding the terminator.
 
static int32 union_get_param (DEVICELIST *dev, DEVICEPARAM *param)
 The get_param routine for the union device type.
 
static int32 union_status_device (DEVICELIST *dev, DEVSTAT *devstat)
 The status_device routine for the union device type. More...
 
static int32 union_device_dismount (DEVICELIST *dev)
 The device_dismount routine for the union device type.
 
static int32 union_buffer_size (DEVICELIST *dev)
 Get buffer size for Union device from underlying devices.
 
static int32 union_ioctl (DEVICELIST *dev, DEVICE_FILEDESCRIPTOR descriptor, int32 opcode, intptr_t arg)
 The ioctl routine for the union device type.
 

Variables

DEVICETYPE Union_Device_Type
 The device type structure for union devices.
 

Detailed Description

Implementation of the union device type.

Macro Definition Documentation

◆ INITIAL_MAP_SIZE

#define INITIAL_MAP_SIZE   199

Initial size of hash table.

Each entry is five 32-bit words (four for the 128-bit hash, one for the device index). The initial size is chosen to fit the initial table including any allocation header in a typical 4Kb OS page.

◆ MAP_ADJACENCY

#define MAP_ADJACENCY   (64 / sizeof(map_entry_t))

Number of slots to test close to each key lookup location. This adjacency figure is set so that we will load at most two 64-byte cache lines when testing a lookup location, which we might do for even a single lookup location. We will have loaded the cache line(s) on the initial test, so we might as well look at the adjacent locations, it's essentially free.

◆ MAP_SIZE_INCREMENT

#define MAP_SIZE_INCREMENT   197

Hash table increment.

When hash insertion fails, the hash table is reallocated with a larger size and all entries are re-inserted. This is the difference in size between old and new tables.

◆ PERSISTENT_MAP_FILE

#define PERSISTENT_MAP_FILE   ".123456789!"

Hidden filename that the persistent map is stored in.

This filename deliberately does not use letters, so it will be the same on case-insensitive and case-sensitive filesystems.

Typedef Documentation

◆ map_entry_t

typedef struct map_entry_t map_entry_t

Hash table to store the mapping of filename to device. There are not a huge number of files in an HHR SW folder (~1000), so we don't need a huge hashtable. We'll use an open hash table with 128-bit murmurhash3 keys, so we can rely on the dispersion of keys to avoid hash key conflicts and to avoid having to store the full filename. Once a filename is hashed, the hash slot is found by taking each hash word modulo the hash table size, until one is found. If all of the slots are used on insertion, the hash table size is increased. The table size is never decreased while the union device is active.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Special values stored in the file map.

Enumerator
FILE_UNKNOWN 

In-band sentinel for unknown files.

FILE_DELETED 

File has been deleted.

FILE_ON_WRITEDEV 

File is on writable device.

Function Documentation

◆ union_set_param()

static int32 union_set_param ( DEVICELIST dev,
DEVICEPARAM param 
)
static

The set_param routine for the union device type.

The parameters that this implementation recognises are:

/Read, which must be a string or array of strings, and it is used to define the set and order of devices (and prefixes) which will be consulted to read files if the file is not present on the writable device.

/Write, which is a string or array defining the device to which write requests are sent.

◆ union_start_file_list()

static void* union_start_file_list ( DEVICELIST dev,
uint8 pattern 
)
static

Prepare file listing.

The union device captures all of the files matching the pattern during the start file listing, and dispenses these to successive next_file calls.

◆ union_start_param()

static int32 union_start_param ( DEVICELIST dev)
static

The start_param routine for the union device type.

The routine is called as part of the currentdevparams operator; the individual parameters are returned one at a time by subsequent calls to the get_param function. union_param_count is used to maintain the state between calls to get_param.

Also return the number of parameters recognized by this implementation of the union device type.

◆ union_status_device()

static int32 union_status_device ( DEVICELIST dev,
DEVSTAT *  devstat 
)
static

The status_device routine for the union device type.

This is in contrast to status_file: it returns information about a device of this device type, rather than a file open on the device. The comprehensive implementation of this routine is likely to be complex. The example here simply gives no useful information.