FatFS R0.08a で現在のディレクトリ名を取得する

本文書の取り扱い

クリエイティブ・コモンズ・ライセンスこの文書は、クリエイティブ・コモンズ・ライセンスの下でライセンスされています。

免責事項

本カスタマイズは無保証です。
使用は全て自己責任で行ってください。

概要

ChaN氏の作成されたFatFs には R0.08a でカレントディレクトリパスの取得を行う f_getcwd() が実装された。しかし、バッファサイズが満たない場合は、エラーとなるほか、カレントディレクトリ名のみが欲しい場合は、パス全体を取得して解析する必要があるため、AVRマイコンのようなメモリ量に制約のある環境では不満が残る。

小生もAVR上でFatFsを用いているが、LFNを有効にするとf_getcwd()のバッファに割り当てるSRAMの不足に悩まされた。

そこで、f_getcwd() を改変し、バッファに満たせるだけのカレントディレクトリ名のみを返す f_getcwdname() 関数を作成した。

謝辞

劇的に簡単にFATファイルシステムを扱うことが可能なFatFsを実装/公開されたChaN氏とFatFsを用いた作例や記事を公開されている方々に心よりの感謝の意を表します。

機能と制約

  • 現在のディレクトリ名をバッファにコピーする
  • バッファ・サイズが不足している場合はバッファ・サイズ-1文字をコピーし、終端にヌル文字を書き込む(strlcpy()関数相当の動作)
    • この場合の戻り値は f_getcwd() と同様にFR_NOT_ENOUGH_CORE となる

動作確認環境

  • PC環境
  • AVR環境
    • ATmega644P
    • ヒロセSDカードソケット
    • SanDisk 2.0GB SDカード
    • AVRStudio 4.18
    • WinAVR WinAVR-20100110

ソースコード

/* ff.c 2540行目と2541行目の間に挿入 */
FRESULT f_getcwdname (
    TCHAR *path,    /* Pointer to the directory path */
    UINT sz_path    /* Size of path */
)
{
    FRESULT res;
    DIR dj;
    UINT n;
    DWORD ccl;
    TCHAR *tp;
    FILINFO fno;
    DEF_NAMEBUF;


    *path = 0;
    res = chk_mounted((const TCHAR**)&path, &dj.fs, 0);    /* Get current volume */
    if (res == FR_OK) {
        INIT_BUF(dj);
        dj.sclust = dj.fs->cdir;            /* Start to follow upper dir from current dir */
        if ((ccl = dj.sclust) != 0) {    /* Repeat while current dir is a sub-dir */
            res = dir_sdi(&dj, 1);            /* Get parent dir */
            if (res != FR_OK) goto FAILED;
            res = dir_read(&dj);
            if (res != FR_OK) goto FAILED;
            dj.sclust = LD_CLUST(dj.dir);    /* Goto parent dir */
            res = dir_sdi(&dj, 0);
            if (res != FR_OK) goto FAILED;
            do {                            /* Find the entry links to the child dir */
                res = dir_read(&dj);
                if (res != FR_OK) break;
                if (ccl == LD_CLUST(dj.dir)) break;    /* Found the entry */
                res = dir_next(&dj, 0);    
            } while (res == FR_OK);
            if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */
            if (res != FR_OK) goto FAILED;
#if _USE_LFN
            fno.lfname = path;
            fno.lfsize = sz_path;
#endif
            get_fileinfo(&dj, &fno);        /* Get the dir name and push it to the buffer */
            tp = fno.fname;
            if (_USE_LFN && *path) tp = path;

            for (n = 0; tp[n] && n < sz_path-1; n++) {
                path[n] = tp[n];
            }
            path[n] = '\0';
            if (tp[n] != '\0') res = FR_NOT_ENOUGH_CORE;
        } else {
            if ( sz_path >= 2 ) {
                path[0] = '/';
                path[1] = '\0';
            } else {
                if ( sz_path == 1 ) {
                    path[0] = '\0';
                }
            	res = FR_NOT_ENOUGH_CORE;
            }
        }
FAILED:
        FREE_BUF();
    }

    LEAVE_FF(dj.fs, res);

}
/* ff.h 430行目と431行目の間に挿入 */
FRESULT f_getcwdname (TCHAR*, UINT);