📄 fs_nand.c
字号:
/* * Copyright (C) 2008 dhewg, #wiidev efnet * * this file is part of wiifuse * http://wiibrew.org/index.php?title=Wiifuse * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include <gccore.h>#include <ogcsys.h>#include <ogc/isfs.h>#include "../../shared.h"#include "global.h"// TODO use libogc stuff when available#define ISFS_ACCESS_R 0x01#define ISFS_ACCESS_W 0x02#define ISFS_ACCESS_RW (ISFS_ACCESS_R | ISFS_ACCESS_W)#define ISFS_MAX_PATHNAMELEN 64#define ISFS_MAX_FILENAMELEN 12#define NAND_TYPE_FILE 0x01#define NAND_TYPE_DIR 0x02s32 ISFS_GetType (const char *filename, u8 *type) { s32 res; u32 num; res = ISFS_ReadDir (filename, NULL, &num); //LOG (2, "ISFS_GetType %d %u", res, num); switch (res) { case 0: case -102: *type = NAND_TYPE_DIR; res = ISFS_OK; break; case -101: *type = NAND_TYPE_FILE; res = ISFS_OK; break; } return res;}enum remote_result get_server_error (const s32 err_code) { switch (err_code) { case -101: return RES_EISDIR; case -102: return RES_EACCES; case -106: return RES_ENOENT; default: LOG_ERR ("unhandled error code: %d", err_code); return RES_ENOENT; }}bool nand_init (u8 **data, u16 *data_size) { s32 res; u64 title_id; static char path[ISFS_MAX_PATHNAMELEN] ATTRIBUTE_ALIGN(32); res = ISFS_Initialize (); if (res != ISFS_OK) return false; res = ES_GetTitleID (&title_id); if (res != ISFS_OK) { LOG_ERR ("ES_GetTitleID failed: %d", res); return false; } res = ES_GetDataDir (title_id, path); if (res != ISFS_OK) { LOG_ERR ("ES_GetDataDir failed: %d", res); return false; } LOG (1, "nand data dir is \"%s\"", path); *data_size = strlen (path); *data = malloc (*data_size); memcpy (*data, path, *data_size); return true;}bool nand_deinit () { return ISFS_Deinitialize () == ISFS_OK;}void get_remote_perms (u8 *u_perms, u8 *g_perms, u8 *o_perms, const u16 perms) { *u_perms = 0; *g_perms = 0; *o_perms = 0; if (perms & MODE_IRUSR) *u_perms |= ISFS_ACCESS_R; if (perms & MODE_IWUSR) *u_perms |= ISFS_ACCESS_W; if (perms & MODE_IRGRP) *g_perms |= ISFS_ACCESS_R; if (perms & MODE_IWGRP) *g_perms |= ISFS_ACCESS_W; if (perms & MODE_IROTH) *o_perms |= ISFS_ACCESS_R; if (perms & MODE_IWOTH) *o_perms |= ISFS_ACCESS_W;}void put_remote_perms (u16 *perms, const u8 u_perms, const u8 g_perms, const u8 o_perms, const bool is_dir) { *perms = 0; if (u_perms & ISFS_ACCESS_R) *perms |= MODE_IRUSR; if (u_perms & ISFS_ACCESS_W) *perms |= MODE_IWUSR; if (g_perms & ISFS_ACCESS_R) *perms |= MODE_IRGRP; if (g_perms & ISFS_ACCESS_W) *perms |= MODE_IWGRP; if (o_perms & ISFS_ACCESS_R) *perms |= MODE_IROTH; if (o_perms & ISFS_ACCESS_W) *perms |= MODE_IWOTH; if (is_dir) { if (u_perms & ISFS_ACCESS_RW) *perms |= MODE_IXUSR; if (g_perms & ISFS_ACCESS_RW) *perms |= MODE_IXGRP; if (o_perms & ISFS_ACCESS_RW) *perms |= MODE_IXOTH; }}enum remote_result nand_access (const char *filename, u8 mode) { s32 res; u8 type; res = ISFS_GetType (filename, &type); if (res != ISFS_OK) return get_server_error (res); if ((mode & ACCESS_X_OK) && (type != NAND_TYPE_DIR)) return RES_ENOTDIR; return RES_OK;}enum remote_result nand_getattr (const char *filename, struct remote_attr *attributes) { s32 fd, res; static fstats fstat ATTRIBUTE_ALIGN(32); u32 owner; u16 group; u8 attr, u_perms, g_perms, o_perms; u8 type; res = ISFS_GetAttr (filename, &owner, &group, &attr, &u_perms, &g_perms, &o_perms); if (res != ISFS_OK) { LOG_ERR ("ISFS_GetAttr failed: %d", res); return get_server_error (res); } LOG (2, "o=0x%08x g=0x%04x a=0x%02x perm=0x%02x,0x%02x,0x%02x (%s)", owner, group, attr, u_perms, g_perms, o_perms, filename); if (attr) printf ("ATTENTION: attr=0x%02x on %s\n", attr, filename); attributes->owner = owner; attributes->group = group; res = ISFS_GetType (filename, &type); if (type == NAND_TYPE_DIR) { attributes->is_dir = 1; attributes->nlink = 2; put_remote_perms (&(attributes->perms), u_perms, g_perms, o_perms, true); return RES_OK; } put_remote_perms (&(attributes->perms), u_perms, g_perms, o_perms, false); fd = ISFS_Open (filename, ISFS_ACCESS_R); if (fd < 0) { LOG_ERR ("ISFS_Open failed: %d", fd); return get_server_error (fd); } res = ISFS_GetFileStats (fd, &fstat); ISFS_Close (fd); if (res != ISFS_OK) { LOG_ERR ("ISFS_GetFileStats failed: %d", res); return get_server_error (res); } attributes->size = fstat.file_length; attributes->nlink = 1; return RES_OK;}enum remote_result nand_open (const char *filename) { s32 fd; fd = ISFS_Open (filename, ISFS_ACCESS_R); if (fd < 0) { LOG_ERR ("ISFS_Open failed: %d", fd); return get_server_error (fd); } ISFS_Close (fd); return RES_OK;}enum remote_result nand_read (const char *filename, const u64 offset, u16 *size, u8 *buffer) { s32 fd, res; s32 off; fd = ISFS_Open (filename, ISFS_ACCESS_R); if (fd < 0) { LOG_ERR ("ISFS_Open failed: %d", fd); return get_server_error (fd); } off = offset & 0x7fffffff; if (off > 0) { res = ISFS_Seek (fd, off, 0); if (res != off) { LOG_ERR ("ISFS_Seek failed: %d", res); ISFS_Close (fd); return get_server_error (res); } } LOG_ERR ("Reading %hu bytes\n", *size); int bytes_read = 0; while (bytes_read < *size) { int bytes_to_read = (*size - bytes_read) > 2048 ? 2048 : (*size - bytes_read); LOG_ERR("Calling ISFS_Read(%d, %p, %d)\n", fd, buffer+bytes_read, bytes_to_read); res = ISFS_Read (fd, buffer+bytes_read, bytes_to_read); if (res < 0) { LOG_ERR ("ISFS_Read failed: %d", res); ISFS_Close (fd); return get_server_error (res); } bytes_read += bytes_to_read; } *size = bytes_read; ISFS_Close (fd); return RES_OK;}enum remote_result nand_opendir (const char *dirname) { s32 res; u8 type; res = ISFS_GetType (dirname, &type); if (res != ISFS_OK) { LOG_ERR ("ISFS_GetType failed: %d", res); return get_server_error (res); } if (type == NAND_TYPE_DIR) return RES_OK; else return RES_ENOTDIR;}enum remote_result nand_readdir (const char *dirname, u8 **data, u16 *data_size) { s32 res; char *list; u32 num; u32 i; res = ISFS_ReadDir (dirname, NULL, &num); if (res != ISFS_OK) { LOG_ERR ("ISFS_ReadDir failed: %d", res); return get_server_error (res); } if (num < 1) { LOG (2, "dir is empty"); return RES_OK; } list = memalign (32, num * (ISFS_MAX_FILENAMELEN + 1) + 1); res = ISFS_ReadDir (dirname, list, &num); if (res != ISFS_OK) { LOG_ERR ("ISFS_ReadDir failed %d", res); free (list); return get_server_error (res); } for (i = 0; i < num; ++i) *data_size += strlen (&list[*data_size]) + 1; *data = malloc (*data_size + 1); memcpy (*data, list, *data_size); (*data)[*data_size] = 0; *data_size += 1; free (list); return RES_OK;}enum remote_result nand_mkdir (const char *dirname, const u16 perms) { u8 u_perms, g_perms, o_perms; s32 res; get_remote_perms (&u_perms, &g_perms, &o_perms, perms); LOG (2, "nand perms 0x%02x 0x%02x 0x%02x", u_perms, g_perms, o_perms); res = ISFS_CreateDir (dirname, 0, u_perms, g_perms, o_perms); if (res != ISFS_OK) { LOG_ERR ("ISFS_CreateDir failed: %d", res); return get_server_error (res); } return RES_OK;}enum remote_result nand_rmdir (const char *dirname) { s32 res; res = ISFS_Delete (dirname); if (res != ISFS_OK) { LOG_ERR ("ISFS_Delete failed: %d", res); return get_server_error (res); } return RES_OK;}enum remote_result nand_create (const char *filename, const u16 perms) { u8 u_perms, g_perms, o_perms; s32 res; get_remote_perms (&u_perms, &g_perms, &o_perms, perms); LOG (2, "nand perms 0x%02x 0x%02x 0x%02x", u_perms, g_perms, o_perms); res = ISFS_CreateFile (filename, 0, u_perms, g_perms, o_perms); if (res != ISFS_OK) { LOG_ERR ("ISFS_CreateFile failed: %d", res); return get_server_error (res); } return RES_OK;}enum remote_result nand_write (const char *filename, const u64 offset, u16 *size, u8 *buffer) { s32 fd, res; s32 off; u8 *buf; fd = ISFS_Open (filename, ISFS_ACCESS_W); if (fd < 0) { LOG_ERR ("ISFS_Open failed: %d", fd); return get_server_error (fd); } off = offset & 0x7fffffff; if (off > 0) { res = ISFS_Seek (fd, off, 0); if (res != off) { LOG_ERR ("ISFS_Seek failed: %d", res); ISFS_Close (fd); return get_server_error (res); } } buf = memalign (32, *size); memcpy (buf, buffer, *size); res = ISFS_Write (fd, buf, *size); free (buf); if (res < 0) { LOG_ERR ("ISFS_Write failed: %d", res); ISFS_Close (fd); return get_server_error (res); } *size = res; ISFS_Close (fd); return RES_OK;}enum remote_result nand_chown (const char *filename, const u32 uid, const u32 gid) { u32 owner; u16 group; u8 attr, u_perms, g_perms, o_perms; s32 res; if (gid > 0xffff) { LOG_ERR ("group id is only 16bit"); res = RES_EACCES; } res = ISFS_GetAttr (filename, &owner, &group, &attr, &u_perms, &g_perms, &o_perms); if (res != ISFS_OK) { LOG_ERR ("ISFS_GetAttr failed: %d", res); return get_server_error (res); } LOG (2, "current nand id's %u %u", owner, group); group = gid & 0xffff; res = ISFS_SetAttr (filename, uid, group, attr, u_perms, g_perms, o_perms); if (res != ISFS_OK) { LOG_ERR ("ISFS_SetAttr failed: %d", res); return get_server_error (res); } return RES_OK;}enum remote_result nand_chmod (const char *filename, const u16 perms) { u32 owner; u16 group; u8 attr, u_perms, g_perms, o_perms; s32 res; res = ISFS_GetAttr (filename, &owner, &group, &attr, &u_perms, &g_perms, &o_perms); if (res != ISFS_OK) { LOG_ERR ("ISFS_GetAttr failed: %d", res); return get_server_error (res); } LOG (2, "current nand perms 0x%02x 0x%02x 0x%02x", u_perms, g_perms, o_perms); get_remote_perms (&u_perms, &g_perms, &o_perms, perms); LOG (2, "new nand perms 0x%02x 0x%02x 0x%02x", u_perms, g_perms, o_perms); res = ISFS_SetAttr (filename, owner, group, attr, u_perms, g_perms, o_perms); if (res != ISFS_OK) { LOG_ERR ("ISFS_SetAttr failed: %d", res); return get_server_error (res); } return RES_OK;}enum remote_result nand_rename (const char *src, const char *dst) { s32 res; res = ISFS_Rename (src, dst); if (res != ISFS_OK) { LOG_ERR ("ISFS_Rename failed: %d", res); return get_server_error (res); } return RES_OK;}enum remote_result nand_unlink (const char *filename) { s32 res; res = ISFS_Delete (filename); if (res != ISFS_OK) { LOG_ERR ("ISFS_Delete failed: %d", res); return get_server_error (res); } return RES_OK;}enum remote_result nand_statfs (const char *filename, u64 *bsize, u64 *blocks, u64 *bfree, u64 *files, u64 *ffree){ *bsize = 0x4000; *blocks = 0x8000; // TODO missing call, just some dummy values so os's wont error out *bfree = 0x4000; *files = 0x400; *ffree = 0x200; return RES_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -