Table of Contents
- Case sensitivity: it depends on who your clients are
- What catia:mappings actually does
- Linux client mount options
One of the persistent frustrations in my life is that Samba/SMB has weird issues around character encoding. This has gotten so bad in the past that I simply gave up on it. It works great for Windows, but with Linux and MacOS clients I ended up running into serious issues, particularly because English is not the only language which I use in filenames. Over time, I figured out that there is a series of magical configuration options, buried deep in the Samba documentation that make it work for Linux and MacOS and I don't think it breaks Windows (though I am not sure about that last part).
Why this isn't the default, I have no idea.
Anyway, this is how we unfuck Samba for Linux/MacOS - in the /etc/samba/smb.conf we need to set the global block:
[global]
dos charset = CP850
unix charset = UTF-8
mangled names = no
server min protocol = SMB3
client min protocol = SMB3
multicast dns register = yes
mangled names = no: 8.3 mangling is a Windows-95-era thing nobody should be inflicting on a civilized system. The min protocol lines explicitly disable SMB1 (recent Samba already does this, but it's worth being loud about). And multicast dns register makes the server discoverable by macOS Finder. Samba handles the _smb._tcp registration itself once that's on; if you want a recognizable Finder icon, drop an Avahi service file alongside it for the device-info record:
1<!-- /etc/avahi/services/smb.service -->
2<?xml version="1.0" standalone='no'?>
3<!DOCTYPE service-group SYSTEM "avahi.dtd">
4<service-group>
5 <name replace-wildcards="yes">%h</name>
6 <service><type>_device-info._tcp</type><port>0</port>
7 <txt-record>model=RackMac</txt-record>
8 </service>
9</service-group>
The model= value (RackMac, MacPro7,1, Xserve, etc.) is what controls the Finder icon.
And then for every share, we need to configure as follows. This is the ansible jinja2 template I use:
1[{{ item.name }}]
2 comment = {{ item.comment }}
3 path = {{ item.path }}
4 browseable = {{ 'yes' if item.browseable else 'no' }}
5 writable = {{ 'yes' if item.writable else 'no' }}
6 guest ok = no
7 valid users = {{ item.valid_users }}
8 create mask = 0744
9 directory mask = 0755
10 mangled names = no
11 case sensitive = yes
12 default case = lower
13 preserve case = yes
14 short preserve case = yes
15 vfs objects = catia fruit streams_xattr
16 fruit:encoding = native
17 fruit:metadata = stream
18 fruit:resource = stream
19 fruit:posix_rename = yes
20 fruit:veto_appledouble = no
21 fruit:nfs_aces = no
22 fruit:wipe_intentionally_left_blank_rfork = yes
23 fruit:delete_empty_adfiles = yes
24 catia:mappings = 0x22:0xa8,0x2a:0xa4,0x2f:0xf8,0x3a:0xf7,0x3c:0xab,0x3e:0xbb,0x3f:0xbf,0x5c:0xff,0x7c:0xa6
And this is what the final result looks like:
[storage]
comment = Infosphere storage array
path = /storage
browseable = yes
writable = yes
guest ok = no
valid users = cyclicircuit
create mask = 0744
directory mask = 0755
mangled names = no
case sensitive = yes
default case = lower
preserve case = yes
short preserve case = yes
vfs objects = catia fruit streams_xattr
fruit:encoding = native
fruit:metadata = stream
fruit:resource = stream
fruit:posix_rename = yes
fruit:veto_appledouble = no
fruit:nfs_aces = no
fruit:wipe_intentionally_left_blank_rfork = yes
fruit:delete_empty_adfiles = yes
catia:mappings = 0x22:0xa8,0x2a:0xa4,0x2f:0xf8,0x3a:0xf7,0x3c:0xab,0x3e:0xbb,0x3f:0xbf,0x5c:0xff,0x7c:0xa6
Case sensitivity: it depends on who your clients are #
This is where Samba is kinda unfixable. For the four case sensitive / default case / preserve case / short preserve case lines above, you have to pick whichever OS is most often the client and optimize for that.
If the share is primarily serving Linux clients, keep those lines as-is. The Linux filesystem underneath is case-sensitive, but by default Samba pretends it isn't, so two paths that differ only in case (Lou.mkv vs lou.mkv) silently collapse to the same file at the SMB layer. That's a data-loss bug waiting to happen during dedup or sync, and it'll bite you in the ass long after you've forgotten about it.
If the share is primarily serving macOS clients, drop those four lines. macOS expects case-insensitive volumes, and a bunch of Mac software (Adobe, some Office templates, Steam) breaks in subtle ways on a case-sensitive backing store. The Linux-side data-loss risk is still there in theory, but in practice Mac clients aren't producing the case-only collisions that cause the problem.
If it's mixed, pick based on whichever side has the workflows you care more about and tell the other side to watch their step. There's no simple answer.
What catia:mappings actually does #
That hex soup maps the characters Windows and macOS won't let you use in filenames to Unicode lookalikes that Linux happily stores:
| Win/Mac char | Maps to | Looks like |
|---|---|---|
" (0x22) |
0xa8 | ¨ |
* (0x2a) |
0xa4 | ¤ |
/ (0x2f) |
0xf8 | ø |
: (0x3a) |
0xf7 | ÷ |
< (0x3c) |
0xab | « |
> (0x3e) |
0xbb | » |
? (0x3f) |
0xbf | ¿ |
\ (0x5c) |
0xff | ÿ |
| (0x7c) |
0xa6 | ¦ |
So a Mac saving My File: V2 lands on disk as My File÷ V2. Its ugly, but it works across platforms (and honestly, what part of this isn't ugly?).
Linux client mount options #
The other half of the situation is to get the matching CIFS mount options on a Linux client, and these are also non-obvious. You're gonna wanna set these in /etc/fstab:
//server/share /mnt/share cifs \
vers=3.1.1,\
credentials=/etc/samba/creds,\
uid=1000,gid=1000,forceuid,forcegid,\
file_mode=0644,dir_mode=0755,\
iocharset=utf8,\
mapposix,\
nounix,\
cache=strict,\
_netdev 0 0
The non-obvious ones:
vers=3.1.1: pin the protocol; never let it negotiate down.mapposix: handles the reserved-char mapping in cooperation with server-sidecatia. Don't use the oldermapchars(deprecated, incompatible).nounix: Samba's old SMB1 UNIX extensions are dead; explicitly disabling avoids fallback weirdness. (If you ever move to Samba 4.19+ with SMB3 POSIX extensions, swapnounixforposix.)iocharset=utf8: pairs with server-sideunix charset = UTF-8.
Sincerest apologies to all the forum posts where I gathered this information over the years, I simply don't have the links to you anymore. If I did, I would cite them.
2026-06-02 Update: Revised this article based on bugs and quality-of-life issues discovered over time running this config. The notable additions:
case sensitive = yes(with the matchingdefault/preserve caselines): the most important addition, but the right setting depends on whether the share is Linux- or Mac-primary (see above).- Expanded
fruit:*options: stop macOS from littering the share with.DS_Storeand._*files by storing that metadata in xattrs instead. Thestreams_xattrVFS object is required forfruit:metadata = streamto actually work. - Explicit SMB3 enforcement via
server min protocol/client min protocol: recent Samba defaults to this already, but worth being loud about. - mDNS + an Avahi service file: so macOS Finder actually sees the server.
- The Linux client mount section: server config is only half the battle.
- The
catia:mappingstable: demystifies the hex soup so it's not just opaque magic.