From 4412ca091e6379def8bc836163c6b580df76619c Mon Sep 17 00:00:00 2001 From: crunchy Date: Wed, 23 Apr 2003 08:34:01 +0000 Subject: start restructuring --- libmpio/src/mpio.c | 1301 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1301 insertions(+) create mode 100644 libmpio/src/mpio.c (limited to 'libmpio/src/mpio.c') diff --git a/libmpio/src/mpio.c b/libmpio/src/mpio.c new file mode 100644 index 0000000..894b6f8 --- /dev/null +++ b/libmpio/src/mpio.c @@ -0,0 +1,1301 @@ +/* + * + * $Id: mpio.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * uses code from mpio_stat.c by + * Yuji Touya (salmoon@users.sourceforge.net) + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * */ + +#include +#include +#include +#include +#include +#include + +#include "cis.h" +#include "defs.h" +#include "debug.h" +#include "directory.h" +#include "io.h" +#include "mpio.h" +#include "smartmedia.h" +#include "fat.h" + +void mpio_bail_out(void); +void mpio_init_internal(mpio_t *); +void mpio_init_external(mpio_t *); +int mpio_check_filename(mpio_filename_t); + +int mpio_file_get_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, + mpio_callback_t, BYTE **); + +int mpio_file_put_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, + mpio_filetype_t, mpio_callback_t, BYTE *, int); + +static BYTE *mpio_model_name[] = { + "MPIO-DME", + "MPIO-DMG", + "MPIO-DMG+", + "MPIO-DMB", + "MPIO-DMB+", + "MPIO-DMK", + "MPIO-FD100", + "MPIO-FL100", + "MPIO-FY100", + "unknown" +}; + +static mpio_error_t mpio_errors[] = { + { MPIO_ERR_FILE_NOT_FOUND, + "The selected file can not be found." }, + { MPIO_ERR_NOT_ENOUGH_SPACE, + "There is not enough space left on the selected memory card." }, + { MPIO_ERR_FILE_EXISTS, + "The selected file already exists and can not be overwritten. Remove it first." }, + { MPIO_ERR_FAT_ERROR, + "Internal error while reading the FAT." }, + { MPIO_ERR_READING_FILE, + "The selected file can not be read." }, + { MPIO_ERR_PERMISSION_DENIED, + "There are not enough rights to access the file/directory." }, + { MPIO_ERR_WRITING_FILE, + "There are no permisson to write to the selected file." }, + { MPIO_ERR_DIR_TOO_LONG, + "The selected directory name is to long." }, + { MPIO_ERR_DIR_NOT_FOUND, + "The selected directory can not be found." }, + { MPIO_ERR_DIR_NOT_A_DIR, + "The selected directory is not a directory." }, + { MPIO_ERR_DIR_NAME_ERROR, + "The selected directory name is not allowed." }, + { MPIO_ERR_DIR_NOT_EMPTY, + "The selected directory is not empty." }, + { MPIO_ERR_DEVICE_NOT_READY, + "Could not open " MPIO_DEVICE "\n" + "Verify that the mpio module is loaded and " + "your MPIO is\nconnected and powered up.\n" }, + { MPIO_ERR_OUT_OF_MEMORY, + "Out of Memory." }, + { MPIO_ERR_INTERNAL, + "Oops, internal ERROR. :-(" }, + { MPIO_ERR_INT_STRING_INVALID, + "Internal Error: Supported is invalid!" } +}; + +static const int mpio_error_num = sizeof mpio_errors / sizeof(mpio_error_t); + +static int _mpio_errno = 0; + +#define MPIO_ERR_RETURN(err) { mpio_id3_end(m); _mpio_errno = err; return -1 ; } + +#define MPIO_CHECK_FILENAME(filename) \ + if (!mpio_check_filename(filename)) { \ + MPIO_ERR_RETURN(MPIO_ERR_INT_STRING_INVALID); \ + } + +void +mpio_bail_out(void){ + printf("I'm utterly confused and aborting now, sorry!"); + printf("Please report this to: mpio-devel@lists.sourceforge.net\n"); + exit(1); +} + +int +mpio_check_filename(mpio_filename_t filename) +{ + BYTE *p=filename; + + while (p < (filename + MPIO_FILENAME_LEN)) + { + if (*p) + return 1; + p++; + } + + return 0; +} + +void +mpio_init_internal(mpio_t *m) +{ + mpio_smartmedia_t *sm = &m->internal; + BYTE i_offset = 0x18; + + /* init main memory parameters */ + sm->manufacturer = m->version[i_offset]; + sm->id = m->version[i_offset + 1]; + sm->chips = 1; + if (!(mpio_id_valid(m->version[i_offset]))) + { + sm->manufacturer = 0; + sm->id = 0; + sm->size = 0; + debug("WARNING: no internal memory found\n"); + return; + } + + + /* look for further installed memory chips + * models with 1, 2 and 4 chips are known + * (there _really_ shouldn't be any other versions out there ...) + */ + while ((sm->chips < 4) && + (mpio_id_valid(m->version[i_offset + (2 * sm->chips)]))) + { + if(mpio_id2mem(sm->id) != + mpio_id2mem(m->version[i_offset + (2 * sm->chips) + 1])) + { + printf("Found a MPIO with internal chips of different sizes!"); + mpio_bail_out(); + } + sm->chips++; + } + + if ((sm->chips == 3) || (sm->chips > 4)) + { + printf("Found a MPIO with %d internal chips", sm->chips); + mpio_bail_out(); + } + + sm->size = sm->chips * mpio_id2mem(sm->id); + debugn(2, "found %d chip(s) with %d MB => %d MB internal mem\n", + sm->chips, mpio_id2mem(sm->id), sm->size); + + /* used for size calculations (see mpio_memory_free) */ + mpio_id2geo(sm->id, &sm->geo); + + /* read FAT information from spare area */ + sm->max_cluster = (sm->size * 1024) / 16; /* 1 cluster == 16 KB */ + sm->max_blocks = sm->max_cluster; + debugn(2, "max_cluster: %d\n", sm->max_cluster); + /* 16 bytes per cluster */ + sm->fat_size = (sm->max_cluster * 16) / SECTOR_SIZE; + debugn(2, "fat_size: %04x\n", sm->fat_size * SECTOR_SIZE); + sm->fat = malloc(sm->fat_size * SECTOR_SIZE); + /* fat will be read in mpio_init, so we can more easily handle + a callback function */ + + if (!(sm->fat_size)) + { + printf("Some values on the way to the FAT calculations did not compute. :-(\n"); + mpio_bail_out(); + } + + + /* Read directory from internal memory */ + sm->dir_offset=0; + sm->root = malloc (sizeof(mpio_directory_t)); + sm->root->name[0] = 0; + sm->root->next = NULL; + sm->root->prev = NULL; + mpio_rootdir_read(m, MPIO_INTERNAL_MEM); + sm->cdir = sm->root; +} + +void +mpio_init_external(mpio_t *m) +{ + mpio_smartmedia_t *sm = &(m->external); + BYTE e_offset = 0x20; + + /* heuristic to find the right offset for the external memory */ + while((e_offset < 0x3a) && !(mpio_id_valid(m->version[e_offset]))) + e_offset++; + + if ((mpio_id_valid(m->version[e_offset])) && + (m->model != MPIO_MODEL_FL100)) /* ignore external memory ATM until + we know how to support it! */ + { + sm->manufacturer = m->version[e_offset]; + sm->id = m->version[e_offset + 1]; + } else { + sm->manufacturer = 0; + sm->id = 0; + sm->chips = 0; + sm->size = 0; + } + + /* init memory parameters if external memory is found */ + if (sm->id != 0) + { + /* Read things from external memory (if available) */ + sm->size = mpio_id2mem(sm->id); + sm->chips = 1; /* external is always _one_ chip !! */ + + mpio_id2geo(sm->id, &sm->geo); + + if (sm->size < 16) + { + debug("Sorry, I don't believe this software works with " + "SmartMedia Cards less than 16MB\n" + "Proceed with care and send any findings to: " + "mpio-devel@lists.sourceforge.net\n"); + } + + /* for reading the spare area later! */ + sm->max_blocks = sm->size / 16 * 1024; /* 1 cluster == 16 KB */ + sm->spare = malloc(sm->max_blocks * 0x10); + } + + /* setup directory support */ + sm->dir_offset=0; + sm->root = malloc (sizeof(mpio_directory_t)); + sm->root->name[0] = 0; + sm->root->next = NULL; + sm->root->prev = NULL; + sm->cdir = sm->root; +} + +mpio_t * +mpio_init(mpio_callback_init_t progress_callback) +{ + mpio_t *new_mpio; + mpio_smartmedia_t *sm; + int id_offset; + BYTE i; + + new_mpio = malloc(sizeof(mpio_t)); + if (!new_mpio) { + debug ("Error allocating memory for mpio_t"); + return NULL; + } + memset(new_mpio, 0, sizeof(mpio_t)); + + new_mpio->fd = open(MPIO_DEVICE, O_RDWR); + + if (new_mpio->fd < 0) { + _mpio_errno = MPIO_ERR_DEVICE_NOT_READY; + return NULL; + } + + /* Read Version Information */ + mpio_io_version_read(new_mpio, new_mpio->version); + + /* fill in values */ + snprintf(new_mpio->firmware.id, 12, "%s", new_mpio->version); + /* fix for newer versions which have a 0x00 in their version */ + for (i=0x0c ; i<0x10 ; i++) + if (new_mpio->version[i] == 0x00) + new_mpio->version[i]=' '; + snprintf(new_mpio->firmware.major, 3, "%s", new_mpio->version + 0x0c); + snprintf(new_mpio->firmware.minor, 3, "%s", new_mpio->version + 0x0e); + snprintf(new_mpio->firmware.year, 5, "%s", new_mpio->version + 0x10); + snprintf(new_mpio->firmware.month, 3, "%s", new_mpio->version + 0x14); + snprintf(new_mpio->firmware.day, 3, "%s", new_mpio->version + 0x16); + + /* there are different identification strings! */ + if (strncmp(new_mpio->version, "MPIO", 4) == 0) { + /* strings: "MPIOxy " */ + id_offset = 4; + + /* string: "MPIO-xy " */ + if (new_mpio->version[id_offset] == '-') + id_offset++; + + /* identify different versions */ + switch (new_mpio->version[id_offset]) + { + case 'E': + new_mpio->model = MPIO_MODEL_DME; + break ; + case 'K': + new_mpio->model = MPIO_MODEL_DMK; + break ; + case 'G': + new_mpio->model = MPIO_MODEL_DMG; + if (new_mpio->version[id_offset+1] == 'P') + new_mpio->model = MPIO_MODEL_DMG_PLUS; + break ; + case 'B': + new_mpio->model = MPIO_MODEL_DMB; + if (new_mpio->version[id_offset+1] == 'P') + new_mpio->model = MPIO_MODEL_DMB_PLUS; + break; + default: + new_mpio->model = MPIO_MODEL_UNKNOWN; + } + } else if (strncmp(new_mpio->version, "FD100", 5) == 0) { + new_mpio->model = MPIO_MODEL_FD100; + } else if (strncmp(new_mpio->version, "FL100", 5) == 0) { + /* we assume this model is not supported */ + new_mpio->model = MPIO_MODEL_FL100; + debug("FL100 found: External memory is ignored, because we don't know how" + " to support it at the moment (MultiMediaCards instead of SmartMedia)\n"); + } else if (strncmp(new_mpio->version, "FY100", 5) == 0) { + new_mpio->model = MPIO_MODEL_FY100; + /* I assume this is like the FD100/FL100, I didn't had the chance to + look at a FY100 firmware yet. -mager */ + debug("FY100 found: Beware, this model is not tested and we don't know" + " if it does work!\n"); + } else { + new_mpio->model = MPIO_MODEL_UNKNOWN; + } + + if (new_mpio->model == MPIO_MODEL_UNKNOWN) { + debug("Unknown version string found!\n" + "Please report this to: mpio-devel@lists.sourceforge.net\n"); + hexdumpn(1, new_mpio->version, CMD_SIZE); + } + + /* internal init */ + mpio_init_internal(new_mpio); + + /* external init */ + mpio_init_external(new_mpio); + + /* read FAT/spare area */ + if (new_mpio->internal.id) + mpio_fat_read(new_mpio, MPIO_INTERNAL_MEM, progress_callback); + + /* read the spare area (for block mapping) */ + if (new_mpio->external.id) + { + sm = &new_mpio->external; + mpio_io_spare_read(new_mpio, MPIO_EXTERNAL_MEM, 0, + sm->size, 0, sm->spare, + (sm->max_blocks * 0x10), progress_callback); + mpio_zone_init(new_mpio, MPIO_EXTERNAL_MEM); + + /* card might be defect */ + if (mpio_bootblocks_read(new_mpio, MPIO_EXTERNAL_MEM)==0) + { + sm->fat = malloc(SECTOR_SIZE*sm->fat_size); + mpio_fat_read(new_mpio, MPIO_EXTERNAL_MEM, NULL); + mpio_rootdir_read(new_mpio, MPIO_EXTERNAL_MEM); + } + } + + /* set default charset for filename conversion */ + new_mpio->charset=strdup(MPIO_CHARSET); + + /* disable ID3 rewriting support */ + new_mpio->id3=0; + strncpy(new_mpio->id3_format, MPIO_ID3_FORMAT, INFO_LINE); + new_mpio->id3_temp[0]=0x00; + + return new_mpio; +} + +/* + * returns available memory + * + * free: give back free memory size + * + */ +int +mpio_memory_free(mpio_t *m, mpio_mem_t mem, int *free) +{ + if (mem==MPIO_INTERNAL_MEM) { + if (!m->internal.size) { + *free=0; + return 0; + } + *free=mpio_fat_free_clusters(m, mem); + return (m->internal.geo.SumSector + * SECTOR_SIZE / 1000 * m->internal.chips); + } + + if (mem==MPIO_EXTERNAL_MEM) { + if (!m->external.size) { + *free=0; + return 0; + } + *free=mpio_fat_free_clusters(m, mem); + return (m->external.geo.SumSector * SECTOR_SIZE / 1000); + } + + return 0; +} + +void +mpio_close(mpio_t *m) +{ + if (m) { + close(m->fd); + + if(m->internal.fat) + free(m->internal.fat); + if(m->external.fat) + free(m->external.fat); + + free(m); + } +} + +mpio_model_t +mpio_get_model(mpio_t *m) +{ + mpio_model_t r; + + if (m) + { + r = m->model; + } else { + r = MPIO_MODEL_UNKNOWN; + } + + return r; +} + +void +mpio_get_info(mpio_t *m, mpio_info_t *info) +{ + int max=INFO_LINE-1; + snprintf(info->firmware_id, max, "\"%s\"", m->firmware.id); + snprintf(info->firmware_version, max, "%s.%s", + m->firmware.major, m->firmware.minor); + snprintf(info->firmware_date, max, "%s.%s.%s", + m->firmware.day, m->firmware.month, m->firmware.year); + snprintf(info->model, max, "%s", mpio_model_name[m->model]); + + if (!m->internal.id) + { + snprintf(info->mem_internal, max, "not available"); + } else { + if (m->internal.chips == 1) + { + snprintf(info->mem_internal, max, "%3dMB (%s)", + mpio_id2mem(m->internal.id), + mpio_id2manufacturer(m->internal.manufacturer)); + } else { + snprintf(info->mem_internal, max, "%3dMB (%s) - %d chips", + mpio_id2mem(m->internal.id)*m->internal.chips, + mpio_id2manufacturer(m->internal.manufacturer), + m->internal.chips); + } + } + + if (m->external.id) + { + snprintf(info->mem_external, max, "%3dMB (%s)", + mpio_id2mem(m->external.id), + mpio_id2manufacturer(m->external.manufacturer)); + } else { + snprintf(info->mem_external, max, "not available"); + } + +} + + +int +mpio_file_get_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_callback_t progress_callback) +{ + return mpio_file_get_real(m, mem, filename, as, progress_callback, NULL); +} + +int +mpio_file_get(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback) +{ + return mpio_file_get_real(m, mem, filename, NULL, progress_callback, NULL); +} + +int +mpio_file_get_to_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback, BYTE **memory) +{ + return mpio_file_get_real(m, mem, filename, NULL, progress_callback, memory); +} + +int +mpio_file_get_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_callback_t progress_callback, + BYTE **memory) +{ + mpio_smartmedia_t *sm; + BYTE block[BLOCK_SIZE]; + int fd, towrite; + BYTE *p; + mpio_fatentry_t *f = 0; + struct utimbuf utbuf; + long mtime; + DWORD filesize, fsize; + BYTE abort = 0; + int merror; + + MPIO_CHECK_FILENAME(filename); + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if(as==NULL) { + as = filename; + } + + /* find file */ + p = mpio_dentry_find_name(m, mem, filename); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, filename); + + if (p) + f = mpio_dentry_get_startcluster(m, mem, p); + + if (f && p) { + filesize=fsize=mpio_dentry_get_filesize(m, mem, p); + + if (memory) + { + *memory = malloc(filesize); + } else { + unlink(filename); + fd = open(as, (O_RDWR | O_CREAT), (S_IRWXU | S_IRGRP | S_IROTH)); + } + + do + { + mpio_io_block_read(m, mem, f, block); + + if (filesize > BLOCK_SIZE) { + towrite = BLOCK_SIZE; + } else { + towrite = filesize; + } + + if (memory) + { + memcpy((*memory)+(fsize-filesize) , block, towrite); + } else { + if (write(fd, block, towrite) != towrite) { + debug("error writing file data\n"); + close(fd); + free (f); + MPIO_ERR_RETURN(MPIO_ERR_WRITING_FILE); + } + } + + filesize -= towrite; + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + if (abort) + debug("aborting operation"); + + } while ((((merror=(mpio_fatentry_next_entry(m, mem, f)))>0) && + (filesize>0)) && (!abort)); + + if (merror<0) + debug("defective block encountered!\n"); + + if(!memory) + { + close (fd); + free (f); + } + + /* read and copied code from mtools-3.9.8/mcopy.c + * to make this one right + */ + mtime=mpio_dentry_get_time(m, mem, p); + utbuf.actime = mtime; + utbuf.modtime = mtime; + utime(filename, &utbuf); + + } else { + debugn(2, "unable to locate the file: %s\n", filename); + _mpio_errno=MPIO_ERR_FILE_NOT_FOUND; + } + + return (fsize-filesize); +} + +int +mpio_file_put_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_filetype_t filetype, + mpio_callback_t progress_callback) +{ + return mpio_file_put_real(m, mem, filename, as, filetype, + progress_callback, NULL,0); +} + +int +mpio_file_put(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filetype_t filetype, mpio_callback_t progress_callback) +{ + return mpio_file_put_real(m, mem, filename, NULL, filetype, + progress_callback, NULL,0); +} + +int +mpio_file_put_from_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filetype_t filetype, + mpio_callback_t progress_callback, + BYTE *memory, int memory_size) +{ + return mpio_file_put_real(m, mem, filename, NULL, filetype, + progress_callback, memory, memory_size); +} + +int +mpio_file_put_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t i_filename, + mpio_filename_t o_filename, mpio_filetype_t filetype, + mpio_callback_t progress_callback, + BYTE *memory, int memory_size) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f, current, firstblock, backup; + WORD start; + BYTE block[BLOCK_SIZE]; + BYTE use_filename[INFO_LINE]; + int fd, toread; + struct stat file_stat; + struct tm tt; + time_t curr; + int id3; + + BYTE *p = NULL; + DWORD filesize, fsize, free, blocks; + BYTE abort = 0; + + if(o_filename == NULL) { + o_filename = i_filename; + } + + MPIO_CHECK_FILENAME(o_filename); + + if (mem==MPIO_INTERNAL_MEM) sm=&m->internal; + if (mem==MPIO_EXTERNAL_MEM) sm=&m->external; + + if (memory) + { + fsize=filesize=memory_size; + } else { + id3 = mpio_id3_do(m, i_filename, use_filename); + if (!id3) + strncat(use_filename, i_filename, INFO_LINE); + if (stat((const char *)use_filename, &file_stat)!=0) { + debug("could not find file: %s\n", use_filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + fsize=filesize=file_stat.st_size; + debugn(2, "filesize: %d\n", fsize); + } + + /* check if there is enough space left */ + mpio_memory_free(m, mem, &free); + if (free*1024entry; + } + + /* find file-id for internal memory */ + if (mem==MPIO_INTERNAL_MEM) + { + f->i_index=mpio_fat_internal_find_fileindex(m); + debugn(2, "fileindex: %02x\n", f->i_index); + f->i_fat[0x01]= f->i_index; + if (m->model >= MPIO_MODEL_FD100) + f->i_fat[0x0e] = f->i_index; + start = f->i_index; + + /* number of blocks needed for file */ + blocks = filesize / 0x4000; + if (filesize % 0x4000) + blocks++; + debugn(2, "blocks: %02x\n", blocks); + f->i_fat[0x02]=(blocks / 0x100) & 0xff; + f->i_fat[0x03]= blocks & 0xff; + } + + if (!memory) + { + /* open file for reading */ + fd = open(use_filename, O_RDONLY); + if (fd==-1) + { + debug("could not open file: %s\n", use_filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + + while ((filesize>BLOCK_SIZE) && (!abort)) { + + if (filesize>=BLOCK_SIZE) { + toread=BLOCK_SIZE; + } else { + toread=filesize; + } + + if (memory) + { + memcpy(block, memory+(fsize-filesize), toread); + } else { + if (read(fd, block, toread)!=toread) { + debug("error reading file data\n"); + close(fd); + MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); + } + } + filesize -= toread; + + /* get new free block from FAT and write current block out */ + memcpy(¤t, f, sizeof(mpio_fatentry_t)); + if (!(mpio_fatentry_next_free(m, mem, f))) + { + debug ("Found no free cluster during mpio_file_put\n" + "This should never happen\n"); + exit(-1); + } + mpio_fatentry_set_next(m ,mem, ¤t, f); + mpio_io_block_write(m, mem, ¤t, block); + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + } + + /* handle the last block to write */ + + if (filesize>=BLOCK_SIZE) { + toread=BLOCK_SIZE; + } else { + toread=filesize; + } + + if (memory) + { + memcpy(block, memory+(fsize-filesize), toread); + } else { + if (read(fd, block, toread)!=toread) { + debug("error reading file data\n"); + close(fd); + MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); + } + } + filesize -= toread; + + /* mark end of FAT chain and write last block */ + mpio_fatentry_set_eof(m ,mem, f); + mpio_io_block_write(m, mem, f, block); + + if (!memory) + close(fd); + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + + if (abort) + { /* delete the just written blocks, because the user + * aborted the operation + */ + debug("aborting operation\n"); + debug("removing already written blocks\n"); + + filesize=fsize; + + memcpy(¤t, &firstblock, sizeof(mpio_fatentry_t)); + memcpy(&backup, &firstblock, sizeof(mpio_fatentry_t)); + + while (mpio_fatentry_next_entry(m, mem, ¤t)) + { + mpio_io_block_delete(m, mem, &backup); + mpio_fatentry_set_free(m, mem, &backup); + memcpy(&backup, ¤t, sizeof(mpio_fatentry_t)); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + } + mpio_io_block_delete(m, mem, &backup); + mpio_fatentry_set_free(m, mem, &backup); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + + } else { + if (memory) + { + time(&curr); + tt = * localtime(&curr); + } + mpio_dentry_put(m, mem, + o_filename, strlen(o_filename), + ((memory)?mktime(&tt):file_stat.st_ctime), + fsize, start, 0x20); + } + + mpio_id3_end(m); + + return fsize-filesize; +} + +int +mpio_file_switch(mpio_t *m, mpio_mem_t mem, + mpio_filename_t file1, mpio_filename_t file2) +{ + BYTE *p1, *p2; + + /* find files */ + p1 = mpio_dentry_find_name(m, mem, file1); + if (!p1) + p1 = mpio_dentry_find_name_8_3(m, mem, file1); + + p2 = mpio_dentry_find_name(m, mem, file2); + if (!p2) + p2 = mpio_dentry_find_name_8_3(m, mem, file2); + + if ((!p1) || (!p2)) + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + + mpio_dentry_switch(m, mem, p1, p2); + + return 0; +} + +int +mpio_file_rename(mpio_t *m, mpio_mem_t mem, + mpio_filename_t old, mpio_filename_t new) +{ + BYTE *p; + + /* find files */ + p = mpio_dentry_find_name(m, mem, old); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, old); + + if (!p) + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + + mpio_dentry_rename(m, mem, p, new); + + return 0; +} + +int mpio_file_move(mpio_t *m,mpio_mem_t mem, mpio_filename_t file, + mpio_filename_t after) +{ + BYTE *p1,*p2; + + if( ( p1 = mpio_dentry_find_name(m,mem,file)) == NULL ) { + if( (p1 = mpio_dentry_find_name_8_3(m, mem, file)) == NULL ) { + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + + if(after!=NULL) { + if( ( p2 = mpio_dentry_find_name(m,mem,after)) == NULL ) { + if( (p2 = mpio_dentry_find_name_8_3(m, mem, after)) == NULL ) { + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + } + + fprintf(stderr," -- moving '%s' after '%s'\n",file,after); + + mpio_dentry_move(m,mem,p1,p2); + + return 0; +} + +int +mpio_memory_format(mpio_t *m, mpio_mem_t mem, + mpio_callback_t progress_callback) +{ + int data_offset; + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + DWORD clusters; + BYTE abort = 0; + BYTE *cis, *mbr, *pbr; + BYTE defect[SECTOR_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + sm=&m->internal; + data_offset = 0x01; + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + data_offset = 0x02; + } + + clusters = sm->size*128; + + + /* TODO: read and write "Config.dat" so the player does not become "dumb" */ + if (mem==MPIO_INTERNAL_MEM) + { + /* clear the fat before anything else, so we can mark clusters defective + * if we found a bad block + */ + /* external mem must be handled diffrently, + * see comment(s) below! + */ + mpio_fat_clear(m, mem); + f = mpio_fatentry_new(m, mem, data_offset, FTYPE_MUSIC); + do + { + + if (!mpio_io_block_delete(m, mem, f)) + mpio_fatentry_set_defect(m, mem, f); + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)(f->entry, sm->max_cluster + 1); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)(f->entry, sm->max_cluster + 1); + } + } + + } while (mpio_fatentry_plus_plus(f)); + free(f); + } + + if (mem == MPIO_EXTERNAL_MEM) { + /* delete all blocks! */ + + i=0; + while (i < sm->max_blocks) + { + mpio_io_block_delete_phys(m, mem, (i * BLOCK_SECTORS)); + i++; + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)(i, sm->max_blocks); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)(i, sm->max_blocks); + } + } + + + } + + /* generate "defect" first block */ + mpio_io_sector_write(m, mem, MPIO_BLOCK_DEFECT, defect); + + /* format CIS area */ + f = mpio_fatentry_new(m, mem, MPIO_BLOCK_CIS, FTYPE_MUSIC); + /* mpio_io_block_delete(m, mem, f); */ + free(f); + cis = (BYTE *)mpio_cis_gen(); /* hmm, why this cast? */ + mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS, cis); + mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS+1, cis); + free(cis); + + /* generate boot blocks ... */ + mbr = (BYTE *)mpio_mbr_gen(m->external.size); + pbr = (BYTE *)mpio_pbr_gen(m->external.size); + /* ... copy the blocks to internal memory structurs ... */ + memcpy(sm->cis, cis, SECTOR_SIZE); + memcpy(sm->mbr, mbr, SECTOR_SIZE); + memcpy(sm->pbr, pbr, SECTOR_SIZE); + /* ... and set internal administration accordingly */ + mpio_mbr_eval(sm); + mpio_pbr_eval(sm); + + if (!sm->fat) /* perhaps we have to build a new FAT */ + sm->fat=malloc(sm->fat_size*SECTOR_SIZE); + mpio_fat_clear(m, mem); + + /* TODO: for external memory we have to work a little "magic" + * to identify and mark "bad blocks" (because we have a set of + * spare ones! + */ + } + + mpio_rootdir_clear(m, mem); + + /* this writes the FAT *and* the root directory */ + mpio_fat_write(m, mem); + + if (progress_callback) + (*progress_callback)(sm->max_cluster+1, sm->max_cluster+1); + + return 0; +} + +int +mpio_file_del(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback) +{ + BYTE *p; + mpio_smartmedia_t *sm; + mpio_fatentry_t *f, backup; + DWORD filesize, fsize; + BYTE abort=0; + + MPIO_CHECK_FILENAME(filename); + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if ((strcmp(filename, "..") == 0) || + (strcmp(filename, ".") == 0)) + { + debugn(2, "directory name not allowed: %s\n", filename); + MPIO_ERR_RETURN(MPIO_ERR_DIR_NAME_ERROR); + } + + /* find file */ + p = mpio_dentry_find_name(m, mem, filename); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, filename); + + if (p) + f = mpio_dentry_get_startcluster(m, mem, p); + + if (f && p) { + if (mpio_dentry_is_dir(m, mem, p) == MPIO_OK) + { + /* ugly */ + mpio_directory_cd(m, mem, filename); + if (mpio_directory_is_empty(m, mem, sm->cdir) != MPIO_OK) + { + mpio_directory_cd(m, mem, ".."); + MPIO_ERR_RETURN(MPIO_ERR_DIR_NOT_EMPTY); + } else { + mpio_directory_cd(m, mem, ".."); + } + } + + filesize=fsize=mpio_dentry_get_filesize(m, mem, p); + do + { + debugn(2, "sector: %4x\n", f->entry); + + mpio_io_block_delete(m, mem, f); + + if (filesize != fsize) + mpio_fatentry_set_free(m, mem, &backup); + + memcpy(&backup, f, sizeof(mpio_fatentry_t)); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)((fsize-filesize), fsize); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)((fsize-filesize), fsize); + } + } + + } while (mpio_fatentry_next_entry(m, mem, f)); +/* mpio_io_block_delete(m, mem, &backup); */ + mpio_fatentry_set_free(m, mem, &backup); + free(f); + + } else { + debugn(2, "unable to locate the file: %s\n", filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + + mpio_dentry_delete(m, mem, filename); + + return MPIO_OK; +} + +int +mpio_sync(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (!sm->size) + return 0; + + /* this writes the FAT *and* the root directory */ + return mpio_fat_write(m, mem); +} + +int +mpio_health(mpio_t *m, mpio_mem_t mem, mpio_health_t *r) +{ + mpio_smartmedia_t *sm; + int i, j, zones; + mpio_fatentry_t *f; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + r->num = sm->chips; + + f = mpio_fatentry_new(m, mem, 0x00, FTYPE_MUSIC); + + for (i=0 ; i < sm->chips; i++) + { + r->data[i].spare = 0; + r->data[i].total = (sm->max_cluster / sm->chips); + r->data[i].broken = 0; + /* now count the broken blocks */ + for(j=0; jdata[i].total; j++) + { + if (mpio_fatentry_is_defect(m, mem, f)) + r->data[i].broken++; + mpio_fatentry_plus_plus(f); + } + } + + free(f); + + return MPIO_OK; + } + + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + + zones = sm->max_cluster / MPIO_ZONE_LBLOCKS + 1; + r->num = zones; + + for(i=0; idata[i].spare = (i?24:22); /* first zone has only 23 due to CIS */ + r->data[i].total = MPIO_ZONE_PBLOCKS; + r->data[i].broken = 0; + /* now count the broken blocks */ + for(j=0; jzonetable[i][j] == MPIO_BLOCK_DEFECT) + r->data[i].broken++; + } + if (r->data[i].spare < r->data[i].broken) + debug("(spare blocks expect trouble!\n"); + } + return MPIO_OK; + } + + return MPIO_ERR_INTERNAL; +} + +int +mpio_memory_dump(mpio_t *m, mpio_mem_t mem) +{ + BYTE block[BLOCK_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + hexdump(m->internal.fat, m->internal.max_blocks*0x10); + hexdump(m->internal.root->dir, DIR_SIZE); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + hexdump(m->external.spare, m->external.max_blocks*0x10); + hexdump(m->external.fat, m->external.fat_size*SECTOR_SIZE); + hexdump(m->external.root->dir, DIR_SIZE); + } + + for (i = 0 ; i<=0x100 ; i++) + mpio_io_sector_read(m, mem, i, block); + + return 0; +} + +int +mpio_errno(void) +{ + int no = _mpio_errno; + _mpio_errno = 0; + + return no; +} + +char * +mpio_strerror(int err) +{ + int i; + + if (err >= 0) return NULL; + + for (i = 0; i < mpio_error_num; i++) { + if (mpio_errors[i].id == err) + return mpio_errors[i].msg; + } + + return NULL; +} + +void +mpio_perror(char *prefix) +{ + char *msg = mpio_strerror(_mpio_errno); + + if (msg == NULL) return; + + if (prefix) + fprintf(stderr, "%s: %s\n", prefix, msg); + else + fprintf(stderr, "%s\n", msg); +} -- cgit v1.2.3