return outlen;
}
-/*
- * cifs_mapchar - convert a host-endian char to proper char in codepage
- * @target - where converted character should be copied
- * @src_char - 2 byte host-endian source character
- * @cp - codepage to which character should be converted
- * @mapchar - should character be mapped according to mapchars mount option?
- *
- * This function handles the conversion of a single character. It is the
- * responsibility of the caller to ensure that the target buffer is large
- * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
- */
-static int
-cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
- bool mapchar)
+/* Convert character using the SFU - "Services for Unix" remapping range */
+static bool
+convert_sfu_char(const __u16 src_char, char *target)
{
- int len = 1;
-
- if (!mapchar)
- goto cp_convert;
-
/*
* BB: Cannot handle remapping UNI_SLASH until all the calls to
* build_path_from_dentry are modified, as they use slash as
*target = '<';
break;
default:
- goto cp_convert;
+ return false;
}
+ return true;
+}
-out:
- return len;
+/* Convert character using the SFM - "Services for Mac" remapping range */
+static bool
+convert_sfm_char(const __u16 src_char, char *target)
+{
+ switch (src_char) {
+ case SFM_COLON:
+ *target = ':';
+ break;
+ case SFM_ASTERISK:
+ *target = '*';
+ break;
+ case SFM_QUESTION:
+ *target = '?';
+ break;
+ case SFM_PIPE:
+ *target = '|';
+ break;
+ case SFM_GRTRTHAN:
+ *target = '>';
+ break;
+ case SFM_LESSTHAN:
+ *target = '<';
+ break;
+ case SFM_SLASH:
+ *target = '\\';
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+/*
+ * cifs_mapchar - convert a host-endian char to proper char in codepage
+ * @target - where converted character should be copied
+ * @src_char - 2 byte host-endian source character
+ * @cp - codepage to which character should be converted
+ * @map_type - How should the 7 NTFS/SMB reserved characters be mapped to UCS2?
+ *
+ * This function handles the conversion of a single character. It is the
+ * responsibility of the caller to ensure that the target buffer is large
+ * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
+ */
+static int
+cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
+ int maptype)
+{
+ int len = 1;
+
+ if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target))
+ return len;
+ else if ((maptype == SFU_MAP_UNI_RSVD) &&
+ convert_sfu_char(src_char, target))
+ return len;
-cp_convert:
+ /* if character not one of seven in special remap set */
len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
if (len <= 0) {
*target = '?';
len = 1;
}
- goto out;
+ return len;
}
/*
*/
int
cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
- const struct nls_table *codepage, bool mapchar)
+ const struct nls_table *codepage, int map_type)
{
int i, charlen, safelen;
int outlen = 0;
* conversion bleed into the null terminator
*/
if (outlen >= safelen) {
- charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
+ charlen = cifs_mapchar(tmp, ftmp, codepage, map_type);
if ((outlen + charlen) > (tolen - nullsize))
break;
}
/* put converted char into 'to' buffer */
- charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
+ charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type);
outlen += charlen;
}
if (!dst)
return NULL;
cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage,
- false);
+ NO_MAP_UNI_RSVD);
} else {
len = strnlen(src, maxlen);
len++;
#define UNI_PIPE (__u16) ('|' + 0xF000)
#define UNI_SLASH (__u16) ('\\' + 0xF000)
+/*
+ * Macs use an older "SFM" mapping of the symbols above. Fortunately it does
+ * not conflict (although almost does) with the mapping above.
+ */
+
+#define SFM_ASTERISK ((__u16) 0xF021)
+#define SFM_QUESTION ((__u16) 0xF025)
+#define SFM_COLON ((__u16) 0xF022)
+#define SFM_GRTRTHAN ((__u16) 0xF024)
+#define SFM_LESSTHAN ((__u16) 0xF023)
+#define SFM_PIPE ((__u16) 0xF027)
+#define SFM_SLASH ((__u16) 0xF026)
+
+/*
+ * Mapping mechanism to use when one of the seven reserved characters is
+ * encountered. We can only map using one of the mechanisms at a time
+ * since otherwise readdir could return directory entries which we would
+ * not be able to open
+ *
+ * NO_MAP_UNI_RSVD = do not perform any remapping of the character
+ * SFM_MAP_UNI_RSVD = map reserved characters using SFM scheme (MAC compatible)
+ * SFU_MAP_UNI_RSVD = map reserved characters ala SFU ("mapchars" option)
+ *
+ */
+#define NO_MAP_UNI_RSVD 0
+#define SFM_MAP_UNI_RSVD 1
+#define SFU_MAP_UNI_RSVD 2
+
/* Just define what we want from uniupr.h. We don't want to define the tables
* in each source file.
*/
#ifdef __KERNEL__
int cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
- const struct nls_table *codepage, bool mapchar);
+ const struct nls_table *cp, int map_type);
int cifs_utf16_bytes(const __le16 *from, int maxbytes,
const struct nls_table *codepage);
int cifs_strtoUTF16(__le16 *, const char *, int, const struct nls_table *);
if (file_info->srch_inf.unicode) {
struct nls_table *nlt = cifs_sb->local_nls;
+ int map_type;
+
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
+ map_type = SFM_MAP_UNI_RSVD;
+ else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+ map_type = SFU_MAP_UNI_RSVD;
+ else
+ map_type = NO_MAP_UNI_RSVD;
name.name = scratch_buf;
name.len =
cifs_from_utf16((char *)name.name, (__le16 *)de.name,
UNICODE_NAME_MAX,
min_t(size_t, de.namelen,
- (size_t)max_len), nlt,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ (size_t)max_len), nlt, map_type);
name.len -= nls_nullsize(nlt);
} else {
name.name = de.name;