示例#1
0
文件: FS.cpp 项目: TurboK234/dolphin
ResultCode HostFileSystem::Rename(Uid, Gid, const std::string& old_path,
                                  const std::string& new_path)
{
  if (!IsValidWiiPath(old_path))
    return ResultCode::Invalid;
  const std::string old_name = BuildFilename(old_path);

  if (!IsValidWiiPath(new_path))
    return ResultCode::Invalid;
  const std::string new_name = BuildFilename(new_path);

  // try to make the basis directory
  File::CreateFullPath(new_name);

  // if there is already a file, delete it
  if (File::Exists(old_name) && File::Exists(new_name))
  {
    File::Delete(new_name);
  }

  // finally try to rename the file
  if (!File::Rename(old_name, new_name))
  {
    ERROR_LOG(IOS_FS, "Rename %s to %s - failed", old_name.c_str(), new_name.c_str());
    return ResultCode::NotFound;
  }

  return ResultCode::Success;
}
示例#2
0
ResultCode HostFileSystem::SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid,
                                       FileAttribute, Modes)
{
  if (!IsValidWiiPath(path))
    return ResultCode::Invalid;
  return ResultCode::Success;
}
示例#3
0
Result<Metadata> HostFileSystem::GetMetadata(Uid, Gid, const std::string& path)
{
  Metadata metadata;
  metadata.uid = 0;
  metadata.gid = 0x3031;  // this is also known as makercd, 01 (0x3031) for nintendo and 08
                          // (0x3038) for MH3 etc

  if (!IsValidWiiPath(path))
    return ResultCode::Invalid;

  std::string file_name = BuildFilename(path);
  metadata.modes = {Mode::ReadWrite, Mode::ReadWrite, Mode::ReadWrite};
  metadata.attribute = 0x00;  // no attributes

  // Hack: if the path that is being accessed is within an installed title directory, get the
  // UID/GID from the installed title TMD.
  Kernel* ios = GetIOS();
  u64 title_id;
  if (ios && IsTitlePath(file_name, Common::FROM_SESSION_ROOT, &title_id))
  {
    IOS::ES::TMDReader tmd = ios->GetES()->FindInstalledTMD(title_id);
    if (tmd.IsValid())
      metadata.gid = tmd.GetGroupId();
  }

  const File::FileInfo info{file_name};
  metadata.is_file = info.IsFile();
  metadata.size = info.GetSize();
  if (!info.Exists())
    return ResultCode::NotFound;
  return metadata;
}
示例#4
0
ResultCode HostFileSystem::CreateDirectory(Uid, Gid, const std::string& path, FileAttribute, Modes)
{
  if (!IsValidWiiPath(path))
    return ResultCode::Invalid;

  std::string name(BuildFilename(path));

  name += "/";
  File::CreateFullPath(name);
  DEBUG_ASSERT_MSG(IOS_FS, File::IsDirectory(name), "CREATE_DIR %s failed", name.c_str());

  return ResultCode::Success;
}
示例#5
0
ResultCode HostFileSystem::Rename(Uid, Gid, const std::string& old_path,
                                  const std::string& new_path)
{
  if (!IsValidWiiPath(old_path))
    return ResultCode::Invalid;
  const std::string old_name = BuildFilename(old_path);

  if (!IsValidWiiPath(new_path))
    return ResultCode::Invalid;
  const std::string new_name = BuildFilename(new_path);

  // try to make the basis directory
  File::CreateFullPath(new_name);

  // If there is already something of the same type at the new path, delete it.
  if (File::Exists(new_name))
  {
    const bool old_is_file = File::IsFile(old_name);
    const bool new_is_file = File::IsFile(new_name);
    if (old_is_file && new_is_file)
      File::Delete(new_name);
    else if (!old_is_file && !new_is_file)
      File::DeleteDirRecursively(new_name);
    else
      return ResultCode::Invalid;
  }

  // finally try to rename the file
  if (!File::Rename(old_name, new_name))
  {
    ERROR_LOG(IOS_FS, "Rename %s to %s - failed", old_name.c_str(), new_name.c_str());
    return ResultCode::NotFound;
  }

  return ResultCode::Success;
}
示例#6
0
ResultCode HostFileSystem::Delete(Uid, Gid, const std::string& path)
{
  if (!IsValidWiiPath(path))
    return ResultCode::Invalid;

  const std::string file_name = BuildFilename(path);
  if (File::Delete(file_name))
    INFO_LOG(IOS_FS, "DeleteFile %s", file_name.c_str());
  else if (File::DeleteDirRecursively(file_name))
    INFO_LOG(IOS_FS, "DeleteDir %s", file_name.c_str());
  else
    WARN_LOG(IOS_FS, "DeleteFile %s - failed!!!", file_name.c_str());

  return ResultCode::Success;
}
示例#7
0
Result<std::vector<std::string>> HostFileSystem::ReadDirectory(Uid, Gid, const std::string& path)
{
  if (!IsValidWiiPath(path))
    return ResultCode::Invalid;

  // the Wii uses this function to define the type (dir or file)
  const std::string dir_name(BuildFilename(path));

  const File::FileInfo file_info(dir_name);

  if (!file_info.Exists())
  {
    WARN_LOG(IOS_FS, "Search not found: %s", dir_name.c_str());
    return ResultCode::NotFound;
  }

  if (!file_info.IsDirectory())
  {
    // It's not a directory, so error.
    return ResultCode::Invalid;
  }

  File::FSTEntry entry = File::ScanDirectoryTree(dir_name, false);

  for (File::FSTEntry& child : entry.children)
  {
    // Decode escaped invalid file system characters so that games (such as
    // Harry Potter and the Half-Blood Prince) can find what they expect.
    child.virtualName = Common::UnescapeFileName(child.virtualName);
  }

  // NOTE(leoetlino): this is absolutely wrong, but there is no way to fix this properly
  // if we use the host filesystem.
  std::sort(entry.children.begin(), entry.children.end(),
            [](const File::FSTEntry& one, const File::FSTEntry& two) {
              return one.virtualName < two.virtualName;
            });

  std::vector<std::string> output;
  for (File::FSTEntry& child : entry.children)
    output.emplace_back(child.virtualName);
  return output;
}
示例#8
0
Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_path)
{
  if (!IsValidWiiPath(wii_path))
    return ResultCode::Invalid;

  DirectoryStats stats{};
  std::string path(BuildFilename(wii_path));
  if (File::IsDirectory(path))
  {
    File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true);
    // add one for the folder itself
    stats.used_inodes = 1 + (u32)parent_dir.size;

    u64 total_size = ComputeTotalFileSize(parent_dir);  // "Real" size to convert to nand blocks

    stats.used_clusters = (u32)(total_size / (16 * 1024));  // one block is 16kb
  }
  else
  {
    WARN_LOG(IOS_FS, "fsBlock failed, cannot find directory: %s", path.c_str());
  }
  return stats;
}
示例#9
0
IPCCommandResult CWII_IPC_HLE_Device_fs::IOCtlV(u32 _CommandAddress)
{
  u32 ReturnValue = FS_RESULT_OK;
  SIOCtlVBuffer CommandBuffer(_CommandAddress);

  // Prepare the out buffer(s) with zeros as a safety precaution
  // to avoid returning bad values
  for (u32 i = 0; i < CommandBuffer.NumberPayloadBuffer; i++)
  {
    Memory::Memset(CommandBuffer.PayloadBuffer[i].m_Address, 0,
                   CommandBuffer.PayloadBuffer[i].m_Size);
  }

  switch (CommandBuffer.Parameter)
  {
  case IOCTLV_READ_DIR:
  {
    const std::string relative_path =
        Memory::GetString(CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size);

    if (!IsValidWiiPath(relative_path))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", relative_path.c_str());
      ReturnValue = FS_RESULT_FATAL;
      break;
    }

    // the Wii uses this function to define the type (dir or file)
    std::string DirName(HLE_IPC_BuildFilename(relative_path));

    INFO_LOG(WII_IPC_FILEIO, "FS: IOCTL_READ_DIR %s", DirName.c_str());

    if (!File::Exists(DirName))
    {
      WARN_LOG(WII_IPC_FILEIO, "FS: Search not found: %s", DirName.c_str());
      ReturnValue = FS_FILE_NOT_EXIST;
      break;
    }
    else if (!File::IsDirectory(DirName))
    {
      // It's not a directory, so error.
      // Games don't usually seem to care WHICH error they get, as long as it's <
      // Well the system menu CARES!
      WARN_LOG(WII_IPC_FILEIO, "\tNot a directory - return FS_RESULT_FATAL");
      ReturnValue = FS_RESULT_FATAL;
      break;
    }

    File::FSTEntry entry = File::ScanDirectoryTree(DirName, false);

    // it is one
    if ((CommandBuffer.InBuffer.size() == 1) && (CommandBuffer.PayloadBuffer.size() == 1))
    {
      size_t numFile = entry.children.size();
      INFO_LOG(WII_IPC_FILEIO, "\t%zu files found", numFile);

      Memory::Write_U32((u32)numFile, CommandBuffer.PayloadBuffer[0].m_Address);
    }
    else
    {
      for (File::FSTEntry& child : entry.children)
      {
        // Decode escaped invalid file system characters so that games (such as
        // Harry Potter and the Half-Blood Prince) can find what they expect.
        child.virtualName = Common::UnescapeFileName(child.virtualName);
      }

      std::sort(entry.children.begin(), entry.children.end(),
                [](const File::FSTEntry& one, const File::FSTEntry& two) {
                  return one.virtualName < two.virtualName;
                });

      u32 MaxEntries = Memory::Read_U32(CommandBuffer.InBuffer[0].m_Address);

      memset(Memory::GetPointer(CommandBuffer.PayloadBuffer[0].m_Address), 0,
             CommandBuffer.PayloadBuffer[0].m_Size);

      size_t numFiles = 0;
      char* pFilename = (char*)Memory::GetPointer((u32)(CommandBuffer.PayloadBuffer[0].m_Address));

      for (size_t i = 0; i < entry.children.size() && i < MaxEntries; i++)
      {
        const std::string& FileName = entry.children[i].virtualName;

        strcpy(pFilename, FileName.c_str());
        pFilename += FileName.length();
        *pFilename++ = 0x00;  // termination
        numFiles++;

        INFO_LOG(WII_IPC_FILEIO, "\tFound: %s", FileName.c_str());
      }

      Memory::Write_U32((u32)numFiles, CommandBuffer.PayloadBuffer[1].m_Address);
    }

    ReturnValue = FS_RESULT_OK;
  }
  break;

  case IOCTLV_GETUSAGE:
  {
    _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer.size() == 2);
    _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[0].m_Size == 4);
    _dbg_assert_(WII_IPC_FILEIO, CommandBuffer.PayloadBuffer[1].m_Size == 4);

    // this command sucks because it asks of the number of used
    // fsBlocks and inodes
    // It should be correct, but don't count on it...
    std::string relativepath =
        Memory::GetString(CommandBuffer.InBuffer[0].m_Address, CommandBuffer.InBuffer[0].m_Size);

    if (!IsValidWiiPath(relativepath))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", relativepath.c_str());
      ReturnValue = FS_RESULT_FATAL;
      break;
    }

    std::string path(HLE_IPC_BuildFilename(relativepath));
    u32 fsBlocks = 0;
    u32 iNodes = 0;

    INFO_LOG(WII_IPC_FILEIO, "IOCTL_GETUSAGE %s", path.c_str());
    if (File::IsDirectory(path))
    {
      // LPFaint99: After I found that setting the number of inodes to the number of children + 1
      // for the directory itself
      // I decided to compare with sneek which has the following 2 special cases which are
      // Copyright (C) 2009-2011  crediar http://code.google.com/p/sneek/
      if ((relativepath.compare(0, 16, "/title/00010001") == 0) ||
          (relativepath.compare(0, 16, "/title/00010005") == 0))
      {
        fsBlocks = 23;  // size is size/0x4000
        iNodes = 42;    // empty folders return a FileCount of 1
      }
      else
      {
        File::FSTEntry parentDir = File::ScanDirectoryTree(path, true);
        // add one for the folder itself
        iNodes = 1 + (u32)parentDir.size;

        u64 totalSize =
            ComputeTotalFileSize(parentDir);  // "Real" size, to be converted to nand blocks

        fsBlocks = (u32)(totalSize / (16 * 1024));  // one bock is 16kb
      }
      ReturnValue = FS_RESULT_OK;

      INFO_LOG(WII_IPC_FILEIO, "FS: fsBlock: %i, iNodes: %i", fsBlocks, iNodes);
    }
    else
    {
      fsBlocks = 0;
      iNodes = 0;
      ReturnValue = FS_RESULT_OK;
      WARN_LOG(WII_IPC_FILEIO, "FS: fsBlock failed, cannot find directory: %s", path.c_str());
    }

    Memory::Write_U32(fsBlocks, CommandBuffer.PayloadBuffer[0].m_Address);
    Memory::Write_U32(iNodes, CommandBuffer.PayloadBuffer[1].m_Address);
  }
  break;

  default:
    PanicAlert("CWII_IPC_HLE_Device_fs::IOCtlV: %i", CommandBuffer.Parameter);
    break;
  }

  Memory::Write_U32(ReturnValue, _CommandAddress + 4);

  return GetFSReply();
}
示例#10
0
s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize,
                                           u32 _BufferOut, u32 _BufferOutSize)
{
  switch (_Parameter)
  {
  case IOCTL_GET_STATS:
  {
    if (_BufferOutSize < 0x1c)
      return -1017;

    WARN_LOG(WII_IPC_FILEIO, "FS: GET STATS - returning static values for now");

    NANDStat fs;

    // TODO: scrape the real amounts from somewhere...
    fs.BlockSize = 0x4000;
    fs.FreeUserBlocks = 0x5DEC;
    fs.UsedUserBlocks = 0x1DD4;
    fs.FreeSysBlocks = 0x10;
    fs.UsedSysBlocks = 0x02F0;
    fs.Free_INodes = 0x146B;
    fs.Used_Inodes = 0x0394;

    std::memcpy(Memory::GetPointer(_BufferOut), &fs, sizeof(NANDStat));

    return FS_RESULT_OK;
  }
  break;

  case IOCTL_CREATE_DIR:
  {
    _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
    u32 Addr = _BufferIn;

    u32 OwnerID = Memory::Read_U32(Addr);
    Addr += 4;
    u16 GroupID = Memory::Read_U16(Addr);
    Addr += 2;
    const std::string wii_path = Memory::GetString(Addr, 64);
    if (!IsValidWiiPath(wii_path))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", wii_path.c_str());
      return FS_RESULT_FATAL;
    }
    std::string DirName(HLE_IPC_BuildFilename(wii_path));
    Addr += 64;
    Addr += 9;  // owner attribs, permission
    u8 Attribs = Memory::Read_U8(Addr);

    INFO_LOG(WII_IPC_FILEIO, "FS: CREATE_DIR %s, OwnerID %#x, GroupID %#x, Attributes %#x",
             DirName.c_str(), OwnerID, GroupID, Attribs);

    DirName += DIR_SEP;
    File::CreateFullPath(DirName);
    _dbg_assert_msg_(WII_IPC_FILEIO, File::IsDirectory(DirName), "FS: CREATE_DIR %s failed",
                     DirName.c_str());

    return FS_RESULT_OK;
  }
  break;

  case IOCTL_SET_ATTR:
  {
    u32 Addr = _BufferIn;

    u32 OwnerID = Memory::Read_U32(Addr);
    Addr += 4;
    u16 GroupID = Memory::Read_U16(Addr);
    Addr += 2;
    const std::string wii_path = Memory::GetString(_BufferIn, 64);
    if (!IsValidWiiPath(wii_path))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", wii_path.c_str());
      return FS_RESULT_FATAL;
    }
    std::string Filename = HLE_IPC_BuildFilename(wii_path);
    Addr += 64;
    u8 OwnerPerm = Memory::Read_U8(Addr);
    Addr += 1;
    u8 GroupPerm = Memory::Read_U8(Addr);
    Addr += 1;
    u8 OtherPerm = Memory::Read_U8(Addr);
    Addr += 1;
    u8 Attributes = Memory::Read_U8(Addr);
    Addr += 1;

    INFO_LOG(WII_IPC_FILEIO, "FS: SetAttrib %s", Filename.c_str());
    DEBUG_LOG(WII_IPC_FILEIO, "    OwnerID: 0x%08x", OwnerID);
    DEBUG_LOG(WII_IPC_FILEIO, "    GroupID: 0x%04x", GroupID);
    DEBUG_LOG(WII_IPC_FILEIO, "    OwnerPerm: 0x%02x", OwnerPerm);
    DEBUG_LOG(WII_IPC_FILEIO, "    GroupPerm: 0x%02x", GroupPerm);
    DEBUG_LOG(WII_IPC_FILEIO, "    OtherPerm: 0x%02x", OtherPerm);
    DEBUG_LOG(WII_IPC_FILEIO, "    Attributes: 0x%02x", Attributes);

    return FS_RESULT_OK;
  }
  break;

  case IOCTL_GET_ATTR:
  {
    _dbg_assert_msg_(WII_IPC_FILEIO, _BufferOutSize == 76,
                     "    GET_ATTR needs an 76 bytes large output buffer but it is %i bytes large",
                     _BufferOutSize);

    u32 OwnerID = 0;
    u16 GroupID = 0x3031;  // this is also known as makercd, 01 (0x3031) for nintendo and 08
                           // (0x3038) for MH3 etc
    const std::string wii_path = Memory::GetString(_BufferIn, 64);
    if (!IsValidWiiPath(wii_path))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", wii_path.c_str());
      return FS_RESULT_FATAL;
    }
    std::string Filename = HLE_IPC_BuildFilename(wii_path);
    u8 OwnerPerm = 0x3;    // read/write
    u8 GroupPerm = 0x3;    // read/write
    u8 OtherPerm = 0x3;    // read/write
    u8 Attributes = 0x00;  // no attributes
    if (File::IsDirectory(Filename))
    {
      INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR Directory %s - all permission flags are set",
               Filename.c_str());
    }
    else
    {
      if (File::Exists(Filename))
      {
        INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR %s - all permission flags are set",
                 Filename.c_str());
      }
      else
      {
        INFO_LOG(WII_IPC_FILEIO, "FS: GET_ATTR unknown %s", Filename.c_str());
        return FS_FILE_NOT_EXIST;
      }
    }

    // write answer to buffer
    if (_BufferOutSize == 76)
    {
      u32 Addr = _BufferOut;
      Memory::Write_U32(OwnerID, Addr);
      Addr += 4;
      Memory::Write_U16(GroupID, Addr);
      Addr += 2;
      memcpy(Memory::GetPointer(Addr), Memory::GetPointer(_BufferIn), 64);
      Addr += 64;
      Memory::Write_U8(OwnerPerm, Addr);
      Addr += 1;
      Memory::Write_U8(GroupPerm, Addr);
      Addr += 1;
      Memory::Write_U8(OtherPerm, Addr);
      Addr += 1;
      Memory::Write_U8(Attributes, Addr);
      Addr += 1;
    }

    return FS_RESULT_OK;
  }
  break;

  case IOCTL_DELETE_FILE:
  {
    _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
    int Offset = 0;

    const std::string wii_path = Memory::GetString(_BufferIn + Offset, 64);
    if (!IsValidWiiPath(wii_path))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", wii_path.c_str());
      return FS_RESULT_FATAL;
    }
    std::string Filename = HLE_IPC_BuildFilename(wii_path);
    Offset += 64;
    if (File::Delete(Filename))
    {
      INFO_LOG(WII_IPC_FILEIO, "FS: DeleteFile %s", Filename.c_str());
    }
    else if (File::DeleteDir(Filename))
    {
      INFO_LOG(WII_IPC_FILEIO, "FS: DeleteDir %s", Filename.c_str());
    }
    else
    {
      WARN_LOG(WII_IPC_FILEIO, "FS: DeleteFile %s - failed!!!", Filename.c_str());
    }

    return FS_RESULT_OK;
  }
  break;

  case IOCTL_RENAME_FILE:
  {
    _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);
    int Offset = 0;

    const std::string wii_path = Memory::GetString(_BufferIn + Offset, 64);
    if (!IsValidWiiPath(wii_path))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", wii_path.c_str());
      return FS_RESULT_FATAL;
    }
    std::string Filename = HLE_IPC_BuildFilename(wii_path);
    Offset += 64;

    const std::string wii_path_rename = Memory::GetString(_BufferIn + Offset, 64);
    if (!IsValidWiiPath(wii_path_rename))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", wii_path_rename.c_str());
      return FS_RESULT_FATAL;
    }
    std::string FilenameRename = HLE_IPC_BuildFilename(wii_path_rename);
    Offset += 64;

    // try to make the basis directory
    File::CreateFullPath(FilenameRename);

    // if there is already a file, delete it
    if (File::Exists(Filename) && File::Exists(FilenameRename))
    {
      File::Delete(FilenameRename);
    }

    // finally try to rename the file
    if (File::Rename(Filename, FilenameRename))
    {
      INFO_LOG(WII_IPC_FILEIO, "FS: Rename %s to %s", Filename.c_str(), FilenameRename.c_str());
    }
    else
    {
      ERROR_LOG(WII_IPC_FILEIO, "FS: Rename %s to %s - failed", Filename.c_str(),
                FilenameRename.c_str());
      return FS_FILE_NOT_EXIST;
    }

    return FS_RESULT_OK;
  }
  break;

  case IOCTL_CREATE_FILE:
  {
    _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0);

    u32 Addr = _BufferIn;
    u32 OwnerID = Memory::Read_U32(Addr);
    Addr += 4;
    u16 GroupID = Memory::Read_U16(Addr);
    Addr += 2;
    const std::string wii_path = Memory::GetString(Addr, 64);
    if (!IsValidWiiPath(wii_path))
    {
      WARN_LOG(WII_IPC_FILEIO, "Not a valid path: %s", wii_path.c_str());
      return FS_RESULT_FATAL;
    }
    std::string Filename(HLE_IPC_BuildFilename(wii_path));
    Addr += 64;
    u8 OwnerPerm = Memory::Read_U8(Addr);
    Addr++;
    u8 GroupPerm = Memory::Read_U8(Addr);
    Addr++;
    u8 OtherPerm = Memory::Read_U8(Addr);
    Addr++;
    u8 Attributes = Memory::Read_U8(Addr);
    Addr++;

    INFO_LOG(WII_IPC_FILEIO, "FS: CreateFile %s", Filename.c_str());
    DEBUG_LOG(WII_IPC_FILEIO, "    OwnerID: 0x%08x", OwnerID);
    DEBUG_LOG(WII_IPC_FILEIO, "    GroupID: 0x%04x", GroupID);
    DEBUG_LOG(WII_IPC_FILEIO, "    OwnerPerm: 0x%02x", OwnerPerm);
    DEBUG_LOG(WII_IPC_FILEIO, "    GroupPerm: 0x%02x", GroupPerm);
    DEBUG_LOG(WII_IPC_FILEIO, "    OtherPerm: 0x%02x", OtherPerm);
    DEBUG_LOG(WII_IPC_FILEIO, "    Attributes: 0x%02x", Attributes);

    // check if the file already exist
    if (File::Exists(Filename))
    {
      INFO_LOG(WII_IPC_FILEIO, "\tresult = FS_RESULT_EXISTS");
      return FS_FILE_EXIST;
    }

    // create the file
    File::CreateFullPath(Filename);  // just to be sure
    bool Result = File::CreateEmptyFile(Filename);
    if (!Result)
    {
      ERROR_LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_fs: couldn't create new file");
      PanicAlert("CWII_IPC_HLE_Device_fs: couldn't create new file");
      return FS_RESULT_FATAL;
    }

    INFO_LOG(WII_IPC_FILEIO, "\tresult = FS_RESULT_OK");
    return FS_RESULT_OK;
  }
  break;
  case IOCTL_SHUTDOWN:
  {
    INFO_LOG(WII_IPC_FILEIO, "Wii called Shutdown()");
    // TODO: stop emulation
  }
  break;
  default:
    ERROR_LOG(WII_IPC_FILEIO, "CWII_IPC_HLE_Device_fs::IOCtl: ni  0x%x", _Parameter);
    PanicAlert("CWII_IPC_HLE_Device_fs::IOCtl: ni  0x%x", _Parameter);
    break;
  }

  return FS_RESULT_FATAL;
}