* Fixed a crashing bug in the identification code: it copied a C++ object on

the stack to an allocated one - on destruction of the latter, the resources
  were already freed.
* Made the identify code more negligent against bad CDs - ie. it will identify
  even broken CDs if they can be mounted.
* Made identification endian aware (it should now also work on big endian
  systems).
* Renamed many structures, methods, and fields to be less verbose, and follow
  our style guide.
* Renamed iso9660.cpp|h to iso9660_identify.cpp|h.
* Renamed iso.c to iso9660.c, rock.h to rock_ridge.h.
* Removed unnecessary cruft from the Jamfile.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22920 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-11-13 14:55:11 +00:00
parent 64a19b4444
commit 5b2c5d03e8
7 changed files with 563 additions and 686 deletions

View File

@ -1,27 +1,13 @@
SubDir HAIKU_TOP src add-ons kernel file_systems iso9660 ;
# save original optimization level
oldOPTIM = $(OPTIM) ;
# set some additional defines
{
SubDirCcFlags -Wall -Wno-multichar ;
SubDirC++Flags -Wall -Wno-multichar -fno-rtti ;
}
UsePrivateHeaders kernel ;
# set some additional defines
SubDirCcFlags -Wall -Wno-multichar ;
SubDirC++Flags -Wall -Wno-multichar -fno-rtti ;
KernelAddon iso9660 :
iso.c
iso9660.cpp
iso9660.c
iso9660_identify.cpp
kernel_interface.cpp
kernel_cpp.cpp
;
SEARCH on [ FGristFiles
kernel_cpp.cpp
] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
# restore original optimization level
OPTIM = $(oldOPTIM) ;

View File

@ -6,7 +6,6 @@
*/
#include "rock.h"
#include "iso.h"
#include <ByteOrder.h>
@ -24,6 +23,8 @@
#include <time.h>
#include <unistd.h>
#include "rock_ridge.h"
//#define TRACE_ISO9660 1
#if TRACE_ISO9660
# define TRACE(x) dprintf x
@ -139,7 +140,7 @@ unicode_to_utf8(const char *src, int32 *srcLen, char *dst, int32 *dstLen)
int32 dstLimit = *dstLen;
int32 srcCount = 0;
int32 dstCount = 0;
for (srcCount = 0; srcCount < srcLimit; srcCount += 2) {
uint16 *UNICODE = (uint16 *)&src[srcCount];
uchar utf8[4];
@ -161,7 +162,7 @@ unicode_to_utf8(const char *src, int32 *srcLen, char *dst, int32 *dstLen)
*srcLen = srcCount;
*dstLen = dstCount;
return ((dstCount > 0) ? B_NO_ERROR : B_ERROR);
return dstCount > 0 ? B_NO_ERROR : B_ERROR;
}

View File

@ -1,564 +0,0 @@
/*
* Copyright 2002, Tyler Dauwalder.
* This file may be used under the terms of the MIT License.
*/
/*!
\file iso9660.cpp
\brief disk_scanner filesystem module for iso9660 CD-ROM filesystems
<h5>iso9660</h5>
The standard to which this module is written is ECMA-119 second
edition, a freely available iso9660 equivalent.
<h5>Joliet</h5>
Joliet support comes courtesy of the following document:
http://www-plateau.cs.berkeley.edu/people/chaffee/jolspec.htm
As specified there, the existence of any of the following escape
sequences in a supplementary volume descriptor's "escape sequences"
field denotes a Joliet volume descriptor using unicode ucs-2
character encoding (2-byte characters, big-endian):
- UCS-2 Level 1: 0x252F40 == "%/@"
- UCS-2 Level 2: 0x252F43 == "%/C"
- UCS-2 Level 3: 0x252F45 == "%/E"
The following UCS-2 characters are considered illegal (we allow them,
printing out a warning if encountered):
- All values between 0x0000 and 0x001f inclusive == control chars
- 0x002A == '*'
- 0x002F == '/'
- 0x003A == ':'
- 0x003B == ';'
- 0x003F == '?'
- 0x005C == '\'
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ByteOrder.h>
#include <fs_info.h>
#include <KernelExport.h>
#include "iso.h"
#include "iso9660.h"
//#define TRACE(x) ;
#define TRACE(x) dprintf x
// misc constants
static const char *kISO9660Signature = "CD001";
static const uint32 kVolumeDescriptorLength = 2048;
#define ISO9660_VOLUME_IDENTIFIER_LENGTH 32
#define ISO9660_ESCAPE_SEQUENCE_LENGTH 32
//! Volume descriptor types
typedef enum {
ISO9660VD_BOOT,
ISO9660VD_PRIMARY,
ISO9660VD_SUPPLEMENTARY,
ISO9660VD_PARTITION,
ISO9660VD_TERMINATOR = 255
} iso9660_volume_descriptor_type;
/*! \brief The portion of the volume descriptor common to all
descriptor types.
*/
typedef struct iso9660_common_volume_descriptor {
uchar volume_descriptor_type;
char standard_identifier[5]; // should be 'CD001'
uchar volume_descriptor_version;
// Remaining bytes are unused
} __attribute__((packed)) iso9660_common_volume_descriptor;
/*! \brief Primary volume descriptor
*/
typedef struct iso9660_primary_volume_descriptor {
iso9660_common_volume_descriptor info;
uchar volume_flags;
char system_identifier[32];
char volume_identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH];
uchar unused01[8];
uint32 volume_space_size_little_endian;
uint32 volume_space_size_big_endian;
uchar unused02[ISO9660_ESCAPE_SEQUENCE_LENGTH];
uint16 volume_set_size_little_endian;
uint16 volume_set_size_big_endian;
uint16 volume_sequence_number_little_endian;
uint16 volume_sequence_number_big_endian;
uint16 logical_block_size_little_endian;
uint16 logical_block_size_big_endian;
uint32 path_table_size_little_endian;
uint32 path_table_size_big_endian;
uint32 ignored02[4];
uchar root_directory_record[34];
char volume_set_identifier[28];
// Remaining bytes are disinteresting to us
} __attribute__((packed)) iso9660_primary_volume_descriptor;
typedef struct iso9660_supplementary_volume_descriptor {
iso9660_common_volume_descriptor info;
uchar volume_flags;
char system_identifier[32];
char volume_identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH];
uchar unused01[8];
uint32 volume_space_size_little_endian;
uint32 volume_space_size_big_endian;
char escape_sequences[ISO9660_ESCAPE_SEQUENCE_LENGTH];
uint16 volume_set_size_little_endian;
uint16 volume_set_size_big_endian;
uint16 volume_sequence_number_little_endian;
uint16 volume_sequence_number_big_endian;
uint16 logical_block_size_little_endian;
uint16 logical_block_size_big_endian;
uint32 path_table_size_little_endian;
uint32 path_table_size_big_endian;
uint32 ignored02[4];
uchar root_directory_record[34];
char volume_set_identifier[28];
// Remaining bytes are disinteresting to us
} __attribute__((packed)) iso9660_supplementary_volume_descriptor;
typedef struct iso9660_directory_record {
uint8 length;
uint8 extended_attribute_record_length;
uint32 location_le;
uint32 location_be;
uint32 data_length;
uchar ignored[14];
uint16 volume_space_le;
} __attribute__((packed)) iso9660_directory_record;
static void dump_directory_record(iso9660_directory_record *record, const char *indent);
//----------------------------------------------------------------------------
// iso9660_info
//----------------------------------------------------------------------------
/*! \brief Creates a new iso9660_info struct with empty volume names.
\note Use the applicable set_XYZ_volume_name() functions rather than
messing with the volume name data members directly.
*/
iso9660_info::iso9660_info()
: iso9660_volume_name(NULL)
, joliet_volume_name(NULL)
{
}
/*! \brief Destroys the struct, freeing the volume name strings.
*/
iso9660_info::~iso9660_info()
{
if (iso9660_volume_name) {
free(iso9660_volume_name);
iso9660_volume_name = NULL;
}
if (joliet_volume_name) {
free(joliet_volume_name);
joliet_volume_name = NULL;
}
}
/*! \brief Returns true if a valid volume name exists.
*/
bool
iso9660_info::is_valid()
{
return iso9660_volume_name || joliet_volume_name;
}
/*! \brief Sets the iso9660 volume name.
\param name UTF-8 string containing the name.
\param length The length (in bytes) of the string.
*/
void
iso9660_info::set_iso9660_volume_name(const char *name, uint32 length)
{
set_string(&iso9660_volume_name, name, length);
}
/*! \brief Sets the Joliet volume name.
\param name UTF-8 string containing the name.
\param length The length (in bytes) of the string.
*/
void
iso9660_info::set_joliet_volume_name(const char *name, uint32 length)
{
set_string(&joliet_volume_name, name, length);
}
/*! \brief Returns the volume name of highest precedence.
Currently, the ordering is (decreasingly):
- Joliet
- iso9660
*/
const char*
iso9660_info::get_preferred_volume_name()
{
if (joliet_volume_name)
return joliet_volume_name;
else
return iso9660_volume_name;
}
/*! \brief Copies the given string into the old string, managing memory
deallocation and allocation as necessary.
*/
void
iso9660_info::set_string(char **string, const char *new_string, uint32 new_length)
{
TRACE(("iso9660_info::set_string(%p (`%s'), `%s', %ld)\n", string, *string, new_string, new_length));
if (string) {
char *&old_string = *string;
if (old_string)
free(old_string);
if (new_string) {
old_string = (char*)malloc(new_length+1);
if (old_string) {
strncpy(old_string, new_string, new_length);
old_string[new_length] = 0;
}
} else {
old_string = NULL;
}
}
}
// #pragma mark - C functions
/*! \brief Converts the given unicode character to utf8.
Courtesy Mr. Axel Dörfler.
\todo Once OpenTracker's locale kit is done, perhaps that functionality
should be used rather than outright stealing the code.
*/
static void
unicode_to_utf8(uint32 c, char **out)
{
char *s = *out;
if (c < 0x80)
*(s++) = c;
else if (c < 0x800) {
*(s++) = 0xc0 | (c>>6);
*(s++) = 0x80 | (c & 0x3f);
} else if (c < 0x10000) {
*(s++) = 0xe0 | (c>>12);
*(s++) = 0x80 | ((c>>6) & 0x3f);
*(s++) = 0x80 | (c & 0x3f);
} else if (c <= 0x10ffff) {
*(s++) = 0xf0 | (c>>18);
*(s++) = 0x80 | ((c>>12) & 0x3f);
*(s++) = 0x80 | ((c>>6) & 0x3f);
*(s++) = 0x80 | (c & 0x3f);
}
*out = s;
}
static const char*
volume_descriptor_type_to_string(iso9660_volume_descriptor_type type)
{
switch (type) {
case ISO9660VD_BOOT: return "boot";
case ISO9660VD_PRIMARY: return "primary";
case ISO9660VD_SUPPLEMENTARY: return "supplementary";
case ISO9660VD_PARTITION: return "partiton";
case ISO9660VD_TERMINATOR: return "terminator";
default: return "invalid";
}
}
static void
dump_common_volume_descriptor(iso9660_common_volume_descriptor *common,
const char *indent, bool print_header)
{
if (print_header)
TRACE(("%siso9660_common_volume_descriptor:\n", indent));
TRACE(("%s volume descriptor type == %d (%s)\n", indent,
common->volume_descriptor_type,
volume_descriptor_type_to_string((iso9660_volume_descriptor_type)common->volume_descriptor_type)));
TRACE(("%s standard identifier == %.5s (%s)\n", indent, common->standard_identifier,
strncmp(common->standard_identifier, kISO9660Signature, 5) == 0 ? "valid" : "INVALID"));
TRACE(("%s volume descriptor version == %d\n", indent, common->volume_descriptor_version));
}
static void
dump_primary_volume_descriptor(iso9660_primary_volume_descriptor *primary,
const char *indent, bool print_header)
{
if (print_header)
TRACE(("%siso9660_primary_volume_descriptor:\n", indent));
dump_common_volume_descriptor(&(primary->info), indent, false);
TRACE(("%s volume identifier == `%.32s'\n", indent,
primary->volume_identifier));
TRACE(("%s volume space size == %ld\n", indent,
primary->volume_space_size_little_endian));
TRACE(("%s volume set size == %d\n", indent,
primary->volume_set_size_little_endian));
TRACE(("%s volume sequence number == %d\n", indent,
primary->volume_sequence_number_little_endian));
TRACE(("%s logical block size == %d\n", indent,
primary->logical_block_size_little_endian));
TRACE(("%s path table size == %ld\n", indent,
primary->path_table_size_little_endian));
TRACE(("%s volume set identifier == %.28s\n", indent,
primary->volume_set_identifier));
dump_directory_record((iso9660_directory_record*)primary->root_directory_record, indent);
}
static void
dump_supplementary_volume_descriptor(iso9660_supplementary_volume_descriptor *supplementary,
const char *indent, bool print_header)
{
if (print_header)
TRACE(("%siso9660_supplementary_volume_descriptor:\n", indent));
dump_primary_volume_descriptor((iso9660_primary_volume_descriptor*)supplementary,
indent, false);
TRACE(("%s escape sequences ==", indent));
for (int i = 0; i < ISO9660_ESCAPE_SEQUENCE_LENGTH; i++) {
TRACE((" %2x", supplementary->escape_sequences[i]));
if (i == ISO9660_ESCAPE_SEQUENCE_LENGTH/2-1)
TRACE(("\n "));
}
TRACE(("\n"));
}
static void
dump_directory_record(iso9660_directory_record *record, const char *indent)
{
TRACE(("%s root directory record:\n", indent));
TRACE(("%s length == %d\n", indent, record->length));
TRACE(("%s location == %ld\n", indent, record->location_le));
TRACE(("%s data length == %ld\n", indent, record->data_length));
TRACE(("%s volume sequence number == %d\n", indent, record->volume_space_le));
}
static status_t
check_common_volume_descriptor(iso9660_common_volume_descriptor *common)
{
status_t error = common ? B_OK : B_BAD_VALUE;
if (!error) {
error = strncmp(common->standard_identifier, kISO9660Signature, 5) == 0
? B_OK : B_BAD_DATA;
}
return error;
}
// #pragma mark - Public functions
// iso9660_fs_identify
/*! \brief Returns true if the given partition is a valid iso9660 partition.
See fs_identify_hook() for more information.
\todo Fill in partitionInfo->mounted_at with something useful.
*/
status_t
iso9660_fs_identify(int deviceFD, iso9660_info *info)
{
char buffer[ISO_PVD_SIZE];
bool exit = false;
status_t error = B_OK;
nspace *vol;
TRACE(("identify(%d, %p)\n", deviceFD, info));
off_t offset = 0x8000;
vol = (nspace *)calloc(sizeof(nspace), 1);
if (vol == NULL)
return ENOMEM;
vol->fd = deviceFD;
// Read through the volume descriptors looking for a primary descriptor.
// If for some reason there are more than one primary descriptor, the
// volume name from the last encountered descriptor will be used.
while (!error && !exit) {// && count++ < 10) {
iso9660_common_volume_descriptor *common = NULL;
// Read the block containing the current descriptor
error = read_pos (vol->fd, offset, (void *)&buffer, ISO_PVD_SIZE);
offset += ISO_PVD_SIZE;
if (error < ISO_PVD_SIZE)
break;
common = (iso9660_common_volume_descriptor*)buffer;
error = check_common_volume_descriptor(common);
// dump_common_volume_descriptor(common, "", true);
// Handle each type of descriptor appropriately
if (!error) {
TRACE(("found %s descriptor\n", volume_descriptor_type_to_string((iso9660_volume_descriptor_type)common->volume_descriptor_type)));
switch (common->volume_descriptor_type) {
case ISO9660VD_BOOT:
break;
case ISO9660VD_PRIMARY:
{
int i;
iso9660_primary_volume_descriptor *primary = (iso9660_primary_volume_descriptor*)buffer;
dump_primary_volume_descriptor(primary, " ", true);
// Cut off any trailing spaces from the volume id. Note
// that this allows for spaces INSIDE the volume id, even
// though that's not technically allowed by the standard;
// this was necessary to support certain RedHat 6.2 CD-ROMs
// from a certain Linux company who shall remain unnamed. ;-)
for (i = ISO9660_VOLUME_IDENTIFIER_LENGTH-1; i >= 0; i--) {
if (primary->volume_identifier[i] != 0x20)
break;
}
// Give a holler if the iso9660 name is already set
if (info->iso9660_volume_name) {
char str[ISO9660_VOLUME_IDENTIFIER_LENGTH+1];
strncpy(str, primary->volume_identifier, i+1);
str[i+1] = 0;
TRACE(("duplicate iso9660 volume name found, using latter (`%s') "
"instead of former (`%s')\n", str,
info->iso9660_volume_name));
}
info->set_iso9660_volume_name(primary->volume_identifier, i+1);
info->maxBlocks = primary->volume_set_size_little_endian;
break;
}
case ISO9660VD_SUPPLEMENTARY:
{
iso9660_supplementary_volume_descriptor *supplementary = (iso9660_supplementary_volume_descriptor*)buffer;
dump_supplementary_volume_descriptor((iso9660_supplementary_volume_descriptor*)supplementary, " ", true);
// Copy and null terminate the escape sequences
char escapes[ISO9660_ESCAPE_SEQUENCE_LENGTH+1];
strncpy(escapes, supplementary->escape_sequences, ISO9660_ESCAPE_SEQUENCE_LENGTH);
escapes[ISO9660_ESCAPE_SEQUENCE_LENGTH] = 0;
// Check for a Joliet VD
if (strstr(escapes, "%/@") || strstr(escapes, "%/C") || strstr(escapes, "%/E")) {
char str[(ISO9660_VOLUME_IDENTIFIER_LENGTH*3/2)+1];
// Since we're dealing with 16-bit Unicode, each UTF-8 sequence
// will be at most 3 bytes long. So we need 3/2 as many chars as
// we start out with.
char *str_iterator = str;
uint16 ch;
// Walk thru the unicode volume name, converting to utf8 as we go.
for (int i = 0;
(ch = B_BENDIAN_TO_HOST_INT16(((uint16*)supplementary->volume_identifier)[i]))
&& i < ISO9660_VOLUME_IDENTIFIER_LENGTH;
i++) {
// Give a warning if the character is technically illegal
if ( ch <= 0x001F
|| ch == 0x002A
|| ch == 0x002F
|| ch == 0x003A
|| ch == 0x003B
|| ch == 0x003F
|| ch == 0x005C)
{
TRACE(("warning: illegal Joliet character found: 0%4x\n", ch));
}
// Convert to utf-8
unicode_to_utf8(ch, &str_iterator);
}
*str_iterator = 0;
// Give a holler if the joliet name is already set
if (info->joliet_volume_name) {
TRACE(("duplicate joliet volume name found, using latter (`%s') "
"instead of former (`%s')\n", str,
info->joliet_volume_name));
}
info->set_joliet_volume_name(str, strlen(str));
} // end "if Joliet VD"
break;
}
case ISO9660VD_PARTITION:
break;
case ISO9660VD_TERMINATOR:
exit = true;
break;
default:
break;
}
}
}
free(vol);
return error;
/*
switch (error) {
case B_OK:
if (info.is_valid()) {
result = true;
if (partitionInfo->file_system_short_name)
strcpy(partitionInfo->file_system_short_name, "iso9660");
if (partitionInfo->file_system_long_name)
strcpy(partitionInfo->file_system_long_name, "iso9660 CD-ROM File System");
partitionInfo->file_system_flags = B_FS_IS_PERSISTENT;
if (priority)
*priority = 0;
// Copy the volume name of highest precedence
if (partitionInfo->volume_name) {
TRACE(("%s: iso9660 name: `%s'\n", kModuleDebugName, info.iso9660_volume_name));
TRACE(("%s: joliet name: `%s'\n", kModuleDebugName, info.joliet_volume_name));
const char *name = info.get_preferred_volume_name();
int length = strlen(name);
if (length > B_FILE_NAME_LENGTH-1)
length = B_FILE_NAME_LENGTH-1;
strncpy(partitionInfo->volume_name, name, length);
partitionInfo->volume_name[length] = 0;
}
return 0.8;
}
break;
case B_BAD_DATA:
TRACE(("%s: identify: bad signature\n", kModuleDebugName));
break;
default:
TRACE(("%s: identify error: 0x%lx\n", kModuleDebugName,
error));
break;
}
return 0.0;
*/
}

View File

@ -0,0 +1,501 @@
/*
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002, Tyler Dauwalder.
*
* This file may be used under the terms of the MIT License.
*/
/*!
<h5>iso9660</h5>
The standard to which this module is written is ECMA-119 second
edition, a freely available iso9660 equivalent.
<h5>Joliet</h5>
Joliet support comes courtesy of the following document:
http://www-plateau.cs.berkeley.edu/people/chaffee/jolspec.htm
As specified there, the existence of any of the following escape
sequences in a supplementary volume descriptor's "escape sequences"
field denotes a Joliet volume descriptor using unicode ucs-2
character encoding (2-byte characters, big-endian):
- UCS-2 Level 1: 0x252F40 == "%/@"
- UCS-2 Level 2: 0x252F43 == "%/C"
- UCS-2 Level 3: 0x252F45 == "%/E"
The following UCS-2 characters are considered illegal (we allow them,
printing out a warning if encountered):
- All values between 0x0000 and 0x001f inclusive == control chars
- 0x002A == '*'
- 0x002F == '/'
- 0x003A == ':'
- 0x003B == ';'
- 0x003F == '?'
- 0x005C == '\'
*/
#include "iso9660_identify.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ByteOrder.h>
#include <fs_info.h>
#include <KernelExport.h>
#include "iso.h"
//#define TRACE(x) ;
#define TRACE(x) dprintf x
// misc constants
static const char *kISO9660Signature = "CD001";
static const uint32 kVolumeDescriptorLength = 2048;
#define ISO9660_VOLUME_IDENTIFIER_LENGTH 32
#define ISO9660_ESCAPE_SEQUENCE_LENGTH 32
//! Volume descriptor types
typedef enum {
ISO9660VD_BOOT,
ISO9660VD_PRIMARY,
ISO9660VD_SUPPLEMENTARY,
ISO9660VD_PARTITION,
ISO9660VD_TERMINATOR = 255
} iso9660_descriptor_type;
/*! \brief The portion of the volume descriptor common to all
descriptor types.
*/
typedef struct iso9660_common_descriptor {
uchar type;
char standard_identifier[5]; // should be 'CD001'
uchar version;
// Remaining bytes are unused
} __attribute__((packed)) iso9660_common_volume_descriptor;
typedef struct iso9660_volume_descriptor {
iso9660_common_descriptor common;
uchar flags;
char system_identifier[32];
char identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH];
uchar _reserved0[8];
uint32 size;
uint32 size_big_endian;
char escape_sequences[ISO9660_ESCAPE_SEQUENCE_LENGTH];
// unused on primary descriptor
uint16 set_size;
uint16 set_size_big_endian;
uint16 sequence_number;
uint16 sequence_number_big_endian;
uint16 logical_block_size;
uint16 logical_block_size_big_endian;
uint32 path_table_size;
uint32 path_table_size_big_endian;
uint32 _reserved1[4];
uchar root_directory_record[34];
char set_identifier[28];
// Remaining bytes are disinteresting to us
} __attribute__((packed)) iso9660_volume_descriptor;
typedef struct iso9660_directory_record {
uint8 length;
uint8 extended_attribute_record_length;
uint32 location;
uint32 location_big_endian;
uint32 data_length;
uchar _reserved[14];
uint16 volume_space;
} __attribute__((packed)) iso9660_directory_record;
static void dump_directory_record(iso9660_directory_record *record,
const char *indent);
// #pragma mark -
/*! \brief Creates a new iso9660_info struct with empty volume names.
\note Use the applicable set_XYZ_volume_name() functions rather than
messing with the volume name data members directly.
*/
iso9660_info::iso9660_info()
:
iso9660_name(NULL),
joliet_name(NULL)
{
}
iso9660_info::~iso9660_info()
{
free(iso9660_name);
free(joliet_name);
}
/*! \brief Returns true if a valid volume name exists.
*/
bool
iso9660_info::IsValid()
{
return iso9660_name != NULL || joliet_name != NULL;
}
/*! \brief Sets the iso9660 volume name.
\param name UTF-8 string containing the name.
\param length The length (in bytes) of the string.
*/
void
iso9660_info::SetISO9660Name(const char *name, uint32 length)
{
_SetString(&iso9660_name, name, length);
}
/*! \brief Sets the Joliet volume name.
\param name UTF-8 string containing the name.
\param length The length (in bytes) of the string.
*/
void
iso9660_info::SetJolietName(const char *name, uint32 length)
{
_SetString(&joliet_name, name, length);
}
/*! \brief Returns the volume name of highest precedence.
Currently, the ordering is (decreasingly):
- Joliet
- iso9660
*/
const char*
iso9660_info::PreferredName()
{
if (joliet_name)
return joliet_name;
return iso9660_name;
}
/*! \brief Copies the given string into the old string, managing memory
deallocation and allocation as necessary.
*/
void
iso9660_info::_SetString(char **string, const char *newString,
uint32 newLength)
{
TRACE(("iso9660_info::set_string(%p ('%s'), '%s', %ld)\n", string,
*string, newString, newLength));
if (string == NULL)
return;
char *&oldString = *string;
free(oldString);
if (newString) {
oldString = (char*)malloc(newLength + 1);
if (oldString != NULL) {
memcpy(oldString, newString, newLength);
oldString[newLength] = '\0';
}
} else
oldString = NULL;
}
// #pragma mark - C functions
/*! \brief Converts the given unicode character to utf8.
*/
static void
unicode_to_utf8(uint32 c, char **out)
{
char *s = *out;
if (c < 0x80)
*(s++) = c;
else if (c < 0x800) {
*(s++) = 0xc0 | (c >> 6);
*(s++) = 0x80 | (c & 0x3f);
} else if (c < 0x10000) {
*(s++) = 0xe0 | (c >> 12);
*(s++) = 0x80 | ((c >> 6) & 0x3f);
*(s++) = 0x80 | (c & 0x3f);
} else if (c <= 0x10ffff) {
*(s++) = 0xf0 | (c >> 18);
*(s++) = 0x80 | ((c >> 12) & 0x3f);
*(s++) = 0x80 | ((c >> 6) & 0x3f);
*(s++) = 0x80 | (c & 0x3f);
}
*out = s;
}
static const char*
descriptor_type_to_string(iso9660_descriptor_type type)
{
switch (type) {
case ISO9660VD_BOOT:
return "boot";
case ISO9660VD_PRIMARY:
return "primary";
case ISO9660VD_SUPPLEMENTARY:
return "supplementary";
case ISO9660VD_PARTITION:
return "partiton";
case ISO9660VD_TERMINATOR:
return "terminator";
default:
return "invalid";
}
}
static void
dump_common_descriptor(iso9660_common_descriptor *common,
const char *indent, bool printHeader)
{
if (printHeader)
TRACE(("%siso9660_common_descriptor:\n", indent));
TRACE(("%s volume descriptor type: %d (%s)\n", indent,
common->type, descriptor_type_to_string(
(iso9660_descriptor_type)common->type)));
TRACE(("%s standard identifier: %.5s (%s)\n", indent,
common->standard_identifier,
strncmp(common->standard_identifier, kISO9660Signature, 5) == 0
? "valid" : "INVALID"));
TRACE(("%s version: %d\n", indent, common->version));
}
static void
dump_primary_descriptor(iso9660_volume_descriptor *primary,
const char *indent, bool printHeader)
{
if (printHeader)
TRACE(("%siso9660_primary_descriptor:\n", indent));
dump_common_descriptor(&primary->common, indent, false);
TRACE(("%s identifier: '%.32s'\n", indent,
primary->identifier));
TRACE(("%s size: %ld\n", indent,
B_LENDIAN_TO_HOST_INT32(primary->size)));
TRACE(("%s set size: %ld\n", indent,
B_LENDIAN_TO_HOST_INT32(primary->set_size)));
TRACE(("%s sequence number: %ld\n", indent,
B_LENDIAN_TO_HOST_INT32(primary->sequence_number)));
TRACE(("%s logical block size: %ld\n", indent,
B_LENDIAN_TO_HOST_INT32(primary->logical_block_size)));
TRACE(("%s path table size: %ld\n", indent,
B_LENDIAN_TO_HOST_INT32(primary->path_table_size)));
TRACE(("%s set identifier: %.28s\n", indent,
primary->set_identifier));
dump_directory_record((iso9660_directory_record*)
primary->root_directory_record, indent);
}
static void
dump_supplementary_descriptor(iso9660_volume_descriptor *supplementary,
const char *indent, bool printHeader)
{
if (printHeader)
TRACE(("%siso9660_supplementary_descriptor:\n", indent));
dump_primary_descriptor(supplementary, indent, false);
TRACE(("%s escape sequences: ", indent));
for (int i = 0; i < ISO9660_ESCAPE_SEQUENCE_LENGTH; i++) {
TRACE((" %2x", supplementary->escape_sequences[i]));
if (i == ISO9660_ESCAPE_SEQUENCE_LENGTH / 2 - 1)
TRACE(("\n "));
}
TRACE(("\n"));
}
static void
dump_directory_record(iso9660_directory_record *record, const char *indent)
{
TRACE(("%s root directory record:\n", indent));
TRACE(("%s length: %d\n", indent, record->length));
TRACE(("%s location: %ld\n", indent,
B_LENDIAN_TO_HOST_INT32(record->location)));
TRACE(("%s data length: %ld\n", indent,
B_LENDIAN_TO_HOST_INT32(record->data_length)));
TRACE(("%s volume space: %d\n", indent,
B_LENDIAN_TO_HOST_INT16(record->volume_space)));
}
static status_t
check_common_descriptor(iso9660_common_descriptor *common)
{
if (common == NULL)
return B_BAD_VALUE;
return strncmp(common->standard_identifier, kISO9660Signature, 5) == 0
? B_OK : B_BAD_DATA;
}
// #pragma mark - Public functions
// iso9660_fs_identify
/*! \brief Returns true if the given partition is a valid iso9660 partition.
See fs_identify_hook() for more information.
\todo Fill in partitionInfo->mounted_at with something useful.
*/
status_t
iso9660_fs_identify(int deviceFD, iso9660_info *info)
{
char buffer[ISO_PVD_SIZE];
bool exit = false;
bool found = false;
status_t error = B_OK;
TRACE(("identify(%d, %p)\n", deviceFD, info));
off_t offset = 0x8000;
// Read through the volume descriptors looking for a primary descriptor.
// If for some reason there are more than one primary descriptor, the
// volume name from the last encountered descriptor will be used.
while (!error && !exit) {// && count++ < 10) {
iso9660_common_descriptor *common = NULL;
// Read the block containing the current descriptor
error = read_pos(deviceFD, offset, (void *)&buffer, ISO_PVD_SIZE);
offset += ISO_PVD_SIZE;
if (error < ISO_PVD_SIZE)
break;
common = (iso9660_common_descriptor*)buffer;
error = check_common_descriptor(common);
if (error < B_OK)
break;
// dump_common_descriptor(common, "", true);
// Handle each type of descriptor appropriately
TRACE(("found %s descriptor\n", descriptor_type_to_string(
(iso9660_descriptor_type)common->type)));
found = true;
switch (common->type) {
case ISO9660VD_BOOT:
break;
case ISO9660VD_PRIMARY:
{
iso9660_volume_descriptor *primary
= (iso9660_volume_descriptor*)buffer;
int i;
dump_primary_descriptor(primary, " ", true);
// Cut off any trailing spaces from the volume id. Note
// that this allows for spaces INSIDE the volume id, even
// though that's not technically allowed by the standard;
// this was necessary to support certain RedHat 6.2 CD-ROMs
// from a certain Linux company who shall remain unnamed. ;-)
for (i = ISO9660_VOLUME_IDENTIFIER_LENGTH - 1; i >= 0;
i--) {
if (primary->identifier[i] != 0x20)
break;
}
// Give a holler if the iso9660 name is already set
if (info->iso9660_name) {
char name[ISO9660_VOLUME_IDENTIFIER_LENGTH + 1];
strlcpy(name, primary->identifier, i + 1);
TRACE(("duplicate iso9660 volume name found, using "
"latter (`%s') instead of former (`%s')\n", name,
info->iso9660_name));
}
info->SetISO9660Name(primary->identifier, i + 1);
info->max_blocks = B_LENDIAN_TO_HOST_INT32(primary->set_size);
break;
}
case ISO9660VD_SUPPLEMENTARY:
{
iso9660_volume_descriptor *supplementary
= (iso9660_volume_descriptor*)buffer;
dump_supplementary_descriptor(supplementary, " ", true);
// Copy and null terminate the escape sequences
char escapes[ISO9660_ESCAPE_SEQUENCE_LENGTH + 1];
strlcpy(escapes, supplementary->escape_sequences,
ISO9660_ESCAPE_SEQUENCE_LENGTH + 1);
// Check for a Joliet VD
if (strstr(escapes, "%/@") || strstr(escapes, "%/C")
|| strstr(escapes, "%/E")) {
char name[(ISO9660_VOLUME_IDENTIFIER_LENGTH * 3 / 2) + 1];
// Since we're dealing with 16-bit Unicode, each
// UTF-8 sequence will be at most 3 bytes long.
char *pos = name;
uint16 ch;
// Walk thru the unicode volume name, converting to utf8 as we go.
for (int i = 0; (ch = B_BENDIAN_TO_HOST_INT16(
((uint16*)supplementary->identifier)[i]))
&& i < ISO9660_VOLUME_IDENTIFIER_LENGTH; i++) {
// Give a warning if the character is technically
// illegal
if (ch <= 0x001F || ch == '*' || ch == '/'
|| ch == ':' || ch == ';'
|| ch == '?' || ch == '\\') {
TRACE(("warning: illegal Joliet character "
"found: 0%4x\n", ch));
}
// Convert to utf-8
unicode_to_utf8(ch, &pos);
}
pos[0] = '\0';
// Give a holler if the joliet name is already set
if (info->joliet_name) {
TRACE(("duplicate joliet volume name found, using "
"latter (`%s') instead of former (`%s')\n",
name, info->joliet_name));
}
info->SetJolietName(name, pos - name);
}
break;
}
case ISO9660VD_PARTITION:
break;
case ISO9660VD_TERMINATOR:
exit = true;
break;
default:
break;
}
}
return found ? B_OK : error;
}

View File

@ -1,10 +1,15 @@
/*
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2002, Tyler Dauwalder.
*
* This file may be used under the terms of the MIT License.
*/
#ifndef ISO9660_IDENTIFY_H
#define ISO9660_IDENTIFY_H
#include <SupportDefs.h>
#ifndef _ISO9660_H
#define _ISO9660_H
/*! \brief Contains all the info of interest pertaining to an
iso9660 volume.
@ -18,22 +23,23 @@ struct iso9660_info {
iso9660_info();
~iso9660_info();
bool is_valid();
bool IsValid();
void set_iso9660_volume_name(const char *name, uint32 length);
void set_joliet_volume_name(const char *name, uint32 length);
void SetISO9660Name(const char *name, uint32 length);
void SetJolietName(const char *name, uint32 length);
const char* get_preferred_volume_name();
const char* PreferredName();
char *iso9660_volume_name;
char *joliet_volume_name;
off_t maxBlocks;
char *iso9660_name;
char *joliet_name;
void set_string(char **string, const char *new_string, uint32 new_length);
off_t max_blocks;
private:
void _SetString(char **string, const char *newString, uint32 newLength);
};
status_t iso9660_fs_identify(int deviceFD, iso9660_info *info);
#endif
#endif // ISO9660_IDENTIFY_H

View File

@ -8,20 +8,16 @@
*/
#include "iso.h"
#include "iso9660.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <malloc.h>
#include <unistd.h>
#include <KernelExport.h>
#include <NodeMonitor.h>
@ -36,95 +32,53 @@
#include <util/kernel_cpp.h>
//#define TRACE_ISO9660 1
#if TRACE_ISO9660
#include "iso.h"
#include "iso9660_identify.h"
//#define TRACE_ISO9660
#ifdef TRACE_ISO9660
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
/* Start of fundamental (read-only) required functions */
static status_t fs_mount(dev_t mountID, const char *device, uint32 flags,
const char *args, void **_data, ino_t *_rootID);
static status_t fs_unmount(void *ns);
static status_t fs_get_vnode_name(void *_ns, void *_node,
char *buffer, size_t bufferSize);
static status_t fs_walk(void *_ns, void *_base, const char *file,
ino_t *_vnodeID, int *_type);
static status_t fs_read_vnode(void *_ns, ino_t vnid, void **node, bool reenter);
static status_t fs_release_vnode(void *_ns, void *_node, bool reenter);
static status_t fs_get_file_map(fs_volume _fs, fs_vnode _node, off_t offset, size_t size,
struct file_io_vec *vecs, size_t *_count);
static status_t fs_read_stat(void *_ns, void *_node, struct stat *st);
static status_t fs_open(void *_ns, void *_node, int omode, void **cookie);
static status_t fs_read(void *_ns, void *_node, void *cookie, off_t pos,
void *buf, size_t *len);
/// fs_free_cookie - free cookie for file created in open.
static status_t fs_free_cookie(void *ns, void *node, void *cookie);
static status_t fs_close(void *ns, void *node, void *cookie);
// fs_access - checks permissions for access.
static status_t fs_access(void *_ns, void *_node, int mode);
// fs_opendir - creates fs-specific "cookie" struct that can tell where
// we are at in the directory list.
static status_t fs_open_dir(void* _ns, void* _node, void** cookie);
// fs_readdir - read 1 or more dirents, keep state in cookie, return
// 0 when no more entries.
static status_t fs_read_dir(void *_ns, void *_node, void *cookie, struct dirent *buf,
size_t bufsize, uint32 *_num);
// fs_rewinddir - set cookie to represent beginning of directory, so
// later fs_readdir calls start at beginning.
static status_t fs_rewind_dir(void *_ns, void *_node, void *cookie);
// fs_closedir - Do whatever you need to to close a directory (sometimes
// nothing), but DON'T free the cookie!
static status_t fs_close_dir(void *_ns, void *_node, void *cookie);
// fs_free_dircookie - Free the fs-specific cookie struct
static status_t fs_free_dir_cookie(void *_ns, void *_node, void *cookie);
// fs_rfsstat - Fill in fs_info struct for device.
static status_t fs_read_fs_stat(void *_ns, struct fs_info *);
// fs_readlink - Read in the name of a symbolic link.
static status_t fs_read_link(void *_ns, void *_node, char *buf, size_t *bufsize);
// #pragma mark - Scanning
struct identify_cookie {
iso9660_info info;
};
// #pragma mark - Scanning
static float
fs_identify_partition(int fd, partition_data *partition, void **_cookie)
{
iso9660_info info;
status_t status = iso9660_fs_identify(fd, &info);
if (status != B_OK)
return status;
iso9660_info *info = new iso9660_info;
identify_cookie *cookie = new identify_cookie;
memcpy(&cookie->info, &info, sizeof(info));
status_t status = iso9660_fs_identify(fd, info);
if (status != B_OK) {
delete info;
return -1;
}
*_cookie = cookie;
return 0.8f;
*_cookie = info;
return 0.6f;
}
static status_t
fs_scan_partition(int fd, partition_data *partition, void *_cookie)
{
identify_cookie *cookie = (identify_cookie *)_cookie;
iso9660_info *info = (iso9660_info *)_cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY ;
partition->block_size = ISO_PVD_SIZE;
partition->content_size = ISO_PVD_SIZE * cookie->info.maxBlocks;
partition->content_name = strdup(cookie->info.get_preferred_volume_name());
partition->content_size = ISO_PVD_SIZE * info->max_blocks;
partition->content_name = strdup(info->PreferredName());
if (partition->content_name == NULL)
return B_NO_MEMORY;
@ -135,9 +89,7 @@ fs_scan_partition(int fd, partition_data *partition, void *_cookie)
static void
fs_free_identify_partition_cookie(partition_data *partition, void *_cookie)
{
identify_cookie *cookie = (identify_cookie *)_cookie;
delete cookie;
delete (iso9660_info *)_cookie;
}
@ -158,7 +110,7 @@ fs_mount(dev_t mountID, const char *device, uint32 flags,
*/
status_t result = EINVAL;
// return EINVAL if it's not a device compatible with the driver.
bool allow_joliet = true;
bool allowJoliet = true;
nspace *vol;
(void)flags;
@ -181,13 +133,13 @@ fs_mount(dev_t mountID, const char *device, uint32 flags,
// look for nojoliet
spot = strstr(buf, "nojoliet");
if (spot != NULL)
allow_joliet = false;
allowJoliet = false;
free(buf);
}
// Try and mount volume as an ISO volume.
result = ISOMount(device, O_RDONLY, &vol, allow_joliet);
result = ISOMount(device, O_RDONLY, &vol, allowJoliet);
// If it is ISO …
if (result == B_NO_ERROR) {

View File

@ -1,13 +1,10 @@
// rock.h
/*
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
// Altername name field flags.
enum
{
enum {
NM_CONTINUE = 1,
NM_CURRENT = 2,
NM_PARENT = 4,
@ -15,14 +12,12 @@ enum
} NMFLAGS;
// Symbolic link field flags
enum
{
enum {
SL_CONTINUE = 1
} SLFLAGS;
// Symbolic link field component flags
enum
{
enum {
SLCP_CONTINUE = 1,
SLCP_CURRENT = 2,
SLCP_PARENT = 4,