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

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