Merge pull request #5936 from leoetlino/wfs-log

WFS: Use a separate log type for WFS related logs
This commit is contained in:
JosJuice 2017-08-17 16:54:21 +02:00 committed by GitHub
commit 4e40fad248
4 changed files with 42 additions and 40 deletions

View File

@ -38,6 +38,7 @@ enum LOG_TYPE
IOS_STM, IOS_STM,
IOS_USB, IOS_USB,
IOS_WC24, IOS_WC24,
IOS_WFS,
IOS_WIIMOTE, IOS_WIIMOTE,
MASTER_LOG, MASTER_LOG,
MEMMAP, MEMMAP,

View File

@ -106,6 +106,7 @@ LogManager::LogManager()
m_log[LogTypes::IOS_NET] = {"IOS_NET", "IOS - Network"}; m_log[LogTypes::IOS_NET] = {"IOS_NET", "IOS - Network"};
m_log[LogTypes::IOS_USB] = {"IOS_USB", "IOS - USB"}; m_log[LogTypes::IOS_USB] = {"IOS_USB", "IOS - USB"};
m_log[LogTypes::IOS_WC24] = {"IOS_WC24", "IOS - WiiConnect24"}; m_log[LogTypes::IOS_WC24] = {"IOS_WC24", "IOS - WiiConnect24"};
m_log[LogTypes::IOS_WFS] = {"IOS_WFS", "IOS - WFS"};
m_log[LogTypes::IOS_WIIMOTE] = {"IOS_WIIMOTE", "IOS - Wii Remote"}; m_log[LogTypes::IOS_WIIMOTE] = {"IOS_WIIMOTE", "IOS - Wii Remote"};
m_log[LogTypes::MASTER_LOG] = {"*", "Master Log"}; m_log[LogTypes::MASTER_LOG] = {"*", "Master Log"};
m_log[LogTypes::MEMCARD_MANAGER] = {"MemCard Manager", "MemCard Manager"}; m_log[LogTypes::MEMCARD_MANAGER] = {"MemCard Manager", "MemCard Manager"};

View File

@ -39,7 +39,7 @@ void ARCUnpacker::Extract(const WriteCallback& callback)
u32 fourcc = Common::swap32(m_whole_file.data()); u32 fourcc = Common::swap32(m_whole_file.data());
if (fourcc != 0x55AA382D) if (fourcc != 0x55AA382D)
{ {
ERROR_LOG(IOS, "ARCUnpacker: invalid fourcc (%08x)", fourcc); ERROR_LOG(IOS_WFS, "ARCUnpacker: invalid fourcc (%08x)", fourcc);
return; return;
} }
@ -97,12 +97,12 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
u32 tmd_addr = Memory::Read_U32(request.buffer_in); u32 tmd_addr = Memory::Read_U32(request.buffer_in);
u32 tmd_size = Memory::Read_U32(request.buffer_in + 4); u32 tmd_size = Memory::Read_U32(request.buffer_in + 4);
INFO_LOG(IOS, "IOCTL_WFSI_PREPARE_DEVICE"); INFO_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE");
constexpr u32 MAX_TMD_SIZE = 0x4000; constexpr u32 MAX_TMD_SIZE = 0x4000;
if (tmd_size > MAX_TMD_SIZE) if (tmd_size > MAX_TMD_SIZE)
{ {
ERROR_LOG(IOS, "IOCTL_WFSI_PREPARE_DEVICE: TMD size too large (%d)", tmd_size); ERROR_LOG(IOS_WFS, "IOCTL_WFSI_PREPARE_DEVICE: TMD size too large (%d)", tmd_size);
return_error_code = IPC_EINVAL; return_error_code = IPC_EINVAL;
break; break;
} }
@ -139,7 +139,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
IOS::ES::Content content_info; IOS::ES::Content content_info;
if (!m_tmd.FindContentById(content_id, &content_info)) if (!m_tmd.FindContentById(content_id, &content_info))
{ {
WARN_LOG(IOS, "%s: Content id %08x not found", ioctl_name, content_id); WARN_LOG(IOS_WFS, "%s: Content id %08x not found", ioctl_name, content_id);
return_error_code = -10003; return_error_code = -10003;
break; break;
} }
@ -147,7 +147,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
memset(m_aes_iv, 0, sizeof(m_aes_iv)); memset(m_aes_iv, 0, sizeof(m_aes_iv));
m_aes_iv[0] = content_info.index >> 8; m_aes_iv[0] = content_info.index >> 8;
m_aes_iv[1] = content_info.index & 0xFF; m_aes_iv[1] = content_info.index & 0xFF;
INFO_LOG(IOS, "%s: Content id %08x found at index %d", ioctl_name, content_id, INFO_LOG(IOS_WFS, "%s: Content id %08x found at index %d", ioctl_name, content_id,
content_info.index); content_info.index);
m_arc_unpacker.Reset(); m_arc_unpacker.Reset();
@ -164,7 +164,7 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
u32 content_id = Memory::Read_U32(request.buffer_in + 0xC); u32 content_id = Memory::Read_U32(request.buffer_in + 0xC);
u32 input_ptr = Memory::Read_U32(request.buffer_in + 0x10); u32 input_ptr = Memory::Read_U32(request.buffer_in + 0x10);
u32 input_size = Memory::Read_U32(request.buffer_in + 0x14); u32 input_size = Memory::Read_U32(request.buffer_in + 0x14);
INFO_LOG(IOS, "%s: %08x bytes of data at %08x from content id %d", ioctl_name, input_size, INFO_LOG(IOS_WFS, "%s: %08x bytes of data at %08x from content id %d", ioctl_name, input_size,
input_ptr, content_id); input_ptr, content_id);
std::vector<u8> decrypted(input_size); std::vector<u8> decrypted(input_size);
@ -181,17 +181,17 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
const char* ioctl_name = request.request == IOCTL_WFSI_FINALIZE_PROFILE ? const char* ioctl_name = request.request == IOCTL_WFSI_FINALIZE_PROFILE ?
"IOCTL_WFSI_FINALIZE_PROFILE" : "IOCTL_WFSI_FINALIZE_PROFILE" :
"IOCTL_WFSI_FINALIZE_CONTENT"; "IOCTL_WFSI_FINALIZE_CONTENT";
INFO_LOG(IOS, "%s", ioctl_name); INFO_LOG(IOS_WFS, "%s", ioctl_name);
auto callback = [this](const std::string& filename, const std::vector<u8>& bytes) { auto callback = [this](const std::string& filename, const std::vector<u8>& bytes) {
INFO_LOG(IOS, "Extract: %s (%zd bytes)", filename.c_str(), bytes.size()); INFO_LOG(IOS_WFS, "Extract: %s (%zd bytes)", filename.c_str(), bytes.size());
std::string path = WFS::NativePath(m_base_extract_path + "/" + filename); std::string path = WFS::NativePath(m_base_extract_path + "/" + filename);
File::CreateFullPath(path); File::CreateFullPath(path);
File::IOFile f(path, "wb"); File::IOFile f(path, "wb");
if (!f) if (!f)
{ {
ERROR_LOG(IOS, "Could not extract %s to %s", filename.c_str(), path.c_str()); ERROR_LOG(IOS_WFS, "Could not extract %s to %s", filename.c_str(), path.c_str());
return; return;
} }
f.WriteBytes(bytes.data(), bytes.size()); f.WriteBytes(bytes.data(), bytes.size());
@ -208,19 +208,19 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
// Bytes 0-4: ?? // Bytes 0-4: ??
// Bytes 4-8: game id // Bytes 4-8: game id
// Bytes 1c-1e: title id? // Bytes 1c-1e: title id?
WARN_LOG(IOS, "IOCTL_WFSI_DELETE_TITLE: unimplemented"); WARN_LOG(IOS_WFS, "IOCTL_WFSI_DELETE_TITLE: unimplemented");
break; break;
case IOCTL_WFSI_IMPORT_TITLE: case IOCTL_WFSI_IMPORT_TITLE:
WARN_LOG(IOS, "IOCTL_WFSI_IMPORT_TITLE: unimplemented"); WARN_LOG(IOS_WFS, "IOCTL_WFSI_IMPORT_TITLE: unimplemented");
break; break;
case IOCTL_WFSI_INIT: case IOCTL_WFSI_INIT:
{ {
INFO_LOG(IOS, "IOCTL_WFSI_INIT"); INFO_LOG(IOS_WFS, "IOCTL_WFSI_INIT");
if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0) if (GetIOS()->GetES()->GetTitleId(&m_title_id) < 0)
{ {
ERROR_LOG(IOS, "IOCTL_WFSI_INIT: Could not get title id."); ERROR_LOG(IOS_WFS, "IOCTL_WFSI_INIT: Could not get title id.");
return_error_code = IPC_EINVAL; return_error_code = IPC_EINVAL;
break; break;
} }
@ -235,12 +235,12 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
} }
case IOCTL_WFSI_SET_DEVICE_NAME: case IOCTL_WFSI_SET_DEVICE_NAME:
INFO_LOG(IOS, "IOCTL_WFSI_SET_DEVICE_NAME"); INFO_LOG(IOS_WFS, "IOCTL_WFSI_SET_DEVICE_NAME");
m_device_name = Memory::GetString(request.buffer_in); m_device_name = Memory::GetString(request.buffer_in);
break; break;
case IOCTL_WFSI_APPLY_TITLE_PROFILE: case IOCTL_WFSI_APPLY_TITLE_PROFILE:
INFO_LOG(IOS, "IOCTL_WFSI_APPLY_TITLE_PROFILE"); INFO_LOG(IOS_WFS, "IOCTL_WFSI_APPLY_TITLE_PROFILE");
m_base_extract_path = StringFromFormat("/vol/%s/_install/%s/content", m_device_name.c_str(), m_base_extract_path = StringFromFormat("/vol/%s/_install/%s/content", m_device_name.c_str(),
m_title_id_str.c_str()); m_title_id_str.c_str());
@ -266,13 +266,13 @@ IPCCommandResult WFSI::IOCtl(const IOCtlRequest& request)
path += StringFromFormat("/extension%d.dol", dol_extension_id); path += StringFromFormat("/extension%d.dol", dol_extension_id);
} }
INFO_LOG(IOS, "IOCTL_WFSI_LOAD_DOL: loading %s at address %08x (size %d)", path.c_str(), INFO_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: loading %s at address %08x (size %d)", path.c_str(),
dol_addr, max_dol_size); dol_addr, max_dol_size);
File::IOFile fp(WFS::NativePath(path), "rb"); File::IOFile fp(WFS::NativePath(path), "rb");
if (!fp) if (!fp)
{ {
WARN_LOG(IOS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str()); WARN_LOG(IOS_WFS, "IOCTL_WFSI_LOAD_DOL: no such file or directory: %s", path.c_str());
return_error_code = WFSI_ENOENT; return_error_code = WFSI_ENOENT;
break; break;
} }

View File

@ -42,18 +42,18 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
{ {
case IOCTL_WFS_INIT: case IOCTL_WFS_INIT:
// TODO(wfs): Implement. // TODO(wfs): Implement.
INFO_LOG(IOS, "IOCTL_WFS_INIT"); INFO_LOG(IOS_WFS, "IOCTL_WFS_INIT");
break; break;
case IOCTL_WFS_UNKNOWN_8: case IOCTL_WFS_UNKNOWN_8:
// TODO(wfs): Figure out what this actually does. // TODO(wfs): Figure out what this actually does.
INFO_LOG(IOS, "IOCTL_WFS_UNKNOWN_8"); INFO_LOG(IOS_WFS, "IOCTL_WFS_UNKNOWN_8");
Memory::Write_U8(7, request.buffer_out); Memory::Write_U8(7, request.buffer_out);
Memory::CopyToEmu(request.buffer_out + 1, "msc01\x00\x00\x00", 8); Memory::CopyToEmu(request.buffer_out + 1, "msc01\x00\x00\x00", 8);
break; break;
case IOCTL_WFS_SHUTDOWN: case IOCTL_WFS_SHUTDOWN:
INFO_LOG(IOS, "IOCTL_WFS_SHUTDOWN"); INFO_LOG(IOS_WFS, "IOCTL_WFS_SHUTDOWN");
// Close all hanging attach/detach ioctls with an appropriate error code. // Close all hanging attach/detach ioctls with an appropriate error code.
for (auto address : m_hanging) for (auto address : m_hanging)
@ -67,14 +67,14 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
break; break;
case IOCTL_WFS_DEVICE_INFO: case IOCTL_WFS_DEVICE_INFO:
INFO_LOG(IOS, "IOCTL_WFS_DEVICE_INFO"); INFO_LOG(IOS_WFS, "IOCTL_WFS_DEVICE_INFO");
Memory::Write_U64(16ull << 30, request.buffer_out); // 16GB storage. Memory::Write_U64(16ull << 30, request.buffer_out); // 16GB storage.
Memory::Write_U8(4, request.buffer_out + 8); Memory::Write_U8(4, request.buffer_out + 8);
break; break;
case IOCTL_WFS_GET_DEVICE_NAME: case IOCTL_WFS_GET_DEVICE_NAME:
{ {
INFO_LOG(IOS, "IOCTL_WFS_GET_DEVICE_NAME"); INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_DEVICE_NAME");
Memory::Write_U8(static_cast<u8>(m_device_name.size()), request.buffer_out); Memory::Write_U8(static_cast<u8>(m_device_name.size()), request.buffer_out);
Memory::CopyToEmu(request.buffer_out + 1, m_device_name.data(), m_device_name.size()); Memory::CopyToEmu(request.buffer_out + 1, m_device_name.data(), m_device_name.size());
break; break;
@ -82,14 +82,14 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
case IOCTL_WFS_ATTACH_DETACH_2: case IOCTL_WFS_ATTACH_DETACH_2:
// TODO(wfs): Implement. // TODO(wfs): Implement.
INFO_LOG(IOS, "IOCTL_WFS_ATTACH_DETACH_2(%u)", request.request); INFO_LOG(IOS_WFS, "IOCTL_WFS_ATTACH_DETACH_2(%u)", request.request);
Memory::Write_U32(1, request.buffer_out); Memory::Write_U32(1, request.buffer_out);
Memory::Write_U32(0, request.buffer_out + 4); // device id? Memory::Write_U32(0, request.buffer_out + 4); // device id?
Memory::Write_U32(0, request.buffer_out + 8); Memory::Write_U32(0, request.buffer_out + 8);
break; break;
case IOCTL_WFS_ATTACH_DETACH: case IOCTL_WFS_ATTACH_DETACH:
INFO_LOG(IOS, "IOCTL_WFS_ATTACH_DETACH(%u)", request.request); INFO_LOG(IOS_WFS, "IOCTL_WFS_ATTACH_DETACH(%u)", request.request);
// Leave hanging, but we need to acknowledge the request at shutdown time. // Leave hanging, but we need to acknowledge the request at shutdown time.
m_hanging.push_back(request.address); m_hanging.push_back(request.address);
@ -97,41 +97,41 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
case IOCTL_WFS_FLUSH: case IOCTL_WFS_FLUSH:
// Nothing to do. // Nothing to do.
INFO_LOG(IOS, "IOCTL_WFS_FLUSH: doing nothing"); INFO_LOG(IOS_WFS, "IOCTL_WFS_FLUSH: doing nothing");
break; break;
// TODO(wfs): Globbing is not really implemented, we just fake the one case // TODO(wfs): Globbing is not really implemented, we just fake the one case
// (listing /vol/*) which is required to get the installer to work. // (listing /vol/*) which is required to get the installer to work.
case IOCTL_WFS_GLOB_START: case IOCTL_WFS_GLOB_START:
INFO_LOG(IOS, "IOCTL_WFS_GLOB_START(%u)", request.request); INFO_LOG(IOS_WFS, "IOCTL_WFS_GLOB_START(%u)", request.request);
Memory::Memset(request.buffer_out, 0, request.buffer_out_size); Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
Memory::CopyToEmu(request.buffer_out + 0x14, m_device_name.data(), m_device_name.size()); Memory::CopyToEmu(request.buffer_out + 0x14, m_device_name.data(), m_device_name.size());
break; break;
case IOCTL_WFS_GLOB_NEXT: case IOCTL_WFS_GLOB_NEXT:
INFO_LOG(IOS, "IOCTL_WFS_GLOB_NEXT(%u)", request.request); INFO_LOG(IOS_WFS, "IOCTL_WFS_GLOB_NEXT(%u)", request.request);
return_error_code = WFS_ENOENT; return_error_code = WFS_ENOENT;
break; break;
case IOCTL_WFS_GLOB_END: case IOCTL_WFS_GLOB_END:
INFO_LOG(IOS, "IOCTL_WFS_GLOB_END(%u)", request.request); INFO_LOG(IOS_WFS, "IOCTL_WFS_GLOB_END(%u)", request.request);
Memory::Memset(request.buffer_out, 0, request.buffer_out_size); Memory::Memset(request.buffer_out, 0, request.buffer_out_size);
break; break;
case IOCTL_WFS_SET_HOMEDIR: case IOCTL_WFS_SET_HOMEDIR:
m_home_directory = m_home_directory =
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in)); Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
INFO_LOG(IOS, "IOCTL_WFS_SET_HOMEDIR: %s", m_home_directory.c_str()); INFO_LOG(IOS_WFS, "IOCTL_WFS_SET_HOMEDIR: %s", m_home_directory.c_str());
break; break;
case IOCTL_WFS_CHDIR: case IOCTL_WFS_CHDIR:
m_current_directory = m_current_directory =
Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in)); Memory::GetString(request.buffer_in + 2, Memory::Read_U16(request.buffer_in));
INFO_LOG(IOS, "IOCTL_WFS_CHDIR: %s", m_current_directory.c_str()); INFO_LOG(IOS_WFS, "IOCTL_WFS_CHDIR: %s", m_current_directory.c_str());
break; break;
case IOCTL_WFS_GET_HOMEDIR: case IOCTL_WFS_GET_HOMEDIR:
INFO_LOG(IOS, "IOCTL_WFS_GET_HOMEDIR: %s", m_home_directory.c_str()); INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_HOMEDIR: %s", m_home_directory.c_str());
Memory::Write_U16(static_cast<u16>(m_home_directory.size()), request.buffer_out); Memory::Write_U16(static_cast<u16>(m_home_directory.size()), request.buffer_out);
Memory::CopyToEmu(request.buffer_out + 2, m_home_directory.data(), m_home_directory.size()); Memory::CopyToEmu(request.buffer_out + 2, m_home_directory.data(), m_home_directory.size());
break; break;
@ -153,13 +153,13 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
if (!fd_obj->Open()) if (!fd_obj->Open())
{ {
ERROR_LOG(IOS, "IOCTL_WFS_OPEN(%s, %d): error opening file", path.c_str(), mode); ERROR_LOG(IOS_WFS, "IOCTL_WFS_OPEN(%s, %d): error opening file", path.c_str(), mode);
ReleaseFileDescriptor(fd); ReleaseFileDescriptor(fd);
return_error_code = WFS_ENOENT; return_error_code = WFS_ENOENT;
break; break;
} }
INFO_LOG(IOS, "IOCTL_WFS_OPEN(%s, %d) -> %d", path.c_str(), mode, fd); INFO_LOG(IOS_WFS, "IOCTL_WFS_OPEN(%s, %d) -> %d", path.c_str(), mode, fd);
Memory::Write_U16(fd, request.buffer_out + 0x14); Memory::Write_U16(fd, request.buffer_out + 0x14);
break; break;
} }
@ -170,17 +170,17 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
FileDescriptor* fd_obj = FindFileDescriptor(fd); FileDescriptor* fd_obj = FindFileDescriptor(fd);
if (fd_obj == nullptr) if (fd_obj == nullptr)
{ {
ERROR_LOG(IOS, "IOCTL_WFS_GET_SIZE: invalid file descriptor %d", fd); ERROR_LOG(IOS_WFS, "IOCTL_WFS_GET_SIZE: invalid file descriptor %d", fd);
return_error_code = WFS_EBADFD; return_error_code = WFS_EBADFD;
break; break;
} }
u64 size = fd_obj->file.GetSize(); u64 size = fd_obj->file.GetSize();
u32 truncated_size = static_cast<u32>(size); u32 truncated_size = static_cast<u32>(size);
INFO_LOG(IOS, "IOCTL_WFS_GET_SIZE(%d) -> %d", fd, truncated_size); INFO_LOG(IOS_WFS, "IOCTL_WFS_GET_SIZE(%d) -> %d", fd, truncated_size);
if (size != truncated_size) if (size != truncated_size)
{ {
ERROR_LOG(IOS, "IOCTL_WFS_GET_SIZE: file %d too large (%" PRIu64 ")", fd, size); ERROR_LOG(IOS_WFS, "IOCTL_WFS_GET_SIZE: file %d too large (%" PRIu64 ")", fd, size);
} }
Memory::Write_U32(truncated_size, request.buffer_out); Memory::Write_U32(truncated_size, request.buffer_out);
break; break;
@ -189,7 +189,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
case IOCTL_WFS_CLOSE: case IOCTL_WFS_CLOSE:
{ {
u16 fd = Memory::Read_U16(request.buffer_in + 0x4); u16 fd = Memory::Read_U16(request.buffer_in + 0x4);
INFO_LOG(IOS, "IOCTL_WFS_CLOSE(%d)", fd); INFO_LOG(IOS_WFS, "IOCTL_WFS_CLOSE(%d)", fd);
ReleaseFileDescriptor(fd); ReleaseFileDescriptor(fd);
break; break;
} }
@ -207,7 +207,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
FileDescriptor* fd_obj = FindFileDescriptor(fd); FileDescriptor* fd_obj = FindFileDescriptor(fd);
if (fd_obj == nullptr) if (fd_obj == nullptr)
{ {
ERROR_LOG(IOS, "IOCTL_WFS_READ: invalid file descriptor %d", fd); ERROR_LOG(IOS_WFS, "IOCTL_WFS_READ: invalid file descriptor %d", fd);
return_error_code = WFS_EBADFD; return_error_code = WFS_EBADFD;
break; break;
} }
@ -229,7 +229,7 @@ IPCCommandResult WFSSRV::IOCtl(const IOCtlRequest& request)
fd_obj->position += read_bytes; fd_obj->position += read_bytes;
} }
INFO_LOG(IOS, "IOCTL_WFS_READ: read %zd bytes from FD %d (%s)", read_bytes, fd, INFO_LOG(IOS_WFS, "IOCTL_WFS_READ: read %zd bytes from FD %d (%s)", read_bytes, fd,
fd_obj->path.c_str()); fd_obj->path.c_str());
return_error_code = static_cast<int>(read_bytes); return_error_code = static_cast<int>(read_bytes);
break; break;
@ -338,7 +338,7 @@ bool WFSSRV::FileDescriptor::Open()
} }
else else
{ {
ERROR_LOG(IOS, "WFSOpen: invalid mode %d", mode); ERROR_LOG(IOS_WFS, "WFSOpen: invalid mode %d", mode);
return false; return false;
} }