phunix/minix/fs/isofs/susp_rock_ridge.c
David van Moolenbroek c2f99d7c3a isofs: rename source directory to "isofs"
Change-Id: Ibe630f720b4399e7ebbbd850650036fbaa9cec7b
2014-09-18 13:00:57 +00:00

249 lines
6.3 KiB
C

/*
* This file contains support for Rock Ridge Interchange Protocol (RRIP)
* extension to ISO 9660.
*/
#include "inc.h"
#include <sys/stat.h>
void parse_susp_rock_ridge_sl(struct rrii_dir_record *dir, char *buffer, int length)
{
/* Parse a Rock Ridge SUSP symbolic link entry (SL). */
int offset = 0;
int slink_size;
u8_t flags, component_length;
while (offset + 2 <= length) {
flags = *((u8_t*)(buffer + offset));
component_length = *((u8_t*)(buffer + offset + 1));
/* Add directory separator if necessary. */
if (dir->slink_rrip[0] != '\0') {
slink_size = strlen(dir->slink_rrip);
if (slink_size + 2 >= ISO9660_RRIP_MAX_FILE_ID_LEN)
return;
dir->slink_rrip[slink_size] = '/';
slink_size++;
}
else
slink_size = strlen(dir->slink_rrip);
switch (flags & 0xF) {
case 0:
case 1: {
/*
* Directory path component.
* Check if component fits within SL entry and
* within symbolic link field.
*/
if ((component_length > length - offset) ||
(slink_size + component_length + 1 >=
ISO9660_RRIP_MAX_FILE_ID_LEN)) {
return;
}
strlcpy(dir->slink_rrip + slink_size,
buffer + offset + 2, component_length+1);
break;
}
case 2: {
/* Current directory path component. */
if (slink_size + 2 >=
ISO9660_RRIP_MAX_FILE_ID_LEN) {
return;
}
strcat(dir->slink_rrip + slink_size, ".");
break;
}
case 4: {
/* Parent directory path component. */
if (slink_size + 3 >=
ISO9660_RRIP_MAX_FILE_ID_LEN) {
return;
}
strcat(dir->slink_rrip + slink_size, "..");
break;
}
case 8: {
/* Root directory path component relative to
the current process. */
if (slink_size + 2 >=
ISO9660_RRIP_MAX_FILE_ID_LEN) {
return;
}
strcat(dir->slink_rrip + slink_size, "/");
break;
}
default: {
/* Unsupported/invalid flags. */
return;
}
}
offset += component_length + 2;
}
}
int parse_susp_rock_ridge(struct rrii_dir_record *dir, char *buffer)
{
/* Parse Rock Ridge SUSP entries for a directory entry. */
char susp_signature[2];
u8_t susp_length;
u8_t susp_version;
int rrii_name_current_size;
int rrii_name_append_size;
int rrii_tf_flags;
int rrii_tf_offset;
u32_t rrii_pn_rdev_major;
u32_t rrii_pn_rdev_minor;
mode_t rrii_px_posix_mode;
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] == 'P') && (susp_signature[1] == 'X') &&
(susp_length >= 36) && (susp_version >= 1)) {
/* POSIX file mode, UID and GID. */
rrii_px_posix_mode = *((u32_t*)(buffer + 4));
/* Check if file mode is supported by isofs. */
switch (rrii_px_posix_mode & _S_IFMT) {
case S_IFCHR:
case S_IFBLK:
case S_IFREG:
case S_IFDIR:
case S_IFLNK: {
dir->d_mode = rrii_px_posix_mode & _S_IFMT;
break;
}
default: {
/* Fall back to what ISO 9660 said. */
dir->d_mode &= _S_IFMT;
break;
}
}
dir->d_mode |= rrii_px_posix_mode & 07777;
dir->uid = *((u32_t*)(buffer + 20));
dir->gid = *((u32_t*)(buffer + 28));
return OK;
}
else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'N') &&
(susp_length >= 20) && (susp_version >= 1)) {
/* Device ID (for character or block special inode). */
rrii_pn_rdev_major = *((u32_t*)(buffer + 4));
rrii_pn_rdev_minor = *((u32_t*)(buffer + 12));
dir->rdev = makedev(rrii_pn_rdev_major, rrii_pn_rdev_minor);
return OK;
}
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'L') &&
(susp_length > 5) && (susp_version >= 1)) {
/* Symbolic link target. Multiple entries may be used to
concatenate the complete path target. */
parse_susp_rock_ridge_sl(dir, buffer + 5, susp_length - 5);
return OK;
}
else if ((susp_signature[0] == 'N') && (susp_signature[1] == 'M') &&
(susp_length > 5) && (susp_version >= 1)) {
/* Alternate POSIX name. Multiple entries may be used to
concatenate the complete filename. */
rrii_name_current_size = strlen(dir->file_id_rrip);
rrii_name_append_size = susp_length - 5;
/* Concatenate only if name component fits. */
if (rrii_name_current_size + rrii_name_append_size + 1 <
ISO9660_RRIP_MAX_FILE_ID_LEN) {
strlcpy(dir->file_id_rrip + rrii_name_current_size,
buffer + 5, rrii_name_append_size+1);
}
return OK;
}
else if ((susp_signature[0] == 'C') && (susp_signature[1] == 'L')) {
/* Ignored, skip. */
return OK;
}
else if ((susp_signature[0] == 'P') && (susp_signature[1] == 'L')) {
/* Ignored, skip. */
return OK;
}
else if ((susp_signature[0] == 'R') && (susp_signature[1] == 'E')) {
/* Ignored, skip. */
return OK;
}
else if ((susp_signature[0] == 'T') && (susp_signature[1] == 'F') &&
(susp_length >= 5) && (susp_version >= 1)) {
/* POSIX timestamp. */
rrii_tf_flags = buffer[5];
rrii_tf_offset = 5;
/*
* ISO 9660 17-byte time format.
* FIXME: 17-byte time format not supported in TF entry.
*/
if (rrii_tf_flags & (1 << 7)) { }
/* ISO 9660 7-byte time format. */
else {
/* Creation time */
if ((rrii_tf_flags & (1 << 0)) &&
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
memcpy(dir->birthtime, buffer+rrii_tf_offset,
ISO9660_SIZE_DATE7);
rrii_tf_offset += ISO9660_SIZE_DATE7;
}
/* Modification time */
if ((rrii_tf_flags & (1 << 1)) &&
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
memcpy(dir->mtime, buffer+rrii_tf_offset,
ISO9660_SIZE_DATE7);
rrii_tf_offset += ISO9660_SIZE_DATE7;
}
/* Last access time. */
if ((rrii_tf_flags & (1 << 2)) &&
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
memcpy(dir->atime, buffer+rrii_tf_offset,
ISO9660_SIZE_DATE7);
rrii_tf_offset += ISO9660_SIZE_DATE7;
}
/* Last attribute change time. */
if ((rrii_tf_flags & (1 << 3)) &&
(rrii_tf_offset + ISO9660_SIZE_DATE7 <= susp_length)) {
memcpy(dir->ctime, buffer+rrii_tf_offset,
ISO9660_SIZE_DATE7);
rrii_tf_offset += ISO9660_SIZE_DATE7;
}
/* The rest is ignored. */
}
return OK;
}
else if ((susp_signature[0] == 'S') && (susp_signature[1] == 'F')) {
/* Ignored, skip. */
return OK;
}
/* Not a Rock Ridge entry. */
return EINVAL;
}