From 762b846cf8ba678f31a854a85e68003d2071be8d Mon Sep 17 00:00:00 2001 From: John Scipione Date: Tue, 4 Feb 2014 20:46:08 -0500 Subject: [PATCH] exfat: Set the mountpoint to same as volume name Fixes #10501 * update copyright headers, attribute to Haiku, Inc. add authors * volume_name gets filled out by a utility function in Utility.cpp * update exfat_entry - rename name_label to just label - adjust volume_label to have 11 uint16 chars plus 8 uint8 reserved - add guid partition info * Added a couple new entry type defines * fName is 34 bytes long which fits the 11 3-byte UTF-8 chars and a \0 --- .../file_systems/exfat/DirectoryIterator.cpp | 6 +- src/add-ons/kernel/file_systems/exfat/Jamfile | 1 + .../kernel/file_systems/exfat/Utility.cpp | 50 +++++++++++++ .../kernel/file_systems/exfat/Utility.h | 21 +++++- .../kernel/file_systems/exfat/Volume.cpp | 25 ++++--- .../kernel/file_systems/exfat/Volume.h | 15 +++- src/add-ons/kernel/file_systems/exfat/exfat.h | 20 +++++- .../file_systems/exfat/kernel_interface.cpp | 70 ++++++++++++++----- 8 files changed, 175 insertions(+), 33 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/exfat/Utility.cpp diff --git a/src/add-ons/kernel/file_systems/exfat/DirectoryIterator.cpp b/src/add-ons/kernel/file_systems/exfat/DirectoryIterator.cpp index 6604270e56..b7cdfb29cc 100644 --- a/src/add-ons/kernel/file_systems/exfat/DirectoryIterator.cpp +++ b/src/add-ons/kernel/file_systems/exfat/DirectoryIterator.cpp @@ -208,9 +208,9 @@ DirectoryIterator::_GetNext(uchar* name, size_t* _nameLength, ino_t* _id, visitor->VisitFileInfo(fCurrent); } else if (fCurrent->type == EXFAT_ENTRY_TYPE_FILENAME) { TRACE("DirectoryIterator::_GetNext() Filename\n"); - memcpy((uint8*)name + nameIndex, fCurrent->name_label.name, - sizeof(fCurrent->name_label.name)); - nameIndex += sizeof(fCurrent->name_label.name); + memcpy((uint8*)name + nameIndex, fCurrent->label.name, + sizeof(fCurrent->label.name)); + nameIndex += sizeof(fCurrent->label.name); name[nameIndex] = '\0'; chunkCount--; if (visitor != NULL) diff --git a/src/add-ons/kernel/file_systems/exfat/Jamfile b/src/add-ons/kernel/file_systems/exfat/Jamfile index f06190c736..d318694523 100644 --- a/src/add-ons/kernel/file_systems/exfat/Jamfile +++ b/src/add-ons/kernel/file_systems/exfat/Jamfile @@ -10,5 +10,6 @@ KernelAddon exfat : encodings.cpp Inode.cpp kernel_interface.cpp + Utility.cpp Volume.cpp ; diff --git a/src/add-ons/kernel/file_systems/exfat/Utility.cpp b/src/add-ons/kernel/file_systems/exfat/Utility.cpp new file mode 100644 index 0000000000..d89adcfc27 --- /dev/null +++ b/src/add-ons/kernel/file_systems/exfat/Utility.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2014 Haiku, Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * John Scipione, jscipione@gmail.com + */ + + +#include "Utility.h" + +#include +#include +#include + +#include + +#include "encodings.h" + + +status_t +volume_name(struct exfat_entry* entry, char* _name) +{ + if (entry == NULL || _name == NULL) + return B_BAD_VALUE; + + if (entry->type == EXFAT_ENTRY_TYPE_NOT_IN_USE) { + const char* untitled = "Untitled"; + size_t length = strlen(untitled); + strncpy(_name, untitled, length); + if (strlen(_name) < length) + return B_NAME_TOO_LONG; + } else if (entry->type == EXFAT_ENTRY_TYPE_LABEL) { + // UCS-2 can encode codepoints in the range U+0000 to U+FFFF + // UTF-8 needs at most 3 bytes to encode values in this range + size_t utf8NameLength = entry->label.length * 3; + memset(_name, 0, utf8NameLength + 1); + // zero out the character array + unicode_to_utf8((const uchar*)entry->label.name, + entry->label.length * 2, (uint8*)_name, &utf8NameLength); + if (strlen(_name) < utf8NameLength) + return B_NAME_TOO_LONG; + } else + return B_NAME_NOT_FOUND; + + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/exfat/Utility.h b/src/add-ons/kernel/file_systems/exfat/Utility.h index 8d4ebe0da5..b4c9000ad7 100644 --- a/src/add-ons/kernel/file_systems/exfat/Utility.h +++ b/src/add-ons/kernel/file_systems/exfat/Utility.h @@ -1,6 +1,12 @@ /* * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. - * This file may be used under the terms of the MIT License. + * Copyright 2014 Haiku, Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * John Scipione, jscipione@gmail.com */ #ifndef UTILITY_H #define UTILITY_H @@ -38,4 +44,17 @@ open_mode_to_access(int openMode) return R_OK | W_OK; } + +/*! Reads the volume name from an exfat entry and writes it to \a _name + as a UTF-8 char array. Writes "Untitled" The volume name is not set. + \returns A status code. + \retval B_OK Wrote the volume name successfully. + \retval B_BAD_VALUE \a entry or \a _name was \c NULL. + \retval B_NAME_NOT_FOUND Volume name was not found in this entry. + \retval B_NAME_TOO_LONG The passed in _name wasn't long enough to + fit the name. +*/ +status_t volume_name(struct exfat_entry* entry, char* _name); + + #endif // UTILITY_H diff --git a/src/add-ons/kernel/file_systems/exfat/Volume.cpp b/src/add-ons/kernel/file_systems/exfat/Volume.cpp index 7299f1ce2a..838ec56815 100644 --- a/src/add-ons/kernel/file_systems/exfat/Volume.cpp +++ b/src/add-ons/kernel/file_systems/exfat/Volume.cpp @@ -1,7 +1,14 @@ /* - * Copyright 2011, Jérôme Duval, korli@users.berlios.de. * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. - * This file may be used under the terms of the MIT License. + * Copyright 2011, Jérôme Duval, korli@users.berlios.de. + * Copyright 2014 Haiku, Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * Jérôme Duval, korli@users.berlios.de + * John Scipione, jscipione@gmail.com */ @@ -11,6 +18,7 @@ #include "Volume.h" #include +#include #include #include #include @@ -22,8 +30,8 @@ #include #include "CachedBlock.h" -#include "encodings.h" #include "Inode.h" +#include "Utility.h" //#define TRACE_EXFAT @@ -222,11 +230,12 @@ bool LabelVisitor::VisitLabel(struct exfat_entry* entry) { TRACE("LabelVisitor::VisitLabel()\n"); - char utfName[30]; - size_t utfLength = 30; - unicode_to_utf8((const uchar*)entry->name_label.name, - entry->name_label.length * 2, (uint8*)utfName, &utfLength); - fVolume->SetName(utfName); + char name[34]; + status_t result = volume_name(entry, name); + if (result != B_OK) + return false; + + fVolume->SetName(name); return true; } diff --git a/src/add-ons/kernel/file_systems/exfat/Volume.h b/src/add-ons/kernel/file_systems/exfat/Volume.h index 4b7e9b3937..f6298852c4 100644 --- a/src/add-ons/kernel/file_systems/exfat/Volume.h +++ b/src/add-ons/kernel/file_systems/exfat/Volume.h @@ -1,7 +1,14 @@ /* - * Copyright 2011, Jérôme Duval, korli@users.berlios.de. * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. - * This file may be used under the terms of the MIT License. + * Copyright 2011, Jérôme Duval, korli@users.berlios.de. + * Copyright 2014 Haiku, Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * Jérôme Duval, korli@users.berlios.de + * John Scipione, jscipione@gmail.com */ #ifndef VOLUME_H #define VOLUME_H @@ -144,7 +151,9 @@ private: fs_volume* fFSVolume; int fDevice; exfat_super_block fSuperBlock; - char fName[32]; + char fName[34]; + // Max number of bytes needed is (11 * 3) + 1 for the \0, + // that is 11 UCS-2 characters converted to UTF-8. uint16 fFlags; uint32 fBlockSize; diff --git a/src/add-ons/kernel/file_systems/exfat/exfat.h b/src/add-ons/kernel/file_systems/exfat/exfat.h index 518916100b..427449e00d 100644 --- a/src/add-ons/kernel/file_systems/exfat/exfat.h +++ b/src/add-ons/kernel/file_systems/exfat/exfat.h @@ -1,6 +1,12 @@ /* * Copyright 2011, Jérôme Duval, korli@users.berlios.de. + * Copyright 2014 Haiku, Inc. All Rights reserved. + * * Distributed under the terms of the MIT License. + * + * Authors: + * Jérôme Duval, korli@users.berlios.de + * John Scipione, jscipione@gmail.com */ #ifndef EXFAT_H #define EXFAT_H @@ -75,10 +81,12 @@ struct exfat_super_block { #define EXFAT_SUPER_BLOCK_MAGIC "EXFAT " +#define EXFAT_ENTRY_TYPE_NOT_IN_USE 0x03 #define EXFAT_ENTRY_TYPE_BITMAP 0x81 #define EXFAT_ENTRY_TYPE_UPPERCASE 0x82 #define EXFAT_ENTRY_TYPE_LABEL 0x83 #define EXFAT_ENTRY_TYPE_FILE 0x85 +#define EXFAT_ENTRY_TYPE_GUID 0xa0 #define EXFAT_ENTRY_TYPE_FILEINFO 0xc0 #define EXFAT_ENTRY_TYPE_FILENAME 0xc1 #define EXFAT_CLUSTER_END 0xffffffff @@ -94,8 +102,16 @@ struct exfat_entry { union { struct { uint8 length; - char name[30]; - } _PACKED name_label; + uint16 name[11]; + uint8 reserved[8]; + } _PACKED label; + struct { + uint8 chunkCount; + uint16 checksum; + uint16 flags; + uint8 guid[16]; + uint8 reserved[10]; + } _PACKED guid; struct { uint8 reserved[3]; uint32 checksum; diff --git a/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp b/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp index 0644447b55..112918db40 100644 --- a/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/exfat/kernel_interface.cpp @@ -1,14 +1,24 @@ /* + * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. * Copyright 2011, Jérôme Duval, korli@users.berlios.de. - * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. - * This file may be used under the terms of the MIT License. + * Copyright 2014 Haiku, Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + * Jérôme Duval, korli@users.berlios.de + * John Scipione, jscipione@gmail.com */ #include +#include #include #include +#include + #include #include #include @@ -36,6 +46,7 @@ struct identify_cookie { exfat_super_block super_block; + char name[34]; }; @@ -66,15 +77,45 @@ iterative_io_finished_hook(void* cookie, io_request* request, status_t status, static float -exfat_identify_partition(int fd, partition_data *partition, void **_cookie) +exfat_identify_partition(int fd, partition_data* _partition, void** _cookie) { - exfat_super_block superBlock; + struct exfat_super_block superBlock; status_t status = Volume::Identify(fd, &superBlock); if (status != B_OK) return -1; - identify_cookie *cookie = new identify_cookie; + identify_cookie* cookie = new (std::nothrow)identify_cookie; + if (cookie == NULL) + return -1; + memcpy(&cookie->super_block, &superBlock, sizeof(exfat_super_block)); + memset(cookie->name, 0, 34); + // zero out volume name + + uint32 rootDirCluster = superBlock.RootDirCluster(); + uint32 blockSize = 1 << superBlock.BlockShift(); + uint32 clusterSize = blockSize << superBlock.BlocksPerClusterShift(); + uint64 rootDirectoryOffset = (uint64)(EXFAT_SUPER_BLOCK_OFFSET + + superBlock.FirstDataBlock() * blockSize + + (rootDirCluster - 2) * clusterSize); + struct exfat_entry entry; + size_t entrySize = sizeof(struct exfat_entry); + for (uint32 i = 0; read_pos(fd, rootDirectoryOffset + i * entrySize, + &entry, entrySize) == (ssize_t)entrySize; i++) { + if (entry.type == EXFAT_ENTRY_TYPE_NOT_IN_USE + || entry.type == EXFAT_ENTRY_TYPE_LABEL) { + if (volume_name(&entry, cookie->name) != B_OK) { + delete cookie; + return -1; + } + break; + } + } + + if (cookie->name[0] == '\0') { + delete cookie; + return -1; + } *_cookie = cookie; return 0.8f; @@ -82,21 +123,18 @@ exfat_identify_partition(int fd, partition_data *partition, void **_cookie) static status_t -exfat_scan_partition(int fd, partition_data *partition, void *_cookie) +exfat_scan_partition(int fd, partition_data* _partition, void* _cookie) { - identify_cookie *cookie = (identify_cookie *)_cookie; + identify_cookie* cookie = (identify_cookie*)_cookie; - partition->status = B_PARTITION_VALID; - partition->flags |= B_PARTITION_FILE_SYSTEM; - partition->content_size = cookie->super_block.NumBlocks() + _partition->status = B_PARTITION_VALID; + _partition->flags |= B_PARTITION_FILE_SYSTEM; + _partition->content_size = cookie->super_block.NumBlocks() << cookie->super_block.BlockShift(); - partition->block_size = 1 << cookie->super_block.BlockShift(); - // TODO volume name isn't in the superblock - partition->content_name = strdup(cookie->super_block.filesystem); - if (partition->content_name == NULL) - return B_NO_MEMORY; + _partition->block_size = 1 << cookie->super_block.BlockShift(); + _partition->content_name = strdup(cookie->name); - return B_OK; + return _partition->content_name != NULL ? B_OK : B_NO_MEMORY; }