Add actual support for relocated directories. In case we hit a placeholder file

pointing to a relocated directory, we now re-initialize the node we are
initializing with the first entry of the pointed at directory. This ought to be
the "." entry containing the proper flags, start block number and data length.
As per the specs we do only keep the file id or alternate name of the
placeholder and take everything else from the relocated directory.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30886 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2009-05-28 00:39:33 +00:00
parent e349faeba8
commit 56b2febaad
3 changed files with 93 additions and 69 deletions
@@ -227,7 +227,8 @@ InitVolDesc(iso9660_volume *volume, char *buffer)
buffer += 2; buffer += 2;
// Fill in directory record. // Fill in directory record.
InitNode(&volume->rootDirRec, buffer, NULL, 0); volume->joliet_level = 0;
InitNode(volume, &volume->rootDirRec, buffer, NULL);
volume->rootDirRec.id = ISO_ROOTNODE_ID; volume->rootDirRec.id = ISO_ROOTNODE_ID;
buffer += 34; buffer += 34;
@@ -283,7 +284,8 @@ InitVolDesc(iso9660_volume *volume, char *buffer)
static status_t static status_t
parse_rock_ridge(iso9660_inode* node, char* buffer, char* end) parse_rock_ridge(iso9660_volume* volume, iso9660_inode* node, char* buffer,
char* end, bool relocated)
{ {
// Now we're at the start of the rock ridge stuff // Now we're at the start of the rock ridge stuff
char* altName = NULL; char* altName = NULL;
@@ -497,11 +499,23 @@ parse_rock_ridge(iso9660_inode* node, char* buffer, char* end)
// Deep directory record masquerading as a file. // Deep directory record masquerading as a file.
case 'CL': case 'CL':
{
TRACE(("RR: found CL, length %u\n", length)); TRACE(("RR: found CL, length %u\n", length));
node->flags |= ISO_IS_DIR; // Reinitialize the node with the information at the
// "." entry of the pointed to directory data
node->startLBN[LSB_DATA] = *(uint32*)(buffer+4); node->startLBN[LSB_DATA] = *(uint32*)(buffer+4);
node->startLBN[MSB_DATA] = *(uint32*)(buffer+8); node->startLBN[MSB_DATA] = *(uint32*)(buffer+8);
char* buffer = (char*)block_cache_get(volume->fBlockCache,
node->startLBN[FS_DATA_FORMAT]);
if (buffer == NULL)
break;
InitNode(volume, node, buffer, NULL, true);
block_cache_put(volume->fBlockCache,
node->startLBN[FS_DATA_FORMAT]);
break; break;
}
case 'PL': case 'PL':
TRACE(("RR: found PL, length %u\n", length)); TRACE(("RR: found PL, length %u\n", length));
@@ -510,8 +524,9 @@ parse_rock_ridge(iso9660_inode* node, char* buffer, char* end)
case 'RE': case 'RE':
// Relocated directory, we should skip. // Relocated directory, we should skip.
TRACE(("RR: found RE, length %u\n", length)); TRACE(("RR: found RE, length %u\n", length));
// TODO: support relocated directories if (!relocated)
return B_NOT_SUPPORTED; return B_NOT_SUPPORTED;
break;
case 'TF': case 'TF':
TRACE(("RR: found TF, length %u\n", length)); TRACE(("RR: found TF, length %u\n", length));
@@ -657,8 +672,10 @@ ISOMount(const char *path, uint32 flags, iso9660_volume **_newVolume,
// Because Joliet-stuff starts at other sector, // Because Joliet-stuff starts at other sector,
// update root directory record. // update root directory record.
if (volume->joliet_level > 0) if (volume->joliet_level > 0) {
InitNode(&volume->rootDirRec, &buffer[156], NULL, 0); InitNode(volume, &volume->rootDirRec, &buffer[156],
NULL);
}
} }
} else if (*(unsigned char *)buffer == 0xff) { } else if (*(unsigned char *)buffer == 0xff) {
// ISO_VD_END // ISO_VD_END
@@ -728,8 +745,8 @@ ISOReadDirEnt(iso9660_volume *volume, dircookie *cookie, struct dirent *dirent,
if (blockData != NULL && totalRead < cookie->totalSize) { if (blockData != NULL && totalRead < cookie->totalSize) {
iso9660_inode node; iso9660_inode node;
size_t bytesRead = 0; size_t bytesRead = 0;
result = InitNode(&node, blockData + cookie->pos, &bytesRead, result = InitNode(volume, &node, blockData + cookie->pos,
volume->joliet_level); &bytesRead);
// if we hit an entry that we don't support, we just skip it // if we hit an entry that we don't support, we just skip it
if (result != B_OK && result != B_NOT_SUPPORTED) if (result != B_OK && result != B_NOT_SUPPORTED)
@@ -786,8 +803,8 @@ ISOReadDirEnt(iso9660_volume *volume, dircookie *cookie, struct dirent *dirent,
status_t status_t
InitNode(iso9660_inode* node, char* buffer, size_t* _bytesRead, InitNode(iso9660_volume* volume, iso9660_inode* node, char* buffer,
uint8 jolietLevel) size_t* _bytesRead, bool relocated)
{ {
uint8 recordLength = *(uint8*)buffer++; uint8 recordLength = *(uint8*)buffer++;
size_t nameLength; size_t nameLength;
@@ -802,10 +819,13 @@ InitNode(iso9660_inode* node, char* buffer, size_t* _bytesRead,
char* end = buffer + recordLength; char* end = buffer + recordLength;
node->cache = NULL; if (!relocated) {
node->name = NULL; node->cache = NULL;
node->attr.slName = NULL; node->name = NULL;
memset(node->attr.stat, 0, sizeof(node->attr.stat)); node->attr.slName = NULL;
memset(node->attr.stat, 0, sizeof(node->attr.stat));
} else
free(node->attr.slName);
node->extAttrRecLen = *(uint8*)buffer++; node->extAttrRecLen = *(uint8*)buffer++;
TRACE(("InitNode - ext attr length is %d\n", (int)node->extAttrRecLen)); TRACE(("InitNode - ext attr length is %d\n", (int)node->extAttrRecLen));
@@ -843,9 +863,14 @@ InitNode(iso9660_inode* node, char* buffer, size_t* _bytesRead,
buffer += 4; buffer += 4;
TRACE(("InitNode - volume seq num is %d\n", (int)node->volSeqNum)); TRACE(("InitNode - volume seq num is %d\n", (int)node->volSeqNum));
node->name_length = *(uint8*)buffer; nameLength = *(uint8*)buffer;
buffer++; buffer++;
TRACE(("InitNode - file id length is %u\n", node->name_length));
// for relocated directories we take the name from the placeholder entry
if (!relocated) {
node->name_length = nameLength;
TRACE(("InitNode - file id length is %u\n", node->name_length));
}
// Set defaults, in case there is no RockRidge stuff. // Set defaults, in case there is no RockRidge stuff.
node->attr.stat[FS_DATA_FORMAT].st_mode |= (node->flags & ISO_IS_DIR) != 0 node->attr.stat[FS_DATA_FORMAT].st_mode |= (node->flags & ISO_IS_DIR) != 0
@@ -857,59 +882,59 @@ InitNode(iso9660_inode* node, char* buffer, size_t* _bytesRead,
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
nameLength = node->name_length; if (!relocated) {
// JOLIET extension:
// on joliet discs, buffer[0] can be 0 for Unicoded filenames,
// so I've added a check here to test explicitely for
// directories (which have length 1)
// Take care of "." and "..", the first two dirents are
// these in iso.
if (node->name_length == 1 && buffer[0] == 0) {
node->name = strdup(".");
node->name_length = 1;
} else if (node->name_length == 1 && buffer[0] == 1) {
node->name = strdup("..");
node->name_length = 2;
} else if (volume->joliet_level > 0) {
// JOLIET extension: convert Unicode16 string to UTF8
// Assume that the unicode->utf8 conversion produces 4 byte
// utf8 characters, and allocate that much space
node->name = (char*)malloc(node->name_length * 2 + 1);
if (node->name == NULL)
return B_NO_MEMORY;
// JOLIET extension: int32 sourceLength = node->name_length;
// on joliet discs, buffer[0] can be 0 for Unicoded filenames, int32 destLength = node->name_length * 2;
// so I've added a check here to test explicitely for
// directories (which have length 1)
// Take care of "." and "..", the first two dirents are
// these in iso.
if (node->name_length == 1 && buffer[0] == 0) {
node->name = strdup(".");
node->name_length = 1;
} else if (node->name_length == 1 && buffer[0] == 1) {
node->name = strdup("..");
node->name_length = 2;
} else if (jolietLevel > 0) {
// JOLIET extension: convert Unicode16 string to UTF8
// Assume that the unicode->utf8 conversion produces 4 byte
// utf8 characters, and allocate that much space
node->name = (char*)malloc(node->name_length * 2 + 1);
if (node->name == NULL)
return B_NO_MEMORY;
int32 sourceLength = node->name_length; status_t status = unicode_to_utf8(buffer, &sourceLength,
int32 destLength = node->name_length * 2; node->name, &destLength);
if (status < B_OK) {
dprintf("iso9660: error converting unicode->utf8\n");
return status;
}
status_t status = unicode_to_utf8(buffer, &sourceLength, node->name[destLength] = '\0';
node->name, &destLength); node->name_length = destLength;
if (status < B_OK) {
dprintf("iso9660: error converting unicode->utf8\n"); sanitize_iso_name(node, false);
return status; } else {
node->name = (char*)malloc(node->name_length + 1);
if (node->name == NULL)
return B_NO_MEMORY;
// convert all characters to lower case
for (uint32 i = 0; i < node->name_length; i++)
node->name[i] = tolower(buffer[i]);
node->name[node->name_length] = '\0';
sanitize_iso_name(node, true);
} }
node->name[destLength] = '\0'; if (node->name == NULL) {
node->name_length = destLength; TRACE(("InitNode - unable to allocate memory!\n"));
sanitize_iso_name(node, false);
} else {
node->name = (char*)malloc(node->name_length + 1);
if (node->name == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
// convert all characters to lower case
for (uint32 i = 0; i < node->name_length; i++) {
node->name[i] = tolower(buffer[i]);
} }
node->name[node->name_length] = '\0';
sanitize_iso_name(node, true);
}
if (node->name == NULL) {
TRACE(("InitNode - unable to allocate memory!\n"));
return B_NO_MEMORY;
} }
buffer += nameLength; buffer += nameLength;
@@ -918,7 +943,7 @@ InitNode(iso9660_inode* node, char* buffer, size_t* _bytesRead,
TRACE(("DirRec ID String is: %s\n", node->name)); TRACE(("DirRec ID String is: %s\n", node->name));
return parse_rock_ridge(node, buffer, end); return parse_rock_ridge(volume, node, buffer, end, relocated);
} }
@@ -216,8 +216,8 @@ status_t ISOMount(const char *path, uint32 flags, iso9660_volume** _newVolume,
bool allowJoliet); bool allowJoliet);
status_t ISOReadDirEnt(iso9660_volume* ns, dircookie* cookie, status_t ISOReadDirEnt(iso9660_volume* ns, dircookie* cookie,
struct dirent* buffer, size_t bufferSize); struct dirent* buffer, size_t bufferSize);
status_t InitNode(iso9660_inode* rec, char* buf, size_t* bytesRead, status_t InitNode(iso9660_volume* volume, iso9660_inode* rec, char* buf,
uint8 jolietLevel); size_t* bytesRead, bool relocated = false);
status_t ConvertRecDate(ISORecDate* inDate, time_t* outDate); status_t ConvertRecDate(ISORecDate* inDate, time_t* outDate);
#endif /* ISO_9660_H */ #endif /* ISO_9660_H */
@@ -264,8 +264,7 @@ fs_walk(fs_volume *_vol, fs_vnode *_base, const char *file, ino_t *_vnodeID)
&& totalRead + blockBytesRead < dataLength && totalRead + blockBytesRead < dataLength
&& blockData[0] != 0 && blockData[0] != 0
&& !done) { && !done) {
initResult = InitNode(&node, blockData, &bytesRead, initResult = InitNode(ns, &node, blockData, &bytesRead);
ns->joliet_level);
TRACE(("fs_walk - InitNode returned %s, filename %s, %u bytes " TRACE(("fs_walk - InitNode returned %s, filename %s, %u bytes "
"read\n", strerror(initResult), node.name, (unsigned)bytesRead)); "read\n", strerror(initResult), node.name, (unsigned)bytesRead));
@@ -341,7 +340,7 @@ fs_read_vnode(fs_volume *_vol, ino_t vnodeID, fs_vnode *_node,
return B_IO_ERROR; return B_IO_ERROR;
} }
status_t result = InitNode(newNode, data + pos, NULL, ns->joliet_level); status_t result = InitNode(ns, newNode, data + pos, NULL);
block_cache_put(ns->fBlockCache, block); block_cache_put(ns->fBlockCache, block);
if (result < B_OK) { if (result < B_OK) {