それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

ファイル名の最大長の限界を、ストレージのフォーマットタイプごとに調べる

ファイル名の限界を調べる。

windows の人からもらった zip ファイルが 展開できなくて、ファイル名の長さの問題だったので、限界値(最大のファイル名の長さ)をぱぱぱっと調べた。

ファイルシステムごとに、ファイルの文字長(ファイルの文字サイズ)が違っていて、本当に困るんですよ。

日本語だと文字数ほとんど使えないLinux

Linuxはファイルの文字数が255バイトになっているので、日本語UTF-8のとき文字数が極めて少ない。

フォーマット 日本語の最大可能文字数
ext4 85文字
btfs 85文字
NTFS 255文字
exFAT 255文字

UTF-8が3バイト前後というのはわかるのですが、85文字はマジでやばい。少なすぎませんかね。

これは、旧来のシステムと互換性切ってでも文字数はほしいところです。LinuxのSambaとかでファイル名が長くて保存されないってよくある問題。ずっと解決しないので、これから先も解決することな無いんだと思う。

カーネルコンパイル時にファイル名のサイズの上限を変えてコンパイルさせれば、ワンチャンあるけど、それした場合、アップデートどうすんの感。

ちなみに、Linuxから実験してるのでNTFSexFATLinuxでマウントしてます。マウントしてたら最大長突破できるのなら、ext4もマウントオプションで突破できるのではないかと思うんだけどね。

XFSやzfsは調べなかったけど、ex4と結果は同じです、同じ定数(NAME_MAX )見てるので。Linuxでマウントしてる限りは、255が適用されちゃう。

linux で現在の最大長を調べる

255 バイトと決まっているのだから、別に調べなくてもいいのだが。調べたいときは次のようにする。

getconf -a | grep -P  '^NAME_MAX'
NAME_MAX                           255

実験に使用したコード

Linux環境で UTF8 で実行を前提に。

ファイル名の文字列の長さを調べていく。

    pwd = Dir.pwd.to_s
    (1..256).map{|i| 
        begin 
            str = ""*i
            FileUtils.touch(str)
            FileUtils.remove(str)
        rescue => e 
            printf "最大のファイルサイズは %3d バイトで、日本語だと %d 文字\n", 
            (""*(i-1)).bytesize ,  (""*(i-1)).size
            break
        end
    }

ディレクトリについても調べる

    pwd = Dir.pwd.to_s

    (1..256).map{|i| 
        begin 
            pwd = Dir.pwd.to_s
        str = "/あ"*i
        FileUtils.mkdir_p(pwd+str)
        FileUtils.rm_rf(pwd+str)
        puts pwd+str
        rescue => e 
            printf "最大のファイルサイズは %3d バイトで、日本語だと %d 文字\n", 
            (""*(i-1)).bytesize ,  (""*(i-1)).size
            printf "パス名を含めた場合、最大のファイルサイズは %3d バイトで、日本語だと %d 文字\n", 
            (pwd+'/'+""*(i-1)).bytesize ,  (pwd+'/'+""*(i-1)).size
            break
        end
    }

ext4 は 255バイト(UTF-8で85文字)で上限

ext4

ただしディレクトリは別カウント

ext4ディレクト

btrfs も 85文字で上限

btrfs

NTFS は「文字数」で255文字

NTFS

exFAT は「文字数」で255文字

exFAT

linuxのどこで定義されているのか。

cat /usr/include/linux/limits.h
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _LINUX_LIMITS_H
#define _LINUX_LIMITS_H

#define NR_OPEN         1024

#define NGROUPS_MAX    65536    /* supplemental group IDs are available */
#define ARG_MAX       131072    /* # bytes of args + environ for exec() */
#define LINK_MAX         127    /* # links a file may have */
#define MAX_CANON        255    /* size of the canonical input queue */
#define MAX_INPUT        255    /* size of the type-ahead buffer */
#define NAME_MAX         255    /* # chars in a file name */
#define PATH_MAX        4096    /* # chars in a path name including nul */
#define PIPE_BUF        4096    /* # bytes in atomic write to a pipe */
#define XATTR_NAME_MAX   255    /* # chars in an extended attribute name */
#define XATTR_SIZE_MAX 65536    /* size of an extended attribute value (64k) */
#define XATTR_LIST_MAX 65536    /* size of extended attribute namelist (64k) */

#define RTSIG_MAX         32

#endif

btrfs とかは回避できなくもない。

btrfs でマウントしたボリュームをを、cifs/smb 経由でvfat でマウントし直せば。。。。できなくはないが後で地獄を見ることになる。

参考資料

cat /usr/include/linux/limits.h

https://serverfault.com/questions/9546/filename-length-limits-on-linux

https://superuser.com/questions/1109959/reconstituting-long-file-names-lfn-from-8-3-on-nas-server-after-system-crash