mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-26 13:52:21 +00:00
fusee: cleanup and simplify emummc logic
This commit is contained in:
parent
e62754ed56
commit
729447eab0
6 changed files with 35 additions and 124 deletions
|
@ -109,7 +109,7 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6
|
||||||
/* Treat the path as a folder with each part inside. */
|
/* Treat the path as a folder with each part inside. */
|
||||||
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
||||||
} else {
|
} else {
|
||||||
target_sector = sector;
|
/* If there are no parts, copy the origin path directly. */
|
||||||
strcpy(target_path, origin_path);
|
strcpy(target_path, origin_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src
|
||||||
/* Treat the path as a folder with each part inside. */
|
/* Treat the path as a folder with each part inside. */
|
||||||
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
||||||
} else {
|
} else {
|
||||||
target_sector = sector;
|
/* If there are no parts, copy the origin path directly. */
|
||||||
strcpy(target_path, origin_path);
|
strcpy(target_path, origin_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ static emudev_device_t *emudev_find_device(const char *name) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path) {
|
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit) {
|
||||||
emudev_device_t *device = NULL;
|
emudev_device_t *device = NULL;
|
||||||
|
|
||||||
if (name[0] == '\0' || devpart == NULL) {
|
if (name[0] == '\0' || devpart == NULL) {
|
||||||
|
@ -120,80 +120,6 @@ int emudev_mount_device(const char *name, const device_partition_t *devpart, con
|
||||||
if (devpart->emu_use_file)
|
if (devpart->emu_use_file)
|
||||||
strcpy(device->origin_path, origin_path);
|
strcpy(device->origin_path, origin_path);
|
||||||
|
|
||||||
device->num_parts = 0;
|
|
||||||
device->part_limit = 0;
|
|
||||||
|
|
||||||
device->devoptab.name = device->name;
|
|
||||||
device->devoptab.deviceData = device;
|
|
||||||
|
|
||||||
/* Initialize immediately. */
|
|
||||||
int rc = device->devpart.initializer(&device->devpart);
|
|
||||||
if (rc != 0) {
|
|
||||||
errno = rc;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate memory for our intermediate sector. */
|
|
||||||
device->tmp_sector = (uint8_t *)malloc(devpart->sector_size);
|
|
||||||
if (device->tmp_sector == NULL) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
device->setup = true;
|
|
||||||
device->registered = false;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int emudev_mount_device_multipart(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit) {
|
|
||||||
emudev_device_t *device = NULL;
|
|
||||||
|
|
||||||
if (name[0] == '\0' || devpart == NULL) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(name) > 32) {
|
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (emudev_find_device(name) != NULL) {
|
|
||||||
errno = EEXIST; /* Device already exists */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invalid number of parts. */
|
|
||||||
if (num_parts < 1) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Part limit is invalid. */
|
|
||||||
if ((part_limit % (1ull << 30)) != 0) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find an unused slot. */
|
|
||||||
for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) {
|
|
||||||
if (!g_emudev_devices[i].setup) {
|
|
||||||
device = &g_emudev_devices[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (device == NULL) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(device, 0, sizeof(emudev_device_t));
|
|
||||||
device->devoptab = g_emudev_devoptab;
|
|
||||||
device->devpart = *devpart;
|
|
||||||
strcpy(device->name, name);
|
|
||||||
strcpy(device->root_path, name);
|
|
||||||
strcat(device->root_path, ":/");
|
|
||||||
strcpy(device->origin_path, origin_path);
|
|
||||||
device->num_parts = num_parts;
|
device->num_parts = num_parts;
|
||||||
device->part_limit = part_limit;
|
device->part_limit = part_limit;
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,7 @@
|
||||||
|
|
||||||
#define EMUDEV_MAX_DEVICES 16
|
#define EMUDEV_MAX_DEVICES 16
|
||||||
|
|
||||||
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path);
|
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit);
|
||||||
int emudev_mount_device_multipart(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit);
|
|
||||||
int emudev_register_device(const char *name);
|
int emudev_register_device(const char *name);
|
||||||
int emudev_unregister_device(const char *name);
|
int emudev_unregister_device(const char *name);
|
||||||
int emudev_unmount_device(const char *name); /* also unregisters. */
|
int emudev_unmount_device(const char *name); /* also unregisters. */
|
||||||
|
|
|
@ -113,7 +113,7 @@ int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterat
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit) {
|
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit) {
|
||||||
efi_header_t hdr;
|
efi_header_t hdr;
|
||||||
efi_entry_t entry;
|
efi_entry_t entry;
|
||||||
size_t offset = 2 * 512; /* Sector #2. */
|
size_t offset = 2 * 512; /* Sector #2. */
|
||||||
|
@ -138,7 +138,7 @@ int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entr
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback(&entry, param, offset, disk, origin_path, is_multipart, num_parts, part_limit) != 0) {
|
if (callback(&entry, param, offset, disk, origin_path, num_parts, part_limit) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,10 +52,10 @@ typedef struct efi_header {
|
||||||
} __attribute__((packed, aligned(4))) efi_header_t;
|
} __attribute__((packed, aligned(4))) efi_header_t;
|
||||||
|
|
||||||
typedef int (*gpt_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk);
|
typedef int (*gpt_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk);
|
||||||
typedef int (*gpt_emu_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit);
|
typedef int (*gpt_emu_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, int num_parts, uint64_t part_limit);
|
||||||
|
|
||||||
int gpt_get_header(efi_header_t *out, FILE *disk, size_t sector_size);
|
int gpt_get_header(efi_header_t *out, FILE *disk, size_t sector_size);
|
||||||
int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterator_t callback, void *param);
|
int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterator_t callback, void *param);
|
||||||
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit);
|
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -352,7 +352,7 @@ static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *par
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit) {
|
static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, int num_parts, uint64_t part_limit) {
|
||||||
(void)entry_offset;
|
(void)entry_offset;
|
||||||
(void)disk;
|
(void)disk;
|
||||||
device_partition_t *parent = (device_partition_t *)param;
|
device_partition_t *parent = (device_partition_t *)param;
|
||||||
|
@ -416,16 +416,9 @@ static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_multipart) {
|
rc = emudev_mount_device(known_partitions[i].mount_point, &devpart, origin_path, num_parts, part_limit);
|
||||||
rc = emudev_mount_device_multipart(known_partitions[i].mount_point, &devpart, origin_path, num_parts, part_limit);
|
if (rc == -1) {
|
||||||
if (rc == -1) {
|
return -1;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rc = emudev_mount_device(known_partitions[i].mount_point, &devpart, origin_path);
|
|
||||||
if (rc == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (known_partitions[i].register_immediately) {
|
if (known_partitions[i].register_immediately) {
|
||||||
rc = emudev_register_device(known_partitions[i].mount_point);
|
rc = emudev_register_device(known_partitions[i].mount_point);
|
||||||
|
@ -564,7 +557,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
||||||
model.emu_use_file = false;
|
model.emu_use_file = false;
|
||||||
|
|
||||||
/* Mount emulated boot0 device. */
|
/* Mount emulated boot0 device. */
|
||||||
rc = emudev_mount_device("boot0", &model, NULL);
|
rc = emudev_mount_device("boot0", &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot0 device. */
|
/* Failed to mount boot0 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -586,7 +579,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
||||||
model.emu_use_file = false;
|
model.emu_use_file = false;
|
||||||
|
|
||||||
/* Mount emulated boot1 device. */
|
/* Mount emulated boot1 device. */
|
||||||
rc = emudev_mount_device("boot1", &model, NULL);
|
rc = emudev_mount_device("boot1", &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot1. */
|
/* Failed to mount boot1. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -602,7 +595,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
||||||
model.emu_use_file = false;
|
model.emu_use_file = false;
|
||||||
|
|
||||||
/* Mount emulated raw NAND device. */
|
/* Mount emulated raw NAND device. */
|
||||||
rc = emudev_mount_device("rawnand", &model, NULL);
|
rc = emudev_mount_device("rawnand", &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount raw NAND. */
|
/* Failed to mount raw NAND. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -626,7 +619,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, false, 0, 0);
|
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, 0, 0);
|
||||||
|
|
||||||
/* Close emulated raw NAND device. */
|
/* Close emulated raw NAND device. */
|
||||||
fclose(rawnand);
|
fclose(rawnand);
|
||||||
|
@ -647,7 +640,6 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
bool is_exfat;
|
bool is_exfat;
|
||||||
char emummc_boot0_path[0x300 + 1] = {0};
|
char emummc_boot0_path[0x300 + 1] = {0};
|
||||||
char emummc_boot1_path[0x300 + 1] = {0};
|
char emummc_boot1_path[0x300 + 1] = {0};
|
||||||
char emummc_rawnand_path[0x300 + 1] = {0};
|
|
||||||
|
|
||||||
/* Check if the SD card is EXFAT formatted. */
|
/* Check if the SD card is EXFAT formatted. */
|
||||||
rc = fsdev_is_exfat("sdmc");
|
rc = fsdev_is_exfat("sdmc");
|
||||||
|
@ -660,17 +652,22 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
/* Set EXFAT status. */
|
/* Set EXFAT status. */
|
||||||
is_exfat = (rc == 1);
|
is_exfat = (rc == 1);
|
||||||
|
|
||||||
|
/* Reject single part in FAT32. */
|
||||||
|
if (!is_exfat && (num_parts <= 1)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
/* We want a folder with the archive bit set. */
|
/* We want a folder with the archive bit set. */
|
||||||
rc = fsdev_get_attr(emummc_path);
|
rc = fsdev_get_attr(emummc_path);
|
||||||
|
|
||||||
/* Failed to get file DOS attributes. */
|
/* Failed to get file DOS attributes. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Our path is not a directory. */
|
/* Our path is not a directory. */
|
||||||
if (!(rc & AM_DIR)) {
|
if (!(rc & AM_DIR)) {
|
||||||
return -1;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the archive bit is not set. */
|
/* Check if the archive bit is not set. */
|
||||||
|
@ -680,7 +677,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
|
|
||||||
/* Failed to set file DOS attributes. */
|
/* Failed to set file DOS attributes. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,11 +691,11 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
|
||||||
|
|
||||||
/* Mount emulated boot0 device. */
|
/* Mount emulated boot0 device. */
|
||||||
rc = emudev_mount_device("boot0", &model, emummc_boot0_path);
|
rc = emudev_mount_device("boot0", &model, emummc_boot0_path, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot0 device. */
|
/* Failed to mount boot0 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register emulated boot0 device. */
|
/* Register emulated boot0 device. */
|
||||||
|
@ -706,7 +703,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
|
|
||||||
/* Failed to register boot0 device. */
|
/* Failed to register boot0 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup an emulation template for boot1. */
|
/* Setup an emulation template for boot1. */
|
||||||
|
@ -719,11 +716,11 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
|
||||||
|
|
||||||
/* Mount emulated boot1 device. */
|
/* Mount emulated boot1 device. */
|
||||||
rc = emudev_mount_device("boot1", &model, emummc_boot1_path);
|
rc = emudev_mount_device("boot1", &model, emummc_boot1_path, 0, 0);
|
||||||
|
|
||||||
/* Failed to mount boot1. */
|
/* Failed to mount boot1. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register emulated boot1 device. */
|
/* Register emulated boot1 device. */
|
||||||
|
@ -731,7 +728,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
|
|
||||||
/* Failed to register boot1 device. */
|
/* Failed to register boot1 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -9;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup a template for raw NAND. */
|
/* Setup a template for raw NAND. */
|
||||||
|
@ -740,19 +737,12 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
model.num_sectors = (256ull << 30) / model.sector_size;
|
model.num_sectors = (256ull << 30) / model.sector_size;
|
||||||
model.emu_use_file = true;
|
model.emu_use_file = true;
|
||||||
|
|
||||||
/* Prepare single raw NAND file path. */
|
|
||||||
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, 0);
|
|
||||||
|
|
||||||
/* Mount emulated raw NAND device from single or multiple parts. */
|
/* Mount emulated raw NAND device from single or multiple parts. */
|
||||||
if (!is_exfat) {
|
rc = emudev_mount_device("rawnand", &model, emummc_path, num_parts, part_limit);
|
||||||
rc = emudev_mount_device_multipart("rawnand", &model, emummc_path, num_parts, part_limit);
|
|
||||||
} else {
|
|
||||||
rc = emudev_mount_device("rawnand", &model, emummc_rawnand_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Failed to mount raw NAND. */
|
/* Failed to mount raw NAND. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register emulated raw NAND device. */
|
/* Register emulated raw NAND device. */
|
||||||
|
@ -760,7 +750,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
|
|
||||||
/* Failed to register raw NAND device. */
|
/* Failed to register raw NAND device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
return -1;
|
return -11;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open emulated raw NAND device. */
|
/* Open emulated raw NAND device. */
|
||||||
|
@ -768,15 +758,11 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
||||||
|
|
||||||
/* Failed to open emulated raw NAND device. */
|
/* Failed to open emulated raw NAND device. */
|
||||||
if (rawnand == NULL) {
|
if (rawnand == NULL) {
|
||||||
return -1;
|
return -12;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||||
if (!is_exfat) {
|
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, num_parts, part_limit);
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, true, num_parts, part_limit);
|
|
||||||
} else {
|
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_rawnand_path, false, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close emulated raw NAND device. */
|
/* Close emulated raw NAND device. */
|
||||||
fclose(rawnand);
|
fclose(rawnand);
|
||||||
|
|
Loading…
Reference in a new issue