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

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