/*
- * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
+#include <sys/types.h>
+#include <sys/errno.h>
+
+#if HFS
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/utfconv.h>
+#include <kern/host.h>
+#include <mach/host_priv.h>
+#include <libkern/OSKextLib.h>
+#include <libkern/OSKextLibPrivate.h>
#include "hfs.h"
+lck_grp_t * encodinglst_lck_grp;
+lck_grp_attr_t * encodinglst_lck_grp_attr;
+lck_attr_t * encodinglst_lck_attr;
+
+
/* hfs encoding converter list */
SLIST_HEAD(encodinglst, hfs_encoding) hfs_encoding_list = {0};
-decl_simple_lock_data(,hfs_encoding_list_slock);
+lck_mtx_t encodinglst_mutex;
/* hfs encoding converter entry */
struct hfs_encoding {
SLIST_ENTRY(hfs_encoding) link;
int refcount;
int kmod_id;
- UInt32 encoding;
+ u_int32_t encoding;
hfs_to_unicode_func_t get_unicode_func;
unicode_to_hfs_func_t get_hfsname_func;
};
-/* XXX We should use an "official" interface! */
-extern kern_return_t kmod_destroy(host_priv_t host_priv, kmod_t id);
-extern struct host realhost;
-
#define MAX_HFS_UNICODE_CHARS (15*5)
-int mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *usedCharLen);
-
-static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs_str);
-
+#if CONFIG_HFS_STD
+static int unicode_to_mac_roman(UniChar *uni_str, u_int32_t unicodeChars, Str31 hfs_str);
+#endif
void
hfs_converterinit(void)
{
SLIST_INIT(&hfs_encoding_list);
- simple_lock_init(&hfs_encoding_list_slock);
+ encodinglst_lck_grp_attr= lck_grp_attr_alloc_init();
+ encodinglst_lck_grp = lck_grp_alloc_init("cnode_hash", encodinglst_lck_grp_attr);
+ encodinglst_lck_attr = lck_attr_alloc_init();
+
+ lck_mtx_init(&encodinglst_mutex, encodinglst_lck_grp, encodinglst_lck_attr);
+
+#if CONFIG_HFS_STD
/*
* add resident MacRoman converter and take a reference
- * since its always "loaded".
+ * since its always "loaded". MacRoman is the default converter
+ * for HFS standard volumes.
+ *
+ * Only do this if we are actually supporting HFS standard
+ * volumes. The converter is not used on configurations
+ * that do not support HFS standard.
*/
hfs_addconverter(0, kTextEncodingMacRoman, mac_roman_to_unicode, unicode_to_mac_roman);
SLIST_FIRST(&hfs_encoding_list)->refcount++;
+#endif
+
+}
+
+#if !CONFIG_HFS_STD
+
+/*
+ * Function stubs are needed for KPI export.
+ * It is a little swizzly to have two separate copies of the stub functions in this file
+ * but the prototypes of these functions are different if we're using the real headers
+ * vs. the dummy prototypes at the end of the file. (hfs_to_unicode_func_t vs. void*)
+ *
+ * As a result, we need our own copies in the no-HFS-Standard configuration
+ */
+int hfs_addconverter( __unused int id,
+ __unused u_int32_t encoding,
+ __unused hfs_to_unicode_func_t get_unicode,
+ __unused unicode_to_hfs_func_t get_hfsname )
+{
+ return(0);
+}
+
+int hfs_getconverter( __unused u_int32_t encoding,
+ __unused hfs_to_unicode_func_t *get_unicode,
+ __unused unicode_to_hfs_func_t *get_hfsname)
+{
+ return(EINVAL);
+}
+
+int hfs_relconverter(__unused u_int32_t encoding)
+{
+ return(EINVAL);
+}
+
+int hfs_remconverter(__unused int id, __unused u_int32_t encoding)
+{
+ return(0);
}
+#else
+
+/*
+ * For configurations that do support HFS standard, we need all of these..
+ */
/*
* hfs_addconverter - add an HFS encoding converter
*
*/
int
-hfs_addconverter(int id, UInt32 encoding, hfs_to_unicode_func_t get_unicode, unicode_to_hfs_func_t get_hfsname)
+hfs_addconverter(int id, u_int32_t encoding, hfs_to_unicode_func_t get_unicode, unicode_to_hfs_func_t get_hfsname)
{
struct hfs_encoding *encp;
MALLOC(encp, struct hfs_encoding *, sizeof(struct hfs_encoding), M_TEMP, M_WAITOK);
- simple_lock(&hfs_encoding_list_slock);
+ lck_mtx_lock(&encodinglst_mutex);
encp->link.sle_next = NULL;
encp->refcount = 0;
encp->kmod_id = id;
SLIST_INSERT_HEAD(&hfs_encoding_list, encp, link);
- simple_unlock(&hfs_encoding_list_slock);
+ lck_mtx_unlock(&encodinglst_mutex);
return (0);
}
* The call is initiated from within the kernel during the unmounting of an hfs voulume.
*/
int
-hfs_remconverter(int id, UInt32 encoding)
+hfs_remconverter(int id, u_int32_t encoding)
{
struct hfs_encoding *encp;
- int busy = 0;
- simple_lock(&hfs_encoding_list_slock);
+ lck_mtx_lock(&encodinglst_mutex);
SLIST_FOREACH(encp, &hfs_encoding_list, link) {
if (encp->encoding == encoding && encp->kmod_id == id) {
encp->refcount--;
/* if converter is no longer in use, release it */
if (encp->refcount <= 0 && encp->kmod_id != 0) {
SLIST_REMOVE(&hfs_encoding_list, encp, hfs_encoding, link);
+ lck_mtx_unlock(&encodinglst_mutex);
FREE(encp, M_TEMP);
+ return (0);
} else {
- busy = 1;
+ lck_mtx_unlock(&encodinglst_mutex);
+ return (1); /* busy */
}
break;
}
}
- simple_unlock(&hfs_encoding_list_slock);
+ lck_mtx_unlock(&encodinglst_mutex);
- return (busy);
+ return (0);
}
* Normally called during the mounting of an hfs voulume.
*/
int
-hfs_getconverter(UInt32 encoding, hfs_to_unicode_func_t *get_unicode, unicode_to_hfs_func_t *get_hfsname)
+hfs_getconverter(u_int32_t encoding, hfs_to_unicode_func_t *get_unicode, unicode_to_hfs_func_t *get_hfsname)
{
struct hfs_encoding *encp;
int found = 0;
- simple_lock(&hfs_encoding_list_slock);
+ lck_mtx_lock(&encodinglst_mutex);
SLIST_FOREACH(encp, &hfs_encoding_list, link) {
if (encp->encoding == encoding) {
found = 1;
break;
}
}
- simple_unlock(&hfs_encoding_list_slock);
+ lck_mtx_unlock(&encodinglst_mutex);
if (!found) {
*get_unicode = NULL;
* Normally called during the unmounting of an hfs voulume.
*/
int
-hfs_relconverter(UInt32 encoding)
+hfs_relconverter(u_int32_t encoding)
{
struct hfs_encoding *encp;
- int found = 0;
- simple_lock(&hfs_encoding_list_slock);
+ lck_mtx_lock(&encodinglst_mutex);
SLIST_FOREACH(encp, &hfs_encoding_list, link) {
if (encp->encoding == encoding) {
- found = 1;
encp->refcount--;
/* if converter is no longer in use, release it */
if (encp->refcount <= 0 && encp->kmod_id != 0) {
- int id = encp->kmod_id;
+ uint32_t loadTag = (uint32_t)encp->kmod_id;
SLIST_REMOVE(&hfs_encoding_list, encp, hfs_encoding, link);
- FREE(encp, M_TEMP);
- encp = NULL;
-
- simple_unlock(&hfs_encoding_list_slock);
- kmod_destroy((host_priv_t) host_priv_self(), id);
- simple_lock(&hfs_encoding_list_slock);
+ lck_mtx_unlock(&encodinglst_mutex);
+
+ FREE(encp, M_TEMP);
+ (void)OSKextUnloadKextWithLoadTag(loadTag);
+ return (0);
}
- break;
+ lck_mtx_unlock(&encodinglst_mutex);
+ return (0);
}
}
- simple_unlock(&hfs_encoding_list_slock);
+ lck_mtx_unlock(&encodinglst_mutex);
- return (found ? 0 : EINVAL);
+ return (EINVAL);
}
-
/*
* Convert HFS encoded string into UTF-8
*
* '/' chars are converted to ':'
*/
int
-hfs_to_utf8(ExtendedVCB *vcb, Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, unsigned char* dstStr)
+hfs_to_utf8(ExtendedVCB *vcb, const Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, unsigned char* dstStr)
{
int error;
UniChar uniStr[MAX_HFS_UNICODE_CHARS];
ItemCount uniCount;
size_t utf8len;
hfs_to_unicode_func_t hfs_get_unicode = VCBTOHFS(vcb)->hfs_get_unicode;
+ u_int8_t pascal_length = 0;
+ /*
+ * Validate the length of the Pascal-style string before passing it
+ * down to the decoding engine.
+ */
+ pascal_length = *((const u_int8_t*)(hfs_str));
+ if (pascal_length > 31) {
+ /* invalid string; longer than 31 bytes */
+ error = EINVAL;
+ return error;
+ }
+
error = hfs_get_unicode(hfs_str, uniStr, MAX_HFS_UNICODE_CHARS, &uniCount);
if (uniCount == 0)
return error;
}
-
/*
* When an HFS name cannot be encoded with the current
* volume encoding then MacRoman is used as a fallback.
*/
int
-mac_roman_to_utf8(Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, unsigned char* dstStr)
+mac_roman_to_utf8(const Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, unsigned char* dstStr)
{
int error;
UniChar uniStr[MAX_HFS_UNICODE_CHARS];
ItemCount uniCount;
size_t utf8len;
+ u_int8_t pascal_length = 0;
+
+ /*
+ * Validate the length of the Pascal-style string before passing it
+ * down to the decoding engine.
+ */
+ pascal_length = *((const u_int8_t*)(hfs_str));
+ if (pascal_length > 31) {
+ /* invalid string; longer than 31 bytes */
+ error = EINVAL;
+ return error;
+ }
error = mac_roman_to_unicode(hfs_str, uniStr, MAX_HFS_UNICODE_CHARS, &uniCount);
return error;
}
-
/*
* Convert Unicode string into HFS encoding
*
return error;
}
+
int
utf8_to_mac_roman(ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr)
{
*/
/* 0x00A0 - 0x00FF = Latin 1 Supplement (30 total) */
-static UInt8 gLatin1Table[] = {
+static u_int8_t gLatin1Table[] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0x00A0 */ 0xCA, 0xC1, 0xA2, 0xA3, 0xDB, 0xB4, '?', 0xA4, 0xAC, 0xA9, 0xBB, 0xC7, 0xC2, '?', 0xA8, 0xF8,
/* 0x00B0 */ 0xA1, 0XB1, '?', '?', 0xAB, 0xB5, 0xA6, 0xe1, 0xFC, '?', 0xBC, 0xC8, '?', '?', '?', 0xC0,
};
/* 0x02C0 - 0x02DF = Spacing Modifiers (8 total) */
-static UInt8 gSpaceModsTable[] = {
+static u_int8_t gSpaceModsTable[] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0x02C0 */ '?', '?', '?', '?', '?', '?', 0xF6, 0xFF, '?', '?', '?', '?', '?', '?', '?', '?',
/* 0x02D0 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xF9, 0xFA, 0xFB, 0xFE, 0xF7, 0xFD, '?', '?'
};
/* 0x2010 - 0x20AF = General Punctuation (17 total) */
-static UInt8 gPunctTable[] = {
+static u_int8_t gPunctTable[] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0x2010 */ '?', '?', '?', 0xd0, 0xd1, '?', '?', '?', 0xd4, 0xd5, 0xe2, '?', 0xd2, 0xd3, 0xe3, '?',
/* 0x2020 */ 0xa0, 0xe0, 0xa5, '?', '?', '?', 0xc9, '?', '?', '?', '?', '?', '?', '?', '?', '?',
};
/* 0x22xx = Mathematical Operators (11 total) */
-static UInt8 gMathTable[] = {
+static u_int8_t gMathTable[] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0x2200 */ '?', '?', 0xb6, '?', '?', '?', 0xc6, '?', '?', '?', '?', '?', '?', '?', '?', 0xb8,
/* 0x2210 */ '?', 0xb7, '?', '?', '?', '?', '?', '?', '?', '?', 0xc3, '?', '?', '?', 0xb0, '?',
};
/* */
-static UInt8 gReverseCombTable[] = {
+static u_int8_t gReverseCombTable[] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0x40 */ 0xDA, 0x40, 0xDA, 0xDA, 0xDA, 0x56, 0xDA, 0xDA, 0xDA, 0x6C, 0xDA, 0xDA, 0xDA, 0xDA, 0x82, 0x98,
/* 0x50 */ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xAE, 0xDA, 0xDA, 0xDA, 0xC4, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
*
* Assumes Unicode input is fully decomposed
*/
-static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs_str)
+static int unicode_to_mac_roman(UniChar *uni_str, u_int32_t unicodeChars, Str31 hfs_str)
{
- UInt8 *p;
+ u_int8_t *p;
const UniChar *u;
UniChar c;
UniChar mask;
- UInt16 inputChars;
- UInt16 pascalChars;
+ u_int16_t inputChars;
+ u_int16_t pascalChars;
OSErr result = noErr;
- UInt8 lsb;
- UInt8 prevChar;
- UInt8 mc;
+ u_int8_t lsb;
+ u_int8_t prevChar;
+ u_int8_t mc;
mask = (UniChar) 0xFF80;
p = &hfs_str[1];
while (inputChars) {
c = *(u++);
- lsb = (UInt8) c;
+ lsb = (u_int8_t) c;
/*
* If its not 7-bit ascii, then we need to map it
break;
case 0x2200:
- if (lsb <= 0x68)
+ if (lsb < 0x68)
mc = gMathTable[lsb];
break;
*/
int
mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str,
- UInt32 maxCharLen, UInt32 *unicodeChars)
+ __unused u_int32_t maxCharLen, u_int32_t *unicodeChars)
{
- const UInt8 *p;
+ const u_int8_t *p;
UniChar *u;
- UInt16 pascalChars;
- UInt8 c;
+ u_int16_t pascalChars;
+ u_int8_t c;
p = hfs_str;
u = uni_str;
while (pascalChars--) {
c = *(p++);
- if ( (SInt8) c >= 0 ) { /* check if seven bit ascii */
+ if ( (int8_t) c >= 0 ) { /* check if seven bit ascii */
*(u++) = (UniChar) c; /* just pad high byte with zero */
} else { /* its a hi bit character */
UniChar uc;
return noErr;
}
+#endif /* CONFIG_STD_HFS */
+
+#else /* not HFS */
+
+/*
+ * These function prototypes are here because hfs.h is not #included
+ * so its prototypes are not provided. These are needed because they are exported
+ * as KPI for the conversion subroutines during mounting of HFS standard.
+ */
+int hfs_addconverter(int id, u_int32_t encoding, void * get_unicode, void * get_hfsname);
+int hfs_getconverter(u_int32_t encoding, void *get_unicode, void *get_hfsname);
+int hfs_relconverter(u_int32_t encoding);
+int hfs_remconverter(int id, u_int32_t encoding);
+
+/* Function stubs are needed for KPI export */
+
+int hfs_addconverter( __unused int id,
+ __unused u_int32_t encoding,
+ __unused void * get_unicode,
+ __unused void * get_hfsname )
+{
+ return(0);
+}
+
+int hfs_getconverter(__unused u_int32_t encoding, __unused void *get_unicode, __unused void *get_hfsname)
+{
+ return(EINVAL);
+}
+
+int hfs_relconverter(__unused u_int32_t encoding)
+{
+ return(EINVAL);
+}
+
+int hfs_remconverter(__unused int id, __unused u_int32_t encoding)
+{
+ return(0);
+}
+#endif
+
+