📄 tmfat32.c
字号:
/*
* Copyright (C) 2003 Koninklijke Philips Electronics N.V.,
* All Rights Reserved.
*
* This source code and any compilation or derivative thereof is the
* proprietary information of Koninklijke Philips Electronics N.V.
* and is confidential in nature.
* Under no circumstances is this software to be exposed to or placed
* under an Open Source License of any type without the expressed
* written permission of Koninklijke Philips Electronics N.V.
*
*----------------------------------------------------------*/
/*!
* \file tmFat32.c
*
* This file implements the tmFat32 API.
*
*/
/*-----------------------------------------------------------
*
* %version: ds08#22 %
* instance: DS_4
* %date_created: Thu Nov 09 17:40:12 2006 %
*
*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Standard include files:
//-----------------------------------------------------------------------------
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
//-----------------------------------------------------------------------------
// Project include files:
//-----------------------------------------------------------------------------
//
#if USE_GENERIC_C
#include <unistd.h>
#include <dirent.h>
#else
#include <tmNxTypes.h>
#include <tmNxCompId.h>
#include <tmDbg.h>
#include <tmbslCore.h>
#include <tmosal.h>
#include <tmbslIde.h>
#include <IODrivers.h>
#include <sys/syslimits.h>
#include <tmFat32.h>
#include <tmFat32Device.h>
#include <tmFat32Ide.h>
#endif
#include <tmFat32Private.h>
#include <tmFat32Debug.h>
#include <tmFat32Ram.h>
//-----------------------------------------------------------------------------
// Types and defines:
//-----------------------------------------------------------------------------
// Set default device driver
#if USE_GENERIC_C || USE_SIMULATOR
#define TMFAT_DEFAULT_DEVICE tmFat32_RamDevice
#else
#define TMFAT_DEFAULT_DEVICE tmFat32_IdeDevice
#endif
#if 1 // Optimized to write as many contiguous clusters as possible
#define WRITE_METHOD SET_CLUSTER_CONTENT_NOCACHE
#else // Non-optimized to write one cluster at a time
#define WRITE_METHOD SET_CLUSTER_CONTENT
#endif
typedef struct DSKSZTOSECPERCLUS
{
UInt32 DiskSize;
UInt8 SecPerClusVal;
} DSKSZTOSECPERCLUS;
#define USE_FILE_SEARCH_RESULTS 0
#define USE_DIR_SEARCH_RESULTS 1
#define CLUSTER_TO_SECTOR(clus) (gptmFat32_PrivateInfo->dataAreaBase + \
((clus) - gptmFat32_PrivateInfo->rootDirCluster) * \
gptmFat32_PrivateInfo->sectorsPerCluster)
//-----------------------------------------------------------------------------
// Global data:
//-----------------------------------------------------------------------------
//
extern tmFat32_Devices_t tmFat32DeviceList[]; // List of supported devices
ptmFat32_FS_t gptmFat32_PrivateInfo;
static tmFat32_FS_t *tmFat32_List = Null; // List of mounted tmFat32 file systems.
#if USE_REENTRANCY
Bool gtmFat32_Locked = False;
#if defined(__TCS__)
tmosalMutexHandle_t gtmFat32_Lock;
#endif // defined(__TCS__)
#endif // USE_REENTRANCY
// Scratch buffers
static char temp_cd[PATH_MAX+1]; // 1024 + 1 Current directory
static UInt8 temp_buffer[32 * 1024]; // 32K Biggest legal cluster
static char temp_path[PATH_MAX+1]; // 1024 + 1 Temp full pathname
static char norm_path1[PATH_MAX+1]; // 1024 + 1 Normalized pathname
static char norm_path2[PATH_MAX+1]; // 1024 + 1 Normalized pathname
static UInt8 temp_dir[DIR_ENTRY_SIZE * (0x3F + 1)]; // 2048 Max possible long name entries
// plus final short name entry
static UInt8 temp_dir2[DIR_ENTRY_SIZE * (0x3F + 1)]; // Another copy
static UInt16 temp_fname[256]; // Long file name (UCS2) is maximum 255, not including trailing NUL.
#if USE_MML
static tmFat32_FS_t temp_fs; // So we can create a heap
#endif
// Illegal characters in a short name
static char illegal_short[] = {0x22, 0x2A, 0x2B, 0x2C, /* 0x2E, */ 0x2F,
0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x5B, 0x5C, 0x5D, 0x7C};
// Illegal characters in a long name
static char illegal_long[] = {0x22, 0x2A, /* 0x2B , 0x2C, */ /* 0x2E, */ 0x2F,
0x3A, /* 0x3B,*/ 0x3C, /*0x3D,*/ 0x3E, 0x3F,
/*0x5B,*/ 0x5C, /*0x5D,*/ 0x7C};
//-----------------------------------------------------------------------------
// Internal Prototypes:
//-----------------------------------------------------------------------------
//
static void UTIL_add_volume(tmFat32_FS_t * p);
static void UTIL_delete_volume(tmFat32_FS_t * p);
static void UTIL_date_time(int op, int what, UInt8 *d, time_t *tout, tmosalDateTime_t *tin);
static int UTIL_get_short_name(UInt8 *src, String name);
static int UTIL_get_long_name(UInt8 *src, String name);
static UInt8 *UTIL_get_cluster_address(UInt32 cluster);
static int UTIL_fat_content(int op, UInt32 entry, UInt32 value, UInt32 *result);
static int UTIL_find_file(String fullpath, ptmFat32_File_t info);
static int UTIL_allocate_cluster(UInt32 *clust, UInt32 chain, Bool clear);
static Bool UTIL_is_FAT(ptmFat32_FS_t p, UInt8 part_type);
static Bool UTIL_is_FAT32(ptmFat32_FS_t p);
static int UTIL_find_magic_sector(tmFat32_DeviceDriver_Read Read,
tmFat32_FS_t *p,UInt64 *sector, UInt8 *secbuf);
static Bool UTIL_find_partition(ptmFat32_FS_t p, UInt64 mbrBase, int index, int depth);
static int UTIL_compare_dos_names(String s1, String s2);
// File I/O driver functions
static tmErrorCode_t _IOD_Init (void);
static tmErrorCode_t _IOD_Term (void);
static Int32 _IOD_Access (String path, Int32 mode);
static Int32 _IOD_Stat (String path, struct stat *buf);
static Int32 _IOD_Fstat ( Int32 file, struct stat *buf);
static Int32 _IOD_Open ( String path, Int32 oflag, Int32 mode);
static Int32 _IOD_Read ( Int32 file, Pointer buf, Int32 nbyte);
static Int32 _IOD_Seek ( Int32 file, Int32 offset, Int32 whence);
static Int32 _IOD_Close ( Int32 file);
static Int32 _IOD_Seek ( Int32 file, Int32 offset, Int32 whence);
static Int32 _IOD_Sync (void);
static Int32 _IOD_FSync (Int32 file);
static DIR* _IOD_Opendir ( ConstString path );
static void _IOD_Rewinddir( DIR* dir );
static struct dirent* _IOD_Readdir ( DIR* dir );
static Int32 _IOD_Closedir ( DIR* dir);
static Int32 _IOD_Mkdir ( String path, Int32 mode );
static Int32 _IOD_Rmdir ( String path );
static Int32 _IOD_Unlink ( String path );
static Int32 _IOD_Move ( String src, String dest );
static Int32 _IOD_Link ( String src, String dest );
static Int32 _IOD_Fcntl ( Int32 file, Int32 cmd, Int32 flags);
static Int32 _IOD_Write ( Int32 file, Pointer buf, Int32 nbyte);
static tmErrorCode_t tmFat32_Term_ForReal(tmFat32_FS_t * p);
//-----------------------------------------------------------------------------
// Internal Functions
//-----------------------------------------------------------------------------
//
static tmErrorCode_t UTIL_Ucs2toUtf8(const UInt16 *ch, UInt8 *utf8)
{
if(ch && (ch[0]==(UInt16)0xfeff || ch[0]==(UInt16)0xfffe)){
ch++;
}
if(utf8==NULL) {
int bytesNeeded = 0, i;
for (i=0; ch[i]/* i<ch.length */; i++) {
if (ch[i] < 0x80) {
++bytesNeeded;
} else if (ch[i] < 0x0800) {
bytesNeeded += 2;
} else {
bytesNeeded += 3;
}
#if 0 /* This is only for UTF32? */
if (ch[i] < 0x10000) {
bytesNeeded += 3;
}
else {
bytesNeeded += 4;
}
#endif
}
return bytesNeeded;
} else {
int i, bytes;
for(i=0, bytes = 0; ch[i]/* i<ch.length */; i++) {
if(ch[i] < 0x80) {
utf8[bytes++] = (UInt8)ch[i];
} else if (ch[i] < 0x0800) {
utf8[bytes++] = (UInt8)(ch[i]>> 6 | 0xC0);
utf8[bytes++] = (UInt8)((ch[i] & 0x3F) | 0x80);
} else {
utf8[bytes++] = (UInt8)(ch[i]>> 12 | 0xE0);
utf8[bytes++] = (UInt8)((ch[i]>> 6 & 0x3F) | 0x80);
utf8[bytes++] = (UInt8)((ch[i] & 0x3F) | 0x80);
}
#if 0 /* This is only for UTF32? */
else if (ch[i] < 0x10000) {
utf8[bytes++] = (UInt8)(ch[i]>> 12 | 0xE0);
utf8[bytes++] = (UInt8)((ch[i]>> 6 & 0x3F) | 0x80);
utf8[bytes++] = (UInt8)((ch[i] & 0x3F) | 0x80);
}
else {
utf8[bytes++] = (UInt8)(ch[i]>> 18 | 0xF0);
utf8[bytes++] = (UInt8)((ch[i]>> 12 & 0x3F) | 0x80);
utf8[bytes++] = (UInt8)((ch[i]>> 6 & 0x3F) | 0x80);
utf8[bytes++] = (UInt8)((ch[i] & 0x3F) | 0x80);
}
#endif
}
utf8[bytes++] = 0; /* NULL-terminator */
return TM_OK/* utf8 */;
}
}
#if USE_MML
// tmml wrapper functions
static tmErrorCode_t UTIL_create_heap(UInt32 size, ptmmlMmspHandle_t heap)
{
tmErrorCode_t rval;
// tmmlMmspNormal is for backward compatibility, not supposed to use it?
// if((rval = tmmlCreate(heap, size, tmmlMmspNormal)) != TM_OK)
if((rval = tmmlCreate(heap, size, tmmlMmspNone)) != TM_OK)
{
TMFAT_DEBUG1 ("tmmlCreate failed: rval = %#x\n", rval);
}
return rval;
}
static tmErrorCode_t UTIL_destroy_heap(ptmmlMmspHandle_t heap)
{
tmErrorCode_t rval;
if((rval = tmmlDelete(*heap)) != TM_OK)
{
TMFAT_DEBUG2 ("tmmlDelete failed: heap = %#x, rval = %#x\n",
heap, rval);
}
else
{
*heap = 0;
}
return rval;
}
static pVoid UTIL_malloc(size_t size)
{
ptmFat32_FS_t p = GFS;
tmErrorCode_t rval;
pVoid pReturn = Null;
TMFAT_ASSERT (p != Null);
rval = tmmlMalloc(p->heap, size, &pReturn, tmmlMallocCleared);
if(rval == TM_OK)
{
// TMFAT_DEBUG1 ("UTIL_malloc: pReturn = %#x\n", pReturn);
}
else
{
TMFAT_DEBUG1 ("UTIL_malloc failed: Null, rval = %#x\n", rval);
}
return pReturn;
}
static void UTIL_free(pVoid pFree)
{
tmmlFree(pFree);
}
#endif // USE_MML
// Cache utilities
// Flush cache. For FAT cache the sector number on the
// disk or the entire FAT cache. For DATA cache the cluster number
// or the entire DATA cache. If flag is FULL_FLUSH then the
// entire appropriate cache is flushed.
static tmErrorCode_t UTIL_flush_cache(int which, UInt32 cluster, UInt64 sector, int flag)
{
tmErrorCode_t status = TM_OK;
ptmFat32_FS_t p = GFS;
UInt64 sec;
UInt32 count;
UInt32 i;
UInt32 offset;
Bool doit;
if (which == FAT_CACHE)
{
Int64 mirrorOffset; // Sector offset to the mirror FAT from the active FAT
if (p->fatMirroring)
{
if (p->activeFat == 0)
mirrorOffset = p->fatSize; // Mirror is second FAT
else
mirrorOffset = -p->fatSize; // Mirror is first FAT
}
else
{
mirrorOffset = 0;
}
// TMFAT_DEBUG2("Flushing FAT cache, (%s) sector=%llu.\n",
// flag == FULL_FLUSH ? "FULL" : "PARTIAL", sector);
for (i = 0; i < p->fatNumSectors; i++)
{
if (flag == FULL_FLUSH)
{
doit = p->fatSectorDirty[i];
sector = p->fatSector[i];
}
else
doit = (sector == p->fatSector[i]) && p->fatSectorDirty[i];
if (doit)
{
offset = i * (p->dev->Info->bytesPerSector / sizeof(UInt32));
status = p->dev->Write(p->dev->Info,
sector,
1,
(UInt8 *) &p->fatCache[offset]);
if (status != TM_OK)
goto done;
// Once more, with feeling
if (p->fatMirroring)
{
status = p->dev->Write(p->dev->Info,
sector + mirrorOffset,
1,
(UInt8 *) &p->fatCache[offset]);
if (status != TM_OK)
goto done;
}
p->fatSectorDirty[i] = False;
if (flag != FULL_FLUSH)
break;
}
}
}
else
{
// TMFAT_DEBUG2("Flushing DATA cache, cluster=%u, %s.\n",
// cluster, (flag == FULL_FLUSH) ? "FULL" : "PARTIAL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -