minix/minix/fs/isofs/susp.c
Jean-Baptiste Boric b1d068470b isofs: reworked for better performance
isofs now uses an in-memory directory listing built on-the-fly instead
of parsing the ISO 9660 data structures over and over for almost every
request. This yields huge performance improvements.

The directory listing is allocated dynamically, but Minix servers aren't
normally supposed to do that because critical servers would crash if the
system runs out of memory. isofs is quite frugal, won't allocate memory
after having the whole directory tree cached and is not that critical
(its most important job is to serve as a root file system during
installation).

The benefits and elegance of this scheme far outweights this small
problem in practice.

Change-Id: I13d070388c07d274cbee0645cbc50295c447c5b6
2015-10-07 12:40:24 +02:00

133 lines
3.2 KiB
C

/*
* This file contains support for System Use Sharing Protocol (SUSP) extension
* to ISO 9660.
*/
#include "inc.h"
#include <sys/stat.h>
#ifdef ISO9660_OPTION_ROCKRIDGE
int parse_susp(struct rrii_dir_record *dir, char *buffer)
{
/* Parse fundamental SUSP entries */
char susp_signature[2];
u8_t susp_length;
u8_t susp_version;
u32_t ca_block_nr;
u32_t ca_offset;
u32_t ca_length;
struct buf *ca_bp;
int r;
susp_signature[0] = buffer[0];
susp_signature[1] = buffer[1];
susp_length = *((u8_t*)buffer + 2);
susp_version = *((u8_t*)buffer + 3);
if ((susp_signature[0] == 'C') && (susp_signature[1] == 'E') &&
(susp_length >= 28) && (susp_version >= 1)) {
/*
* Continuation area, perform a recursion.
*
* FIXME: Currently we're parsing only first logical block of a
* continuation area, and infinite recursion is not checked.
*/
ca_block_nr = *((u32_t*)(buffer + 4));
ca_offset = *((u32_t*)(buffer + 12));
ca_length = *((u32_t*)(buffer + 20));
/* Truncate continuation area to fit one logical block. */
if (ca_offset >= v_pri.logical_block_size_l) {
return EINVAL;
}
if (ca_offset + ca_length > v_pri.logical_block_size_l) {
ca_length = v_pri.logical_block_size_l - ca_offset;
}
r = lmfs_get_block(&ca_bp, fs_dev, ca_block_nr, NORMAL);
if (r != OK)
return r;
parse_susp_buffer(dir, b_data(ca_bp) + ca_offset, ca_length);
lmfs_put_block(ca_bp);
return OK;
}
else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'D')) {
/* Padding, skip. */
return OK;
}
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'P')) {
/* Ignored, skip. */
return OK;
}
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'T')) {
/* Terminator entry, stop processing. */
return(ECANCELED);
}
else if ((susp_signature[0] == 'E') && (susp_signature[1] == 'R')) {
/* Ignored, skip. */
return OK;
}
else if ((susp_signature[0] == 'E') && (susp_signature[1] == 'S')) {
/* Ignored, skip. */
return OK;
}
/* Not a SUSP fundamental entry. */
return EINVAL;
}
void parse_susp_buffer(struct rrii_dir_record *dir, char *buffer, u32_t size)
{
/*
* Parse a SUSP system use entry for the ISO 9660.
* This is the main entry point for parsing SUSP data : SUSP entries are
* routed from here to the relevant handling functions.
*/
char susp_signature[2];
u8_t susp_length;
int parser_return;
while (TRUE) {
/* A SUSP entry can't be smaller than 4 bytes. */
if (size < 4)
return;
susp_signature[0] = buffer[0];
susp_signature[1] = buffer[1];
susp_length = *((u8_t*)buffer + 2);
/* Check if SUSP entry is present. */
if (((susp_signature[0] == 0) && (susp_signature[1] == 0)) ||
(susp_length > size) || (susp_length < 4))
return;
/* Check for SUSP fundamental entry. */
parser_return = parse_susp(dir, buffer);
if (parser_return == ECANCELED)
return;
else if (parser_return == OK)
goto next_entry;
/* Check for Rock Ridge entry. */
if (opt.norock == FALSE) {
parser_return = parse_susp_rock_ridge(dir, buffer);
if (parser_return == ECANCELED)
return;
else if (parser_return == OK)
goto next_entry;
}
/* Parse next SUSP entry. */
next_entry:
buffer += susp_length;
size -= susp_length;
}
}
#endif