]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_encodings.c
xnu-2782.40.9.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_encodings.c
index fdf03bc701619538fb374d0ac28db89b7e95f9bd..d4fc65fc6d1e176c6fe9378fa818880aefb0c4b8 100644 (file)
@@ -1,16 +1,19 @@
 /*
- * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2013 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  * 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. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * 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.
+ * 
+ * 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
  * 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(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
@@ -84,13 +148,13 @@ hfs_converterinit(void)
  *
  */
 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;
@@ -100,7 +164,7 @@ hfs_addconverter(int id, UInt32 encoding, hfs_to_unicode_func_t get_unicode, uni
        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);
 }
 
@@ -117,12 +181,11 @@ hfs_addconverter(int id, UInt32 encoding, hfs_to_unicode_func_t get_unicode, uni
  * 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--;
@@ -130,16 +193,19 @@ hfs_remconverter(int id, UInt32 encoding)
                        /* 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);
 }
 
 
@@ -149,12 +215,12 @@ hfs_remconverter(int id, UInt32 encoding)
  * 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;
@@ -164,7 +230,7 @@ hfs_getconverter(UInt32 encoding, hfs_to_unicode_func_t *get_unicode, unicode_to
                        break;
                }
        }
-       simple_unlock(&hfs_encoding_list_slock);
+       lck_mtx_unlock(&encodinglst_mutex);
 
        if (!found) {
                *get_unicode = NULL;
@@ -182,38 +248,35 @@ hfs_getconverter(UInt32 encoding, hfs_to_unicode_func_t *get_unicode, unicode_to
  * 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_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
  *
@@ -221,14 +284,26 @@ hfs_relconverter(UInt32 encoding)
  * '/' 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)
@@ -245,18 +320,29 @@ hfs_to_utf8(ExtendedVCB *vcb, Str31 hfs_str, ByteCount maxDstLen, ByteCount *act
        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);
        
@@ -274,7 +360,6 @@ mac_roman_to_utf8(Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, u
        return error;
 }
 
-
 /*
  * Convert Unicode string into HFS encoding
  *
@@ -314,6 +399,7 @@ utf8_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, const unsigned char* srcStr, Str
        return error;
 }
 
+
 int
 utf8_to_mac_roman(ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr)
 {
@@ -334,7 +420,7 @@ 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,
@@ -345,14 +431,14 @@ static UInt8 gLatin1Table[] = {
 };
 
 /* 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,  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',  '?',
@@ -367,7 +453,7 @@ static UInt8 gPunctTable[] = {
 };
 
 /* 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,  '?',
@@ -379,7 +465,7 @@ static UInt8 gMathTable[] = {
 };
 
 /* */
-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,
@@ -440,18 +526,18 @@ static UInt8 gReverseCombTable[] = {
  *
  * 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];
@@ -461,7 +547,7 @@ static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs
        
        while (inputChars) {
                c = *(u++);
-               lsb = (UInt8) c;
+               lsb = (u_int8_t) c;
 
                /*
                 * If its not 7-bit ascii, then we need to map it
@@ -485,7 +571,7 @@ static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs
                                break;
 
                        case 0x2200:
-                               if (lsb <= 0x68)
+                               if (lsb < 0x68)
                                        mc = gMathTable[lsb];
                                break;
 
@@ -614,13 +700,13 @@ static UniChar gHiBitCombUnicode[128] = {
  * Unicode output is fully decomposed
  */
 int
-mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str,
-                               UInt32 maxCharLen, UInt32 *unicodeChars)
+mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str,
+                               __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;
@@ -630,7 +716,7 @@ mac_roman_to_unicode(Str31 hfs_str, UniChar *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;
@@ -652,3 +738,44 @@ mac_roman_to_unicode(Str31 hfs_str, UniChar *uni_str,
        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
+
+