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_t * | createFileState (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 uint8 * | makeFileName (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. | |
Implementation of the union device type.
#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.
#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.
#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.
#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 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.
anonymous enum |
|
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.
|
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.
|
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.
|
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.