[C/C++/PPC Platform] What's wrong here?

Joined
Apr 7, 2009
Messages
647
Reaction score
26
I'm using devkitPro; Programmer's Notepad.

This code isn't compiling:

launch.cpp
PHP:
#include "launch.h"

extern void __exception_closeall();
extern s32 __IOS_ShutdownSubsystems();

s32 getImageType(void * addr)
{
	Elf32_Ehdr *ehdr; /* Elf header structure pointer */

    ehdr = (Elf32_Ehdr *) addr;

    if (!IS_ELF (*ehdr))
        return 0;

    if (ehdr->e_type != ET_EXEC)
        return -1;

    if (ehdr->e_machine != EM_PPC)
        return -1;

    return 1;
}

int launch(char locdir[999], char filname[13])
{
	//Set this...
	
	for(unsigned int i = 0; i < strlen(locdir); i++)
	{
		if((i+1) != strlen(locdir))
			locdir[i] = locdir[i +1];
		else
			locdir[i] = '/';
	}
	printf("%s", locdir);
	sleep(5000);
	//Variables
	FATFS ffs;
	DIR appdir;
	
	char filename[50+1];
	char thefile[1][50];
	FILINFO finfo;
	FIL fp;
	
	WORD bytes_read;
	u32 bytes_read_total;
	u8 *data = (u8 *)0x92000000;
	s32 res;
	u32 level;
	
	void (*ep)();
	
	//Mount FAT FS
	if(f_mount(0, &ffs) != FR_OK)
		return -1;
		
	res = f_opendir(&appdir, locdir);
	
	if(res != FR_OK)
		return -1;
		
	memset(&finfo, 0, sizeof(finfo));
	f_readdir(&appdir, &finfo);
	
	while(strlen(finfo.fname) != 0)
	{
		if(strtoupper(finfo.fname) == strtoupper(filname))
		{
			memcpy(thefile[0], finfo.fname, strlen(finfo.fname));
			printf(thefile[0]);
			sleep(5000);
		}
		
		f_readdir(&appdir, &finfo);
	}
	snprintf(filename, 50, "%s%s", locdir, filname);
	
	//"Pre-checking" phase
	if(f_stat(filename, &finfo) != FR_OK)
		return -1;
	if(f_open(&fp, filename, FA_READ) != FR_OK)
		return -1;
	
	//Now that we're done with our checks, let's start reading the file.
	bytes_read = bytes_read_total = 0;
	
	while(bytes_read < finfo.fsize)
	{
		if(f_read(&fp, data + bytes_read_total, 0x200, &bytes_read) != FR_OK)
			return -1;
			
		if(bytes_read == 0)//Nothing to read, we're done
			break;//Exit this loop
			
		bytes_read_total += bytes_read;
	}
	
	res = getImageType(data);
	
	if(res == 0)//ELF
	{
		
	}
	else//Probably a DOL...
	{
		ep = (void(*)())load_dol_image(data);
	}
	f_close(&fp);
	sd_deinit();
	
	__IOS_ShutdownSubsystems();
	_CPU_ISR_Disable (level);
	__exception_closeall ();
	//This is it!
	ep();
	//And we're back.
	_CPU_ISR_Restore (level);
	
	//Successful?
	return 0;
}

launch.h
PHP:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <ogcsys.h>
#include <gccore.h>
#include <ogc/ios.h>
#include <unistd.h>

#include "ops.h"

#include "sdio.h"
#include "tff.h"
#include "dol.h"
#include "elf_abi.h"

#include "asm.h"
#include "processor.h"

s32 getImageType(void * addr);
int launch(char locdir[999], char filename[13]);

Makefile
Code:
#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPPC)),)
$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=<path to>devkitPPC)
endif

include $(DEVKITPPC)/wii_rules

#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET		:=	$(notdir $(CURDIR))
BUILD		:=	build
SOURCES		:=	source source/libwiigui source/images source/fonts source/sounds
DATA		:=	data  
INCLUDES	:=	source

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------

CFLAGS		=	-g -O2 -Wall $(MACHDEP) $(INCLUDE)
CXXFLAGS	=	-save-temps -Xassembler [email protected] $(CFLAGS)
LDFLAGS		=	-g $(MACHDEP) -Wl,-Map,$(notdir $@).map

#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS :=	-lpng -lz -lfat -lwiiuse -lbte -lasnd -logc -lvorbisidec -lfreetype
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS	:= $(PORTLIBS)

#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------

export OUTPUT	:=	$(CURDIR)/$(TARGETDIR)/$(TARGET)
export VPATH	:=	$(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
export DEPSDIR	:=	$(CURDIR)/$(BUILD)

#---------------------------------------------------------------------------------
# automatically build a list of object files for our project
#---------------------------------------------------------------------------------
CFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
sFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
SFILES		:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
TTFFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ttf)))
PNGFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png)))
OGGFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ogg)))
PCMFILES	:=	$(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcm)))
	
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
	export LD	:=	$(CC)
else
	export LD	:=	$(CXX)
endif

export OFILES	:=	$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \
					$(sFILES:.s=.o) $(SFILES:.S=.o) \
					$(TTFFILES:.ttf=.ttf.o) $(PNGFILES:.png=.png.o) \
					$(OGGFILES:.ogg=.ogg.o) $(PCMFILES:.pcm=.pcm.o)

#---------------------------------------------------------------------------------
# build a list of include paths
#---------------------------------------------------------------------------------
export INCLUDE	:=	$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
					$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
					-I$(CURDIR)/$(BUILD) \
					-I$(LIBOGC_INC) -I$(PORTLIBS)/include/freetype2

#---------------------------------------------------------------------------------
# build a list of library paths
#---------------------------------------------------------------------------------
export LIBPATHS	:=	$(foreach dir,$(LIBDIRS),-L$(dir)/lib) \
					-L$(LIBOGC_LIB)

export OUTPUT	:=	$(CURDIR)/$(TARGET)
.PHONY: $(BUILD) clean

#---------------------------------------------------------------------------------
$(BUILD):
	@[ -d $@ ] || mkdir -p $@
	@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile

#---------------------------------------------------------------------------------
clean:
	@echo clean ...
	@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol

#---------------------------------------------------------------------------------
run:
	wiiload $(OUTPUT).dol

#---------------------------------------------------------------------------------
reload:
	wiiload -r $(OUTPUT).dol

#---------------------------------------------------------------------------------
else

DEPENDS	:=	$(OFILES:.o=.d)

#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).dol: $(OUTPUT).elf
$(OUTPUT).elf: $(OFILES)

#---------------------------------------------------------------------------------
# This rule links in binary data with .ttf, .png, and .mp3 extensions
#---------------------------------------------------------------------------------
%.ttf.o : %.ttf
	@echo $(notdir $<)
	$(bin2o)

%.png.o : %.png
	@echo $(notdir $<)
	$(bin2o)
	
%.ogg.o : %.ogg
	@echo $(notdir $<)
	$(bin2o)
	
%.pcm.o : %.pcm
	@echo $(notdir $<)
	$(bin2o)

-include $(DEPENDS)

#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------

Errors:
Code:
linking ... WiiControl.elf
launch.o: In function `launch(char*, char*)':
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:55: undefined reference to `f_mount(unsigned char, _FATFS*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:58: undefined reference to `f_opendir(_DIR*, char const*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:64: undefined reference to `f_readdir(_DIR*, _FILINFO*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:75: undefined reference to `f_readdir(_DIR*, _FILINFO*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:80: undefined reference to `f_stat(char const*, _FILINFO*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:82: undefined reference to `f_open(_FIL*, char const*, unsigned char)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:90: undefined reference to `f_read(_FIL*, void*, unsigned short, unsigned short*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:109: undefined reference to `f_close(_FIL*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:110: undefined reference to `sd_deinit()'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:114: undefined reference to `__exception_closeall()'
collect2: ld returned 1 exit status
make[1]: *** [/c/Users/Administrator/Desktop/WiiControl/WiiControl.elf] Error 1
"make": *** [build] Error 2

> Process Exit Code: 2
> Time Taken: 01:05
 
When C++ file compiles, it looks for (variable)main

eg.
PHP:
int main () { // Looks for this first
cout << "Hello World";
}

This wont work

PHP:
int FUNCTION () { // Looks for this first
cout << "Hello World";
}

I'm still a (sortof) beginner, but a lot of people get this wrong, and its one of the most commen problems
I dont know if the header relocates that, but it looks too obvious to me.
 
Last edited:
What does that have anything to do with this?

It has COMPLETE RELEVANCE
there is no main function....

THIS
PHP:
int launch(char locdir[999], char filname[13])

to this
PHP:
int main(char locdir[999], char filname[13])
AND THIS ( in header file)
PHP:
int launch(char locdir[999], char filename[13]);
TO THIS
PHP:
int main(char locdir[999], char filename[13]);
 
Last edited:
It has COMPLETE RELEVANCE
there is no main function....
Then the linker would show an error for undefined reference to main. In fact, it would still say main is missing after your proposed fix, because the arguments don't match.

As to the actual question, sorry no clue except for checking again for missing libraries.
 
Code:
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:55: undefined reference to `f_mount(unsigned char, _FATFS*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:58: undefined reference to `f_opendir(_DIR*, char const*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:64: undefined reference to `f_readdir(_DIR*, _FILINFO*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:75: undefined reference to `f_readdir(_DIR*, _FILINFO*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:80: undefined reference to `f_stat(char const*, _FILINFO*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:82: undefined reference to `f_open(_FIL*, char const*, unsigned char)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:90: undefined reference to `f_read(_FIL*, void*, unsigned short, unsigned short*)'
c:/Users/Administrator/Desktop/WiiControl/source/launch.cpp:109: undefined reference to `f_close(_FIL*)'

Because your linker is linked outside and not to your header file.

Exit code bec you cant exit the function without the MAIN..

be more helpfull if u told us if this was a console or what project type it is....
 
This is a ELF/DOL project, which runs on PowerPC platforms, to be more exact, the Wii Platform, via homebrew.

devkitPro.org • Portal

I'm using programmer's notepad.

@Sifex:
It doesn't have relevance because this file isn't the file with the main function.
Basically, what Negata said.

EDIT 2: Could it be that tff.h's definition file is a C file?
I change launch.cpp to launch.c, and it compiled.
But still, the example that used tff.h was a cpp file, so I'd like to get this straightened out.
 
Last edited:
You're not linking against a needed object or lib file. Namely the one that implements those file f_ functions.
 
You're not linking against a needed object or lib file. Namely the one that implements those file f_ functions.

If you check my SRC above, you'll see that I did include tff.h.
So I don't see what's wrong with it...

tff.c:
PHP:
/*--------------------------------------------------------------------------/
/  FatFs - Tiny FAT file system module  R0.04b                (C)ChaN, 2007
/---------------------------------------------------------------------------/
/ The FatFs module is an experimenal project to implement FAT file system to
/ cheap microcontrollers. This is a free software and is opened for education,
/ research and development under license policy of following trems.
/
/  Copyright (C) 2007, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is no warranty.
/ * You can use, modify and/or redistribute it for personal, non-profit or
/   profit use without any restriction under your responsibility.
/ * Redistributions of source code must retain the above copyright notice.
/
/---------------------------------------------------------------------------/
/  Feb 26, 2006  R0.00  Prototype.
/  Apr 29, 2006  R0.01  First stable version.
/  Jun 01, 2006  R0.02  Added FAT12 support.
/                       Removed unbuffered mode.
/                       Fixed a problem on small (<32M) patition.
/  Jun 10, 2006  R0.02a Added a configuration option (_FS_MINIMUM).
/  Sep 22, 2006  R0.03  Added f_rename().
/                       Changed option _FS_MINIMUM to _FS_MINIMIZE.
/  Dec 09, 2006  R0.03a Improved cluster scan algolithm to write files fast.
/  Feb 04, 2007  R0.04  Added FAT32 supprt.
/                       Changed some interfaces incidental to FatFs.
/                       Changed f_mountdrv() to f_mount().
/  Apr 01, 2007  R0.04a Added a capability of extending file size to f_lseek().
/                       Added minimization level 3.
/                       Fixed a problem in FAT32 support.
/  May 05, 2007  R0.04b Added a configuration option _USE_NTFLAG.
/                       Added FSInfo support.
/                       Fixed some problems corresponds to FAT32 support.
/                       Fixed DBCS name can result FR_INVALID_NAME.
/                       Fixed short seek (<= csize) collapses the file object.
/---------------------------------------------------------------------------*/

#include <string.h>
#include "tff.h"		/* Tiny-FatFs declarations */
#include "diskio.h"		/* Include file for user provided disk functions */

typedef enum { FALSE = 0, TRUE } BOOL;

static
FATFS *FatFs;			/* Pointer to the file system objects (logical drive) */
static
WORD fsid;				/* File system mount ID */


/*-------------------------------------------------------------------------
 
  Module Private Functions
 
-------------------------------------------------------------------------*/


/*-----------------------------------------------------------------------*/
/* Change window offset                                                  */
/*-----------------------------------------------------------------------*/

static
BOOL move_window (		/* TRUE: successful, FALSE: failed */
  DWORD sector		/* Sector number to make apperance in the FatFs->win */
)						/* Move to zero only writes back dirty window */
{
  DWORD wsect;
  FATFS *fs = FatFs;


  wsect = fs->winsect;
  if (wsect != sector)
    {	/* Changed current window */
#if !_FS_READONLY
      BYTE n;
      if (fs->winflag)
        {	/* Write back dirty window if needed */
          if (disk_write(0, fs->win, wsect, 1) != RES_OK)
            return FALSE;
          fs->winflag = 0;
          if (wsect < (fs->fatbase + fs->sects_fat))
            {	/* In FAT area */
              for (n = fs->n_fats; n >= 2; n--)
                {	/* Refrect the change to all FAT copies */
                  wsect += fs->sects_fat;
                  disk_write(0, fs->win, wsect, 1);
                }
            }
        }
#endif
      if (sector)
        {
          if (disk_read(0, fs->win, sector, 1) != RES_OK)
            return FALSE;
          fs->winsect = sector;
        }
    }
  return TRUE;
}




/*-----------------------------------------------------------------------*/
/* Clean-up cached data                                                  */
/*-----------------------------------------------------------------------*/

#if !_FS_READONLY
static
FRESULT sync (void)		/* FR_OK: successful, FR_RW_ERROR: failed */
{
  FATFS *fs = FatFs;


  fs->winflag = 1;
  if (!move_window(0)) return FR_RW_ERROR;
#if _USE_FSINFO
  if (fs->fs_type == FS_FAT32 && fs->fsi_flag)
    {		/* Update FSInfo sector if needed */
      fs->winsect = 0;
      memset(fs->win, 0, 512);
      ST_WORD(&fs->win[BS_55AA], 0xAA55);
      ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252);
      ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272);
      ST_DWORD(&fs->win[FSI_Free_Count], fs->free_clust);
      ST_DWORD(&fs->win[FSI_Nxt_Free], fs->last_clust);
      disk_write(0, fs->win, fs->fsi_sector, 1);
      fs->fsi_flag = 0;
    }
#endif
  if (disk_ioctl(0, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR;
  return FR_OK;
}
#endif




/*-----------------------------------------------------------------------*/
/* Get a cluster status                                                  */
/*-----------------------------------------------------------------------*/

static
CLUST get_cluster (		/* 0,>=2: successful, 1: failed */
  CLUST clust			/* Cluster# to get the link information */
)
{
  WORD wc, bc;
  DWORD fatsect;
  FATFS *fs = FatFs;


  if (clust >= 2 && clust < fs->max_clust)
    {		/* Valid cluster# */
      fatsect = fs->fatbase;
      switch (fs->fs_type)
        {
        case FS_FAT12 :
          bc = (WORD)clust * 3 / 2;
          if (!move_window(fatsect + bc / 512)) break;
          wc = fs->win[bc % 512];
          bc++;
          if (!move_window(fatsect + bc / 512)) break;
          wc |= (WORD)fs->win[bc % 512] << 8;
          return (clust & 1) ? (wc >> 4) : (wc & 0xFFF);

        case FS_FAT16 :
          if (!move_window(fatsect + clust / 256)) break;
          return LD_WORD(&fs->win[((WORD)clust * 2) % 512]);
#if _FAT32
        case FS_FAT32 :
          if (!move_window(fatsect + clust / 128)) break;
          return LD_DWORD(&fs->win[((WORD)clust * 4) % 512]) & 0x0FFFFFFF;
#endif
        }
    }

  return 1;	/* There is no cluster information, or an error occured */
}




/*-----------------------------------------------------------------------*/
/* Change a cluster status                                               */
/*-----------------------------------------------------------------------*/

#if !_FS_READONLY
static
BOOL put_cluster (		/* TRUE: successful, FALSE: failed */
  CLUST clust,		/* Cluster# to change */
  CLUST val			/* New value to mark the cluster */
)
{
  WORD bc;
  BYTE *p;
  DWORD fatsect;
  FATFS *fs = FatFs;


  fatsect = fs->fatbase;
  switch (fs->fs_type)
    {
    case FS_FAT12 :
      bc = (WORD)clust * 3 / 2;
      if (!move_window(fatsect + bc / 512)) return FALSE;
      p = &fs->win[bc % 512];
      *p = (clust & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
      bc++;
      fs->winflag = 1;
      if (!move_window(fatsect + bc / 512)) return FALSE;
      p = &fs->win[bc % 512];
      *p = (clust & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
      break;

    case FS_FAT16 :
      if (!move_window(fatsect + clust / 256)) return FALSE;
      ST_WORD(&fs->win[((WORD)clust * 2) % 512], (WORD)val);
      break;
#if _FAT32
    case FS_FAT32 :
      if (!move_window(fatsect + clust / 128)) return FALSE;
      ST_DWORD(&fs->win[((WORD)clust * 4) % 512], val);
      break;
#endif
    default :
      return FALSE;
    }
  fs->winflag = 1;
  return TRUE;
}
#endif /* !_FS_READONLY */




/*-----------------------------------------------------------------------*/
/* Remove a cluster chain                                                */
/*-----------------------------------------------------------------------*/

#if !_FS_READONLY
static
BOOL remove_chain (		/* TRUE: successful, FALSE: failed */
  CLUST clust			/* Cluster# to remove chain from */
)
{
  CLUST nxt;
  FATFS *fs = FatFs;


  while (clust >= 2 && clust < fs->max_clust)
    {
      nxt = get_cluster(clust);
      if (nxt == 1) return FALSE;
      if (!put_cluster(clust, 0)) return FALSE;
      if (fs->free_clust != (CLUST)0xFFFFFFFF)
        {
          fs->free_clust++;
#if _USE_FSINFO
          fs->fsi_flag = 1;
#endif
        }
      clust = nxt;
    }
  return TRUE;
}
#endif




/*-----------------------------------------------------------------------*/
/* Stretch or create a cluster chain                                     */
/*-----------------------------------------------------------------------*/

#if !_FS_READONLY
static
CLUST create_chain (	/* 0: no free cluster, 1: error, >=2: new cluster number */
  CLUST clust			/* Cluster# to stretch, 0 means create new */
)
{
  CLUST cstat, ncl, scl, mcl;
  FATFS *fs = FatFs;


  mcl = fs->max_clust;
  if (clust == 0)
    {		/* Create new chain */
      scl = fs->last_clust;			/* Get last allocated cluster */
      if (scl < 2 || scl >= mcl) scl = 1;
    }
  else
    {					/* Stretch existing chain */
      cstat = get_cluster(clust);		/* Check the cluster status */
      if (cstat < 2) return 1;		/* It is an invalid cluster */
      if (cstat < mcl) return cstat;	/* It is already followed by next cluster */
      scl = clust;
    }

  ncl = scl;				/* Start cluster */
  for (;;)
    {
      ncl++;							/* Next cluster */
      if (ncl >= mcl)
        {				/* Wrap around */
          ncl = 2;
          if (ncl > scl) return 0;	/* No free custer */
        }
      cstat = get_cluster(ncl);		/* Get the cluster status */
      if (cstat == 0) break;			/* Found a free cluster */
      if (cstat == 1) return 1;		/* Any error occured */
      if (ncl == scl) return 0;		/* No free custer */
    }

  if (!put_cluster(ncl, (CLUST)0x0FFFFFFF)) return 1;	/* Mark the new cluster "in use" */
  if (clust && !put_cluster(clust, ncl)) return 1;	/* Link it to previous one if needed */

  fs->last_clust = ncl;				/* Update fsinfo */
  if (fs->free_clust != (CLUST)0xFFFFFFFF)
    {
      fs->free_clust--;
#if _USE_FSINFO
      fs->fsi_flag = 1;
#endif
    }

  return ncl;		/* Return new cluster number */
}
#endif /* !_FS_READONLY */




/*-----------------------------------------------------------------------*/
/* Get sector# from cluster#                                             */
/*-----------------------------------------------------------------------*/

static
DWORD clust2sect (	/* !=0: sector number, 0: failed - invalid cluster# */
  CLUST clust		/* Cluster# to be converted */
)
{
  FATFS *fs = FatFs;


  clust -= 2;
  if (clust >= (fs->max_clust - 2)) return 0;		/* Invalid cluster# */
  return (DWORD)clust * fs->sects_clust + fs->database;
}




/*-----------------------------------------------------------------------*/
/* Move directory pointer to next                                        */
/*-----------------------------------------------------------------------*/

static
BOOL next_dir_entry (	/* TRUE: successful, FALSE: could not move next */
  DIR *dirobj			/* Pointer to directory object */
)
{
  CLUST clust;
  WORD idx;
  FATFS *fs = FatFs;


  idx = dirobj->index + 1;
  if ((idx & 15) == 0)
    {		/* Table sector changed? */
      dirobj->sect++;			/* Next sector */
      if (!dirobj->clust)
        {		/* In static table */
          if (idx >= fs->n_rootdir) return FALSE;	/* Reached to end of table */
        }
      else
        {					/* In dynamic table */
          if (((idx / 16) & (fs->sects_clust - 1)) == 0)
            {	/* Cluster changed? */
              clust = get_cluster(dirobj->clust);			/* Get next cluster */
              if (clust < 2 || clust >= fs->max_clust)	/* Reached to end of table */
                return FALSE;
              dirobj->clust = clust;				/* Initialize for new cluster */
              dirobj->sect = clust2sect(clust);
            }
        }
    }
  dirobj->index = idx;	/* Lower 4 bit of dirobj->index indicates offset in dirobj->sect */
  return TRUE;
}




/*-----------------------------------------------------------------------*/
/* Get file status from directory entry                                  */
/*-----------------------------------------------------------------------*/

#if _FS_MINIMIZE <= 1
static
void get_fileinfo (		/* No return code */
  FILINFO *finfo, 	/* Ptr to store the File Information */
  const BYTE *dir		/* Ptr to the directory entry */
)
{
  BYTE n, c, a;
  char *p;


  p = &finfo->fname[0];
  a = _USE_NTFLAG ? dir[DIR_NTres] : 0;	/* NT flag */
  for (n = 0; n < 8; n++)
    {	/* Convert file name (body) */
      c = dir[n];
      if (c == ' ') break;
      if (c == 0x05) c = 0xE5;
      if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20;
      *p++ = c;
    }
  if (dir[8] != ' ')
    {		/* Convert file name (extension) */
      *p++ = '.';
      for (n = 8; n < 11; n++)
        {
          c = dir[n];
          if (c == ' ') break;
          if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20;
          *p++ = c;
        }
    }
  *p = '\0';

  finfo->fattrib = dir[DIR_Attr];			/* Attribute */
  finfo->fsize = LD_DWORD(&dir[DIR_FileSize]);	/* Size */
  finfo->fdate = LD_WORD(&dir[DIR_WrtDate]);	/* Date */
  finfo->ftime = LD_WORD(&dir[DIR_WrtTime]);	/* Time */
}
#endif /* _FS_MINIMIZE <= 1 */




/*-----------------------------------------------------------------------*/
/* Pick a paragraph and create the name in format of directory entry     */
/*-----------------------------------------------------------------------*/

static
char make_dirfile (			/* 1: error - detected an invalid format, '\0'or'/': next character */
  const char **path,		/* Pointer to the file path pointer */
  char *dirname			/* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */
)
{
  BYTE n, t, c, a, b;


  memset(dirname, ' ', 8+3);	/* Fill buffer with spaces */
  a = 0;
  b = 0x18;	/* NT flag */
  n = 0;
  t = 8;
  for (;;)
    {
      c = *(*path)++;
      if (c == '\0' || c == '/')
        {		/* Reached to end of str or directory separator */
          if (n == 0) break;
          dirname[11] = _USE_NTFLAG ? (a & b) : 0;
          return c;
        }
      if (c <= ' ' || c == 0x7F) break;		/* Reject invisible chars */
      if (c == '.')
        {
          if (!(a & 1) && n >= 1 && n <= 8)
            {	/* Enter extension part */
              n = 8;
              t = 11;
              continue;
            }
          break;
        }
      if (_USE_SJIS &&
          ((c >= 0x81 && c <= 0x9F) ||		/* Accept S-JIS code */
           (c >= 0xE0 && c <= 0xFC)))
        {
          if (n == 0 && c == 0xE5)		/* Change heading \xE5 to \x05 */
            c = 0x05;
          a ^= 1;
          goto md_l2;
        }
      if (c == '"') break;				/* Reject " */
      if (c <= ')') goto md_l1;			/* Accept ! # $ % & ' ( ) */
      if (c <= ',') break;				/* Reject * + , */
      if (c <= '9') goto md_l1;			/* Accept - 0-9 */
      if (c <= '?') break;				/* Reject : ; < = > ? */
      if (!(a & 1))
        {	/* These checks are not applied to S-JIS 2nd byte */
          if (c == '|') break;			/* Reject | */
          if (c >= '[' && c <= ']') break;/* Reject [ \ ] */
          if (_USE_NTFLAG && c >= 'A' && c <= 'Z')
            (t == 8) ? (b &= ~0x08) : (b &= ~0x10);
          if (c >= 'a' && c <= 'z')
            {		/* Convert to upper case */
              c -= 0x20;
              if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10);
            }
        }
md_l1:
      a &= ~1;
md_l2:
      if (n >= t) break;
      dirname[n++] = c;
    }
  return 1;
}



/*-----------------------------------------------------------------------*/
/* Trace a file path                                                     */
/*-----------------------------------------------------------------------*/

static
FRESULT trace_path (	/* FR_OK(0): successful, !=0: error code */
  DIR *dirobj,		/* Pointer to directory object to return last directory */
  char *fn,			/* Pointer to last segment name to return */
  const char *path,	/* Full-path string to trace a file or directory */
  BYTE **dir			/* Directory pointer in Win[] to retutn */
)
{
  CLUST clust;
  char ds;
  BYTE *dptr = NULL;
  FATFS *fs = FatFs;

  /* Initialize directory object */
  clust = fs->dirbase;
#if _FAT32
  if (fs->fs_type == FS_FAT32)
    {
      dirobj->clust = dirobj->sclust = clust;
      dirobj->sect = clust2sect(clust);
    }
  else
#endif
    {
      dirobj->clust = dirobj->sclust = 0;
      dirobj->sect = clust;
    }
  dirobj->index = 0;
  dirobj->fs = fs;

  if (*path == '\0')
    {							/* Null path means the root directory */
      *dir = NULL;
      return FR_OK;
    }

  for (;;)
    {
      ds = make_dirfile(&path, fn);					/* Get a paragraph into fn[] */
      if (ds == 1) return FR_INVALID_NAME;
      for (;;)
        {
          if (!move_window(dirobj->sect)) return FR_RW_ERROR;
          dptr = &fs->win[(dirobj->index & 15) * 32];		/* Pointer to the directory entry */
          if (dptr[DIR_Name] == 0)						/* Has it reached to end of dir? */
            return !ds ? FR_NO_FILE : FR_NO_PATH;
          if (dptr[DIR_Name] != 0xE5						/* Matched? */
              && !(dptr[DIR_Attr] & AM_VOL)
              && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break;
          if (!next_dir_entry(dirobj))					/* Next directory pointer */
            return !ds ? FR_NO_FILE : FR_NO_PATH;
        }
      if (!ds)
        {
          *dir = dptr;
          return FR_OK;
        }				/* Matched with end of path */
      if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH;	/* Cannot trace because it is a file */
      clust =												/* Get cluster# of the directory */
#if _FAT32
        ((DWORD)LD_WORD(&dptr[DIR_FstClusHI]) << 16) |
#endif
        LD_WORD(&dptr[DIR_FstClusLO]);
      dirobj->clust = dirobj->sclust = clust;				/* Restart scannig with the new directory */
      dirobj->sect = clust2sect(clust);
      dirobj->index = 2;
    }
}



/*-----------------------------------------------------------------------*/
/* Reserve a directory entry                                             */
/*-----------------------------------------------------------------------*/

#if !_FS_READONLY
static
FRESULT reserve_direntry (	/* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */
  DIR *dirobj,			/* Target directory to create new entry */
  BYTE **dir				/* Pointer to pointer to created entry to retutn */
)
{
  CLUST clust;
  DWORD sector;
  BYTE c, n, *dptr;
  FATFS *fs = FatFs;


  /* Re-initialize directory object */
  clust = dirobj->sclust;
  if (clust)
    {	/* Dyanmic directory table */
      dirobj->clust = clust;
      dirobj->sect = clust2sect(clust);
    }
  else
    {		/* Static directory table */
      dirobj->sect = fs->dirbase;
    }
  dirobj->index = 0;

  do
    {
      if (!move_window(dirobj->sect)) return FR_RW_ERROR;
      dptr = &fs->win[(dirobj->index & 15) * 32];	/* Pointer to the directory entry */
      c = dptr[DIR_Name];
      if (c == 0 || c == 0xE5)
        {			/* Found an empty entry! */
          *dir = dptr;
          return FR_OK;
        }
    }
  while (next_dir_entry(dirobj));				/* Next directory pointer */
  /* Reached to end of the directory table */

  /* Abort when static table or could not stretch dynamic table */
  if (!clust || !(clust = create_chain(dirobj->clust))) return FR_DENIED;
  if (clust == 1 || !move_window(0)) return FR_RW_ERROR;

  fs->winsect = sector = clust2sect(clust);			/* Cleanup the expanded table */
  memset(fs->win, 0, 512);
  for (n = fs->sects_clust; n; n--)
    {
      if (disk_write(0, fs->win, sector, 1) != RES_OK)
        return FR_RW_ERROR;
      sector++;
    }
  fs->winflag = 1;
  *dir = fs->win;
  return FR_OK;
}
#endif /* !_FS_READONLY */




/*-----------------------------------------------------------------------*/
/* Load boot record and check if it is a FAT boot record                 */
/*-----------------------------------------------------------------------*/

static
BYTE check_fs (		/* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */
  DWORD sect		/* Sector# to check if it is a FAT boot record or not */
)
{
  FATFS *fs = FatFs;

  if (disk_read(0, fs->win, sect, 1) != RES_OK)	/* Load boot record */
    return 2;
  if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)		/* Check record signature */
    return 2;

  if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3))	/* Check FAT signature */
    return 0;
#if _FAT32
  if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80))
    return 0;
#endif
  return 1;
}




/*-----------------------------------------------------------------------*/
/* Make sure that the file system is valid                               */
/*-----------------------------------------------------------------------*/

static
FRESULT auto_mount (		/* FR_OK(0): successful, !=0: any error occured */
  const char **path,		/* Pointer to pointer to the path name (drive number) */
  BYTE chk_wp				/* !=0: Check media write protection for wrinting fuctions */
)
{
  BYTE fmt;
  DSTATUS stat;
  DWORD bootsect, fatsize, totalsect, maxclust;
  const char *p = *path;
  FATFS *fs = FatFs;



  while (*p == ' ') p++;	/* Strip leading spaces */
  if (*p == '/') p++;		/* Strip heading slash */
  *path = p;				/* Return pointer to the path name */

  /* Is the file system object registered? */
  if (!fs) return FR_NOT_ENABLED;

  /* Chekck if the logical drive has been mounted or not */
  if (fs->fs_type)
    {
      stat = disk_status(0);
      if (!(stat & STA_NOINIT))
        {				/* If the physical drive is kept initialized */
#if !_FS_READONLY
          if (chk_wp && (stat & STA_PROTECT))	/* Check write protection if needed */
            return FR_WRITE_PROTECTED;
#endif
          return FR_OK;						/* The file system object is valid */
        }
    }

  /* The logical drive has not been mounted, following code attempts to mount the logical drive */

  memset(fs, 0, sizeof(FATFS));		/* Clean-up the file system object */
  stat = disk_initialize(0);			/* Initialize low level disk I/O layer */
  if (stat & STA_NOINIT)				/* Check if the drive is ready */
    return FR_NOT_READY;
#if !_FS_READONLY
  if (chk_wp && (stat & STA_PROTECT))	/* Check write protection if needed */
    return FR_WRITE_PROTECTED;
#endif

  /* Search FAT partition on the drive */
  fmt = check_fs(bootsect = 0);		/* Check sector 0 as an SFD format */
  if (fmt == 1)
    {						/* Not a FAT boot record, it may be patitioned */
      /* Check a partition listed in top of the partition table */
      if (fs->win[MBR_Table+4])
        {					/* Is the 1st partition existing? */
          bootsect = LD_DWORD(&fs->win[MBR_Table+8]);	/* Partition offset in LBA */
          fmt = check_fs(bootsect);				/* Check the partition */
        }
    }
  if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != 512)	/* No valid FAT patition is found */
    return FR_NO_FILESYSTEM;

  /* Initialize the file system object */
  fatsize = LD_WORD(&fs->win[BPB_FATSz16]);			/* Number of sectors per FAT */
  if (!fatsize) fatsize = LD_DWORD(&fs->win[BPB_FATSz32]);
  fs->sects_fat = (CLUST)fatsize;
  fs->n_fats = fs->win[BPB_NumFATs];					/* Number of FAT copies */
  fatsize *= fs->n_fats;								/* (Number of sectors in FAT area) */
  fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]);	/* FAT start sector (lba) */
  fs->sects_clust = fs->win[BPB_SecPerClus];			/* Number of sectors per cluster */
  fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]);	/* Nmuber of root directory entries */
  totalsect = LD_WORD(&fs->win[BPB_TotSec16]);		/* Number of sectors on the file system */
  if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]);
  fs->max_clust = maxclust = (totalsect				/* Last cluster# + 1 */
                              - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / 16
                             ) / fs->sects_clust + 2;

  fmt = FS_FAT12;										/* Determine the FAT sub type */
  if (maxclust > 0xFF7) fmt = FS_FAT16;
  if (maxclust > 0xFFF7)
#if !_FAT32
    return FR_NO_FILESYSTEM;
#else
    fmt = FS_FAT32;
  if (fmt == FS_FAT32)
    fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]);	/* Root directory start cluster */
  else
#endif
  fs->dirbase = fs->fatbase + fatsize;			/* Root directory start sector (lba) */
  fs->database = fs->fatbase + fatsize + fs->n_rootdir / 16;	/* Data start sector (lba) */
  fs->fs_type = fmt;									/* FAT sub-type */

#if !_FS_READONLY
  fs->free_clust = (CLUST)0xFFFFFFFF;
#if _USE_FSINFO
  /* Load fsinfo sector if needed */
  if (fmt == FS_FAT32)
    {
      fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]);
      if (disk_read(0, fs->win, fs->fsi_sector, 1) == RES_OK &&
          LD_WORD(&fs->win[BS_55AA]) == 0xAA55 &&
          LD_DWORD(&fs->win[FSI_LeadSig]) == 0x41615252 &&
          LD_DWORD(&fs->win[FSI_StrucSig]) == 0x61417272)
        {
          fs->last_clust = LD_DWORD(&fs->win[FSI_Nxt_Free]);
          fs->free_clust = LD_DWORD(&fs->win[FSI_Free_Count]);
        }
    }
#endif
#endif
  fs->id = ++fsid;									/* File system mount ID */
  return FR_OK;
}




/*-----------------------------------------------------------------------*/
/* Check if the file/dir object is valid or not                          */
/*-----------------------------------------------------------------------*/

static
FRESULT validate (		/* FR_OK(0): The id is valid, !=0: Not valid */
  const FATFS *fs,	/* Pointer to the file system object */
  WORD id				/* id member of the target object to be checked */
)
{
  if (!fs || fs->id != id)
    return FR_INVALID_OBJECT;
  if (disk_status(0) & STA_NOINIT)
    return FR_NOT_READY;

  return FR_OK;
}




/*--------------------------------------------------------------------------
 
   Public Functions
 
--------------------------------------------------------------------------*/


/*-----------------------------------------------------------------------*/
/* Mount/Unmount a Locical Drive                                         */
/*-----------------------------------------------------------------------*/

FRESULT f_mount (
  BYTE drv,		/* Logical drive number to be mounted/unmounted */
  FATFS *fs		/* Pointer to new file system object (NULL for unmount)*/
)
{
  FATFS *fsobj;


  if (drv) return FR_INVALID_DRIVE;
  fsobj = FatFs;
  FatFs = fs;
  if (fsobj) memset(fsobj, 0, sizeof(FATFS));
  if (fs) memset(fs, 0, sizeof(FATFS));

  return FR_OK;
}




/*-----------------------------------------------------------------------*/
/* Open or Create a File                                                 */
/*-----------------------------------------------------------------------*/

FRESULT f_open (
  FIL *fp,			/* Pointer to the blank file object */
  const char *path,	/* Pointer to the file name */
  BYTE mode			/* Access mode and file open mode flags */
)
{
  FRESULT res;
  BYTE *dir;
  DIR dirobj;
  char fn[8+3+1];
  FATFS *fs = FatFs;


  fp->fs = NULL;
#if !_FS_READONLY
  mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
  res = auto_mount(&path, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
#else
  mode &= FA_READ;
  res = auto_mount(&path, 0);
#endif
  if (res != FR_OK) return res;

  /* Trace the file path */
  res = trace_path(&dirobj, fn, path, &dir);	/* Trace the file path */

#if !_FS_READONLY
  /* Create or Open a File */
  if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW))
    {
      CLUST rs;
      DWORD dw;
      if (res != FR_OK)
        {		/* No file, create new */
          if (res != FR_NO_FILE) return res;
          res = reserve_direntry(&dirobj, &dir);
          if (res != FR_OK) return res;
          memset(dir, 0, 32);		/* Initialize the new entry */
          memcpy(&dir[DIR_Name], fn, 8+3);
          dir[DIR_NTres] = fn[11];
          mode |= FA_CREATE_ALWAYS;
        }
      else
        {				/* Any object is already existing */
          if (mode & FA_CREATE_NEW)			/* Cannot create new */
            return FR_EXIST;
          if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR)))	/* Cannot overwrite (R/O or DIR) */
            return FR_DENIED;
          if (mode & FA_CREATE_ALWAYS)
            {		/* Resize it to zero */
#if _FAT32
              rs = ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) | LD_WORD(&dir[DIR_FstClusLO]);
              ST_WORD(&dir[DIR_FstClusHI], 0);
#else
              rs = LD_WORD(&dir[DIR_FstClusLO]);
#endif
              ST_WORD(&dir[DIR_FstClusLO], 0);	/* cluster = 0 */
              ST_DWORD(&dir[DIR_FileSize], 0);	/* size = 0 */
              fs->winflag = 1;
              dw = fs->winsect;				/* Remove the cluster chain */
              if (!remove_chain(rs) || !move_window(dw))
                return FR_RW_ERROR;
              fs->last_clust = rs - 1;		/* Reuse the cluster hole */
            }
        }
      if (mode & FA_CREATE_ALWAYS)
        {
          dir[DIR_Attr] = AM_ARC;		/* New attribute */
          dw = get_fattime();
          ST_DWORD(&dir[DIR_WrtTime], dw);	/* Updated time */
          ST_DWORD(&dir[DIR_CrtTime], dw);	/* Created time */
          fs->winflag = 1;
        }
    }
  /* Open a File */
  else
    {
#endif /* !_FS_READONLY */
      if (res != FR_OK) return res;		/* Trace failed */
      if (dir == NULL || (dir[DIR_Attr] & AM_DIR))	/* It is a directory */
        return FR_NO_FILE;
#if !_FS_READONLY
      if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
        return FR_DENIED;
    }

  fp->dir_sect = fs->winsect;			/* Pointer to the directory entry */
  fp->dir_ptr = dir;
#endif
  fp->flag = mode;							/* File access mode */
  fp->org_clust =								/* File start cluster */
#if _FAT32
    ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
#endif
    LD_WORD(&dir[DIR_FstClusLO]);
  fp->fsize = LD_DWORD(&dir[DIR_FileSize]);	/* File size */
  fp->fptr = 0;								/* File ptr */
  fp->sect_clust = 1;							/* Sector counter */
  fp->fs = fs;
  fp->id = fs->id;				/* Owner file system object of the file */

  return FR_OK;
}




/*-----------------------------------------------------------------------*/
/* Read File                                                             */
/*-----------------------------------------------------------------------*/

FRESULT f_read (
  FIL *fp, 		/* Pointer to the file object */
  void *buff,		/* Pointer to data buffer */
  WORD btr,		/* Number of bytes to read */
  WORD *br		/* Pointer to number of bytes read */
)
{
  DWORD sect, remain;
  WORD rcnt;
  CLUST clust;
  BYTE cc, *rbuff = buff;
  FRESULT res;
  FATFS *fs = fp->fs;


  *br = 0;
  res = validate(fs, fp->id);						/* Check validity of the object */
  if (res) return res;
  if (fp->flag & FA__ERROR) return FR_RW_ERROR;	/* Check error flag */
  if (!(fp->flag & FA_READ)) return FR_DENIED;	/* Check access mode */
  remain = fp->fsize - fp->fptr;
  if (btr > remain) btr = (WORD)remain;			/* Truncate read count by number of bytes left */

  for ( ;  btr;									/* Repeat until all data transferred */
        rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt)
    {
      if ((fp->fptr % 512) == 0)
        {				/* On the sector boundary */
          if (--fp->sect_clust)
            {					/* Decrement left sector counter */
              sect = fp->curr_sect + 1;			/* Get current sector */
            }
          else
            {								/* On the cluster boundary, get next cluster */
              clust = (fp->fptr == 0) ?
                      fp->org_clust : get_cluster(fp->curr_clust);
              if (clust < 2 || clust >= fs->max_clust)
                goto fr_error;
              fp->curr_clust = clust;				/* Current cluster */
              sect = clust2sect(clust);			/* Get current sector */
              fp->sect_clust = fs->sects_clust;	/* Re-initialize the left sector counter */
            }
          fp->curr_sect = sect;					/* Update current sector */
          cc = btr / 512;							/* When left bytes >= 512, */
          if (cc)
            {								/* Read maximum contiguous sectors directly */
              if (cc > fp->sect_clust) cc = fp->sect_clust;
              if (disk_read(0, rbuff, sect, cc) != RES_OK)
                goto fr_error;
              fp->sect_clust -= cc - 1;
              fp->curr_sect += cc - 1;
              rcnt = cc * 512;
              continue;
            }
        }
      if (!move_window(fp->curr_sect)) goto fr_error;	/* Move sector window */
      rcnt = 512 - (WORD)(fp->fptr % 512);			/* Copy fractional bytes from sector window */
      if (rcnt > btr) rcnt = btr;
      memcpy(rbuff, &fs->win[(WORD)fp->fptr % 512], rcnt);
    }

  return FR_OK;

fr_error:	/* Abort this function due to an unrecoverable error */
  fp->flag |= FA__ERROR;
  return FR_RW_ERROR;
}




#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* Write File                                                            */
/*-----------------------------------------------------------------------*/

FRESULT f_write (
  FIL *fp,			/* Pointer to the file object */
  const void *buff,	/* Pointer to the data to be written */
  WORD btw,			/* Number of bytes to write */
  WORD *bw			/* Pointer to number of bytes written */
)
{
  DWORD sect;
  WORD wcnt;
  CLUST clust;
  BYTE cc;
  FRESULT res;
  const BYTE *wbuff = buff;
  FATFS *fs = fp->fs;


  *bw = 0;
  res = validate(fs, fp->id);						/* Check validity of the object */
  if (res) return res;
  if (fp->flag & FA__ERROR) return FR_RW_ERROR;	/* Check error flag */
  if (!(fp->flag & FA_WRITE)) return FR_DENIED;	/* Check access mode */
  if (fp->fsize + btw < fp->fsize) return FR_OK;	/* File size cannot reach 4GB */

  for ( ;  btw;									/* Repeat until all data transferred */
        wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt)
    {
      if ((fp->fptr % 512) == 0)
        {				/* On the sector boundary */
          if (--(fp->sect_clust))
            {				/* Decrement left sector counter */
              sect = fp->curr_sect + 1;			/* Get current sector */
            }
          else
            {								/* On the cluster boundary, get next cluster */
              if (fp->fptr == 0)
                {				/* Is top of the file */
                  clust = fp->org_clust;
                  if (clust == 0)					/* No cluster is created yet */
                    fp->org_clust = clust = create_chain(0);	/* Create a new cluster chain */
                }
              else
                {							/* Middle or end of file */
                  clust = create_chain(fp->curr_clust);			/* Trace or streach cluster chain */
                }
              if (clust == 0) break;				/* Disk full */
              if (clust == 1 || clust >= fs->max_clust) goto fw_error;
              fp->curr_clust = clust;				/* Current cluster */
              sect = clust2sect(clust);			/* Get current sector */
              fp->sect_clust = fs->sects_clust;	/* Re-initialize the left sector counter */
            }
          fp->curr_sect = sect;					/* Update current sector */
          cc = btw / 512;							/* When left bytes >= 512, */
          if (cc)
            {								/* Write maximum contiguous sectors directly */
              if (cc > fp->sect_clust) cc = fp->sect_clust;
              if (disk_write(0, wbuff, sect, cc) != RES_OK)
                goto fw_error;
              fp->sect_clust -= cc - 1;
              fp->curr_sect += cc - 1;
              wcnt = cc * 512;
              continue;
            }
          if (fp->fptr >= fp->fsize)
            {			/* Flush R/W window if needed */
              if (!move_window(0)) goto fw_error;
              fs->winsect = fp->curr_sect;
            }
        }
      if (!move_window(fp->curr_sect))			/* Move sector window */
        goto fw_error;
      wcnt = 512 - (WORD)(fp->fptr % 512);			/* Copy fractional bytes bytes to sector window */
      if (wcnt > btw) wcnt = btw;
      memcpy(&fs->win[(WORD)fp->fptr % 512], wbuff, wcnt);
      fs->winflag = 1;
    }

  if (fp->fptr > fp->fsize) fp->fsize = fp->fptr;	/* Update file size if needed */
  fp->flag |= FA__WRITTEN;						/* Set file changed flag */
  return FR_OK;

fw_error:	/* Abort this function due to an unrecoverable error */
  fp->flag |= FA__ERROR;
  return FR_RW_ERROR;
}




/*-----------------------------------------------------------------------*/
/* Synchronize between File and Disk                                     */
/*-----------------------------------------------------------------------*/

FRESULT f_sync (
  FIL *fp		/* Pointer to the file object */
)
{
  DWORD tim;
  BYTE *dir;
  FRESULT res;
  FATFS *fs = fp->fs;


  res = validate(fs, fp->id);				/* Check validity of the object */
  if (res == FR_OK)
    {
      if (fp->flag & FA__WRITTEN)
        {		/* Has the file been written? */
          /* Update the directory entry */
          if (!move_window(fp->dir_sect))
            return FR_RW_ERROR;
          dir = fp->dir_ptr;
          dir[DIR_Attr] |= AM_ARC;						/* Set archive bit */
          ST_DWORD(&dir[DIR_FileSize], fp->fsize);		/* Update file size */
          ST_WORD(&dir[DIR_FstClusLO], fp->org_clust);	/* Update start cluster */
#if _FAT32
          ST_WORD(&dir[DIR_FstClusHI], fp->org_clust >> 16);
#endif
          tim = get_fattime();					/* Updated time */
          ST_DWORD(&dir[DIR_WrtTime], tim);
          fp->flag &= ~FA__WRITTEN;
          res = sync();
        }
    }
  return res;
}

#endif /* !_FS_READONLY */




/*-----------------------------------------------------------------------*/
/* Close File                                                            */
/*-----------------------------------------------------------------------*/

FRESULT f_close (
  FIL *fp		/* Pointer to the file object to be closed */
)
{
  FRESULT res;


#if !_FS_READONLY
  res = f_sync(fp);
#else
  res = validate(fp->fs, fp->id);
#endif
  if (res == FR_OK)
    fp->fs = NULL;

  return res;
}




#if _FS_MINIMIZE <= 2
/*-----------------------------------------------------------------------*/
/* Seek File Pointer                                                     */
/*-----------------------------------------------------------------------*/
#if 0
FRESULT f_lseek (
  FIL *fp,		/* Pointer to the file object */
  DWORD ofs		/* File pointer from top of file */
)
{
  CLUST clust;
  DWORD csize;
  BYTE csect;
  FRESULT res;
  FATFS *fs = fp->fs;


  res = validate(fs, fp->id);			/* Check validity of the object */
  if (res) return res;

  if (fp->flag & FA__ERROR) return FR_RW_ERROR;
#if !_FS_READONLY
  if (ofs > fp->fsize && !(fp->flag & FA_WRITE))
#else
  if (ofs > fp->fsize)
#endif
    ofs = fp->fsize;
  fp->fptr = 0;
  fp->sect_clust = 1;		/* Set file R/W pointer to top of the file */

  /* Move file R/W pointer if needed */
  if (ofs)
    {
      clust = fp->org_clust;	/* Get start cluster */
#if !_FS_READONLY
      if (!clust)
        {			/* If the file does not have a cluster chain, create new cluster chain */
          clust = create_chain(0);
          if (clust == 1) goto fk_error;
          fp->org_clust = clust;
        }
#endif
      if (clust)
        {			/* If the file has a cluster chain, it can be followed */
          csize = (DWORD)fs->sects_clust * 512;		/* Cluster size in unit of byte */
          for (;;)
            {									/* Loop to skip leading clusters */
              fp->curr_clust = clust;					/* Update current cluster */
              if (ofs <= csize) break;
#if !_FS_READONLY
              if (fp->flag & FA_WRITE)				/* Check if in write mode or not */
                clust = create_chain(clust);		/* Force streached if in write mode */
              else
#endif
                clust = get_cluster(clust);			/* Only follow cluster chain if not in write mode */
              if (clust == 0)
                {						/* Stop if could not follow the cluster chain */
                  ofs = csize;
                  break;
                }
              if (clust == 1 || clust >= fs->max_clust) goto fk_error;
              fp->fptr += csize;						/* Update R/W pointer */
              ofs -= csize;
            }
          csect = (BYTE)((ofs - 1) / 512);			/* Sector offset in the cluster */
          fp->curr_sect = clust2sect(clust) + csect;	/* Current sector */
          fp->sect_clust = fs->sects_clust - csect;	/* Left sector counter in the cluster */
          fp->fptr += ofs;							/* Update file R/W pointer */
        }
    }
#if !_FS_READONLY
  if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize)
    {	/* Set updated flag if in write mode */
      fp->fsize = fp->fptr;
      fp->flag |= FA__WRITTEN;
    }
#endif

  return FR_OK;

fk_error:	/* Abort this function due to an unrecoverable error */
  fp->flag |= FA__ERROR;
  return FR_RW_ERROR;
}

#endif


#if _FS_MINIMIZE <= 1
/*-----------------------------------------------------------------------*/
/* Open a directroy                                                      */
/*-----------------------------------------------------------------------*/

FRESULT f_opendir (
  DIR *dirobj,		/* Pointer to directory object to create */
  const char *path	/* Pointer to the directory path */
)
{
  BYTE *dir;
  char fn[8+3+1];
  FRESULT res;
  FATFS *fs = FatFs;


  res = auto_mount(&path, 0);
  if (res != FR_OK) return res;

  res = trace_path(dirobj, fn, path, &dir);	/* Trace the directory path */
  if (res == FR_OK)
    {							/* Trace completed */
      if (dir != NULL)
        {						/* It is not the root dir */
          if (dir[DIR_Attr] & AM_DIR)
            {		/* The entry is a directory */
              dirobj->clust =
#if _FAT32
                ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
#endif
                LD_WORD(&dir[DIR_FstClusLO]);
              dirobj->sect = clust2sect(dirobj->clust);
              dirobj->index = 2;
            }
          else
            {						/* The entry is not a directory */
              res = FR_NO_FILE;
            }
        }
      dirobj->id = fs->id;
    }
  return res;
}




/*-----------------------------------------------------------------------*/
/* Read Directory Entry in Sequense                                      */
/*-----------------------------------------------------------------------*/

FRESULT f_readdir (
  DIR *dirobj,		/* Pointer to the directory object */
  FILINFO *finfo		/* Pointer to file information to return */
)
{
  BYTE *dir, c;
  FRESULT res;
  FATFS *fs = dirobj->fs;


  res = validate(fs, dirobj->id);			/* Check validity of the object */
  if (res) return res;

  finfo->fname[0] = 0;
  while (dirobj->sect)
    {
      if (!move_window(dirobj->sect))
        return FR_RW_ERROR;
      dir = &fs->win[(dirobj->index & 15) * 32];		/* pointer to the directory entry */
      c = dir[DIR_Name];
      if (c == 0) break;								/* Has it reached to end of dir? */
      if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL))		/* Is it a valid entry? */
        get_fileinfo(finfo, dir);
      if (!next_dir_entry(dirobj)) dirobj->sect = 0;	/* Next entry */
      if (finfo->fname[0]) break;						/* Found valid entry */
    }

  return FR_OK;
}




#if _FS_MINIMIZE == 0
/*-----------------------------------------------------------------------*/
/* Get File Status                                                       */
/*-----------------------------------------------------------------------*/

FRESULT f_stat (
  const char *path,	/* Pointer to the file path */
  FILINFO *finfo		/* Pointer to file information to return */
)
{
  BYTE *dir;
  char fn[8+3+1];
  FRESULT res;
  DIR dirobj;


  res = auto_mount(&path, 0);
  if (res != FR_OK) return res;

  res = trace_path(&dirobj, fn, path, &dir);	/* Trace the file path */
  if (res == FR_OK)
    {							/* Trace completed */
      if (dir)	/* Found an object */
        get_fileinfo(finfo, dir);
      else		/* It is root dir */
        res = FR_INVALID_NAME;
    }

  return res;
}




#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* Get Number of Free Clusters                                           */
/*-----------------------------------------------------------------------*/

FRESULT f_getfree (
  const char *drv,	/* Logical drive number */
  DWORD *nclust,		/* Pointer to the double word to return number of free clusters */
  FATFS **fatfs		/* Pointer to pointer to the file system object to return */
)
{
  DWORD n, sect;
  CLUST clust;
  BYTE fat, f, *p;
  FRESULT res;
  FATFS *fs;


  /* Get drive number */
  res = auto_mount(&drv, 0);
  if (res != FR_OK) return res;
  *fatfs = fs = FatFs;

  /* If number of free cluster is valid, return it without cluster scan. */
  if (fs->free_clust <= fs->max_clust - 2)
    {
      *nclust = fs->free_clust;
      return FR_OK;
    }

  /* Count number of free clusters */
  fat = fs->fs_type;
  n = 0;
  if (fat == FS_FAT12)
    {
      clust = 2;
      do
        {
          if ((WORD)get_cluster(clust) == 0) n++;
        }
      while (++clust < fs->max_clust);
    }
  else
    {
      clust = fs->max_clust;
      sect = fs->fatbase;
      f = 0;
      p = 0;
      do
        {
          if (!f)
            {
              if (!move_window(sect++)) return FR_RW_ERROR;
              p = fs->win;
            }
          if (!_FAT32 || fat == FS_FAT16)
            {
              if (LD_WORD(p) == 0) n++;
              p += 2;
              f += 1;
            }
          else
            {
              if (LD_DWORD(p) == 0) n++;
              p += 4;
              f += 2;
            }
        }
      while (--clust);
    }
  fs->free_clust = n;
#if _USE_FSINFO
  if (fat == FS_FAT32) fs->fsi_flag = 1;
#endif

  *nclust = n;
  return FR_OK;
}




/*-----------------------------------------------------------------------*/
/* Delete a File or a Directory                                          */
/*-----------------------------------------------------------------------*/

FRESULT f_unlink (
  const char *path			/* Pointer to the file or directory path */
)
{
  BYTE *dir, *sdir;
  DWORD dsect;
  char fn[8+3+1];
  CLUST dclust;
  FRESULT res;
  DIR dirobj;
  FATFS *fs = FatFs;


  res = auto_mount(&path, 1);
  if (res != FR_OK) return res;

  res = trace_path(&dirobj, fn, path, &dir);	/* Trace the file path */
  if (res != FR_OK) return res;				/* Trace failed */
  if (dir == NULL) return FR_INVALID_NAME;	/* It is the root directory */
  if (dir[DIR_Attr] & AM_RDO) return FR_DENIED;	/* It is a R/O object */
  dsect = fs->winsect;
  dclust =
#if _FAT32
    ((DWORD)LD_WORD(&dir[DIR_FstClusHI]) << 16) |
#endif
    LD_WORD(&dir[DIR_FstClusLO]);
  if (dir[DIR_Attr] & AM_DIR)
    {				/* It is a sub-directory */
      dirobj.clust = dclust;					/* Check if the sub-dir is empty or not */
      dirobj.sect = clust2sect(dclust);
      dirobj.index = 2;
      do
        {
          if (!move_window(dirobj.sect)) return FR_RW_ERROR;
          sdir = &fs->win[(dirobj.index & 15) * 32];
          if (sdir[DIR_Name] == 0) break;
          if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL))
            return FR_DENIED;	/* The directory is not empty */
        }
      while (next_dir_entry(&dirobj));
    }

  if (!move_window(dsect)) return FR_RW_ERROR;	/* Mark the directory entry 'deleted' */
  dir[DIR_Name] = 0xE5;
  fs->winflag = 1;
  if (!remove_chain(dclust)) return FR_RW_ERROR;	/* Remove the cluster chain */

  return sync();
}




/*-----------------------------------------------------------------------*/
/* Create a Directory                                                    */
/*-----------------------------------------------------------------------*/

FRESULT f_mkdir (
  const char *path		/* Pointer to the directory path */
)
{
  BYTE *dir, *fw, n;
  char fn[8+3+1];
  DWORD sect, dsect, tim;
  CLUST dclust, pclust;
  FRESULT res;
  DIR dirobj;
  FATFS *fs = FatFs;


  res = auto_mount(&path, 1);
  if (res != FR_OK) return res;

  res = trace_path(&dirobj, fn, path, &dir);	/* Trace the file path */
  if (res == FR_OK) return FR_EXIST;			/* Any file or directory is already existing */
  if (res != FR_NO_FILE) return res;

  res = reserve_direntry(&dirobj, &dir); 		/* Reserve a directory entry */
  if (res != FR_OK) return res;
  sect = fs->winsect;
  dclust = create_chain(0);					/* Allocate a cluster for new directory table */
  if (dclust == 1) return FR_RW_ERROR;
  dsect = clust2sect(dclust);
  if (!dsect) return FR_DENIED;
  if (!move_window(dsect)) return FR_RW_ERROR;

  fw = fs->win;
  memset(fw, 0, 512);							/* Clear the directory table */
  for (n = 1; n < fs->sects_clust; n++)
    {
      if (disk_write(0, fw, ++dsect, 1) != RES_OK)
        return FR_RW_ERROR;
    }

  memset(&fw[DIR_Name], ' ', 8+3);			/* Create "." entry */
  fw[DIR_Name] = '.';
  fw[DIR_Attr] = AM_DIR;
  tim = get_fattime();
  ST_DWORD(&fw[DIR_WrtTime], tim);
  memcpy(&fw[32], &fw[0], 32);
  fw[33] = '.';	/* Create ".." entry */
  pclust = dirobj.sclust;
#if _FAT32
  ST_WORD(&fw[   DIR_FstClusHI], dclust >> 16);
  if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0;
  ST_WORD(&fw[32+DIR_FstClusHI], pclust >> 16);
#endif
  ST_WORD(&fw[   DIR_FstClusLO], dclust);
  ST_WORD(&fw[32+DIR_FstClusLO], pclust);
  fs->winflag = 1;

  if (!move_window(sect)) return FR_RW_ERROR;
  memset(&dir[0], 0, 32);						/* Clean-up the new entry */
  memcpy(&dir[DIR_Name], fn, 8+3);			/* Name */
  dir[DIR_NTres] = fn[11];
  dir[DIR_Attr] = AM_DIR;						/* Attribute */
  ST_DWORD(&dir[DIR_WrtTime], tim);			/* Crated time */
  ST_WORD(&dir[DIR_FstClusLO], dclust);		/* Table start cluster */
#if _FAT32
  ST_WORD(&dir[DIR_FstClusHI], dclust >> 16);
#endif

  return sync();
}




/*-----------------------------------------------------------------------*/
/* Change File Attribute                                                 */
/*-----------------------------------------------------------------------*/

FRESULT f_chmod (
  const char *path,	/* Pointer to the file path */
  BYTE value,			/* Attribute bits */
  BYTE mask			/* Attribute mask to change */
)
{
  FRESULT res;
  BYTE *dir;
  DIR dirobj;
  char fn[8+3+1];


  res = auto_mount(&path, 1);
  if (res == FR_OK)
    {
      res = trace_path(&dirobj, fn, path, &dir);	/* Trace the file path */
      if (res == FR_OK)
        {			/* Trace completed */
          if (dir == NULL)
            {
              res = FR_INVALID_NAME;
            }
          else
            {
              mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC;	/* Valid attribute mask */
              dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask);	/* Apply attribute change */
              res = sync();
            }
        }
    }
  return res;
}




/*-----------------------------------------------------------------------*/
/* Rename File/Directory                                                 */
/*-----------------------------------------------------------------------*/

FRESULT f_rename (
  const char *path_old,	/* Pointer to the old name */
  const char *path_new	/* Pointer to the new name */
)
{
  FRESULT res;
  DWORD sect_old;
  BYTE *dir_old, *dir_new, direntry[32-11];
  DIR dirobj;
  char fn[8+3+1];
  FATFS *fs = FatFs;


  res = auto_mount(&path_old, 1);
  if (res != FR_OK) return res;

  res = trace_path(&dirobj, fn, path_old, &dir_old);	/* Check old object */
  if (res != FR_OK) return res;			/* The old object is not found */
  if (!dir_old) return FR_NO_FILE;
  sect_old = fs->winsect;					/* Save the object information */
  memcpy(direntry, &dir_old[11], 32-11);

  res = trace_path(&dirobj, fn, path_new, &dir_new);	/* Check new object */
  if (res == FR_OK) return FR_EXIST;			/* The new object name is already existing */
  if (res != FR_NO_FILE) return res;			/* Is there no old name? */
  res = reserve_direntry(&dirobj, &dir_new); 	/* Reserve a directory entry */
  if (res != FR_OK) return res;

  memcpy(&dir_new[DIR_Attr], direntry, 32-11);	/* Create new entry */
  memcpy(&dir_new[DIR_Name], fn, 8+3);
  dir_new[DIR_NTres] = fn[11];
  fs->winflag = 1;

  if (!move_window(sect_old)) return FR_RW_ERROR;	/* Remove old entry */
  dir_old[DIR_Name] = 0xE5;

  return sync();
}

#endif /* !_FS_READONLY */
#endif /* _FS_MINIMIZE == 0 */
#endif /* _FS_MINIMIZE <= 1 */
#endif /* _FS_MINIMIZE <= 2 */

tff.h
PHP:
/*--------------------------------------------------------------------------/
/  Tiny-FatFs - FAT file system module include file  R0.04b   (C)ChaN, 2007
/---------------------------------------------------------------------------/
/ FatFs module is an experimenal project to implement FAT file system to
/ cheap microcontrollers. This is a free software and is opened for education,
/ research and development under license policy of following trems.
/
/  Copyright (C) 2007, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is no warranty.
/ * You can use, modify and/or redistribute it for personal, non-profit or
/   profit use without any restriction under your responsibility.
/ * Redistributions of source code must retain the above copyright notice.
/
/---------------------------------------------------------------------------*/

#ifndef _FATFS


#define _MCU_ENDIAN		2
/* The _MCU_ENDIAN defines which access method is used to the FAT structure.
/  1: Enable word access.
/  2: Disable word access and use byte-by-byte access instead.
/  When the architectural byte order of the MCU is big-endian and/or address
/  miss-aligned access is prohibited, the _MCU_ENDIAN must be set to 2.
/  If it is not the case, it can be set to 1 for good code efficiency. */

#define _FS_READONLY	1
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/  writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename
/  and useless f_getfree. */

#define _FS_MINIMIZE	0
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/  0: Full function.
/  1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod and f_rename are removed.
/  2: f_opendir and f_readdir are removed in addition to level 1.
/  3: f_lseek is removed in addition to level 2. */

#define _FAT32	1
/* To enable FAT32 support in addition of FAT12/16, set _FAT32 to 1. */

#define _USE_FSINFO	0
/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */

#define	_USE_SJIS	0
/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
/  only US-ASCII(7bit) code can be accepted as file/directory name. */

#define	_USE_NTFLAG	0
/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
/  Note that the files are always accessed in case insensitive. */


#include "integer.h"


/* Type definition for cluster number */
#if _FAT32
typedef DWORD	CLUST;
#else
typedef WORD	CLUST;
#undef _USE_FSINFO
#define _USE_FSINFO	0
#endif


/* File system object structure */
typedef struct _FATFS
  {
    WORD	id;				/* File system mount ID */
    WORD	n_rootdir;		/* Number of root directory entries */
    DWORD	winsect;		/* Current sector appearing in the win[] */
    DWORD	fatbase;		/* FAT start sector */
    DWORD	dirbase;		/* Root directory start sector */
    DWORD	database;		/* Data start sector */
    CLUST	sects_fat;		/* Sectors per fat */
    CLUST	max_clust;		/* Maximum cluster# + 1 */
#if !_FS_READONLY
    CLUST	last_clust;		/* Last allocated cluster */
    CLUST	free_clust;		/* Number of free clusters */
#if _USE_FSINFO
    DWORD	fsi_sector;		/* fsinfo sector */
    BYTE	fsi_flag;		/* fsinfo dirty flag (1:must be written back) */
    BYTE	pad1;
#endif
#endif
    BYTE	fs_type;		/* FAT sub type */
    BYTE	sects_clust;	/* Sectors per cluster */
    BYTE	n_fats;			/* Number of FAT copies */
    BYTE	winflag;		/* win[] dirty flag (1:must be written back) */
    BYTE	win[512];		/* Disk access window for Directory/FAT/File */
  }
FATFS;


/* Directory object structure */
typedef struct _DIR
  {
    WORD	id;			/* Owner file system mount ID */
    WORD	index;		/* Current index */
    FATFS*	fs;			/* Pointer to the owner file system object */
    CLUST	sclust;		/* Start cluster */
    CLUST	clust;		/* Current cluster */
    DWORD	sect;		/* Current sector */
  }
DIR;


/* File object structure */
typedef struct _FIL
  {
    WORD	id;				/* Owner file system mount ID */
    BYTE	flag;			/* File status flags */
    BYTE	sect_clust;		/* Left sectors in cluster */
    FATFS*	fs;				/* Pointer to owner file system */
    DWORD	fptr;			/* File R/W pointer */
    DWORD	fsize;			/* File size */
    CLUST	org_clust;		/* File start cluster */
    CLUST	curr_clust;		/* Current cluster */
    DWORD	curr_sect;		/* Current sector */
#if !_FS_READONLY
    DWORD	dir_sect;		/* Sector containing the directory entry */
    BYTE*	dir_ptr;		/* Ponter to the directory entry in the window */
#endif
  }
FIL;


/* File status structure */
typedef struct _FILINFO
  {
    DWORD fsize;			/* Size */
    WORD fdate;				/* Date */
    WORD ftime;				/* Time */
    BYTE fattrib;			/* Attribute */
    char fname[8+1+3+1];	/* Name (8.3 format) */
  }
FILINFO;


/* File function return code (FRESULT) */

typedef enum {
  FR_OK = 0,			/* 0 */
  FR_NOT_READY,		/* 1 */
  FR_NO_FILE,			/* 2 */
  FR_NO_PATH,			/* 3 */
  FR_INVALID_NAME,	/* 4 */
  FR_INVALID_DRIVE,	/* 5 */
  FR_DENIED,			/* 6 */
  FR_EXIST,			/* 7 */
  FR_RW_ERROR,		/* 8 */
  FR_WRITE_PROTECTED,	/* 9 */
  FR_NOT_ENABLED,		/* 10 */
  FR_NO_FILESYSTEM,	/* 11 */
  FR_INVALID_OBJECT	/* 12 */
} FRESULT;



/*-----------------------------------------------------*/
/* FatFs module application interface                  */

FRESULT f_mount (BYTE, FATFS*);						/* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const char*, BYTE);			/* Open or create a file */
FRESULT f_read (FIL*, void*, WORD, WORD*);			/* Read data from a file */
FRESULT f_write (FIL*, const void*, WORD, WORD*);	/* Write data to a file */
FRESULT f_lseek (FIL*, DWORD);						/* Move file pointer of a file object */
FRESULT f_close (FIL*);								/* Close an open file object */
FRESULT f_opendir (DIR*, const char*);				/* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*);					/* Read a directory item */
FRESULT f_stat (const char*, FILINFO*);				/* Get file status */
FRESULT f_getfree (const char*, DWORD*, FATFS**);	/* Get number of free clusters on the drive */
FRESULT f_sync (FIL*);								/* Flush cached data of a writing file */
FRESULT f_unlink (const char*);						/* Delete an existing file or directory */
FRESULT	f_mkdir (const char*);						/* Create a new directory */
FRESULT f_chmod (const char*, BYTE, BYTE);			/* Change file/dir attriburte */
FRESULT f_rename (const char*, const char*);		/* Rename/Move a file or directory */


/* User defined function to give a current time to fatfs module */

DWORD get_fattime (void);	/* 31-25: Year(0-127 +1980), 24-21: Month(1-12), 20-16: Day(1-31) */
/* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */



/* File access control and file status flags (FIL.flag) */

#define	FA_READ				0x01
#define	FA_OPEN_EXISTING	0x00
#if !_FS_READONLY
#define	FA_WRITE			0x02
#define	FA_CREATE_NEW		0x04
#define	FA_CREATE_ALWAYS	0x08
#define	FA_OPEN_ALWAYS		0x10
#define FA__WRITTEN			0x20
#endif
#define FA__ERROR			0x80


/* FAT sub type (FATFS.fs_type) */

#define FS_FAT12	1
#define FS_FAT16	2
#define FS_FAT32	3


/* File attribute bits for directory entry */

#define	AM_RDO	0x01	/* Read only */
#define	AM_HID	0x02	/* Hidden */
#define	AM_SYS	0x04	/* System */
#define	AM_VOL	0x08	/* Volume label */
#define AM_LFN	0x0F	/* LFN entry */
#define AM_DIR	0x10	/* Directory */
#define AM_ARC	0x20	/* Archive */



/* Offset of FAT structure members */

#define BS_jmpBoot			0
#define BS_OEMName			3
#define BPB_BytsPerSec		11
#define BPB_SecPerClus		13
#define BPB_RsvdSecCnt		14
#define BPB_NumFATs			16
#define BPB_RootEntCnt		17
#define BPB_TotSec16		19
#define BPB_Media			21
#define BPB_FATSz16			22
#define BPB_SecPerTrk		24
#define BPB_NumHeads		26
#define BPB_HiddSec			28
#define BPB_TotSec32		32
#define BS_55AA				510

#define BS_DrvNum			36
#define BS_BootSig			38
#define BS_VolID			39
#define BS_VolLab			43
#define BS_FilSysType		54

#define BPB_FATSz32			36
#define BPB_ExtFlags		40
#define BPB_FSVer			42
#define BPB_RootClus		44
#define BPB_FSInfo			48
#define BPB_BkBootSec		50
#define BS_DrvNum32			64
#define BS_BootSig32		66
#define BS_VolID32			67
#define BS_VolLab32			71
#define BS_FilSysType32		82

#define	FSI_LeadSig			0
#define	FSI_StrucSig		484
#define	FSI_Free_Count		488
#define	FSI_Nxt_Free		492

#define MBR_Table			446

#define	DIR_Name			0
#define	DIR_Attr			11
#define	DIR_NTres			12
#define	DIR_CrtTime			14
#define	DIR_CrtDate			16
#define	DIR_FstClusHI		20
#define	DIR_WrtTime			22
#define	DIR_WrtDate			24
#define	DIR_FstClusLO		26
#define	DIR_FileSize		28



/* Multi-byte word access macros  */

#if _MCU_ENDIAN == 1	/* Use word access */
#define	LD_WORD(ptr)		(WORD)(*(WORD*)(BYTE*)(ptr))
#define	LD_DWORD(ptr)		(DWORD)(*(DWORD*)(BYTE*)(ptr))
#define	ST_WORD(ptr,val)	*(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define	ST_DWORD(ptr,val)	*(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else
#if _MCU_ENDIAN == 2	/* Use byte-by-byte access */
#define	LD_WORD(ptr)		(WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define	LD_DWORD(ptr)		(DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr))
#define	ST_WORD(ptr,val)	*(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
#define	ST_DWORD(ptr,val)	*(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
#else
#error Do not forget to set _MCU_ENDIAN properly!
#endif
#endif



#define _FATFS
#endif /* _FATFS */
 
Perhaps you included the header in your compilation, but perhaps also you forgot the tff.c compilation + link along with it. These kinds of errors are linker errors, this is the only cause for such errors.
 
As just2n has explained its not your includes that are the issue. But in fact the way you link the complier to that of your headers.

Show us the command lines for your complier to that of your libs. and includes.
 
Is that a special version of FatFs you're using because it's been a while there is no tff, only ff remains:
ELM - FatFs Generic File System Module
Code:
/ Apr 01,'09 R0.07  Merged Tiny-FatFs as a buffer configuration option.

You gotta define in ff.h:
Code:
#define   _FS_TINY   1
The 0.08 is dated from 2010.

Anyway, did you check this project?
wmb-asm - Project Hosting on Google Code

It uses DEVKITPPC for some of his stuff and ff so perhaps it would be interesting to compare your makefiles and how it makes it work.
Btw he's using R0.08 version.
 
Back