Annotation of nono/vm/windrv.cpp, revision 1.1.1.3

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2023 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // Windrv (相当)
                      9: //
                     10: 
                     11: // Windrv インスタンスは、設定 (Windrv の有無) によらず常に生成するが、
                     12: // メモリにマップするかどうかが変わる。
                     13: // Windrv 設定がない時にインスタンスごと作らない方式だと、設定を無効にすると
                     14: // 同時にログ識別子も無効になってコマンドラインの -L windrv オプションも
                     15: // エラーになってしまう。これは操作性がよくないので WindrvDevice の
                     16: // インスタンスは常に存在してほしい。一方、常にメモリマップ上に載せておくと
                     17: // Windrv を無効にしているにも関わらずメモリマップモニタで表示されるのが
                     18: // 気になることになるため。
                     19: 
                     20: #if !defined(TEST_WINDRV)
                     21: 
                     22: #include "windrv.h"
                     23: #include "config.h"
                     24: #include "hostwindrv.h"
1.1.1.2   root       25: #include "mainbus.h"
1.1       root       26: #include "mpu680x0.h"
                     27: #include <fcntl.h>
                     28: #include <sys/time.h>
                     29: #include <algorithm>
                     30: 
                     31: // コンストラクタ
                     32: WindrvDevice::WindrvDevice()
                     33:        : inherited(OBJ_WINDRV)
                     34: {
                     35:        for (int i = 0; i < hosts.size(); i++) {
                     36:                hosts[i].reset();
                     37:        }
                     38: }
                     39: 
                     40: // デストラクタ
                     41: WindrvDevice::~WindrvDevice()
                     42: {
                     43:        for (auto& host : hosts) {
                     44:                if ((bool)host) {
                     45:                        host.reset();
                     46:                }
                     47:        }
                     48: }
                     49: 
                     50: // 設定ファイルを読んで Windrv を組み込む場合は true を返す。
                     51: /*static*/ bool
                     52: WindrvDevice::IsWindrv()
                     53: {
                     54:        const ConfigItem& item = gConfig->Find("windrv-path");
                     55:        return (item.AsString().empty() == false);
                     56: }
                     57: 
                     58: bool
                     59: WindrvDevice::Create()
                     60: {
                     61:        if (IsWindrv()) {
                     62:                // 対応するホストドライバを作成。
                     63:                // 今はまだ1つのみ。
                     64:                hosts[0].reset(new HostWindrv(this));
                     65:                if ((bool)hosts[0] == false) {
                     66:                        return false;
                     67:                }
                     68:        }
                     69: 
                     70:        return true;
                     71: }
                     72: 
                     73: void
                     74: WindrvDevice::SetLogLevel(int loglevel_)
                     75: {
                     76:        inherited::SetLogLevel(loglevel_);
                     77: 
                     78:        for (auto& host : hosts) {
                     79:                if ((bool)host) {
                     80:                        host->SetLogLevel(loglevel_);
                     81:                }
                     82:        }
                     83: }
                     84: 
                     85: // 初期化
                     86: bool
                     87: WindrvDevice::Init()
                     88: {
                     89:        mainbus = GetMainbusDevice();
                     90:        mpu680x0 = GetMPU680x0Device(mpu);
                     91: 
                     92:        // 今は1つしかない。
                     93:        HostWindrv *host = hosts[0].get();
                     94:        if (host != NULL) {
                     95:                const ConfigItem& item = gConfig->Find("windrv-path");
                     96:                // パスが空ならここには来ないはず。
                     97:                assert(item.AsString().empty() == false);
                     98:                std::string path = gMainApp.NormalizePath(item.AsString());
1.1.1.2   root       99:                if (host->InitRootPath(path) == false) {
                    100:                        item.Err("Invalid root path");
                    101:                        return false;
                    102:                }
1.1       root      103:        }
                    104: 
                    105:        return true;
                    106: }
                    107: 
                    108: void
                    109: WindrvDevice::ResetHard(bool poweron)
                    110: {
                    111:        // FILES 管理バッファをクリア。
                    112:        for (auto& it : filesmap) {
                    113:                delete it.second;
                    114:        }
                    115:        filesmap.clear();
                    116: 
                    117:        // FCB バッファをクリア。
                    118:        for (auto& it : fcbmap) {
                    119:                delete it.second;
                    120:        }
                    121:        fcbmap.clear();
                    122: }
                    123: 
                    124: busdata
1.1.1.2   root      125: WindrvDevice::ReadPort(uint32 offset)
1.1       root      126: {
                    127:        busdata data;
                    128: 
1.1.1.2   root      129:        switch (offset) {
                    130:         case 0x1000:   // 識別ポート
1.1       root      131:                data = GetIdent();
                    132:                putlog(2, "Ident -> $%02x", data.Data());
                    133:                break;
                    134:         default:               // 他はバスエラー
                    135:                data.SetBusErr();
                    136:                break;
                    137:        }
1.1.1.2   root      138: 
                    139:        data |= BusData::Size1;
1.1       root      140:        return data;
                    141: }
                    142: 
                    143: busdata
1.1.1.2   root      144: WindrvDevice::WritePort(uint32 offset, uint32 data)
1.1       root      145: {
1.1.1.2   root      146:        busdata r;
                    147: 
                    148:        switch (offset) {
                    149:         case 0x1000:   // 動作ポート
1.1       root      150:                // 実行
                    151:                Execute();
1.1.1.2   root      152:                break;
1.1       root      153:         default:               // 他はバスエラー
1.1.1.2   root      154:                r.SetBusErr();
                    155:                break;
1.1       root      156:        }
1.1.1.2   root      157: 
                    158:        r |= BusData::Size1;
                    159:        return r;
1.1       root      160: }
                    161: 
                    162: busdata
1.1.1.2   root      163: WindrvDevice::PeekPort(uint32 offset)
1.1       root      164: {
1.1.1.2   root      165:        switch (offset) {
                    166:         case 0x1000:   // 識別ポート
1.1       root      167:                return GetIdent();
                    168:         default:               // 他はバスエラー
1.1.1.2   root      169:                return BusData::BusErr;
1.1       root      170:        }
                    171: }
                    172: 
1.1.1.2   root      173: bool
                    174: WindrvDevice::PokePort(uint32 offset, uint32 data)
                    175: {
                    176:        return false;
                    177: }
                    178: 
1.1       root      179: // モード識別ポートの読み出し
                    180: uint32
                    181: WindrvDevice::GetIdent() const
                    182: {
                    183:        return 'W';     // WINDRV 互換
                    184: }
                    185: 
                    186: // コマンド実行
                    187: void
                    188: WindrvDevice::Execute()
                    189: {
                    190:        uint32 error;
                    191: 
                    192:        // A5 レジスタ経由で受け取るらしい。
                    193:        a5 = mpu680x0->reg.A[5];
                    194: 
                    195:        // エラー情報をクリア。
                    196:        WriteMem16(a5 + 3, 0);
                    197: 
                    198:        // コマンド番号取得。
                    199:        command = ReadMem8(a5 + 2);
                    200: 
                    201:        cmdname = "Cmd";
                    202:        if (__predict_false(loglevel >= 2)) {
                    203:                cmdname += string_format(" $%02x", command);
                    204:        }
                    205: 
                    206:        if (command == 0x40) {
                    207:                // 初期化コマンドだけいろいろ挙動が違う。
                    208:                CmdInitialize();
                    209:                error = 0;
                    210:        } else {
                    211:                // コマンド実行。
                    212:                uint32 result = DispatchCommand();
                    213: 
                    214:                // 結果を整理。
                    215:                SetResult(result);
                    216: 
                    217:                // 戻り値は result ではなくエラー情報のようだ。
                    218:                error = ReadMem8(a5 + 3) | (ReadMem8(a5 + 4) << 8);
                    219:        }
                    220: 
                    221:        mpu680x0->reg.D[0] = error;
                    222: }
                    223: 
                    224: // コマンドに分岐。
                    225: uint32
                    226: WindrvDevice::DispatchCommand()
                    227: {
                    228:        uint32 result;
                    229: 
                    230:        // ユニット番号取得。
                    231:        int unit = ReadMem8(a5 + 1);
                    232: 
                    233:        // 初期化コマンド以外ならユニット番号をチェック。
                    234:        if (unit >= hosts.size()) {
                    235:                return -Human68k::ERR_INVALID_UNIT_IA;
                    236:        }
                    237:        HostWindrv *host = hosts[unit].get();
                    238:        if (host == NULL) {
                    239:                return -Human68k::ERR_INVALID_UNIT_IA;
                    240:        }
                    241: 
                    242:        // 最上位ビットはベリファイフラグのようだ。(無視する)
                    243:        switch (command & 0x7f) {
                    244:         case 0x41:     result = CmdCheckDir(host);             break;  // ディレクトリチェック
                    245:         case 0x42:     result = CmdMakeDir(host);              break;  // ディレクトリ作成
                    246:         case 0x43:     result = CmdRemoveDir(host);    break;  // ディレクトリ削除
                    247:         case 0x44:     result = CmdRename(host);               break;  // ファイル名変更
                    248:         case 0x45:     result = CmdDelete(host);               break;  // ファイル削除
                    249:         case 0x46:     result = CmdAttribute(host);    break;  // ファイル属性取得設定
                    250:         case 0x47:     result = CmdFiles(host);                break;  // ファイル検索(First)
                    251:         case 0x48:     result = CmdNFiles(host);               break;  // ファイル検索(Next)
                    252:         case 0x49:     result = CmdCreate(host);               break;  // ファイル作成
                    253:         case 0x4a:     result = CmdOpen(host);                 break;  // ファイルオープン
                    254:         case 0x4b:     result = CmdClose(host);                break;  // ファイルクローズ
                    255:         case 0x4c:     result = CmdRead(host);                 break;  // ファイル読み込み
                    256:         case 0x4d:     result = CmdWrite(host);                break;  // ファイル書き込み
                    257:         case 0x4e:     result = CmdSeek(host);                 break;  // ファイルシーク
                    258:         case 0x4f:     result = CmdFileTime(host);             break;  // ファイル更新時刻
                    259:         case 0x50:     result = CmdGetCapacity(host);  break;  // 容量取得
                    260:         case 0x51:     result = CmdCtrlDrive(host);    break;  // ドライブ制御/状態検査
                    261:         case 0x52:     result = CmdGetDPB(host);               break;  // DPB取得
                    262:         case 0x53:     result = CmdDiskRead(host);             break;  // セクタ読み込み
                    263:         case 0x54:     result = CmdDiskWrite(host);    break;  // セクタ書き込み
                    264:         case 0x55:     result = CmdIoControl(host);    break;  // IOCTRL
                    265:         case 0x56:     result = CmdFlush(host);                break;  // フラッシュ
                    266:         case 0x57:     result = CmdCheckMedia(host);   break;  // メディア交換チェック
                    267:         case 0x58:     result = CmdLock(host);                 break;  // 排他制御
                    268:         default:
                    269:                // 無効なコマンド
                    270:                putlog(1, "Cmd $%02x (INVALID)", command);
                    271:                result = -Human68k::ERR_INVALID_COMMAND_IA;
                    272:                break;
                    273:        }
                    274:        return result;
                    275: }
                    276: 
                    277: // $40 初期化
                    278: //
                    279: // IN
                    280: //   +0, 1.B: 定数 ($16)
                    281: //      +2, 1.B: コマンド ($40)
                    282: //     +18, 1.L: 引数が書いてあるアドレス
                    283: //     +22, 1.B: (先頭の) ドライブ番号 (A:=0、…)
                    284: // OUT
                    285: //      +3, 1.W: エラーコード(下位、上位の順)
                    286: //     +13, 1.B: ユニット数
                    287: //     +14, 1.L: デバイスドライバの終了アドレス + 1
                    288: uint32
                    289: WindrvDevice::CmdInitialize()
                    290: {
                    291:        if (__predict_false(loglevel >= 1)) {
                    292:                cmdname += " Initialize";
                    293:                putlog(2, "%s", cmdname.c_str());
                    294:        }
                    295: 
                    296:        // ベースドライブ名を取得。
                    297:        uint32 base = ReadMem8(a5 + 22);
                    298:        if (base >= 26) {
                    299:                uint32 result = Human68k::RES_INVALID_DRIVE;
                    300:                putlog(2, "%s => %s", cmdname.c_str(), ResultStr(result).c_str());
                    301:                return result;
                    302:        }
                    303: 
1.1.1.2   root      304:        uint drives = 0;
1.1       root      305:        for (auto& host : hosts) {
                    306:                if ((bool)host) {
                    307:                        uint32 result = host->Initialize();
                    308:                        if ((int32)result < 0) {
                    309:                                return result;
                    310:                        }
                    311:                        drives++;
                    312:                }
                    313:        }
                    314: 
                    315:        if (loglevel == 1) {
                    316:                putlogn("%s => %c:", cmdname.c_str(), 'A' + base);
                    317:        } else {
1.1.1.2   root      318:                putlog(2, "%s Base=%c: Drives=%u", cmdname.c_str(), 'A' + base, drives);
1.1       root      319:        }
                    320: 
                    321:        WriteMem8(a5 + 13, drives);
                    322:        return 0;
                    323: }
                    324: 
                    325: // $41 ディレクトリチェック
                    326: //
                    327: // IN
                    328: //   +0, 1.B: 定数 ($1a)
                    329: //   +1, 1.B: ユニット番号
                    330: //   +2, 1.B: コマンド ($41/$c1)
                    331: //     +14, 1.L: NAMESTS 構造体のアドレス
                    332: // OUT
                    333: //   +3, 1.W: エラーコード (下位、上位の順)
                    334: //  +18, 1.L: ステータスコード
                    335: //
                    336: // NAMESTS の drive:path に存在を確認したいディレクトリのパス。
                    337: uint32
                    338: WindrvDevice::CmdCheckDir(HostWindrv *host)
                    339: {
                    340:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    341: 
                    342:        if (__predict_false(loglevel >= 1)) {
                    343:                cmdname += string_format(" CheckDir %s", ns.PrintDrivePath().c_str());
                    344:                putlog(2, "%s", cmdname.c_str());
                    345:        }
                    346: 
                    347:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    348:        if ((bool)vdir == false) {
                    349:                return Human68k::RES_DIR_NOT_FOUND;
                    350:        }
                    351:        return 0;
                    352: }
                    353: 
                    354: // $42 ディレクトリ作成
                    355: //
                    356: // IN
                    357: //   +0, 1.B: 定数 ($1a)
                    358: //   +1, 1.B: ユニット番号
                    359: //   +2, 1.B: コマンド ($42/$c2)
                    360: //     +14, 1.L: NAMESTS 構造体のアドレス
                    361: // OUT
                    362: //   +3, 1.W: エラーコード (下位、上位の順)
                    363: //  +18, 1.L: ステータスコード
                    364: //
                    365: // NAMESTS の drive:path 配下の name に作成したいディレクトリ名。
                    366: // 同名のディレクトリがある場合はエラー。
                    367: uint32
                    368: WindrvDevice::CmdMakeDir(HostWindrv *host)
                    369: {
                    370:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    371: 
                    372:        if (__predict_false(loglevel >= 1)) {
                    373:                cmdname += string_format(" MakeDir %s '%s'",
                    374:                        ns.PrintDrivePath().c_str(), ns.GetName().c_str());
                    375:                putlog(2, "%s", cmdname.c_str());
                    376:        }
                    377: 
                    378:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    379:        if ((bool)vdir == false) {
                    380:                return Human68k::RES_DIR_NOT_FOUND;
                    381:        }
                    382: 
                    383:        const VDirent *ent = vdir->MatchName(ns.GetName(), false);
                    384:        if (ent) {
                    385:                return Human68k::RES_FILE_EXISTS;
                    386:        }
                    387:        uint32 result = host->MakeDir(vdir->GetPath() + ns.GetName());
                    388:        return result;
                    389: }
                    390: 
                    391: // $43 ディレクトリ削除
                    392: //
                    393: // IN
                    394: //   +0, 1.B: 定数 ($1a)
                    395: //   +1, 1.B: ユニット番号
                    396: //   +2, 1.B: コマンド ($43/$c3)
                    397: //     +14, 1.L: NAMESTS 構造体アドレス
                    398: // OUT
                    399: //   +3, 1.W: エラーコード (下位、上位の順)
                    400: //  +18, 1.L: ステータスコード
                    401: //
                    402: // NAMESTS の drive:path 配下の name に削除したいディレクトリ名。
                    403: // ディレクトリが空でない場合はエラー。
                    404: uint32
                    405: WindrvDevice::CmdRemoveDir(HostWindrv *host)
                    406: {
                    407:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    408: 
                    409:        if (__predict_false(loglevel >= 1)) {
                    410:                cmdname += string_format(" RemoveDir %s '%s'",
                    411:                        ns.PrintDrivePath().c_str(), ns.GetName().c_str());
                    412:                putlog(2, "%s", cmdname.c_str());
                    413:        }
                    414: 
                    415:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    416:        if ((bool)vdir == false) {
                    417:                return Human68k::RES_DIR_NOT_FOUND;
                    418:        }
                    419: 
                    420:        const VDirent *ent = vdir->MatchName(ns.GetName(), true);
                    421:        if (ent == NULL) {
                    422:                return Human68k::RES_DIR_NOT_FOUND;
                    423:        }
                    424:        // ディレクトリが空かどうかは RemoveDir() にお任せしてある。
                    425:        uint32 result = host->RemoveDir(vdir->GetPath() + ent->name);
                    426:        return result;
                    427: }
                    428: 
                    429: // $44 ファイル名変更
                    430: //
                    431: // IN
                    432: //   +0, 1.B: 定数 ($1a)
                    433: //   +1, 1.B: ユニット番号
                    434: //   +2, 1.B: コマンド ($44/$c4)
                    435: //     +14, 1.L: NAMESTS 構造体アドレス (旧ファイル名)
                    436: //     +18, 1.L: NAMESTS 構造体アドレス (新ファイル名)
                    437: // OUT
                    438: //   +3, 1.W: エラーコード (下位、上位の順)
                    439: //  +18, 1.L: ステータスコード
                    440: //
                    441: // o パスが違う場合はディレクトリを移動する (ドライブはどちらも同じはず)。
                    442: // o 新ファイル名がすでに存在する場合はエラー。
                    443: // o システムファイル、書き込み禁止ファイルはファイル名の変更はできない。
                    444: //   (システムファイルのディレクトリの移動を伴うファイル名の変更は可らしい)
                    445: // o ディレクトリ、ボリュームラベル、隠しファイル、書き込み禁止ファイルは
                    446: //   ディレクトリ間の移動はできない。
                    447: uint32
                    448: WindrvDevice::CmdRename(HostWindrv *host)
                    449: {
                    450:        NAMESTS oldns(this, ReadMemAddr(a5 + 14));
                    451:        NAMESTS newns(this, ReadMemAddr(a5 + 18));
                    452: 
                    453:        if (__predict_false(loglevel >= 1)) {
                    454:                cmdname += string_format(" Rename %s '%s' to %s '%s'",
                    455:                        oldns.PrintDrivePath().c_str(), oldns.GetName().c_str(),
                    456:                        newns.PrintDrivePath().c_str(), newns.GetName().c_str());
                    457:                putlog(2, "%s", cmdname.c_str());
                    458:        }
                    459: 
                    460:        // 移動元
                    461:        AutoVDir oldvdir(host, host->OpenVDir(oldns.GetPath()));
                    462:        if ((bool)oldvdir == false) {
                    463:                return Human68k::RES_DIR_NOT_FOUND;
                    464:        }
                    465:        const VDirent *oldent = oldvdir->MatchName(oldns.GetName(), true);
                    466:        if (oldent == NULL) {
                    467:                return Human68k::RES_FILE_NOT_FOUND;
                    468:        }
                    469: 
                    470:        // 移動先
                    471:        AutoVDir newvdir(host, host->OpenVDir(newns.GetPath()));
                    472:        if ((bool)newvdir == false) {
                    473:                return Human68k::RES_DIR_NOT_FOUND;
                    474:        }
                    475:        const VDirent *newent = newvdir->MatchName(newns.GetName(), false);
                    476:        if (newent) {
                    477:                return Human68k::RES_FILE_EXISTS;
                    478:        }
                    479: 
                    480:        // 移動元ファイルの属性。
                    481:        uint32 attr = host->GetAttribute(oldvdir->GetPath() + oldent->name);
                    482:        if ((int32)attr < 0) {
                    483:                return attr;
                    484:        }
                    485:        // 書き込み禁止ファイルなら何も出来ない。
                    486:        if ((attr & Human68k::ATTR_RDONLY)) {
                    487:                return Human68k::RES_NOT_A_FILE;
                    488:        }
                    489: 
                    490:        // ディレクトリなら、ディレクトリ間の移動は出来ない。
                    491:        if ((attr & Human68k::ATTR_DIR)) {
                    492:                if (oldvdir->GetPath() != newvdir->GetPath()) {
                    493:                        return Human68k::RES_NOT_A_FILE;
                    494:                }
                    495:        }
                    496: 
                    497:        // ボリューム、システムファイル、隠しファイルはまだない。
                    498: 
                    499:        uint32 result = host->Rename(
                    500:                oldvdir->GetPath() + oldent->name,
                    501:                newvdir->GetPath() + newns.GetName());
                    502:        return result;
                    503: }
                    504: 
                    505: // $45 ファイル削除
                    506: //
                    507: // IN
                    508: //   +0, 1.B: 定数 ($1a)
                    509: //   +1, 1.B: ユニット番号
                    510: //   +2, 1.B: コマンド ($45/$c5)
                    511: //     +14, 1.L: NAMESTS 構造体アドレス
                    512: // OUT
                    513: //   +3, 1.W: エラーコード (下位、上位の順)
                    514: //  +18, 1.L: ステータスコード
                    515: //
                    516: // ディレクトリ、ボリュームラベル、システムファイル、書き込み禁止ファイル
                    517: // ならエラー。
                    518: uint32
                    519: WindrvDevice::CmdDelete(HostWindrv *host)
                    520: {
                    521:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    522: 
                    523:        if (__predict_false(loglevel >= 1)) {
                    524:                cmdname += string_format(" Delete %s '%s'",
                    525:                        ns.PrintDrivePath().c_str(), ns.GetName().c_str());
                    526:                putlog(2, "%s", cmdname.c_str());
                    527:        }
                    528: 
                    529:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    530:        if ((bool)vdir == false) {
                    531:                return Human68k::RES_DIR_NOT_FOUND;
                    532:        }
                    533: 
                    534:        const VDirent *ent = vdir->MatchName(ns.GetName(), true);
                    535:        if (ent == NULL) {
                    536:                return Human68k::RES_FILE_NOT_FOUND;
                    537:        }
                    538:        uint32 result = host->Delete(vdir->GetPath() + ent->name);
                    539:        return result;
                    540: }
                    541: 
                    542: // $46 ファイル属性取得/設定
                    543: //
                    544: // IN
                    545: //   +0, 1.B: 定数 ($1a)
                    546: //   +1, 1.B: ユニット番号
                    547: //   +2, 1.B: コマンド ($46/$c6)
                    548: //     +13, 1.B: 設定する属性、0xff なら取得
                    549: //     +14, 1.L: NAMESTS 構造体アドレス
                    550: // OUT
                    551: //   +3, 1.W: エラーコード (下位、上位の順)
                    552: //  +18, 1.L: ステータスコード
                    553: uint32
                    554: WindrvDevice::CmdAttribute(HostWindrv *host)
                    555: {
                    556:        uint32 attr = ReadMem8(a5 + 13);
                    557:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    558:        if (__predict_false(loglevel >= 1)) {
                    559:                if (attr == 0xff) {
                    560:                        cmdname += string_format(" Attribute(Get) %s '%s'",
                    561:                                ns.PrintDrivePath().c_str(), ns.GetName().c_str());
                    562:                } else {
                    563:                        cmdname += string_format(" Attribute(Set) %s '%s' %s",
                    564:                                ns.PrintDrivePath().c_str(), ns.GetName().c_str(),
                    565:                                Human68k::AttrStr(attr).c_str());
                    566:                }
                    567:                putlog(2, "%s", cmdname.c_str());
                    568:        }
                    569: 
                    570:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    571:        if ((bool)vdir == false) {
                    572:                return Human68k::RES_DIR_NOT_FOUND;
                    573:        }
                    574: 
                    575:        const VDirent *ent = vdir->MatchName(ns.GetName(), true);
                    576:        if (ent == NULL) {
                    577:                return Human68k::RES_FILE_NOT_FOUND;
                    578:        }
                    579: 
                    580:        std::string fullname = vdir->GetPath() + ent->name;
                    581:        uint32 result;
                    582:        if (attr == 0xff) {
                    583:                // 取得
                    584:                result = host->GetAttribute(fullname);
                    585:                if ((int32)result >= 0) {
                    586:                        if (__predict_false(loglevel >= 2)) {
                    587:                                putlogn("result=$%02x(%s)", result,
                    588:                                        Human68k::AttrStr(result).c_str());
                    589:                        } else if (__predict_false(loglevel == 1)) {
                    590:                                putlogn("%s => %s", cmdname.c_str(),
                    591:                                        Human68k::AttrStr(result).c_str());
                    592:                        }
                    593:                        cmdname.clear();
                    594:                }
                    595:        } else {
                    596:                // 設定
                    597:                result = host->SetAttribute(fullname, attr);
                    598:        }
                    599:        return result;
                    600: }
                    601: 
                    602: // $47 ファイル検索(First)
                    603: //
                    604: // IN
                    605: //   +0, 1.B: 定数 ($1a)
                    606: //   +1, 1.B: ユニット番号
                    607: //   +2, 1.B: コマンド ($47/$c7)
                    608: //     +13, 1.B: 設定する属性、0xff なら取得
                    609: //     +14, 1.L: NAMESTS 構造体アドレス (検索対象)
                    610: //     +18, 1.L: FILES 構造体アドレス (検索バッファ)
                    611: // OUT
                    612: //      +3, 1.W: エラーコード (下位、上位の順)
                    613: //     +18, 1.L: ステータスコード
                    614: //
                    615: // NAMESTS の drive:path 配下から name (ワイルドカードあり) にマッチして
                    616: // 検索属性(+13.B) で立ててあるビットがどれか立っている(でいいのかな?)
                    617: // エントリを探して先頭の1つを FILES に返す。
                    618: // 見付からなければ RES_FILE_NOT_FOUND を返す。
                    619: uint32
                    620: WindrvDevice::CmdFiles(HostWindrv *host)
                    621: {
                    622:        uint8 attr = ReadMem8(a5 + 13);
                    623:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    624:        uint32 filesaddr = ReadMemAddr(a5 + 18);
                    625:        uint32 result;
                    626: 
                    627:        if (__predict_false(loglevel >= 1)) {
                    628:                cmdname += string_format(" Files %s '%s' (%s)",
                    629:                        ns.PrintDrivePath().c_str(), ns.GetName().c_str(),
                    630:                        Human68k::AttrStr(attr).c_str());
                    631:                putlog(2, "%s", cmdname.c_str());
                    632:        }
                    633: 
                    634:        // 同じ FILES バッファが見付かればクリア。ボリューム検索より先に行う。
                    635:        FilesBuf *fbuf = SearchFilesBuf(filesaddr);
                    636:        if (fbuf) {
                    637:                putlog(2, "Reuse FilesBuf at $%08x", filesaddr);
                    638:                fbuf->Init(filesaddr, host);
                    639:        }
                    640: 
                    641:        // ボリュームの検索はたびたび来るけどサポートしてないので先に弾く。
                    642:        // これは検索が成功した(マッチしたのが0だっただけ)扱いのログを出す。
                    643:        if (attr == Human68k::ATTR_VOLUME) {
                    644:                result = Human68k::RES_LAST_FILE;
                    645:                if (__predict_false(loglevel == 1)) {
                    646:                        putlogn("%s", cmdname.c_str());
                    647:                        putlogn("Cmd Files  => %s", ResultStr(result).c_str());
                    648:                        cmdname.clear();
                    649:                }
                    650:                return result;
                    651:        }
                    652: 
                    653:        if (fbuf == NULL) {
                    654:                fbuf = AllocFilesBuf(filesaddr, host);
                    655:                if (fbuf == NULL) {
                    656:                        return Human68k::RES_NO_MEMORY;
                    657:                }
                    658:        }
                    659: 
                    660:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    661:        if ((bool)vdir == false) {
                    662:                return Human68k::RES_DIR_NOT_FOUND;
                    663:        }
                    664: 
                    665:        // FilesBuf にマッチしたエントリ一覧を作成。
                    666:        fbuf->path = vdir->GetPath();
                    667:        for (const VDirent& ent : vdir->list) {
                    668:                if (__predict_false(ent.IsValid() == false)) {
                    669:                        continue;
                    670:                }
                    671: 
                    672:                // 属性が一致するか。
                    673:                // attr に立っているビットがエントリ側にも立っているか、かな。
                    674:                // ent のほうはディレクトリかどうかしか区別がない。
                    675:                if (ent.IsDir()) {
                    676:                        if ((attr & Human68k::ATTR_DIR) == 0) {
                    677:                                continue;
                    678:                        }
                    679:                } else {
                    680:                        if ((attr & Human68k::ATTR_ARCHIVE) == 0) {
                    681:                                continue;
                    682:                        }
                    683:                }
                    684: 
                    685:                // ルートディレクトリなら "." と ".." を除外。
                    686:                if (vdir->GetPath() == "/") {
                    687:                        if (ent.name == "." || ent.name == "..") {
                    688:                                continue;
                    689:                        }
                    690:                }
                    691: 
                    692:                // ファイル名が一致するか (ワイルドカードを含む)。
                    693:                if (MatchFilename(ent.name, ns) == false) {
                    694:                        continue;
                    695:                }
                    696: 
                    697:                fbuf->list.emplace_back(ent.name);
                    698:        }
                    699: 
                    700:        result = FilesCommon(fbuf, filesaddr);
                    701:        if (result == 0) {
                    702:                if (loglevel == 1) {
                    703:                        putlogn("%s", cmdname.c_str());
                    704:                        putlogn("Cmd Files  '%s'", fbuf->fname.c_str());
                    705:                        cmdname.clear();
                    706:                }
                    707:        }
                    708:        return result;
                    709: }
                    710: 
                    711: // $48 ファイル検索(NFiles)
                    712: //
                    713: // IN
                    714: //   +0, 1.B: 定数 ($1a)
                    715: //   +1, 1.B: ユニット番号
                    716: //   +2, 1.B: コマンド ($48/$c8)
                    717: //     +18, 1.L: FILES 構造体アドレス (検索バッファ)
                    718: // OUT
                    719: //      +3, 1.W: エラーコード (下位、上位の順)
                    720: //     +18, 1.L: ステータスコード
                    721: uint32
                    722: WindrvDevice::CmdNFiles(HostWindrv *host)
                    723: {
                    724:        if (__predict_false(loglevel >= 1)) {
                    725:                cmdname += " NFiles";
                    726:                putlog(2, "%s", cmdname.c_str());
                    727:        }
                    728: 
                    729:        uint32 filesaddr = ReadMemAddr(a5 + 18);
                    730:        FilesBuf *fbuf = SearchFilesBuf(filesaddr);
                    731:        if (fbuf == NULL) {
                    732:                return Human68k::RES_FILE_NOT_FOUND;
                    733:        }
                    734: 
                    735:        uint32 result = FilesCommon(fbuf, filesaddr);
                    736:        if (result == 0) {
                    737:                if (loglevel == 1) {
                    738:                        putlogn("%s '%s'", cmdname.c_str(), fbuf->fname.c_str());
                    739:                        cmdname.clear();
                    740:                }
                    741:        }
                    742:        return result;
                    743: }
                    744: 
                    745: // Files/NFiles の共通部分。
                    746: // FilesBuf から一つ取り出して VM メモリ filesaddr に書き出す。
                    747: uint32
                    748: WindrvDevice::FilesCommon(FilesBuf *fbuf, uint32 filesaddr)
                    749: {
                    750:        HostWindrv *host = fbuf->host;
                    751:        assert(host);
                    752: 
                    753:        // 取り出せても取り出せなくても参照時刻は更新。
                    754:        fbuf->UpdateATime();
                    755: 
                    756:        // 見付かった先頭の一つを返す。
                    757:        while (fbuf->list.empty() == false) {
                    758:                fbuf->fname = fbuf->list.front();
                    759:                fbuf->list.pop_front();
                    760: 
                    761:                Human68k::FILES files;
                    762:                if (host->GetFileStat(&files, fbuf->path + fbuf->fname) == false) {
                    763:                        continue;
                    764:                }
                    765: 
                    766:                putlog(2, "name: '%s'", fbuf->fname.c_str());
                    767:                files.name = fbuf->fname;
                    768:                files.sector = fbuf->key;
                    769:                files.offset = 0;
                    770:                files.WriteToMem(this, filesaddr);
                    771:                return 0;
                    772:        }
                    773: 
                    774:        return Human68k::RES_LAST_FILE;
                    775: }
                    776: 
                    777: // $49 ファイル作成
                    778: //
                    779: // IN
                    780: //   +0, 1.B: 定数 ($1a)
                    781: //   +1, 1.B: ユニット番号
                    782: //   +2, 1.B: コマンド ($49/$c9)
                    783: //  +13, 1.B: ファイル属性
                    784: //     +14, 1.L: NAMESTS 構造体アドレス
                    785: //  +18, 1.L: モード
                    786: //  +22, 1.L: FCB 構造体アドレス
                    787: // OUT
                    788: //   +3, 1.W: エラーコード (下位、上位の順)
                    789: //  +18, 1.L: ステータスコード
                    790: //
                    791: // 同名ファイルがすでに存在していた場合、モードが 0 ならエラーを返す。
                    792: // モードが 1 なら既存ファイルを削除してからファイルを作成する。
                    793: // ボリュームラベルには未対応。
                    794: uint32
                    795: WindrvDevice::CmdCreate(HostWindrv *host)
                    796: {
                    797:        uint32 result;
                    798: 
                    799:        uint8 attr = ReadMem8(a5 + 13);
                    800:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    801:        uint32 mode = ReadMem32(a5 + 18);
                    802:        uint32 fcbaddr = ReadMemAddr(a5 + 22);
                    803:        FCB fcb(this, fcbaddr, host);
                    804: 
                    805:        if (__predict_false(loglevel >= 1)) {
1.1.1.2   root      806:                cmdname += string_format(" Create $%06x %s '%s' (%s) mode=%u",
1.1       root      807:                        fcbaddr, ns.PrintDrivePath().c_str(), ns.GetName().c_str(),
                    808:                        Human68k::AttrStr(attr).c_str(), mode);
                    809:                putlog(2, "%s", cmdname.c_str());
                    810:        }
                    811: 
                    812:        // 同じ FCB が見付かれば先に閉じてしまうか。
                    813:        FCB *oldfcb = SearchFCB(fcbaddr);
                    814:        if (oldfcb) {
                    815:                FreeFCB(oldfcb);
                    816:        }
                    817: 
                    818:        // ボリュームラベルには未対応。
                    819:        if (attr == Human68k::ATTR_VOLUME) {
                    820:                return Human68k::RES_NOT_A_FILE;
                    821:        }
                    822: 
                    823:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    824:        if ((bool)vdir == false) {
                    825:                return Human68k::RES_DIR_NOT_FOUND;
                    826:        }
                    827: 
                    828:        // 同名のファイルが(1つ以上)存在していた場合。
                    829:        if (vdir->MatchName(ns.GetName(), false) != NULL) {
                    830:                if (mode == 0) {
                    831:                        // モード 0 ならエラーにする。
                    832:                        return Human68k::RES_FILE_EXISTS;
                    833:                } else {
                    834:                        // モード 1 なら削除して作成なので既存ファイルが1つでないと困る。
                    835:                        const VDirent *ent = vdir->MatchName(ns.GetName(), true);
                    836:                        if (ent == NULL) {
                    837:                                // 複数候補があると消そうにも消せない…。
                    838:                                return Human68k::RES_FILE_EXISTS;
                    839:                        } else {
                    840:                                // 既存ファイルは1つなので削除する。
                    841:                                result = host->Delete(vdir->GetPath() + ent->name);
                    842:                                if ((int32)result < 0) {
                    843:                                        return result;
                    844:                                }
                    845:                        }
                    846:                }
                    847:        }
                    848: 
                    849:        const std::string fullname = vdir->GetPath() + ns.GetName();
                    850:        result = host->CreateFile(&fcb, fullname, attr);
                    851:        if ((int32)result < 0) {
                    852:                return result;
                    853:        }
                    854: 
                    855:        // ここで内部に登録。
                    856:        // ディスクリプタもコピーされるがただの整数なので問題ない。ほんとだろうか。
                    857:        return AddFCB(fcb);
                    858: }
                    859: 
                    860: // $4a ファイルオープン
                    861: //
                    862: // IN
                    863: //   +0, 1.B: 定数 ($1a)
                    864: //   +1, 1.B: ユニット番号
                    865: //   +2, 1.B: コマンド ($4a/$ca)
                    866: //     +14, 1.L: NAMESTS 構造体アドレス
                    867: //  +22, 1.L: FCB 構造体アドレス
                    868: // OUT
                    869: //   +3, 1.W: エラーコード (下位、上位の順)
                    870: //  +18, 1.L: ステータスコード
                    871: //
                    872: // o 成功すれば、FCB のファイル名、更新日時、ファイルサイズを更新する。
                    873: // o ディレクトリ、ボリュームラベルはオープンできない。
                    874: // o システムファイル、書き込み禁止ファイルは読み込みモード以外ではオープン
                    875: //   できない。
                    876: uint32
                    877: WindrvDevice::CmdOpen(HostWindrv *host)
                    878: {
                    879:        NAMESTS ns(this, ReadMemAddr(a5 + 14));
                    880:        uint32 fcbaddr = ReadMemAddr(a5 + 22);
                    881:        FCB fcb(this, fcbaddr, host);
                    882:        uint8 mode = fcb.GetMode();
                    883: 
                    884:        if (__predict_false(loglevel >= 1)) {
                    885:                cmdname += string_format(" Open $%06x %s '%s' %s",
                    886:                        fcbaddr, ns.PrintDrivePath().c_str(), ns.GetName().c_str(),
                    887:                        Human68k::OpenModeStr(mode).c_str());
                    888:                putlog(2, "%s", cmdname.c_str());
                    889:        }
                    890: 
                    891:        // 同じ FCB が見付かれば先に閉じてしまうか。
                    892:        FCB *oldfcb = SearchFCB(fcbaddr);
                    893:        if (oldfcb) {
                    894:                FreeFCB(oldfcb);
                    895:        }
                    896: 
                    897:        AutoVDir vdir(host, host->OpenVDir(ns.GetPath()));
                    898:        if ((bool)vdir == false) {
                    899:                return Human68k::RES_DIR_NOT_FOUND;
                    900:        }
                    901: 
                    902:        const VDirent *ent = vdir->MatchName(ns.GetName(), true);
                    903:        if (ent == NULL) {
                    904:                return Human68k::RES_FILE_NOT_FOUND;
                    905:        }
                    906: 
                    907:        // エントリがディレクトリかどうかはこの時点で分かる。
                    908:        // ボリュームラベルは現状存在しない。
                    909:        if (ent->IsDir()) {
                    910:                return Human68k::RES_NOT_A_FILE;
                    911:        }
                    912: 
                    913:        const std::string fullname = vdir->GetPath() + ent->name;
                    914:        if (mode != Human68k::OPEN_RDONLY) {
                    915:                // 書き込みを伴うなら、ファイルの属性を確認。
                    916:                uint32 attr = host->GetAttribute(fullname);
                    917:                if ((int32)attr < 0) {
                    918:                        return Human68k::RES_NOT_A_FILE;
                    919:                }
                    920: 
                    921:                if ((attr & Human68k::ATTR_RDONLY)) {
                    922:                        return Human68k::RES_CANNOT_WRITE;
                    923:                }
                    924:        }
                    925: 
                    926:        uint32 result = host->Open(&fcb, fullname);
                    927:        if ((int32)result < 0) {
                    928:                return result;
                    929:        }
                    930: 
                    931:        // タイムスタンプとサイズは Open() がセットしている。
                    932:        // 名前はこっちでセットする。
                    933:        fcb.SetName(ns.GetName1(), ns.GetName2(), ns.GetExt());
                    934: 
                    935:        // ここで内部に登録。
                    936:        // ディスクリプタもコピーされるがただの整数なので問題ない。ほんとだろうか。
                    937:        return AddFCB(fcb);
                    938: }
                    939: 
                    940: // $4b ファイルクローズ
                    941: //
                    942: // IN
                    943: //   +0, 1.B: 定数 ($1a)
                    944: //   +1, 1.B: ユニット番号
                    945: //   +2, 1.B: コマンド ($4b/$cb)
                    946: //  +22, 1.L: FCB 構造体アドレス
                    947: // OUT
                    948: //   +3, 1.W: エラーコード (下位、上位の順)
                    949: //  +18, 1.L: ステータスコード
                    950: uint32
                    951: WindrvDevice::CmdClose(HostWindrv *host)
                    952: {
                    953:        uint32 fcbaddr = ReadMemAddr(a5 + 22);
                    954: 
                    955:        if (__predict_false(loglevel >= 1)) {
                    956:                cmdname += string_format(" Close $%06x", fcbaddr);
                    957:                putlog(2, "%s", cmdname.c_str());
                    958:        }
                    959: 
                    960:        FCB *fcb = SearchFCB(fcbaddr);
                    961:        if (fcb == NULL) {
                    962:                return Human68k::RES_INVALID_MEM; // ?
                    963:        }
                    964: 
                    965:        FreeFCB(fcb);
                    966:        return 0;
                    967: }
                    968: 
                    969: // $4c ファイル読み込み
                    970: //
                    971: // IN
                    972: //   +0, 1.B: 定数 ($1a)
                    973: //   +1, 1.B: ユニット番号
                    974: //   +2, 1.B: コマンド ($4c/$cc)
                    975: //     +14, 1.L: 読み込み先アドレス
                    976: //  +18, 1.L: 読み込みバイト数
                    977: //  +22, 1.L: FCB 構造体アドレス
                    978: // OUT
                    979: //   +3, 1.W: エラーコード (下位、上位の順)
                    980: //  +18, 1.L: ステータスコード
                    981: //
                    982: // 読み込みバイト数が負数ならファイルサイズを指定したものとする。
                    983: // ステータスコードに読み込んだバイト数。
                    984: uint32
                    985: WindrvDevice::CmdRead(HostWindrv *host)
                    986: {
                    987:        uint32 dstaddr = ReadMemAddr(a5 + 14);
                    988:        uint32 reqlen = ReadMem32(a5 + 18);
                    989:        uint32 fcbaddr = ReadMemAddr(a5 + 22);
                    990: 
                    991:        if (__predict_false(loglevel >= 1)) {
                    992:                cmdname += string_format(" Read $%06x len=$%x", fcbaddr, reqlen);
                    993:                putlog(2, "%s", cmdname.c_str());
                    994:        }
                    995: 
                    996:        FCB *fcb = SearchFCB(fcbaddr);
                    997:        if (fcb == NULL) {
                    998:                return Human68k::RES_INVALID_MEM; // ?
                    999:        }
                   1000: 
                   1001:        // 負数ならファイルサイズとするらしい。
                   1002:        if ((int32)reqlen < 0) {
                   1003:                reqlen = fcb->GetSize();
                   1004:        }
                   1005: 
                   1006:        std::array<uint8, 65536> buf;
                   1007:        uint32 totallen = 0;
                   1008:        for (;;) {
                   1009:                uint32 remain = reqlen - totallen;
                   1010:                if (remain == 0) {
                   1011:                        break;
                   1012:                }
                   1013:                int len = std::min(remain, (uint32)buf.size());
                   1014:                int n = host->Read(fcb, buf.data(), len);
                   1015:                if (n < 0) {
                   1016:                        return Human68k::RES_INVALID_MEM; // ?
                   1017:                }
                   1018:                if (n == 0) {
                   1019:                        break;
                   1020:                }
                   1021:                WriteMem(dstaddr, buf.data(), n);
                   1022:                dstaddr +=n;
                   1023:                totallen += n;
                   1024:        }
                   1025: 
                   1026:        fcb->AddPos(totallen);
                   1027: 
                   1028:        return totallen;
                   1029: }
                   1030: 
                   1031: // $4d ファイル書き込み
                   1032: //
                   1033: // IN
                   1034: //   +0, 1.B: 定数 ($1a)
                   1035: //   +1, 1.B: ユニット番号
                   1036: //   +2, 1.B: コマンド ($4d/$cd)
                   1037: //     +14, 1.L: 書き込み元アドレス
                   1038: //  +18, 1.L: 書き込みバイト数
                   1039: //  +22, 1.L: FCB 構造体アドレス
                   1040: // OUT
                   1041: //   +3, 1.W: エラーコード (下位、上位の順)
                   1042: //  +18, 1.L: ステータスコード
                   1043: //
                   1044: // 書き込みバイト数が負数ならファイルサイズを指定したものとする。
                   1045: // ステータスコードに読み込んだバイト数。
                   1046: uint32
                   1047: WindrvDevice::CmdWrite(HostWindrv *host)
                   1048: {
                   1049:        uint32 srcaddr = ReadMemAddr(a5 + 14);
                   1050:        uint32 reqlen = ReadMem32(a5 + 18);
                   1051:        uint32 fcbaddr = ReadMemAddr(a5 + 22);
                   1052: 
                   1053:        if (__predict_false(loglevel >= 1)) {
                   1054:                cmdname += string_format(" Write $%06x len=$%x", fcbaddr, reqlen);
                   1055:                putlog(2, "%s", cmdname.c_str());
                   1056:        }
                   1057: 
                   1058:        FCB *fcb = SearchFCB(fcbaddr);
                   1059:        if (fcb == NULL) {
                   1060:                return Human68k::RES_INVALID_MEM; // ?
                   1061:        }
                   1062: 
                   1063:        // 負数ならファイルサイズとするらしい。
                   1064:        if ((int32)reqlen < 0) {
                   1065:                reqlen = fcb->GetSize();
                   1066:        }
                   1067: 
                   1068:        std::array<uint8, 65536> buf;
                   1069:        uint32 totallen = 0;
                   1070:        for (;;) {
                   1071:                uint32 remain = reqlen - totallen;
                   1072:                if (remain == 0) {
                   1073:                        break;
                   1074:                }
                   1075:                int len = std::min(remain, (uint32)buf.size());
                   1076:                ReadMem(buf.data(), srcaddr, len);
                   1077:                int n = host->Write(fcb, buf.data(), len);
                   1078:                if (n < 0) {
                   1079:                        return Human68k::RES_INVALID_MEM; // ?
                   1080:                }
                   1081:                if (n == 0) {
                   1082:                        break;
                   1083:                }
                   1084:                srcaddr += n;
                   1085:                totallen += n;
                   1086:        }
                   1087: 
                   1088:        fcb->AddPos(totallen);
                   1089: 
                   1090:        return totallen;
                   1091: }
                   1092: 
                   1093: // $4e ファイルシーク
                   1094: //
                   1095: // IN
                   1096: //   +0, 1.B: 定数 ($1a)
                   1097: //   +1, 1.B: ユニット番号
                   1098: //   +2, 1.B: コマンド ($4e/$ce)
                   1099: //  +13, 1.B: whence (0:先頭から、1:現在位置から、2:末尾から)
                   1100: //  +18, 1.L: オフセット
                   1101: //  +22, 1.L: FCB 構造体アドレス
                   1102: // OUT
                   1103: //   +3, 1.W: エラーコード (下位、上位の順)
                   1104: //  +18, 1.L: ステータスコード
                   1105: uint32
                   1106: WindrvDevice::CmdSeek(HostWindrv *host)
                   1107: {
                   1108:        uint8 mode = ReadMem8(a5 + 13);
                   1109:        int32 offset = ReadMem32(a5 + 18);
                   1110:        uint32 fcbaddr = ReadMemAddr(a5 + 22);
                   1111: 
                   1112:        if (__predict_false(loglevel >= 1)) {
1.1.1.2   root     1113:                cmdname += string_format(" Seek $%06x ($%x, %u)",
1.1       root     1114:                        fcbaddr, offset, mode);
                   1115:                putlog(2, "%s", cmdname.c_str());
                   1116:        }
                   1117: 
                   1118:        FCB *fcb = SearchFCB(fcbaddr);
                   1119:        if (fcb == NULL) {
                   1120:                return Human68k::RES_INVALID_MEM; // ?
                   1121:        }
                   1122: 
                   1123:        // 全世界的に同じ値だと思うけど…。
                   1124:        int whence;
                   1125:        switch (mode) {
                   1126:         case 0:        whence = SEEK_SET;      break;
                   1127:         case 1:        whence = SEEK_CUR;      break;
                   1128:         case 2:        whence = SEEK_END;      break;
                   1129:         default:
                   1130:                return Human68k::RES_CANNOT_SEEK;
                   1131:        }
                   1132: 
                   1133:        uint32 result = host->Seek(fcb, offset, whence);
                   1134:        if ((int32)result < 0) {
                   1135:                return result;
                   1136:        }
                   1137: 
                   1138:        fcb->SetPos(result);
                   1139:        return result;
                   1140: }
                   1141: 
                   1142: // $4f ファイル更新時刻の取得/設定
                   1143: //
                   1144: // IN
                   1145: //   +0, 1.B: 定数 ($1a)
                   1146: //   +1, 1.B: ユニット番号
                   1147: //   +2, 1.B: コマンド ($4f/$cf)
                   1148: //  +18, 1.L: 日付時刻 (0 なら取得)
                   1149: //  +22, 1.L: FCB 構造体アドレス
                   1150: // OUT
                   1151: //   +3, 1.W: エラーコード (下位、上位の順)
                   1152: //  +18, 1.L: ステータスコード
                   1153: //
                   1154: // 取得が成功すればステータスコードに日付時刻。
                   1155: uint32
                   1156: WindrvDevice::CmdFileTime(HostWindrv *host)
                   1157: {
                   1158:        uint32 datetime = ReadMem32(a5 + 18);
                   1159:        uint32 fcbaddr = ReadMemAddr(a5 + 22);
                   1160: 
                   1161:        if (__predict_false(loglevel >= 1)) {
                   1162:                if (datetime == 0) {
                   1163:                        cmdname += string_format(" FileTime(Get) $%06x", fcbaddr);
                   1164:                } else {
                   1165:                        cmdname += string_format(" FileTime(Set) $%06x ($%08x)", fcbaddr,
                   1166:                                datetime);
                   1167:                }
                   1168:                putlog(2, "%s", cmdname.c_str());
                   1169:        }
                   1170: 
                   1171:        FCB *fcb = SearchFCB(fcbaddr);
                   1172:        if (fcb == NULL) {
                   1173:                return Human68k::RES_INVALID_MEM; // ?
                   1174:        }
                   1175: 
                   1176:        uint32 result;
                   1177:        if (datetime == 0) {
                   1178:                result = host->GetFileTime(fcb);
                   1179:        } else {
                   1180:                result = host->SetFileTime(fcb, datetime);
                   1181:        }
                   1182:        return result;
                   1183: }
                   1184: 
                   1185: // $50 GetCapacity
                   1186: //
                   1187: // IN
                   1188: //   +0, 1.B: 定数 ($1a)
                   1189: //   +1, 1.B: ユニット番号
                   1190: //   +2, 1.B: コマンド ($50/$d0)
                   1191: //  +14, 1.L: capacity 構造体アドレス
                   1192: // OUT
                   1193: //   +3, 1.W: エラーコード (下位、上位の順)
                   1194: //  +18, 1.L: ステータスコード
                   1195: uint32
                   1196: WindrvDevice::CmdGetCapacity(HostWindrv *host)
                   1197: {
                   1198:        if (__predict_false(loglevel >= 1)) {
                   1199:                cmdname += " GetCapacity";
                   1200:                putlog(2, "%s", cmdname.c_str());
                   1201:        }
                   1202: 
                   1203:        uint32 capaddr = ReadMemAddr(a5 + 14);
                   1204: 
                   1205:        Human68k::capacity cap;
                   1206:        uint32 result = host->GetCapacity(&cap);
                   1207:        if ((int32)result < 0) {
                   1208:                return result;
                   1209:        }
                   1210:        uint32 availbytes = cap.avail_clusters *
                   1211:                cap.sectors_per_cluster * cap.bytes_per_sector;
                   1212: 
                   1213:        cap.WriteToMem(this, capaddr);
                   1214: 
                   1215:        return availbytes;
                   1216: }
                   1217: 
                   1218: // $51 ドライブ制御/状態検査
                   1219: //
                   1220: // IN
                   1221: //   +0, 1.B: 定数 ($1a)
                   1222: //   +1, 1.B: ユニット番号
                   1223: //   +2, 1.B: コマンド ($51/$d1)
                   1224: //  +13, 1.B: 内部コマンド
                   1225: //  +14, 1.L: 引数列のアドレス
                   1226: // OUT
                   1227: //   +3, 1.W: エラーコード (下位、上位の順)
                   1228: //  +13, 1.B: ドライブの状態
                   1229: //  +18, 1.L: ステータスコード
                   1230: //
                   1231: // 内部コマンドは以下らしい。IOCS B_DRVCHK 参照。
                   1232: //  0: 状態検査1
                   1233: //  1: 排出
                   1234: //  2: 排出禁止
                   1235: //  3: 排出許可
                   1236: //  4: メディア未挿入時に LED 点滅
                   1237: //  5: メディア未挿入時に LED 消灯
                   1238: //  6: 排出禁止2 (OS 用)
                   1239: //  7: 排出許可2 (OS 用)
                   1240: //  8: -
                   1241: //  9: 状態検査2
                   1242: //
                   1243: // 応答のドライブの状態は以下のビットマップらしい。
                   1244: //  0x80: LED 点灯
                   1245: //  0x40: 排出禁止
                   1246: //  0x20: 排出禁止2
                   1247: //  0x10: 排出禁止1
                   1248: //  0x08: 書き込み禁止
                   1249: //  0x04: ドライブが準備出来ていない
                   1250: //  0x02: メディア挿入
                   1251: //  0x01: メディア誤挿入
                   1252: uint32
                   1253: WindrvDevice::CmdCtrlDrive(HostWindrv *host)
                   1254: {
                   1255:        uint8 ctrl = ReadMem8(a5 + 13);
                   1256: 
                   1257:        uint8 res;
                   1258:        switch (ctrl) {
                   1259:         case 0:        // 状態検査1
                   1260:                if (__predict_false(loglevel >= 1)) {
1.1.1.2   root     1261:                        cmdname += string_format(" CtrlDrive(%u)", ctrl);
1.1       root     1262:                        putlog(2, "%s", cmdname.c_str());
                   1263:                }
                   1264:                res = 0x02;     // メディア挿入
                   1265:                break;
                   1266: 
                   1267:         default:
                   1268:                if (__predict_false(loglevel >= 1)) {
1.1.1.2   root     1269:                        cmdname += string_format(" CtrlDrive(%u) (NOT IMPLEMENTED)", ctrl);
1.1       root     1270:                        putlog(2, "%s", cmdname.c_str());
                   1271:                }
                   1272:                return -Human68k::ERR_INVALID_COMMAND_IA;
                   1273:        }
                   1274:        WriteMem8(a5 + 13, res);
                   1275:        return 0;
                   1276: }
                   1277: 
                   1278: // $52 DPB 取得
                   1279: //
                   1280: // IN
                   1281: //   +0, 1.B: 定数 ($1a)
                   1282: //   +1, 1.B: ユニット番号
                   1283: //   +2, 1.B: コマンド ($52/$d2)
                   1284: //  +14, 1.L: DPB 構造体アドレス (実際には+2 を指している)
                   1285: // OUT
                   1286: //   +3, 1.W: エラーコード (下位、上位の順)
                   1287: //  +18, 1.L: ステータスコード
                   1288: uint32
                   1289: WindrvDevice::CmdGetDPB(HostWindrv *host)
                   1290: {
                   1291:        if (__predict_false(loglevel >= 1)) {
                   1292:                cmdname += " GetDPB";
                   1293:                putlog(2, "%s", cmdname.c_str());
                   1294:        }
                   1295: 
                   1296:        uint32 dpbaddr = ReadMemAddr(a5 + 14);
                   1297: 
                   1298:        Human68k::capacity cap;
                   1299:        uint32 result = host->GetCapacity(&cap);
                   1300:        if ((int32)result < 0) {
                   1301:                return result;
                   1302:        }
                   1303: 
                   1304:        uint shift = 31 - __builtin_clz(cap.sectors_per_cluster);
                   1305: 
                   1306:        // クラスタ 0: -
                   1307:        // クラスタ 1: FAT
                   1308:        // クラスタ 2: ルートディレクトリ
                   1309:        // クラスタ 3: データ領域
                   1310:        uint32 fat_sect  = cap.sectors_per_cluster * 1;
                   1311:        uint32 root_sect = cap.sectors_per_cluster * 2;
                   1312:        uint32 data_sect = cap.sectors_per_cluster * 3;
                   1313: 
                   1314:        Human68k::DPB dpb;
                   1315:        memset(&dpb, 0, sizeof(dpb));
                   1316:        dpb.sector_size = cap.bytes_per_sector;
                   1317:        dpb.cluster_size = cap.sectors_per_cluster - 1;
                   1318:        dpb.shift = shift;
                   1319:        dpb.fat_sector = fat_sect;
                   1320:        dpb.fat_max = 1;
                   1321:        dpb.fat_size = cap.sectors_per_cluster;
                   1322:        dpb.file_max = (cap.sectors_per_cluster * cap.bytes_per_sector / 32);
                   1323:        dpb.cluster_max = cap.total_clusters;
                   1324:        dpb.root_sector = root_sect;
                   1325:        dpb.data_sector = data_sect;
                   1326:        dpb.media = 0xf3;
                   1327:        putmsg(2, "sector_size=$%x, cluster_size=$%x",
                   1328:                dpb.sector_size, dpb.cluster_size);
1.1.1.2   root     1329:        putmsg(2, "shift=%u, fat_sector=$%x fat_size=$%x",
1.1       root     1330:                dpb.shift, dpb.fat_sector, dpb.fat_size);
                   1331:        putmsg(2, "file_max=$%x cluster_max=$%x",
                   1332:                dpb.file_max, dpb.cluster_max);
1.1.1.2   root     1333:        putmsg(2, "root_sector=%u data_sector=%u",
1.1       root     1334:                dpb.root_sector, dpb.data_sector);
                   1335: 
                   1336:        // DPB を書き戻す。
                   1337:        // ここに渡されるアドレスは DPB+2 を指している。
                   1338:        dpb.WriteToMem(this, dpbaddr - 2);
                   1339: 
                   1340:        return result;
                   1341: }
                   1342: 
                   1343: uint32
                   1344: WindrvDevice::CmdDiskRead(HostWindrv *host)
                   1345: {
                   1346:        cmdname += " DiskRead (NOT IMPLEMENTED)";
                   1347:        putlog(0, "%s", cmdname.c_str());
                   1348:        return -Human68k::ERR_INVALID_COMMAND_IA;
                   1349: }
                   1350: 
                   1351: uint32
                   1352: WindrvDevice::CmdDiskWrite(HostWindrv *host)
                   1353: {
                   1354:        cmdname += " DiskWrite (NOT IMPLEMENTED)";
                   1355:        putlog(0, "%s", cmdname.c_str());
                   1356:        return -Human68k::ERR_INVALID_COMMAND_IA;
                   1357: }
                   1358: 
                   1359: uint32
                   1360: WindrvDevice::CmdIoControl(HostWindrv *host)
                   1361: {
                   1362:        cmdname += " IoControl (NOT IMPLEMENTED)";
                   1363:        putlog(0, "%s", cmdname.c_str());
                   1364:        return -Human68k::ERR_INVALID_COMMAND_IA;
                   1365: }
                   1366: 
                   1367: // $56 フラッシュ
                   1368: //
                   1369: // IN
                   1370: //   +0, 1.B: 定数 ($1a)
                   1371: //   +1, 1.B: ユニット番号
                   1372: //   +2, 1.B: コマンド ($56/$d6)
                   1373: // OUT
                   1374: //   +3, 1.W: エラーコード (下位、上位の順)
                   1375: //  +18, 1.L: ステータスコード
                   1376: uint32
                   1377: WindrvDevice::CmdFlush(HostWindrv *host)
                   1378: {
                   1379:        if (__predict_false(loglevel >= 1)) {
                   1380:                cmdname += " Flush";
                   1381:                putlog(2, "%s", cmdname.c_str());
                   1382:        }
                   1383: 
                   1384:        uint32 result = host->Flush();
                   1385:        return result;
                   1386: }
                   1387: 
                   1388: // $57 メディア交換チェック
                   1389: //
                   1390: // IN
                   1391: //   +0, 1.B: 定数 ($1a)
                   1392: //   +1, 1.B: ユニット番号
                   1393: //   +2, 1.B: コマンド ($57/$d7)
                   1394: // OUT
                   1395: //   +3, 1.W: エラーコード (下位、上位の順)
                   1396: //  +18, 1.L: ステータスコード
                   1397: uint32
                   1398: WindrvDevice::CmdCheckMedia(HostWindrv *host)
                   1399: {
                   1400:        // 頻繁に呼ばれるのでレベル上げておく。
                   1401:        if (__predict_false(loglevel >= 1)) {
                   1402:                cmdname += " CheckMedia";
                   1403:                putlog(3, "%s", cmdname.c_str());
                   1404:                cmdname.clear();
                   1405:        }
                   1406: 
                   1407:        // メディアが有効なら 1 を返すようだ。
                   1408:        // 現状リムーバブルメディアには対応していないので常に 1 を返す。
                   1409:        return 1;
                   1410: }
                   1411: 
                   1412: uint32
                   1413: WindrvDevice::CmdLock(HostWindrv *host)
                   1414: {
                   1415:        cmdname += " Lock (NOT IMPLEMENTED)";
                   1416:        putlog(0, "%s", cmdname.c_str());
                   1417:        return -Human68k::ERR_INVALID_COMMAND_IA;
                   1418: }
                   1419: 
                   1420: // 結果コードを処理して VM メモリに書き出す。
                   1421: //
                   1422: // デバイスドライバの各コマンドからの応答フォーマットには
                   1423: // +3.W (エラーコード) と +18.L (ステータスコード) があり、
                   1424: // 以下のように応答させるようだ。
                   1425: //
                   1426: // o 白帯の出るエラーの場合、
                   1427: //   +3.W のほうにエラーコード(ERR_*)、+18.L のほうは -1(?)。
                   1428: // o (白帯でない)エラーの場合、
                   1429: //   +3.W のほうは 0、+18.L のほうにステータスコード。
                   1430: // o 正常系の場合、
                   1431: //   +3.W のほうは 0、+18.L に 0 か正の値?
                   1432: // XXX FileTime (や Seek) のように 32bit 全域が有効な戻り値の場合
                   1433: // どういう扱いになってるかまでは調べてない。
                   1434: //
                   1435: // コマンドからの戻り値を
                   1436: // o 白帯なら -ERR_*。これには IGNORE/RETRY/ABORT のいずれかが立っているはず
                   1437: //   なので、必ず -0x1000 より絶対値が大きい値になる。
                   1438: // o 白帯でないエラーなら RES_*。
                   1439: // o 正常なら 0 以上。
                   1440: // とすることで SetResult() が +3.W と +18.L によしなに書き出す。
                   1441: void
                   1442: WindrvDevice::SetResult(uint32 result)
                   1443: {
                   1444:        // ログ表示。
                   1445:        if (__predict_false(loglevel >= 1)) {
                   1446:                // cmdname が空なら出力済み。
                   1447:                if (cmdname.empty() == false) {
                   1448:                        if (loglevel == 1) {
                   1449:                                // ここでまとめて表示 (長い、1行で)。
                   1450:                                putlogn("%s => %s", cmdname.c_str(), ResultStr(result).c_str());
                   1451:                        } else {
                   1452:                                // level 2 ならエラー時のみ表示
                   1453:                                // level 3 なら正常時も表示
                   1454:                                int thresh = result != 0 ? 2 : 3;
                   1455:                                putlog(thresh, "result=%s", ResultStr(result).c_str());
                   1456:                        }
                   1457:                }
                   1458:        }
                   1459: 
                   1460:        // 結果を格納。
                   1461:        if ((int32)result <= -0x1000) {
                   1462:                WriteMem8(a5 + 3, result & 0xff);
                   1463:                WriteMem8(a5 + 4, (result >> 8) & 0xff);
                   1464:                // ?
                   1465:                if ((result & Human68k::ERR_RETRY) == 0) {
                   1466:                        WriteMem32(a5 + 18, result);
                   1467:                }
                   1468:        } else {
                   1469:                WriteMem32(a5 + 18, result);
                   1470:        }
                   1471: }
                   1472: 
                   1473: // result を表示用に整形して返す。
                   1474: /*static*/ std::string
                   1475: WindrvDevice::ResultStr(uint32 result)
                   1476: {
                   1477:        if (__predict_true((int32)result >= 0)) {
                   1478:                // 正常
                   1479:                return string_format("$%x", result);
                   1480:        }
                   1481: 
                   1482:        const char *msg = Human68k::GetResultMsg(result);
                   1483:        if (__predict_true((int32)result > -0x1000)) {
                   1484:                // エラー応答
                   1485:                if (__predict_true(msg)) {
                   1486:                        return string_format("%d(%s)", (int32)result, msg);
                   1487:                } else {
                   1488:                        return string_format("%d", (int32)result);
                   1489:                }
                   1490:        } else {
                   1491:                // 白帯
                   1492:                if (__predict_true(msg)) {
                   1493:                        return string_format("-$%04x(%s)", -(int32)result, msg);
                   1494:                } else {
                   1495:                        return string_format("-$%04x", -(int32)result);
                   1496:                }
                   1497:        }
                   1498: }
                   1499: 
                   1500: // VM メモリから1バイト読み込む。
                   1501: uint32
                   1502: WindrvDevice::ReadMem8(uint32 addr) const
                   1503: {
1.1.1.2   root     1504:        return mainbus->HVRead1(addr);
1.1       root     1505: }
                   1506: 
                   1507: // VM メモリに1バイト書き出す。
                   1508: void
                   1509: WindrvDevice::WriteMem8(uint32 addr, uint32 data)
                   1510: {
1.1.1.2   root     1511:        mainbus->HVWrite1(addr, data & 0xff);
1.1       root     1512: }
                   1513: 
                   1514: // VM メモリから1ワード読み込む。
                   1515: uint32
                   1516: WindrvDevice::ReadMem16(uint32 addr) const
                   1517: {
1.1.1.2   root     1518:        return mainbus->HVRead2(addr);
1.1       root     1519: }
                   1520: 
                   1521: // VM メモリに1ワード書き出す。
                   1522: void
                   1523: WindrvDevice::WriteMem16(uint32 addr, uint32 data)
                   1524: {
1.1.1.2   root     1525:        mainbus->HVWrite2(addr, data);
1.1       root     1526: }
                   1527: 
                   1528: // VM メモリから1ロングワード読み込む。
                   1529: uint32
                   1530: WindrvDevice::ReadMem32(uint32 addr) const
                   1531: {
1.1.1.2   root     1532:        return mainbus->HVRead4(addr);
1.1       root     1533: }
                   1534: 
                   1535: // VM メモリに1ロングワード書き出す。
                   1536: void
                   1537: WindrvDevice::WriteMem32(uint32 addr, uint32 data)
                   1538: {
1.1.1.2   root     1539:        mainbus->HVWrite4(addr, data);
1.1       root     1540: }
                   1541: 
                   1542: // VM メモリからアドレスを読み込む。(下位24bitのみにする)
                   1543: uint32
                   1544: WindrvDevice::ReadMemAddr(uint32 addr) const
                   1545: {
                   1546:        uint32 data = ReadMem32(addr);
                   1547:        return data & 0x00ffffff;
                   1548: }
                   1549: 
                   1550: // VM メモリにアドレスを書き出す。(下位24bitのみにする)
                   1551: void
                   1552: WindrvDevice::WriteMemAddr(uint32 addr, uint32 data)
                   1553: {
                   1554:        data &= 0x00ffffff;
                   1555:        WriteMem32(addr, data);
                   1556: }
                   1557: 
                   1558: // VM メモリから指定の領域を読み込む。
                   1559: // dst はホストの領域、srcaddr はゲスト内のアドレス。
                   1560: void
                   1561: WindrvDevice::ReadMem(void *dst, uint32 srcaddr, int len) const
                   1562: {
                   1563:        uint8 *d = (uint8 *)dst;
                   1564:        for (int i = 0; i < len; i++) {
1.1.1.2   root     1565:                *d++ = mainbus->HVRead1(srcaddr++);
1.1       root     1566:        }
                   1567: }
                   1568: 
                   1569: // VM メモリに指定の領域を書き出す。
                   1570: // dstaddr はゲスト内のアドレス、src はホストの領域。
                   1571: void
                   1572: WindrvDevice::WriteMem(uint32 dstaddr, const void *src, int len)
                   1573: {
                   1574:        const uint8 *s = (const uint8 *)src;
                   1575:        for (int i = 0; i < len; i++) {
1.1.1.2   root     1576:                mainbus->HVWrite1(dstaddr++, *s++);
1.1       root     1577:        }
                   1578: }
                   1579: 
                   1580: // fname が ns の検索パターンに一致すれば true を返す。
                   1581: bool
                   1582: WindrvDevice::MatchFilename(const std::string& fname_, const NAMESTS& ns) const
                   1583: {
                   1584:        if (ns.wildcard == 21) {
                   1585:                // "*.*" なら調べずに全部一致。
                   1586:                return true;
                   1587:        }
                   1588: 
                   1589:        std::string fname;
                   1590:        std::string pname;
                   1591:        if (option_case_sensitive) {
                   1592:                fname = fname_;
                   1593:                pname = ns.GetName();
                   1594:        } else {
                   1595:                fname = string_tolower(fname_);
                   1596:                pname = string_tolower(ns.GetName());
                   1597:        }
                   1598: 
                   1599:        if (ns.wildcard == 0) {
                   1600:                // ワイルドカードなしなら単純比較。
                   1601:                if (strcmp(fname.c_str(), pname.c_str()) == 0) {
                   1602:                        return true;
                   1603:                }
                   1604:                return false;
                   1605:        } else {
                   1606:                return MatchWildcard(fname, pname);
                   1607:        }
                   1608: }
                   1609: 
                   1610: #endif // !TEST_WINDRV
                   1611: 
                   1612: // fname がパターン pname と一致すれば true を返す。
                   1613: // pname にはワイルドカード '?' が使われている('*' は展開済み)。
                   1614: // fname, pname の大文字小文字は必要に応じて処理済み。
                   1615: // TODO: 漢字対応
                   1616: /*static*/ bool
                   1617: WindrvDevice::MatchWildcard(const std::string& fname, const std::string& pname)
                   1618: {
                   1619:        std::string pstr;
                   1620:        std::string fstr;
                   1621: 
                   1622:        // TODO: 現状マルチピリオドには対応していないのでこれでいい。
                   1623: 
                   1624:        // pname、fname をそれぞれ 21文字固定形式にする。
                   1625:        auto p = pname.find('.');
                   1626:        if (p == std::string::npos) {
                   1627:                pstr = string_format("%-18s%-3s", pname.c_str(), "");
                   1628:        } else {
                   1629:                std::string p1 = pname.substr(0, p);
                   1630:                pstr = string_format("%-18s%-3s", p1.c_str(), &pname[p + 1]);
                   1631:        }
                   1632: 
                   1633:        p = fname.find('.');
                   1634:        if (p == std::string::npos) {
                   1635:                fstr = string_format("%-18s%-3s", fname.c_str(), "");
                   1636:        } else {
                   1637:                std::string f1 = fname.substr(0, p);
                   1638:                fstr = string_format("%-18s%-3s", f1.c_str(), &fname[p + 1]);
                   1639:        }
                   1640: 
                   1641:        // 比較。
                   1642:        for (int i = 0, iend = pstr.size(); i < iend; i++) {
                   1643:                if (pstr[i] != '?') {
                   1644:                        if (fstr[i] != pstr[i]) {
                   1645:                                return false;
                   1646:                        }
                   1647:                }
                   1648:        }
                   1649:        return true;
                   1650: }
                   1651: 
                   1652: #if !defined(TEST_WINDRV)
                   1653: 
                   1654: // addr に対応する FILES バッファを探して返す。
                   1655: // 見付からなければ NULL を返す。
                   1656: FilesBuf *
                   1657: WindrvDevice::SearchFilesBuf(uint32 addr) const
                   1658: {
                   1659:        auto it = filesmap.find(addr);
                   1660:        if (it == filesmap.end()) {
                   1661:                return NULL;
                   1662:        }
                   1663:        return it->second;
                   1664: }
                   1665: 
                   1666: // addr に対応する FILES バッファを作成して返す。
                   1667: FilesBuf *
                   1668: WindrvDevice::AllocFilesBuf(uint32 addr, HostWindrv *host)
                   1669: {
                   1670:        if (filesmap.size() >= MaxFilesBuf) {
                   1671:                // 仕方ないので最も古いのを消すか…。
                   1672:                auto it = std::min_element(filesmap.begin(), filesmap.end(),
                   1673:                        [](const auto& a, const auto& b) {
                   1674:                                return a.second->GetATime() < b.second->GetATime();
                   1675:                        }
                   1676:                );
                   1677:                delete it->second;
                   1678:                filesmap.erase(it);
                   1679:        }
                   1680:        putlog(2, "%s for $%08x", __func__, addr);
                   1681:        filesmap.emplace(addr, new FilesBuf(addr, host));
                   1682:        return filesmap[addr];
                   1683: }
                   1684: 
                   1685: // addr に対応する FCB を探して返す。
                   1686: // 見付からなければ NULL を返す。
                   1687: Windrv::FCB *
                   1688: WindrvDevice::SearchFCB(uint32 addr) const
                   1689: {
                   1690:        auto it = fcbmap.find(addr);
                   1691:        if (it == fcbmap.end()) {
                   1692:                return NULL;
                   1693:        }
                   1694:        return it->second;
                   1695: }
                   1696: 
                   1697: // fcb のコピーを FCB を登録する。
                   1698: uint32
                   1699: WindrvDevice::AddFCB(const Windrv::FCB& fcb)
                   1700: {
                   1701:        assert(fcbmap.find(fcb.GetAddr()) == fcbmap.end());
                   1702: 
                   1703:        FCB *newfcb;
                   1704:        try {
                   1705:                newfcb = new FCB(fcb);
                   1706:        } catch (...) {
                   1707:                newfcb = NULL;
                   1708:        }
                   1709:        if (newfcb == NULL) {
                   1710:                return Human68k::RES_NO_MEMORY;
                   1711:        }
                   1712: 
                   1713:        fcbmap.emplace(newfcb->GetAddr(), newfcb);
                   1714:        return 0;
                   1715: }
                   1716: 
                   1717: // fcb を解放する。
                   1718: // ホスト側のディスクリプタがオープンされていればクローズする。
                   1719: void
                   1720: WindrvDevice::FreeFCB(FCB *fcb)
                   1721: {
                   1722:        assert(fcb);
                   1723: 
                   1724:        fcb->Close();
                   1725:        auto it = fcbmap.find(fcb->GetAddr());
                   1726:        if (it != fcbmap.end()) {
                   1727:                fcbmap.erase(it);
                   1728:        }
                   1729: }
                   1730: 
                   1731: 
                   1732: //
                   1733: // FilesBuf
                   1734: //
                   1735: 
                   1736: // コンストラクタ
                   1737: FilesBuf::FilesBuf(uint32 key_, HostWindrv *host_)
                   1738: {
                   1739:        Init(key_, host_);
                   1740: }
                   1741: 
                   1742: // 初期化
                   1743: void
                   1744: FilesBuf::Init(uint32 key_, HostWindrv *host_)
                   1745: {
                   1746:        key = key_;
                   1747:        host = host_;
                   1748:        path.clear();
                   1749:        list.clear();
                   1750:        UpdateATime();
                   1751: }
                   1752: 
                   1753: // 参照時刻を更新。
                   1754: void
                   1755: FilesBuf::UpdateATime()
                   1756: {
                   1757:        struct timeval tv;
                   1758: 
                   1759:        gettimeofday(&tv, NULL);
                   1760:        atime = (uint64)tv.tv_sec * 1000'000 + (uint64)tv.tv_usec;
                   1761: }
                   1762: 
                   1763: 
                   1764: //
                   1765: // Human68k
                   1766: //
                   1767: 
                   1768: // 属性 attr をデバッグ表示用文字列にして返す。
                   1769: /*static*/ std::string
                   1770: Human68k::AttrStr(uint8 attr)
                   1771: {
                   1772:        static const char attrchr[6] = {
                   1773:                'A',    // Archive
                   1774:                'D',    // Directory
                   1775:                'V',    // Volume
                   1776:                'S',    // System
                   1777:                'H',    // Hidden
                   1778:                'R',    // ReadOnly
                   1779:        };
                   1780:        char buf[8 + 1];
                   1781:        char *d = buf;
                   1782: 
                   1783:        // bit 7,6 はサポートしていないので立ってる時だけ表示。
                   1784:        if (__predict_false((attr & 0xc0) != 0)) {
                   1785:                *d++ = (attr & 0x80) ? '7' : '-';
                   1786:                *d++ = (attr & 0x40) ? '6' : '-';
                   1787:        }
                   1788:        uint8 mask = 0x20;
                   1789:        for (int i = 0; i < 6; i++) {
                   1790:                *d++ = (attr & mask) ? attrchr[i] : '-';
                   1791:                mask >>= 1;
                   1792:        }
                   1793:        *d = '\0';
                   1794:        return std::string(buf);
                   1795: }
                   1796: 
                   1797: // オープンモードを表示用文字列にする。
                   1798: /*static*/ std::string
                   1799: Human68k::OpenModeStr(uint8 openmode)
                   1800: {
                   1801:        switch (openmode) {
                   1802:         case OPEN_RDONLY:      return "O_RDONLY";
                   1803:         case OPEN_WRONLY:      return "O_WRONLY";
                   1804:         case OPEN_RDWR:        return "O_RDWR";
                   1805:         default:
                   1806:                return string_format("$%02x", openmode);
                   1807:        }
                   1808: }
                   1809: 
                   1810: /*static*/ const char * const
                   1811: Human68k::result_msg[] =
                   1812: {
                   1813:        "File exists",                                                  // -80 RES_FILE_EXIST
                   1814: 
                   1815:        "Invalid Function",                                             //  -1 RES_INVALID_FUNC
                   1816:        "File not found",                                               //  -2 RES_FILE_NOT_FOUND
                   1817:        "Directory not found",                                  //  -3 RES_DIR_NOT_FOUND
                   1818:        "Too many opened handles",                              //  -4 RES_TOO_MANY_HANDLE
                   1819:        "Directory or volume",                                  //  -5 RES_NOT_A_FILE
                   1820:        "Handle not opened",                                    //  -6 RES_NOT_OPENED
                   1821:        "Broken memory",                                                //  -7 RES_INVALID_MEM
                   1822:        "Out of memory",                                                //  -8 RES_NO_MEMORY
                   1823:        "Invalid pointer",                                              //  -9 RES_INVALID_PTR
                   1824:        "Invalid environment",                                  // -10 RES_INVALID_ENV
                   1825:        "Illegal executable format",                    // -11 RES_ILLEGAL_FORMAT
                   1826:        "Invalid open mode",                                    // -12 RES_INVALID_MODE
                   1827:        "Invalid path",                                                 // -13 RES_INVALID_PATH
                   1828:        "Invalid parameter",                                    // -14 RES_INVALID_PARAM
                   1829:        "Invalid drive",                                                // -15 RES_INVALID_DRIVE
                   1830:        "Current directory cannot be removed",  // -16 RES_CURRENT_DIR
                   1831:        "No ioctrl for this device",                    // -17 RES_NO_IOCTRL
                   1832:        "No more files found",                                  // -18 RES_LAST_FILE
                   1833:        "Cannot Write a file",                                  // -19 RES_CANNOT_WRITE
                   1834:        "Directory exists",                                             // -20 RES_DIR_EXISTS
                   1835:        "Cannot delete because file exists",    // -21 RES_CANNOT_DELETE
                   1836:        "Cannot rename because file exists",    // -22 RES_CANNOT_RENAME
                   1837:        "Disk full",                                                    // -23 RES_DISK_FULL
                   1838:        "Directory entry full",                                 // -24 RES_DIR_FULL
                   1839:        "Cannot Seek",                                                  // -25 RES_CANNOT_SEEK
                   1840:        "Supervisor called again",                              // -26 RES_SUPERVISOR
                   1841:        "Thread name exists",                                   // -27 RES_THREAD_EXISTS
                   1842:        "Inter-process buffer write-protected", // -28 RES_PROCESS_BUF
                   1843:        "Cannot execute background process",    // -29 RES_BACKGROUND
                   1844:        NULL,   // -30
                   1845:        NULL,   // -31
                   1846:        "Lock buffer full",                                             // -32 RES_NO_LOCKBUF
                   1847:        "Locked",                                                               // -33 RES_LOCKED
                   1848:        "Drive handle opened",                                  // -34 RES_DRIVE_OPENED
                   1849:        "Too many links",                                               // -35 RES_TOO_MANY_LINKS
                   1850: };
                   1851: 
                   1852: /*static*/ const char * const
                   1853: Human68k::err_msg[] =
                   1854: {
                   1855:        NULL,
                   1856:        "Invalid unit number",          // $0001 ERR_INVALID_UNIT
                   1857:        NULL,                                           // $0002
                   1858:        "Invalid command",                      // $0003 ERR_INVALID_COMMAND
                   1859:        NULL,                                           // $0004
                   1860:        NULL,                                           // $0005
                   1861:        NULL,                                           // $0006
                   1862:        NULL,                                           // $0007
                   1863:        NULL,                                           // $0008
                   1864:        NULL,                                           // $0009
                   1865:        "Write error",                          // $000a ERR_WRITE
                   1866:        "Read error",                           // $000b ERR_READ
                   1867:        "Unknown error",                        // $000c ERR_MISC
                   1868:        NULL,                                           // $000d
                   1869:        "Write protected",                      // $000e ERR_WRITE_PROTECT
                   1870: };
                   1871: 
                   1872: // ステータスコードまたはエラーコード result に対応するメッセージを返す。
                   1873: // なければ NULL を返す。
                   1874: // result は負数を渡すこと。
                   1875: // result がエラーコードの場合 Ignore/Retry/Abort ビットの差異は無視する。
                   1876: /*static*/ const char *
                   1877: Human68k::GetResultMsg(uint32 result)
                   1878: {
                   1879:        assert((int32)result < 0);
                   1880: 
                   1881:        result = -(int32)result;
                   1882:        if (result < 0x1000) {
                   1883:                // これ一つだけ遠いのでリマップする
                   1884:                if (__predict_false(result == 80)) {
                   1885:                        result = 0;
                   1886:                }
                   1887:                if (__predict_true(result < countof(result_msg))) {
                   1888:                        return result_msg[result];
                   1889:                }
                   1890:        } else {
                   1891:                result &= 0xfff;
                   1892: 
                   1893:                if (__predict_true(result < countof(err_msg))) {
                   1894:                        return err_msg[result];
                   1895:                }
                   1896:        }
                   1897:        return NULL;
                   1898: }
                   1899: 
                   1900: #endif // !TEST_WINDRV
                   1901: 
                   1902: // Unix 時刻を MS-DOS 形式の日付時刻に変換する。
                   1903: /*static*/ uint32
                   1904: Human68k::Unixtime2DateTime(time_t t)
                   1905: {
                   1906:        struct tm *tm = localtime(&t);
                   1907:        int year = tm->tm_year + 1900;
                   1908:        int mon  = tm->tm_mon + 1;
                   1909:        int day  = tm->tm_mday;
                   1910:        int hour = tm->tm_hour;
                   1911:        int min  = tm->tm_min;
                   1912:        int sec  = tm->tm_sec;
                   1913: 
                   1914:        if (year < 1980) {
                   1915:                year = 1980;
                   1916:                mon  = 1;
                   1917:                day  = 1;
                   1918:                hour = 0;
                   1919:                min  = 0;
                   1920:                sec  = 0;
                   1921:        }
                   1922: 
                   1923:        uint32 datetime =
                   1924:                  ((year - 1980) << 25)
                   1925:                | (mon << 21)
                   1926:                | (day << 16)
                   1927:                | (hour << 11)
                   1928:                | (min << 5)
                   1929:                | (sec / 2);
                   1930:        return datetime;
                   1931: }
                   1932: 
                   1933: // MS-DOS 形式の日付時刻を Unix 時刻に変換する。
                   1934: /*static*/ time_t
                   1935: Human68k::DateTime2Unixtime(uint32 datetime)
                   1936: {
                   1937:        int year = (datetime >> 25) + 1980;
                   1938:        int mon  = (datetime >> 21) & 0xf;
                   1939:        int mday = (datetime >> 16) & 0x1f;
                   1940:        int hour = (datetime >> 11) & 0x1f;
                   1941:        int min  = (datetime >>  5) & 0x3f;
                   1942:        int sec  = (datetime & 0x1f) << 1;
                   1943: 
                   1944:        struct tm tm {};
                   1945:        tm.tm_year = year - 1900;
                   1946:        tm.tm_mon  = mon - 1;
                   1947:        tm.tm_mday = mday;
                   1948:        tm.tm_hour = hour;
                   1949:        tm.tm_min  = min;
                   1950:        tm.tm_sec  = sec;
                   1951:        return mktime(&tm);
                   1952: }
                   1953: 
                   1954: #if !defined(TEST_WINDRV)
                   1955: 
                   1956: // この FILES を (parent を通じて) VM メモリに書き出す。
                   1957: // Files/NFiles で書き戻す必要のあるフィールドのみ。
                   1958: void
                   1959: Human68k::FILES::WriteToMem(WindrvDevice *parent, uint32 addr) const
                   1960: {
                   1961:        //parent->WriteMem8 (addr + 0x00, sattr);
                   1962:        //parent->WriteMem8 (addr + 0x01, drive);
                   1963:        parent->WriteMem32(addr + 0x02, sector);
                   1964:        parent->WriteMem16(addr + 0x08, offset);
                   1965:        parent->WriteMem8 (addr + 0x15, attr);
                   1966:        parent->WriteMem16(addr + 0x16, time);
                   1967:        parent->WriteMem16(addr + 0x18, date);
                   1968:        parent->WriteMem32(addr + 0x1a, size);
                   1969: 
                   1970:        std::array<char, 23> namebuf {};
                   1971:        strlcpy(namebuf.data(), name.c_str(), namebuf.size());
                   1972:        parent->WriteMem(addr + 0x1e, namebuf.data(), namebuf.size());
                   1973: }
                   1974: 
                   1975: // この capacity を (parent を通じて) VM メモリに書き出す。
                   1976: void
                   1977: Human68k::capacity::WriteToMem(WindrvDevice *parent, uint32 addr) const
                   1978: {
                   1979:        parent->WriteMem16(addr + 0, avail_clusters);
                   1980:        parent->WriteMem16(addr + 2, total_clusters);
                   1981:        parent->WriteMem16(addr + 4, sectors_per_cluster);
                   1982:        parent->WriteMem16(addr + 6, bytes_per_sector);
                   1983: }
                   1984: 
                   1985: // この DPB を (parent を通じて) VM メモリに書き出す。
                   1986: void
                   1987: Human68k::DPB::WriteToMem(WindrvDevice *parent, uint32 addr) const
                   1988: {
                   1989:        parent->WriteMem16(addr +  2, sector_size);
                   1990:        parent->WriteMem8 (addr +  4, cluster_size);
                   1991:        parent->WriteMem8 (addr +  5, shift);
                   1992:        parent->WriteMem16(addr +  6, fat_sector);
                   1993:        parent->WriteMem8 (addr +  8, fat_max);
                   1994:        parent->WriteMem8 (addr +  9, fat_size);
                   1995:        parent->WriteMem16(addr + 10, file_max);
                   1996:        parent->WriteMem16(addr + 12, data_sector);
                   1997:        parent->WriteMem16(addr + 14, cluster_max);
                   1998:        parent->WriteMem16(addr + 16, root_sector);
                   1999:        parent->WriteMem8 (addr + 20, media);
                   2000: }
                   2001: 
                   2002: 
                   2003: //
                   2004: // FCB
                   2005: //
                   2006: 
                   2007: // コンストラクタ (Human68k のほう)
                   2008: Human68k::FCB::FCB(WindrvDevice *parent_, uint32 addr_)
                   2009: {
                   2010:        parent = parent_;
                   2011:        addr = addr_;
                   2012: }
                   2013: 
                   2014: uint32
                   2015: Human68k::FCB::GetPos() const
                   2016: {
                   2017:        return parent->ReadMem32(addr + 0x06);
                   2018: }
                   2019: 
                   2020: void
                   2021: Human68k::FCB::SetPos(uint32 pos)
                   2022: {
                   2023:        parent->WriteMem32(addr + 0x06, pos);
                   2024: }
                   2025: 
                   2026: void
                   2027: Human68k::FCB::AddPos(uint32 diff)
                   2028: {
                   2029:        uint32 pos = GetPos();
                   2030:        SetPos(pos + diff);
                   2031: }
                   2032: 
                   2033: uint8
                   2034: Human68k::FCB::GetMode() const
                   2035: {
                   2036:        return parent->ReadMem8(addr + 0x0e);
                   2037: }
                   2038: 
                   2039: void
                   2040: Human68k::FCB::SetDateTime(uint32 datetime)
                   2041: {
                   2042:        uint32 date = datetime >> 16;
                   2043:        uint32 time = datetime & 0xffff;
                   2044:        parent->WriteMem16(addr + 0x3a, time);
                   2045:        parent->WriteMem16(addr + 0x3c, date);
                   2046: }
                   2047: 
                   2048: uint32
                   2049: Human68k::FCB::GetSize() const
                   2050: {
                   2051:        return parent->ReadMem32(addr + 0x40);
                   2052: }
                   2053: 
                   2054: void
                   2055: Human68k::FCB::SetSize(uint32 size)
                   2056: {
                   2057:        parent->WriteMem32(addr + 0x40, size);
                   2058: }
                   2059: 
                   2060: void
                   2061: Human68k::FCB::SetName(const std::string& name1, const std::string& name2,
                   2062:        const std::string& ext)
                   2063: {
                   2064:        std::array<char, 8 + 10> namebuf;
                   2065:        std::array<char, 3>  extbuf;
                   2066: 
                   2067:        // name1
                   2068:        int i = 0;
                   2069:        for (auto c : name1) {
                   2070:                namebuf[i++] = c;
                   2071:        }
                   2072:        while (i < 8) {
                   2073:                namebuf[i++] = ' ';
                   2074:        }
                   2075: 
                   2076:        // name2
                   2077:        for (auto c : name2) {
                   2078:                namebuf[i++] = c;
                   2079:        }
                   2080:        while (i < 8 + 10) {
                   2081:                namebuf[i++] = '\0';
                   2082:        }
                   2083: 
                   2084:        // ext
                   2085:        i = 0;
                   2086:        for (auto c : ext) {
                   2087:                extbuf[i++] = c;
                   2088:        }
                   2089:        while (i < 3) {
                   2090:                extbuf[i++] = ' ';
                   2091:        }
                   2092: 
                   2093:        parent->WriteMem(addr + 0x24, namebuf.data(), 8);
                   2094:        parent->WriteMem(addr + 0x30, namebuf.data() + 8, 10);
                   2095:        parent->WriteMem(addr + 0x2c, extbuf.data(), extbuf.size());
                   2096: }
                   2097: 
                   2098: // コンストラクタ (Windrv のほう)
                   2099: Windrv::FCB::FCB(WindrvDevice *parent, uint32 addr, HostWindrv *host_)
                   2100:        : inherited(parent, addr)
                   2101: {
                   2102:        host = host_;
                   2103: }
                   2104: 
                   2105: // FCB をクローズする。
                   2106: // CmdOpen() の構造上デストラクタではクローズしないので明示的に呼ぶこと。
                   2107: void
                   2108: Windrv::FCB::Close()
                   2109: {
                   2110:        if (host) {
                   2111:                host->Close(this);
                   2112:        }
                   2113: }
                   2114: 
                   2115: 
                   2116: //
                   2117: // NAMESTS
                   2118: //
                   2119: 
                   2120: // コンストラクタ
                   2121: WindrvDevice::NAMESTS::NAMESTS(WindrvDevice *windrv, uint32 addr)
                   2122: {
                   2123:        std::array<uint8, Size> data;
                   2124:        int i;
                   2125: 
                   2126:        windrv->ReadMem(data.data(), addr, data.size());
                   2127: 
                   2128:        // メンバをセット。
                   2129:        wildcard = data[0];
                   2130:        drive = data[1];
                   2131: 
                   2132:        // パスは '\\' らしいけど '\t' が来るようだ。何故?
                   2133:        // どちらにしてもここでは '/' にする。
                   2134:        for (i = 0; i < 65; i++) {
                   2135:                uint8 c = data[2 + i];
                   2136:                if (c == '\0') {
                   2137:                        break;
                   2138:                }
                   2139:                if (c == '\\' || c == '\t') {
                   2140:                        c = '/';
                   2141:                }
                   2142:                path += c;
                   2143:        }
                   2144: 
                   2145:        // name1, ext は ' ' でパディングされているので取り除く。
                   2146:        for (i = 0; i < 8; i++) {
                   2147:                uint8 c = data[0x43 + i];
                   2148:                if (c == ' ') {
                   2149:                        break;
                   2150:                }
                   2151:                name1 += c;
                   2152:        }
                   2153: 
                   2154:        for (i = 0; i < 3; i++) {
                   2155:                uint8 c = data[0x4b + i];
                   2156:                if (c == ' ') {
                   2157:                        break;
                   2158:                }
                   2159:                ext += c;
                   2160:        }
                   2161: 
                   2162:        // name2 は '\0' でパディングされている。
                   2163:        for (i = 0; i < 10; i++) {
                   2164:                uint8 c = data[0x4e + i];
                   2165:                if (c == '\0') {
                   2166:                        break;
                   2167:                }
                   2168:                name2 += c;
                   2169:        }
                   2170: }
                   2171: 
                   2172: // ドライブ:パスを返す。
                   2173: std::string
                   2174: WindrvDevice::NAMESTS::GetDrivePath() const
                   2175: {
                   2176:        std::string buf;
                   2177: 
                   2178:        buf = 'A' + drive;
                   2179:        buf += ':';
                   2180:        buf += GetPath();
                   2181:        return buf;
                   2182: }
                   2183: 
                   2184: // ファイル名文字列を返す。
                   2185: std::string
                   2186: WindrvDevice::NAMESTS::GetName() const
                   2187: {
                   2188:        std::string buf;
                   2189: 
                   2190:        buf = name1 + name2;
                   2191:        if (ext.empty() == false) {
                   2192:                buf += '.';
                   2193:                buf += ext;
                   2194:        }
                   2195:        return buf;
                   2196: }
                   2197: 
                   2198: // ドライブ:パス+ファイル名を返す。
                   2199: std::string
                   2200: WindrvDevice::NAMESTS::GetFull() const
                   2201: {
                   2202:        return GetDrivePath() + GetName();
                   2203: }
                   2204: 
                   2205: // ドライブとパス名のログ表示用文字列を返す。
                   2206: // "D:'/path/'"
                   2207: std::string
                   2208: WindrvDevice::NAMESTS::PrintDrivePath() const
                   2209: {
                   2210:        std::string buf;
                   2211: 
                   2212:        buf = 'A' + drive;
                   2213:        buf += ":'";
                   2214:        buf += GetPath();
                   2215:        buf += '\'';
                   2216:        return buf;
                   2217: }
                   2218: 
                   2219: 
                   2220: //
                   2221: // VDir
                   2222: //
                   2223: 
                   2224: // コンストラクタ
                   2225: VDir::VDir()
                   2226: {
                   2227: }
                   2228: 
                   2229: // コンストラクタ
                   2230: VDir::VDir(HostWindrv *host_, const std::string& path_)
                   2231: {
                   2232:        host = host_;
                   2233:        path = path_;
                   2234: }
                   2235: 
                   2236: // このディレクトリを使用開始する。
                   2237: void
                   2238: VDir::Acquire()
                   2239: {
                   2240:        refcount++;
                   2241: }
                   2242: 
                   2243: // このディレクトリを使用終了する。
                   2244: void
                   2245: VDir::Release()
                   2246: {
                   2247:        if (__predict_true(refcount > 0)) {
                   2248:                refcount--;
                   2249:        } else {
                   2250:                host->putlogf(0, lstr("%s %s: refcount=%d",
                   2251:                        __func__, path.c_str(), refcount));
                   2252:        }
                   2253: }
                   2254: 
                   2255: // name にマッチするエントリを返す。
                   2256: // want_exist == true なら(オープンや削除のために)存在する1つを見付けたい方。
                   2257: // want_exist == false なら(作成する前とかに)存在しないことを確認したい方。
                   2258: //
                   2259: // 大文字小文字を区別しないモードで、大文字と小文字の同じファイル名が
                   2260: // 複数あった場合、true なら見付かったが1つに定まらないので NULL を返す。
                   2261: // false ならいずれにしろ存在するのでどれか1つを返す。
                   2262: const VDirent *
                   2263: VDir::MatchName(const std::string& name, bool want_exist) const
                   2264: {
                   2265:        if (Windrv::option_case_sensitive) {
                   2266:                // 大文字小文字を区別する場合。
                   2267:                for (const auto& e : list) {
                   2268:                        if (e.name == name) {
                   2269:                                return &e;
                   2270:                        }
                   2271:                }
                   2272:                return NULL;
                   2273:        } else {
                   2274:                // 大文字小文字を区別しない場合。
                   2275:                const VDirent *found = NULL;
                   2276:                int n = 0;
                   2277:                for (const auto& e : list) {
                   2278:                        if (strcasecmp(e.name.c_str(), name.c_str()) == 0) {
                   2279:                                if (n++ == 0) {
                   2280:                                        found = &e;
                   2281:                                }
                   2282:                        }
                   2283:                }
                   2284:                // 1つ以下なら確定。
                   2285:                if (n <= 1) {
                   2286:                        return found;
                   2287:                }
                   2288:                // 2つ以上なら、
                   2289:                if (want_exist) {
                   2290:                        return NULL;
                   2291:                } else {
                   2292:                        return found;
                   2293:                }
                   2294:        }
                   2295: }
                   2296: 
                   2297: // 参照時刻を更新する。
                   2298: void
                   2299: VDir::UpdateATime()
                   2300: {
                   2301:        struct timeval tv;
                   2302: 
                   2303:        gettimeofday(&tv, NULL);
                   2304:        atime = (uint64)tv.tv_sec * 1000'000 + (uint64)tv.tv_usec;
                   2305: }
                   2306: 
                   2307: 
                   2308: //
                   2309: // AutoVDir
                   2310: //
                   2311: 
                   2312: // デストラクタ
                   2313: AutoVDir::~AutoVDir()
                   2314: {
                   2315:        if (host && vdir) {
                   2316:                host->CloseVDir(vdir);
                   2317:        }
                   2318: }
                   2319: 
                   2320: 
                   2321: //
                   2322: // VDirent
                   2323: //
                   2324: 
                   2325: // コンストラクタ
                   2326: VDirent::VDirent(const std::string& name_, bool isdir_)
                   2327:        : name(name_), isdir(isdir_), isvalid(true)
                   2328: {
                   2329: }
                   2330: 
                   2331: #endif // !TEST_WINDRV

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.