You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1620 lines
47 KiB

/*
It is an open source software to implement FAT file system to
small embedded systems. This is a free software and is opened for education,
research and commercial developments under license policy of following trems.
(C) 2013 vinxru
(C) 2010, ChaN, all right reserved.
It is a free software and there is NO WARRANTY.
No restriction on use. You can use, modify and redistribute it for
personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
Redistributions of source code must retain the above copyright notice.
Version 0.99 30-05-2013
P.S. goto allows you to save memory! Like other horrors bellow.
Program size: 3070 words (6140 bytes), 75% of FLASH at ATMega8 !!!
*/
/*
ß íå ñòàë äîáàâëÿòü êîíòðîëü íà ñïåöèàëüíûå èìåíà
CON,PRN,AUX,CLOCK$,NUL,COM1,COM2,COM3,COM4,LPT1,LPT2,LPT3
÷òî áû íå çàíèìàòü ìèêðîêîíòðîëëåð. Ôàéëû ñ òàêèìè èìåíàìè
îñòàâëÿþ íà ñîâåñòè ïðîãðàììèñòà.
*/
//#include <stdafx.h>
#include "fs.h"
#include "sd.h"
#include <string.h>
#include <avr/pgmspace.h>
#include "DS3231.h"
/* Âñïîìîãàòåëüíûå ôóíêöèè äëÿ ðàáîòû ñ âðåìåíåì */
static uint8_t fs_update_timestamp(void);
/**************************************************************************
* Óïàêîâêà âðåìåíè â ôîðìàò FAT *
* Âîçâðàùàåò 16-áèòíîå çíà÷åíèå: *
* áèòû 15-11: ÷àñû (0-23) *
* áèòû 10-5: ìèíóòû (0-59) *
* áèòû 4-0: ñåêóíäû / 2 (0-29) *
**************************************************************************/
static uint16_t fat_pack_time(void)
{
uint8_t hour = ds3231GetHour();
uint8_t min = ds3231GetMinute();
uint8_t sec = ds3231GetSecond();
/* Ïðîâåðêà è êîððåêöèÿ çíà÷åíèé */
if (hour > 23) hour = 0;
if (min > 59) min = 0;
if (sec > 59) sec = 0;
return (uint16_t)((hour << 11) | (min << 5) | (sec >> 1));
}
/**************************************************************************
* Óïàêîâêà äàòû â ôîðìàò FAT *
* Âîçâðàùàåò 16-áèòíîå çíà÷åíèå: *
* áèòû 15-9: ãîä (îò 1980, 0-127) *
* áèòû 8-5: ìåñÿö (1-12) *
* áèòû 4-0: äåíü (1-31) *
**************************************************************************/
static uint16_t fat_pack_date(void)
{
uint8_t year = ds3231GetYear();
uint8_t month = (uint8_t)ds3231GetMonth();
uint8_t day = ds3231GetDate();
/* Ïðîâåðêà è êîððåêöèÿ çíà÷åíèé */
if (year > 99) year = 0; /* 2000-2099 */
if (month < 1 || month > 12) month = 1;
if (day < 1 || day > 31) day = 1;
/* Ãîä îò 1980: 2000 + year - 1980 = 20 + year */
uint16_t year_offset = 20 + year; /* Äëÿ 2024: 20 + 24 = 44 */
if (year_offset > 127) year_offset = 0;
return (uint16_t)((year_offset << 9) | (month << 5) | day);
}
uint8_t buf[512];
/* Äëÿ íàãëÿäíîñòè */
#define LD_uint16_t(ptr) (*(uint16_t*)(ptr))
#define LD_uint32_t(ptr) (*(uint32_t*)(ptr))
/* Çíà÷åíèÿ fs_type */
#define FS_FAT16 0
#define FS_FAT32 1
#define FS_ERROR 2
/* Ñïåöèàëüíûå çíà÷åíèÿ êëàñòåðîâ */
#define FREE_CLUSTER 0
#define LAST_CLUSTER 0x0FFFFFFF
/* Ñèñòåìíûå ïåðåìåííûå. Èíôîðìàöèÿ èç boot-ñåêòîðà */
uint8_t fs_type; /* FS_FAT16, FS_FAT32, FS_ERROR */
uint32_t fs_fatbase; /* Àäðåñ ïåðâîé FAT */
uint32_t fs_fatbase2; /* Àäðåñ âòîðîé FAT */
uint8_t fs_csize; /* Ðàçìåð êëàñòåðà â ñåêòîðàõ */
uint16_t fs_n_rootdir; /* Êîë-âî çàïèñåé â êîðíåâîì êàòàëîãå (òîëüêî FAT16) */
uint32_t fs_n_fatent; /* Êîë-âî êëàñòåðîâ */
uint32_t fs_dirbase; /* Êîðíåâîé êàòàëîã (ñåêòîð äëÿ FAT16, êëàñòåð äëÿ FAT32) */
uint32_t fs_database; /* Àäðåñ âòîðîãî êëàñòåðà */
/* Ñèñòåìíûå ïåðåìåííûå. Îñòàëüíîå */
uint8_t lastError; /* Ïîñëåäíÿÿ îøèáêà */
uint32_t fs_fatoptim; /* Ïåðâûé ñâîáîäíûé êëàñòåð */
uint32_t fs_tmp; /* Èñïîëüçóåþòñÿ äëÿ ðàçíûõ öåëåé */
uint16_t fs_wtotal; /* Èñïîëüçóåòñÿ ôóíêöèÿìè fs_write_start, fs_write_end*/
/* Îòêðûòûå ôàéëû/ïàïêè */
File fs_file;
#ifndef FS_DISABLE_SWAP
File fs_secondFile;
#endif
/* Ñòðóêòóðà boot-ñåêòîðà */
#define BPB_SecPerClus 13
#define BPB_RsvdSecCnt 14
#define BPB_NumFATs 16
#define BPB_RootEntCnt 17
#define BPB_TotSec16 19
#define BPB_FATSz16 22
#define BPB_TotSec32 32
#define BS_FilSysType 54
#define BPB_FATSz32 36
#define BPB_RootClus 44
#define BS_FilSysType32 82
#define MBR_Table 446
/**************************************************************************
* ×òåíèå ñåêòîðà â áóôåð *
**************************************************************************/
static uint8_t sd_readBuf(uint32_t sector)
{
return sd_read(buf, sector, 0, 512);
}
/**************************************************************************
* Çàïèñü áóôåðà â ñåêòîð *
**************************************************************************/
static uint8_t sd_writeBuf(uint32_t sector)
{
return sd_write512(buf, sector);
}
/**************************************************************************
* Èíèöèàëèçàöèÿ *
**************************************************************************/
uint8_t fs_init()
{
uint32_t bsect, fsize, tsect;
/* Ñáðàñûâàåì îïòèìèçàöèþ */
fs_fatoptim = 2;
/* Ïðåäîòâðàùàåì îøèáêè ïðîãðàììèñòà */
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_NONE;
#ifndef FS_DISABLE_SWAP
fs_secondFile.opened = OPENED_NONE;
#endif
fs_type = FS_ERROR;
#endif
/* Èíèöèàëèçàöèÿ íàêîïèòåëÿ */
//if(sd_init()) return 1;
/* Èùåì ôàéëîâóþ ñèñòåìó */
bsect = 0;
while(1)
{
if(sd_readBuf(bsect)) return 1;
if(LD_uint16_t(buf + 510) == 0xAA55)
{
if(LD_uint16_t(buf + BS_FilSysType ) == 0x4146) break;
if(LD_uint16_t(buf + BS_FilSysType32) == 0x4146) break;
/* Âîçìîæíî ýòî MBR */
if(bsect == 0 && buf[MBR_Table+4])
{
bsect = LD_uint32_t(buf + (MBR_Table + 8));
if(bsect != 0) continue;
}
}
abort_noFS:
lastError = ERR_NO_FILESYSTEM;
return 1;
}
/* Ðàçìåð òàáëèöû FAT â ñåêòîðàõ */
fsize = LD_uint16_t(buf + BPB_FATSz16);
if(fsize == 0) fsize = LD_uint32_t(buf + BPB_FATSz32);
/* Ðàçìåð ôàéëîâîé ñèñòåìû â ñåêòîðàõ */
tsect = LD_uint16_t( buf + BPB_TotSec16);
if(tsect == 0) tsect = LD_uint32_t(buf + BPB_TotSec32);
/* Ðàçìåð êîðíåâîãî êàòàëîãà (äîëæíî áûòü êðàòíî 16 è äëÿ FAT32 äîëæíî áûòü ðàíî íóëþ) */
fs_n_rootdir = LD_uint16_t(buf + BPB_RootEntCnt);
/* Àäðåñà òàáëèö FAT â ñåêòîðàõ */
fs_fatbase = bsect + LD_uint16_t(buf + BPB_RsvdSecCnt);
fs_fatbase2 = 0;
if(buf[BPB_NumFATs] >= 2) fs_fatbase2 = fs_fatbase + fsize;
/* Êîë-âî ñåêòîðîâ íà êëàñòåð */
fs_csize = buf[BPB_SecPerClus];
/* Êîë-âî êëàñòåðîâ */
fsize *= buf[BPB_NumFATs];
fs_n_fatent = (tsect - LD_uint16_t(buf + BPB_RsvdSecCnt) - fsize - fs_n_rootdir / 16) / fs_csize + 2;
/* Àäðåñ 2-îãî êëàñòåðà */
fs_database = fs_fatbase + fsize + fs_n_rootdir / 16;
/* Îïðåäåëåíèå ôàéëîâîé ñèñòåìû */
/* FAT 12 */
if(fs_n_fatent < 0xFF7) goto abort_noFS;
/* FAT 16 */
if(fs_n_fatent < 0xFFF7)
{
fs_dirbase = fs_fatbase + fsize;
fs_type = FS_FAT16;
return 0;
}
/* FAT 32 */
fs_dirbase = LD_uint32_t(buf + BPB_RootClus);
/* Ñáðàñûâàåì ñ÷åò÷èê ñâîáîäíîãî ìåñòà */
if(LD_uint16_t(buf + BPB_RsvdSecCnt)>0)
{
bsect++;
if(sd_readBuf(bsect)) return 1;
if(LD_uint32_t(buf) == 0x41615252 && LD_uint32_t(buf + 0x1E4) == 0x61417272 && LD_uint32_t(buf + 0x1FC) == 0xAA550000)
{
LD_uint32_t(buf + 0x1E8) = 0xFFFFFFFF;
LD_uint32_t(buf + 0x1EC) = 0xFFFFFFFF;
if(sd_writeBuf(bsect)) return 1;
}
}
fs_type = FS_FAT32;
return 0;
}
/**************************************************************************
* Ïðîâåðêà íàëè÷èÿ äèñêà è åñëè íóæíî, òî åãî èíèöèàëèçàöèÿ *
**************************************************************************/
uint8_t fs_check()
{
if(!sd_check()) return 0;
return fs_init();
}
/**************************************************************************
* Ïîëó÷èòü êëàñòåð èç FS_DIRENTRY *
* Ôóíêöèÿ íå ïîðòèò buf (ôóíêöèè, â êîòîðûõ ýòîãî íå íàïèñàíî, ïîðòÿò) *
**************************************************************************/
static uint32_t fs_getEntryCluster()
{
uint32_t c = LD_uint16_t(FS_DIRENTRY + DIR_FstClusLO);
if(fs_type != FS_FAT16) c |= ((uint32_t)LD_uint16_t(FS_DIRENTRY + DIR_FstClusHI)) << 16;
return c;
}
/**************************************************************************
* Ïîëó÷èòü ñëåäóþùèé êëàñòåð. *
* Àðãóìåíò è ðåçóëüòàò íàõîäÿòñÿ â fs_tmp. *
**************************************************************************/
static uint8_t fs_nextCluster()
{
if(fs_type == FS_FAT16)
{
if(sd_read((uint8_t*)&fs_tmp, fs_fatbase + fs_tmp / 256, (uint16_t)(uint8_t)fs_tmp * 2, 2)) goto abort;
fs_tmp &= 0xFFFF;
}
else
{
if(sd_read((uint8_t*)&fs_tmp, fs_fatbase + fs_tmp / 128, (uint16_t)((uint8_t)fs_tmp % 128) * 4, 4)) goto abort;
fs_tmp &= 0x0FFFFFFF;
}
/* Äëÿ óäîáñòâà ðàçðàáîòêè çàìåíÿåì ïîñëåäíèé êëàñòåð íà íîëü. */
if(fs_tmp < 2 || fs_tmp >= fs_n_fatent)
fs_tmp = 0;
return 0;
abort:
return 1;
}
/**************************************************************************
* Ïðåîáðàçîâàòü íîìåð êëàñòåðà â íîìåð ñåêòîðà *
* Àðãóìåíò è ðåçóëüòàò íàõîäÿòñÿ â fs_tmp. *
* Ôóíêöèÿ íå ïîðòèò buf *
***************************************************************************/
static void fs_clust2sect()
{
fs_tmp = (fs_tmp - 2) * fs_csize + fs_database;
}
/**************************************************************************
* Ïîëó÷èòü î÷åðåäíîé ôàéë èëè ïàïêó *
* Óäàëåííûå ôàéëû, ìåòêè òîìà, ïîñëåäíèé ýëåìåíò, LFN ïîêàçûâàþòñÿ *
* *
* Îïèñàíèå ðàáîòû ïîëíîñòüþ èäåíòè÷íî ôóíêöèè íèæå, ïîýòîìó çäåñü íå *
* ïðèâåäåíî *
* *
* Ôóíêöèÿ íå ïîðòèò buf[0..MAX_FILENAME-1] *
***************************************************************************/
static uint8_t fs_readdirInt()
{
if(fs_file.entry_able)
{
fs_file.entry_index++;
/* Â ïàïêå íå ìîæåò áûòü áîëüøå 65536 ôàéëîâ, à â êîðíå FAT16 íå áîëüøå fs_n_rootdir */
if(fs_file.entry_index == 0 || (fs_file.entry_cluster == 0 && fs_file.entry_index == fs_n_rootdir))
{
fs_file.entry_index = 0;
retEnd:
FS_DIRENTRY[DIR_Name] = 0; /* Ïðèçíàê ïîñëåäíåãî ôàéëà äëÿ ïîëüçîâàòåëÿ âûçûâàþùåãî fs_dirread */
fs_file.entry_able = 0;
return 0;
}
/* Ãðàíèöà ñåêòîðà */
if(fs_file.entry_index % 16 == 0)
{
fs_file.entry_sector++;
/* Ãðàíèöà êëàñòåðà */
if(fs_file.entry_cluster != 0 && ((fs_file.entry_index / 16) % fs_csize) == 0)
{
/* Ñëåäóþùèé êëàñòåð */
fs_tmp = fs_file.entry_cluster;
if(fs_nextCluster()) return 1;
if(fs_tmp == 0) goto retEnd; /* Ïîñëåäíèé êëàñòåð, óñòàíàëèâàåì fs_file.entry_able = 0 */
/* Ñîõðàíÿåì */
fs_file.entry_cluster = fs_tmp;
fs_clust2sect();
fs_file.entry_sector = fs_tmp;
}
}
}
else
{
fs_file.entry_index = 0;
fs_file.entry_able = 1;
fs_tmp = fs_file.entry_start_cluster;
/* Ïåðâûé êëàñòåð è ñåêòîð ïàïêè. Ýòîò êîä íå èìååò ñìûñëà âûïîëíÿòü
äëÿ FAT16, íî çàòî êîä õîðîøî ñæèìàåòñÿ. Ò.ê. ýòîò êóñîê êîäà àíàëîãè÷åí
êóñêó âûøå. */
fs_file.entry_cluster = fs_tmp;
fs_clust2sect();
fs_file.entry_sector = fs_tmp;
/* Êîðíåâàÿ ïàïêà FS_FAT16 */
if(fs_file.entry_cluster == 0) fs_file.entry_sector = fs_dirbase;
}
return sd_read(FS_DIRENTRY, fs_file.entry_sector, (uint16_t)((fs_file.entry_index % 16) * 32), 32);
}
/**************************************************************************
* Ïîëó÷èòü î÷åðåäíîé ôàéë èëè ïàïêó (óäàëåííûå ôàéëû ïðîïóñêàþòñÿ) *
* *
* Ýòà ôóíêöèÿ âûçûâàåòñÿ ïîñëå fs_opendir, êîòîðàÿ íàñòðàèâàåò âñå *
* íóæíûå ïåðåìåííûå, ïîýòîìó âàì íè÷åãî òðîãàòü íå íàäî. Èíôîðìàöèÿ *
* íèæå ïðèâåäåíà äëÿ ëó÷øåãî ïîíèìàíèÿ ðàáîòû *
* *
* Åñëè íà âõîäå entry_able=0, òî íà÷èíàåòñÿ íîâûé ïîèñê â ïàïêå *
* ïî àäðåñó entry_start_cluster. Ïðè ýòîì èíèöèàëèçèðóþòñÿ ïåðåìåííûå: *
* entry_able, entry_index, entry_sector, entry_cluster. *
* *
* Åñëè íà âõîäå fs_file.entry_able=1, òî èñïîëüçóþòñÿ ýòè 4 ïåðåìåííûå. *
* *
* Íà âûõîäå *
* entry_able - åñëè 0 çíà÷èò äîñòèãíóò êîíåö êàòàëîãà *
* entry_sector - ñåêòîð îïèñàòåëÿ *
* entry_cluster - êëàñòåð îïèñàòåëÿ *
* entry_index - íîìåð îïèñàòåëÿ *
* FS_DIRENTRY - îïèñàòåëü *
* *
* Ôóíêöèÿ íå ïîðòèò buf[0..MAX_FILENAME-1] *
**************************************************************************/
uint8_t fs_readdir_nocheck()
{
while(!fs_readdirInt())
{
if(FS_DIRENTRY[DIR_Name] == 0) fs_file.entry_able = 0;
if(fs_file.entry_able == 0) return 0;
if(FS_DIRENTRY[DIR_Name] == 0xE5) continue; /* Ìîæåò áûòü åùå 0x05 */
if(FS_DIRENTRY[DIR_Name] == '.') continue;
if((FS_DIRENTRY[DIR_Attr] & AM_VOL) == 0) return 0;
}
return 1;
}
uint8_t fs_readdir()
{
#ifndef FS_DISABLE_CHECK
/* Ïàïêà äîëæíà áûòü îòêðûòà */
if(fs_file.opened != OPENED_DIR)
{
lastError = ERR_NOT_OPENED;
return 1;
}
#endif
return fs_readdir_nocheck();
}
/**************************************************************************
* Ñîõðàíèòü èçìåíåíèÿ â îáå òàáëèöû FAT *
**************************************************************************/
static uint8_t fs_saveFatSector(uint32_t sector)
{
if(fs_fatbase2) if(sd_writeBuf(fs_fatbase2+sector)) return 1;
return sd_writeBuf(fs_fatbase+sector);
}
/**************************************************************************
* Âûäåëèòü êëàñòåð *
* *
* Íàéäåííûé êëàñòåð ñîõðàíÿåòñÿ â fs_tmp *
**************************************************************************/
/* Ðàäè ôóíêöèè fs_getfree ïðèøëîñü óñëîæíèòü ôóíêöèþ fs_allocCluster.
Åñëè ôóíêöèÿ íå èñïîëüçóåòñÿ, òî ìîæíî ñ ïîìîùüþ ìàêðîñà FS_DISABLE_GETFREESPACE
èñêëþ÷èòü ëèøíèé êîä */
#ifdef FS_DISABLE_GETFREESPACE
#define DIS(X)
#define ALLOCCLUSTER
#else
#define DIS(X) X
#define ALLOCCLUSTER 0
#endif
static uint8_t fs_allocCluster(DIS(uint8_t freeSpace))
{
uint8_t i;
uint32_t s;
uint8_t *a;
/* Íà÷èíàåì ïîèñê ñ ýòîãî êëàñòåðà */
fs_tmp = fs_fatoptim;
/* Ïîñëåäîâàòåëüíî ïåðåáèðàåì ñåêòîðà */
while(1)
{
/* Ñåêòîð è ñìåùåíèå */
s = fs_tmp / 256, i = (uint8_t)fs_tmp, a = (uint8_t*)((uint16_t*)buf + i);
if(fs_type != FS_FAT16) s = fs_tmp / 128, i |= 128, a = (uint8_t*)((uint32_t*)buf - 128 + i);
/* ×èòàåì ñåêòîð */
if(sd_readBuf(fs_fatbase + s)) goto abort;
/* Ñðåäè 128/256 ÷èñåë â ñåêòîðå èùåì 0 */
/* Êó÷à ïðîâåðîê âíóòðè öèêëà íå ñàìîå áûñòðîå ðåøåíèå, íî çàòî ïîëó÷àåòñÿ î÷åíü êîìïàêòíûé êîä. */
do
{
/* Êëàñòåðû êîí÷èëèñü */
if(fs_tmp >= fs_n_fatent)
{
DIS(if(freeSpace) return 0;) lastError = ERR_NO_FREE_SPACE;
goto abort;
}
/* Èùåì ñâîáîäíûé êëàñòåð è ïîìå÷àåì êàê ïîñëåäíèé */
if(fs_type == FS_FAT16)
{
if(LD_uint16_t(a) == 0)
{
DIS(if(!freeSpace)
{
) LD_uint16_t(a) = (uint16_t)LAST_CLUSTER;
goto founded;
DIS(
}
fs_file.sector++;)
}
a += 2;
}
else
{
if(LD_uint32_t(a) == 0)
{
DIS(if(!freeSpace)
{
) LD_uint32_t(a) = LAST_CLUSTER;
goto founded;
DIS(
}
fs_file.sector++;)
}
a += 4;
}
/* Ñ÷åò÷èê */
++fs_tmp, ++i;
}
while(i != 0);
}
founded:
/* Îïòèìèçàöèÿ */
fs_fatoptim = fs_tmp;
/* Ñîõðàíÿåì èçìåíåíèÿ */
return fs_saveFatSector(s);
abort:
return 1;
}
#undef DIS
/**************************************************************************
* Èçìåíåíèå òàáëèöû FAT *
* *
* Åñëè fs_tmp!=0, òî FAT[cluster] = fs_tmp *
* Åñëè fs_tmp==0, òî swap(FAT[cluster], fs_tmp) *
**************************************************************************/
static uint8_t fs_setNextCluster(uint32_t cluster)
{
uint32_t s, prev;
void* a;
/* Âû÷èñëÿåì ñåêòîð */
s = cluster / 128;
if(fs_type == FS_FAT16) s = cluster / 256;
/* ×èòàåì ñåêòîð */
if(sd_readBuf(fs_fatbase + s)) return 1;
/* Èçìåíÿåì îòäåëüíûé êëàñòåð */
if(fs_type == FS_FAT16)
{
a = (uint16_t*)buf + (uint8_t)cluster;
prev = LD_uint16_t(a);
LD_uint16_t(a) = (uint16_t)fs_tmp;
}
else
{
a = (uint32_t*)buf + (uint8_t)cluster % 128;
prev = LD_uint32_t(a);
LD_uint32_t(a) = fs_tmp;
}
/* Îïòèìèçàöèÿ ïîèñêà ñâîáîäíîãî êëàñòåðà. Âíåçàïíî if() if() çàíèìàåò ìåíüøå ÏÇÓ, ÷åì && */
if(fs_tmp == FREE_CLUSTER) if(cluster < fs_fatoptim) fs_fatoptim = cluster;
/* Ðåçóëüòàò */
if(fs_tmp == LAST_CLUSTER || fs_tmp == FREE_CLUSTER)
fs_tmp = prev;
/* Ñîõðàíÿåì ñåêòîð */
return fs_saveFatSector(s);
}
/**************************************************************************
* Óñòàíîâèòü â îïèñàòåëü êëàñòåð *
**************************************************************************/
static void fs_setEntryCluster(uint8_t* entry, uint32_t cluster)
{
LD_uint16_t(entry + DIR_FstClusLO) = (uint16_t)(cluster);
LD_uint16_t(entry + DIR_FstClusHI) = (uint16_t)(cluster >> 16);
}
/**************************************************************************
* Î÷èñòèòü êëàñòåð è áóôåð *
**************************************************************************/
static uint8_t fs_eraseCluster(uint8_t i)
{
memset(buf, 0, 512);
for(; i < fs_csize; ++i)
if(sd_writeBuf(fs_tmp + i)) return 1;
return 0;
}
/**************************************************************************
* Âûäåëèòü îïèñàòåëü â êàòàëîãå *
* *
* entry_able äîëæíî áûòü ðàâíî 0 *
* entry_start_cluster äîëæåí ñîäåðæàòü ïåðâûé êëàñòåð ïàïêè *
**************************************************************************/
static uint8_t* fs_allocEntry()
{
/* Èùåì â ïàïêå ïóñòîé îïèñàòåëü. */
while(1)
{
if(fs_readdirInt()) return 0;
/* Êëàñòåðû êîí÷èëèñü */
if(!fs_file.entry_able) break;
/* Ýòî ñâîáîäíûé îïèñàòåëü */
if(FS_DIRENTRY[0] == 0xE5 || FS_DIRENTRY[0] == 0) /* Ìîæåò áûòü åùå 0x05 */
{
/* ×èòàåì ñåêòîð */
if(sd_readBuf(fs_file.entry_sector)) return 0;
/* Íàéäåííûé îïèñàòåëü */
return buf + (fs_file.entry_index % 16) * 32;
}
}
/* Îãðàíè÷åíèå ïî êîë-âó ôàéëîâ */
/* Êîðíåâîé êàòàëîã FAT16 òàê æå âåðíåò fs_file.entry_index == 0 */
if(fs_file.entry_index == 0)
{
lastError = ERR_DIR_FULL;
return 0;
}
/* Âûäåëèòü êëàñòåð. Ðåçóëüòàò â fs_tmp */
if(fs_allocCluster(ALLOCCLUSTER)) return 0;
/* Äîáàâèòü åùå îäèí êëàñòåð ê ïàïêå. */
if(fs_setNextCluster(fs_file.entry_cluster)) return 0; /* fs_tmp ñîõðàíèòñÿ, òàê êàê îí íå LAST è íå FREE */
/* Çàïîëíÿåì îòâåò */
fs_file.entry_cluster = fs_tmp;
fs_clust2sect();
fs_file.entry_sector = fs_tmp;
/* Î÷èùàåì êëàñòåð è çà îäíî BUF (èñïîëüçóåòñÿ ïåðåìåííàÿ fs_tmp) */
fs_eraseCluster(0);
/* Íàéäåííûé îïèñàòåëü */
return buf;
}
/**************************************************************************
* Îòêðûòü/ñîçäàòü ôàéë èëè ïàïêó *
* *
* Èìÿ ôàéëà â buf. Îíî íå äîëæíî ïðåâûøàòü FS_MAXFILE ñèìîëîâ âêëþ÷àÿ 0 *
* *
* what = OPENED_NONE - Îòêðûòü ôàéë èëè ïàïêó *
* what = OPENED_FILE - Ñîçäàòü ôàéë (ñîçäàííûé ôàéë îòêðûò) *
* what = OPENED_DIR - Ñîçäàòü ïàïêó (ñîçäàííàÿ ïàïêà íå îòêðûòà) *
* what | 0x80 - Íå ñîçäàâàòü ôàéë â ïàïêå entry_start_cluster *
* *
* Íà âûõîäå *
* FS_DIRENTRY - îïèñàòåëü *
* fs_file.entry_able - 0 (åñëè îòêðûò ñóùåñòâóþùèé ôàéë/ïàïêà) *
* fs_file.entry_sector - ñåêòîð îïèñàòåëÿ *
* fs_file.entry_cluster - êëàñòåð îïèñàòåëÿ *
* fs_file.entry_index - íîìåð îïèñàòåëÿ *
* fs_file.entry_start_cluster - ïåðâûé êëàñòåð ôàéëà èëè ïàïêè *
* fs_parent_dir_cluster - ïåðâûé êëàñòåð ïàïêè ïðåäêà (CREATE) *
* fs_file.ptr - 0 (åñëè îòêðûò ôàéë) *
* fs_file.size - ðàçìåð ôàéëà (åñëè îòêðûò ôàéë) *
* *
* Ôóíêöèÿ íå ïîðòèò buf[0..MAX_FILENAME-1] *
**************************************************************************/
static uint8_t fs_open0_create(uint8_t dir); /* forward */
static uint8_t* fs_open0_name(uint8_t *p); /* forward */
#define FS_DIRFIND (buf + 469) /* 11 áàéò èñïîëüçóþùèåñÿ âíóòðè ôóíêöèè fs_open0 */
#define fs_notrootdir (*(uint8_t*)&fs_file.size) /* Èñïîëüçóåòñÿ fs_open0, â ýòî âðåìÿ ïåðåìåííûå fs_file. íå ñîäåæàò íóæíûõ çíà÷åíèÿ */
#define fs_parent_dir_cluster fs_file.sector /* Òàê æå èñïîëüçóåòñÿ fs_file.sector äëÿ õðàíåíèÿ ïåðâîãî êëàñòåðà ïàïêè ïðåäêà. */
uint8_t fs_open0(uint8_t what)
{
uint8_t *path;
uint8_t r;
/* Ïðîâåðêà îøèáîê ïðîãðàììèñòà */
#ifndef FS_DISABLE_CHECK
if(fs_type == FS_ERROR)
{
lastError = ERR_NO_FILESYSTEM;
goto abort;
}
fs_file.opened = OPENED_NONE;
#endif
/* Ïðåäîòâðàùåíèå ðåêóðñèè */
r = what & 0x80;
what &= 0x7F;
fs_parent_dir_cluster = fs_file.entry_start_cluster;
/* Êîðíåâîé êàòàëîã */
fs_notrootdir = 0;
fs_file.entry_start_cluster = fs_dirbase;
if(fs_type == FS_FAT16) fs_file.entry_start_cluster = 0;
/* Êîðíåâàÿ ïàïêà */
if(buf[0] == 0)
{
if(what) goto abort_noPath;
FS_DIRENTRY[0] = 0; /* Ïðèçíàê êîðíåâîé ïàïêè */
FS_DIRENTRY[DIR_Attr] = AM_DIR; /* Äëÿ óïðîùåíèÿ îïðåäåëåíèÿ ôàéë/ïàïêà çàïèøåì ñþäà AM_DIR */
}
else
{
path = buf;
while(1)
{
/* Ïîëó÷àåì î÷åðåäíîå èìÿ èç path â FS_DIRFIND */
path = fs_open0_name(path);
if(path == (uint8_t*)1) goto abort_noPath;
/* Èùåì èìÿ â ïàïêå */
fs_file.entry_able = 0;
while(1)
{
if(fs_readdir_nocheck()) return 1;
if(fs_file.entry_able == 0) break;
if(!memcmp(FS_DIRENTRY, FS_DIRFIND, 11)) break;
}
/* Ïîñëåäíèé ýëåìåíòó ïóòè â ðåæèìå ñîçäàíèÿ */
if(what && path == 0)
{
fs_parent_dir_cluster = fs_file.entry_start_cluster; /* Ñîõðàíÿåì â ýòîé ïåðåìåííîé ðåçóëüòàò äëÿ ôóíöèè fs_move */
if(fs_type == FS_FAT32 && fs_parent_dir_cluster == fs_dirbase) fs_parent_dir_cluster = 0;
if(fs_file.entry_able == 0) return fs_open0_create(what-1); /* Ïðîäîëæèì òàì */
lastError = ERR_FILE_EXISTS;
goto abort;
}
/* Ôàéë/ïàïêà íå íàéäåíà */
if(fs_file.entry_able == 0) goto abort_noPath;
/* ×òî òî íàéäåíî */
fs_file.entry_start_cluster = fs_getEntryCluster();
/* Ýòî áûë ïîñëåäíèé ýëåìåíò ïóòè */
if(path == 0) break;
/* Ýòî äîëæíà áûòü ïàïêà */
if((FS_DIRENTRY[DIR_Attr] & AM_DIR) == 0) goto abort_noPath;
/* Ïðåäîòâðàùàåì ðåêóðñèþ äëÿ ôóíêöèè fs_move */
if(r && fs_file.entry_start_cluster == fs_parent_dir_cluster) goto abort_noPath;
/* Íàäåííàÿ ïàïêà óæå íå áóäåò êîðíåâîé */
fs_notrootdir = 1;
}
}
/* Óñòàíàâëèâàåì ïåðåìåííûå */
fs_file.entry_able = 0;
fs_file.size = LD_uint32_t(FS_DIRENTRY + DIR_FileSize);
fs_file.ptr = 0;
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_FILE;
if(FS_DIRENTRY[DIR_Attr] & AM_DIR) fs_file.opened = OPENED_DIR;
#endif
/* Íåëüçÿ äâàæäû îòêðûâàòü ôàéë */
#ifndef FS_DISABLE_CHECK
#ifndef FS_DISABLE_SWAP
if(fs_secondFile.opened==OPENED_FILE && fs_file.opened==OPENED_FILE && fs_secondFile.entry_sector == fs_file.entry_sector && fs_secondFile.entry_index==fs_file.entry_index)
{
fs_file.opened = OPENED_NONE;
lastError = ERR_ALREADY_OPENED;
goto abort;
}
#endif
#endif
return 0;
abort_noPath:
lastError = ERR_NO_PATH;
abort:
return 1;
}
static uint8_t exists(const /*flash*/ uint8_t* str, uint8_t c)
{
while(*str)
if(*str++ == c)
return c;
return 0;
}
static uint8_t * fs_open0_name(uint8_t *p)
{
uint8_t c, ni, i;
memset(FS_DIRFIND, ' ', 11);
i = 0;
ni = 8;
while(1)
{
c = *p++;
if(c == 0)
{
if(i == 0) break; /* Ïóñòîå èìÿ ôàéëà */
return 0;
}
if(c == '/') return p;
if(c == '.')
{
if(i == 0) break; /* Ïóñòîå èìÿ ôàéëà */
#ifndef FS_DISABLE_CHECK
if(ni != 8) break; /* Âòîðàÿ òî÷êà */
#endif
i = 8;
ni = 11;
continue;
}
/* Ñëèøêîì äëèííîå èìå */
if(i == ni) break;
/* Çàïðåùåííûå ñèìâîëû */
#ifndef FS_DISABLE_CHECK
if(exists((const /*flash*/ uint8_t*)"+,;=[]*?<:>\\|\"", c)) break;
if(c <= 0x20) break;
if(c >= 0x80) break;
#endif
/* Ïðèâîäèì ê âåðõíåìó ðåãèñòðó */
if(c >= 'a' && c <= 'z') c -= 0x20;
/* Ñîõðàíÿåì èìÿ */
FS_DIRFIND[i++] = c;
}
/* Îøèáêà */
return (uint8_t*)1;
}
static uint8_t fs_open0_create(uint8_t dir)
{
uint8_t new_name[11];
uint32_t allocatedCluster;
uint8_t* allocatedEntry;
/* Ñîõðàíÿåì èìÿ, òàê êàê âåñü áóôåð áóäåò çàòåðò */
memcpy(new_name, FS_DIRFIND, 11);
/* Âûäåëÿåì êëàñòåð äëÿ ïàïêè */
if(dir)
{
if(fs_allocCluster(ALLOCCLUSTER)) goto abort; /* fs_file.entry_start_cluster èçìåíåí íå áóäåò, òàì ïåðâûé êëàñòåð ïàïêè â êîòîðîé ìû ñîçäàäèì ôàéë */
allocatedCluster = fs_tmp;
}
/* Äîáàâëÿåì â ïàïêó îïèñàòåëü (ñåêòîð íå ñîõðàíåí) */
allocatedEntry = fs_allocEntry();
if(allocatedEntry == 0)
{
/*  ñëó÷àå îøèáêè îñâîáîæäàåì êëàñòåð */
fs_tmp = FREE_CLUSTER;
fs_setNextCluster(allocatedCluster);
goto abort;
}
/* Óñòàíàëèâàåì èìÿ â îïèñàòåëü. */
memset(allocatedEntry, 0, 32);
memcpy(allocatedEntry, new_name, 11);
/* ========== ÓÑÒÀÍÎÂÊÀ ÄÀÒÛ È ÂÐÅÌÅÍÈ ========== */
/* Ïîëó÷àåì òåêóùåå âðåìÿ è äàòó */
uint16_t fat_time = fat_pack_time();
uint16_t fat_date = fat_pack_date();
/* Óñòàíàâëèâàåì âðåìÿ ñîçäàíèÿ */
LD_uint16_t(allocatedEntry + DIR_CrtTime) = fat_time;
LD_uint16_t(allocatedEntry + DIR_CrtDate) = fat_date;
/* Óñòàíàâëèâàåì âðåìÿ ïîñëåäíåé çàïèñè (òàêîå æå, êàê è âðåìÿ ñîçäàíèÿ) */
LD_uint16_t(allocatedEntry + DIR_WrtTime) = fat_time;
LD_uint16_t(allocatedEntry + DIR_WrtDate) = fat_date;
/* Îáíóëÿåì çàðåçåðâèðîâàííîå ïîëå (äëÿ ñîâìåñòèìîñòè) */
allocatedEntry[DIR_NTres] = 0;
/* ============================================== */
if(!dir)
{
/* Ñîõðàíÿåì îïèñàòåëü íà äèñê */
if(sd_writeBuf(fs_file.entry_sector)) goto abort;
/* fs_file.entry_sector, fs_file.entry_index - óñòàíàâëèàåòñÿ â fs_allocCluster */
fs_file.entry_start_cluster = 0;
fs_file.size = 0;
fs_file.ptr = 0;
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_FILE;
#endif
return 0;
}
/* Ýòî ïàïêà */
allocatedEntry[DIR_Attr] = AM_DIR;
fs_setEntryCluster(allocatedEntry, allocatedCluster);
/* Ñîõðàíÿåì îïèñàòåëü íà äèñê */
if(sd_writeBuf(fs_file.entry_sector)) goto abort;
/* Ñåêòîð äëÿ íîâîé ïàïêè */
fs_tmp = allocatedCluster;
fs_clust2sect();
/* Î÷èùàåì fs_tmp è çà îäíî buf */
fs_eraseCluster(1);
/* Ñîçäàåì ïóñòóþ ïàïêó */
memset(buf, ' ', 11);
buf[0] = '.';
buf[11] = 0x10;
fs_setEntryCluster(buf, allocatedCluster);
/* Óñòàíàâëèâàåì äàòó/âðåìÿ äëÿ çàïèñè "." â ïàïêå */
LD_uint16_t(buf + DIR_CrtTime) = fat_time;
LD_uint16_t(buf + DIR_CrtDate) = fat_date;
LD_uint16_t(buf + DIR_WrtTime) = fat_time;
LD_uint16_t(buf + DIR_WrtDate) = fat_date;
memset(buf+32, ' ', 11);
buf[32] = '.';
buf[33] = '.';
buf[32+11] = 0x10;
if(fs_notrootdir) fs_setEntryCluster(buf + 32, fs_file.entry_start_cluster); /* Ñåé÷àñ â fs_file.size==0 çíà÷èò êîðíåâîé êàòàëîã */
/* Óñòàíàâëèâàåì äàòó/âðåìÿ äëÿ çàïèñè ".." â ïàïêå */
LD_uint16_t(buf + 32 + DIR_CrtTime) = fat_time;
LD_uint16_t(buf + 32 + DIR_CrtDate) = fat_date;
LD_uint16_t(buf + 32 + DIR_WrtTime) = fat_time;
LD_uint16_t(buf + 32 + DIR_WrtDate) = fat_date;
/* Ñîõðàíÿåì ïàïêó */
return sd_writeBuf(fs_tmp);
abort:
return 1;
}
/**************************************************************************
* Îòêðûòü ôàéë *
**************************************************************************/
uint8_t fs_open()
{
if(fs_openany()) goto abort;
#ifndef FS_DISABLE_CHECK
if(fs_file.opened == OPENED_FILE) return 0;
fs_file.opened = OPENED_NONE;
#else
if((FS_DIRENTRY[DIR_Attr] & AM_DIR) == 0) return 0;
#endif
lastError = ERR_NO_PATH;
abort:
return 1;
}
/**************************************************************************
* Îòêðûòü ïàïêó *
**************************************************************************/
uint8_t fs_opendir()
{
if(fs_openany()) goto abort;
#ifndef FS_DISABLE_CHECK
if(fs_file.opened == OPENED_DIR) return 0;
fs_file.opened = OPENED_NONE;
#else
if(FS_DIRENTRY[DIR_Attr] & AM_DIR) return 0;
#endif
lastError = ERR_NO_PATH;
abort:
return 1;
}
/**************************************************************************
* Âû÷èñëèòü íîìåð ñëåäóþùåãî ñåêòîðà äëÿ ÷òåíèÿ/çàïèñè *
* Âûçûâàåòñÿ òîëüêî èç fs_read0, fs_write_start *
**************************************************************************/
static uint8_t fs_nextRWSector()
{
if(fs_file.ptr == 0)
{
/* ×òåíèå ôàéëà åùå íå íà÷àòî */
fs_tmp = fs_file.entry_start_cluster;
}
else
{
/* Åùå íå êîíåö ñåêòîðà */
if((uint16_t)fs_file.ptr % 512) return 0;
/* Ñëåäóþùèé ñåêòîð */
fs_file.sector++;
/* Åùå íå êîíåö êëàñòåðà */
if(((fs_file.sector - fs_database) % fs_csize) != 0) return 0;
/* Ñëåäóþùèé êëàñòåð */
fs_tmp = fs_file.cluster;
if(fs_nextCluster()) return 1;
}
/* Åñëè ýòî áûë ïîñëåäíèé êëàñòåð, äîáàâëÿåì íîâûé */
if(fs_tmp == 0)
{
if(fs_allocCluster(ALLOCCLUSTER)) return 1;
if(fs_file.ptr == 0) fs_file.entry_start_cluster = fs_tmp;
else fs_setNextCluster(fs_file.cluster); /* fs_tmp ñîõðàíèòñÿ, òàê êàê îí íå LAST è íå FREE */
}
/* Îê */
fs_file.cluster = fs_tmp;
fs_clust2sect();
fs_file.sector = fs_tmp;
return 0;
}
/**************************************************************************
* Ïðî÷èòàòü èç ôàéëà íåñêîëüêî áàéò â buf *
* *
* Ïîëüçîâàòåëü íå äîëæåí âûõîäèòü çà ïðåäåëû ôàéëà ïðè ÷òåíèè, èíà÷å *
* âîçíèêíåò óòå÷êà ñâîáîæíîãî ìåñòà íà äèñêå. *
* *
* Àðãóìåíòû: *
* ptr - áóôåð äëÿ ÷òåíèÿ, ìîæåò áûòü buf *
* len - êîë-âî áàéò, êîòîðûå íåîáõîäèìî ïðî÷èòàòü *
**************************************************************************/
uint8_t fs_read0(uint8_t* ptr, uint16_t len)
{
uint16_t sectorLen;
/* Ïðîâåðêà îøèáîê ïðîãðàììèñòà */
#ifndef FS_DISABLE_CHECK
if(fs_file.opened != OPENED_FILE)
{
lastError = ERR_NOT_OPENED;
goto abort;
}
#endif
while(len)
{
/* Åñëè óêàçàòåëü íàõîäèòñÿ íà ãðàíèöå ñåêòîðà */
if(fs_nextRWSector()) goto abort;
/* Êîë-âî áàéò äî êîíöà ñåêòîðà */
sectorLen = 512 - ((uint16_t)fs_file.ptr % 512);
if(len < sectorLen) sectorLen = len;
/* ×èòàåì äàííûå */
if(ptr)
{
if(sd_read(ptr, fs_file.sector, (uint16_t)fs_file.ptr % 512, sectorLen)) goto abort;
ptr += sectorLen;
}
/* Óâåëè÷èâàåì ñìåùåíèå */
fs_file.ptr += sectorLen;
len -= sectorLen;
}
/* Óâåëè÷åíèå ðàçìåðà ôàéëà */
if(fs_file.ptr > fs_file.size) fs_file.size = fs_file.ptr, fs_file.changed = 1;
return 0;
abort:
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_NONE;
#endif
return 1;
}
/**************************************************************************
* Ïðî÷èòàòü èç ôàéëà íåñêîëüêî áàéò â buf *
* *
* Àðãóìåíòû: *
* ptr - áóôåð äëÿ ÷òåíèÿ, ìîæåò áûòü buf *
* len - êîë-âî áàéò, êîòîðûå íåîáõîäèìî ïðî÷èòàòü *
* readed - óêàçàòåëü, äëÿ ñîõðàíåíèÿ êîë-âà ðåàëüíî ïðî÷èòàííûõ áàéò *
**************************************************************************/
uint8_t fs_read(uint8_t* ptr, uint16_t len, uint16_t* readed)
{
/* Îãðàíè÷èâàåì êîë-âî áàéò äëÿ ÷òåíèÿ */
if(len > fs_file.size - fs_file.ptr) len = (uint16_t)(fs_file.size - fs_file.ptr);
*readed = len;
/* Ïðîâåðêà íà îøèáêè ïðîèñõîäèò òàì */
return fs_read0(ptr, len);
}
/**************************************************************************
* Ñîõðàíèòü äëèíó ôàéëà è ïðåâûé êëàñòåð â îïèñòàåëü *
* Âûçûâàåòñÿ èç fs_lseek, fs_write_start, fs_write_end, fs_write_eof *
**************************************************************************/
static char fs_saveFileLength()
{
uint8_t* entry;
if(fs_file.changed == 0) return 0;
fs_file.changed = 0;
/* Èçìåíåíèå îïèñàòåëÿ ôàéëà */
if(sd_readBuf(fs_file.entry_sector)) return 1;
entry = buf + (fs_file.entry_index % 16) * 32;
LD_uint32_t(entry + DIR_FileSize) = fs_file.size;
fs_setEntryCluster(entry, fs_file.entry_start_cluster);
return sd_writeBuf(fs_file.entry_sector);
}
/**************************************************************************
* Óñòàíîâèòü ñìåùåíèå ÷òåíèÿ/çàïèñè ôàéëà *
**************************************************************************/
#define LSEEK_STEP 32768
uint8_t fs_lseek(uint32_t off, uint8_t mode)
{
uint32_t l;
/* Ðåæèì */
if(mode==1) off += fs_file.ptr;
else if(mode==2) off += fs_file.size;
/* Ìîæíî çàìåíèòü íà fs_file.ptr = 0 äëÿ óìåíüøåíèÿ êîäà*/
if(off >= fs_file.ptr) off -= fs_file.ptr;
else fs_file.ptr = 0;
do /* Âûïîëíÿåì îäèí öèêë äàæå äëÿ off=0, òàê êàê âíóòðè ïðîèñõîäèò ïðîâåðêà íà îøèáêè */
{
l = off;
if(l > LSEEK_STEP) l = LSEEK_STEP;
if(fs_read0(0, (uint16_t)l)) return 1;
off -= l;
}
while(off);
/* Ðàçìåð ôàéëà ìîã èçìåíèòñÿ */
fs_saveFileLength();
/* Ðåçóëüòàò */
fs_tmp = fs_file.ptr;
return 0;
}
/**************************************************************************
* Çàïèñàòü â ôàéë (øàã 1) *
***************************************************************************/
uint8_t fs_write_start()
{
uint16_t len;
/* Ïðîâåðêà îøèáîê ïðîãðàììèñòà */
#ifndef FS_DISABLE_CHECK
if(fs_file.opened != OPENED_FILE)
{
lastError = ERR_NOT_OPENED;
goto abort;
}
if(fs_wtotal == 0)
{
lastError = ERR_NO_DATA;
goto abort;
}
#endif
/* Ñêîëüêî ìîæíî åùå äîïèñàòü â ýòîò ñåêòîð? */
len = 512 - (uint16_t)fs_file.ptr % 512;
/* Îãðàíè÷èâàåì îñòàòêîì äàííûõ â ôàéëå */
if(len > fs_wtotal) len = (uint16_t)fs_wtotal;
/* Âû÷èñëåíèå fs_file.sector, âûäåëåíèå êëàñòåðîâ */
if(fs_nextRWSector()) goto abort; /* Äîëæíî âûëåòàòü òîëüêî ïî îøèáêàì ERR_NO_FREE_SPACE, ERR_DISK_ERR */
/* Êîððåêòèðóåì äëèíó ôàéëà */
if(fs_file.size < fs_file.ptr + len)
{
fs_file.size = fs_file.ptr + len;
fs_file.changed = 1;
}
/* ×èòàåì äàííûå ñåêòîðà, åñëè íå âåñü ñåêòîð áóäåò çàïîëíåí */
if(len != 512)
{
if(sd_readBuf(fs_file.sector)) goto abort;
}
fs_file_wlen = len;
fs_file_woff = (uint16_t)fs_file.ptr % 512;
return 0;
abort:
/* Ñêîðåå âñåãî ýòî îøèáêà ERR_NO_FREE_SPACE */
/* Åñëè ðàçìåð ôàéëà áûë èçìåíåí, òî íàäî áû ñîõðàíèòü èçìåíåíèÿ â îïèñàòåëü ôàéëà. */
fs_saveFileLength();
/* Çàêðûâàåì ôàéë */
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_NONE;
#endif
return 1;
}
/**************************************************************************
* Çàïèñàòü â ôàéë (øàã 2) *
***************************************************************************/
uint8_t fs_write_end()
{
#ifndef FS_DISABLE_CHECK
if(fs_file.opened != OPENED_FILE)
{
lastError = ERR_NOT_OPENED;
goto abort;
}
#endif
/* Çàïèñûâàåì èçìåíåíèÿ íà äèñê */
if(sd_writeBuf(fs_file.sector)) goto abort;
/*  ñëó÷àå îøèáêè ôàéë ìîæåò ñîäåðæàòü áîëüøå êëàñòåðîâ, ÷åì òðåáóåòñÿ ïî åãî ðàçìåðó. */
/* Íî ýòî íå ïëîõî, äàííûå íå ïîâðåæäåíû. À ýòà îøèáêà ïðîÿâèòñÿ ëèøü â óìåíüøåíèè */
/* ìåñòà íà äèñêå. */
/* Ñ÷åò÷èêè */
fs_file.ptr += fs_file_wlen;
fs_wtotal -= fs_file_wlen;
/* Åñëè çàïèñü çàêîí÷åíà, ñîõðàíÿåì ðàçìåðà ôàéëà è ïåðâûé êëàñòåð */
if(fs_wtotal == 0)
{
if(fs_saveFileLength()) goto abort;
if(fs_update_timestamp() != 0) {
/* Îøèáêà îáíîâëåíèÿ âðåìåíè - íå êðèòè÷íî, íî ìîæíî âåðíóòü îøèáêó */
/* goto abort; */ /* Ðàñêîììåíòèðóéòå, åñëè õîòèòå âîçâðàùàòü îøèáêó */
}
}
/* Îê */
return 0;
abort:
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_NONE;
#endif
return 1;
}
/**************************************************************************
* Îñâîáîäèòü öåïî÷êó êëàñòåðîâ íà÷èíàÿ ñ fs_tmp *
**************************************************************************/
static uint8_t fs_freeChain()
{
uint32_t c;
while(1)
{
if(fs_tmp < 2 || fs_tmp >= fs_n_fatent) return 0;
/* Îñâîáîäèòü êëàñòåð fs_tmp è çàïèñòü â fs_tmp ñëåäóþùèé çà íèì êëàñòåð */
c = fs_tmp, fs_tmp = FREE_CLUSTER;
if(fs_setNextCluster(c)) break; /* fs_tmp áóäåò ñîäåðæàòü ñëåäóþùèé êëàñòåð, òàê êàê çàïèñûâàåòñÿ FREE_CLUSTER */
}
return 1;
}
/**************************************************************************
* Ïåðåìåñòèòü ôàéë/ïàïêó *
**************************************************************************/
uint8_t fs_move0()
{
uint8_t* entry;
uint8_t tmp[21];
uint16_t old_index;
uint32_t old_sector, old_start_cluster;
#ifndef FS_DISABLE_CHECK
if(fs_file.opened == OPENED_NONE)
{
lastError = ERR_NOT_OPENED;
goto abort;
}
#endif
/* Çàïîìèíàåì ñòàðûé îïèñàòåëü */
old_index = fs_file.entry_index;
old_sector = fs_file.entry_sector;
old_start_cluster = fs_file.entry_start_cluster;
/* Ñîçäàåì íîâûé ôàéë. Â ïàïêó îí ïðåâðàòèòñÿ ïîçæå. 0x80 - ýòî ïðåäîòâðàùàåì ðåêóðñèþ. */
if(fs_open0(OPENED_FILE | 0x80)) goto abort;
/* Ïðåäîòâðàùàåì îøèáêè ïðîãðàììèñòà */
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_NONE;
#ifndef FS_DISABLE_SWAP
fs_secondFile.opened = OPENED_NONE;
#endif
#endif
/* fs_file.sector ñîäåæèò ïåðâûé êëàñòåð ïàïêè, â êîòîðîé íàõîäèòñÿ ñîçäàííûé ôàéë. */
/* Óäàëåíèå ñòàðîãî ôàéëà/ïàïêè è ïåðåíîñ âñåõ ñâîéñòâ */
if(sd_readBuf(old_sector)) goto abort;
entry = buf + (old_index % 16) * 32;
memcpy(tmp, entry+11, 21);
entry[0] = 0xE5;
if(sd_writeBuf(old_sector)) goto abort;
/* Êîïèðóåì âñå ñâîéñòâà íîâîìó ôàéëó, òåì ñàìûì ïðåâðàùàÿ åãî â ïàïêó */
if(sd_readBuf(fs_file.entry_sector)) goto abort;
entry = buf + (fs_file.entry_index % 16) * 32;
memcpy(entry+11, tmp, 21);
if(sd_writeBuf(fs_file.entry_sector)) goto abort;
/* Â ïàïêå íàäî åùå ñêîððåòèðîâàòü îïèñàòåëü .. */
if(entry[DIR_Attr] & AM_DIR)
{
fs_tmp = old_start_cluster; /* Ïåðâûé êëàñòåð íàøåé ïàïêè */
fs_clust2sect();
if(sd_readBuf(fs_tmp)) goto abort;
fs_setEntryCluster(buf+32, fs_parent_dir_cluster); /* Ïåðâûé êëàñòåð ïàïêè ïðåäêà.*/
if(sd_writeBuf(fs_tmp)) goto abort;
}
return 0;
abort:
return 1;
}
uint8_t fs_move(const char* from, const char* to)
{
strcpy((char*)buf, from);
if(fs_openany()) return 1;
strcpy((char*)buf, to);
return fs_move0();
}
/**************************************************************************
* Óäàëèòü ôàéë èëè ïóñòóþ ïàïêó *
* Èìÿ ôàéëà äîëæíî ñîäåðæàòüñÿ â buf è íå ïðåâûøàòü FS_MAXFILE ñèìîëîâ *
* âêëþ÷àÿ òåðìèíàòîð *
**************************************************************************/
uint8_t fs_delete()
{
uint32_t entrySector;
uint8_t* entry;
/* Òàì áóäåò ïðîâåðåí fs_type == FS_ERROR */
if(fs_openany()) goto abort;
/* Ïðåäîòâðàùàåì îøèáêè ïðîãðàììèñòà */
fs_file.opened = OPENED_NONE;
#ifndef FS_DISABLE_SWAP
fs_secondFile.opened = OPENED_NONE;
#endif
/* Êîðíåâóþ ïàïêó óäàëÿòü íåëüçÿ */
if(FS_DIRENTRY[0] == 0)
{
lastError = ERR_NO_PATH;
goto abort;
}
/* Ñîõðàíÿåì èíòåðôîðìàöèþ î íàéäåííîì ôàéëå, òàê êàê fs_readdir íèæå èõ ïðèáüåò */
entrySector = fs_file.entry_sector;
entry = buf + (fs_file.entry_index % 16) * 32;
/* Â ïàïêå íå äîëæíî áûòü ôàéëîâ */
if(FS_DIRENTRY[DIR_Attr] & AM_DIR)
{
/* Ïåðåìàòûâåì ïàïêó íà íà÷àëî */
fs_file.entry_able = 0;
/* Èùåì ïåðâûé ôàéë èëè ïàïêó */
/* fs_file.entry_start_cluster ñîõðÿíÿåòñÿ (ñîäåðæèò ïåðâûé êëàñòåð ôàéëà èëè ïàïêè) */
if(fs_readdir_nocheck()) goto abort;
/* Åñëè íàøëè, òî îøèáêà */
if(fs_file.entry_able)
{
lastError = ERR_DIR_NOT_EMPTY;
goto abort;
}
}
/* Óäàëÿåì îïèñàòåëü */
if(sd_readBuf(entrySector)) goto abort;
entry[0] = 0xE5;
if(sd_writeBuf(entrySector)) goto abort;
/* Îñâîáîæäàåì öåïî÷êó êëàñòåðîâ */
fs_tmp = fs_file.entry_start_cluster;
return fs_freeChain();
abort:
return 1;
}
/**************************************************************************
* Îáíîâèòü âðåìÿ ïîñëåäíåé çàïèñè ôàéëà *
* Ôàéë äîëæåí áûòü îòêðûò *
**************************************************************************/
static uint8_t fs_update_timestamp(void)
{
#ifndef FS_DISABLE_CHECK
if(fs_file.opened != OPENED_FILE && fs_file.opened != OPENED_DIR)
{
lastError = ERR_NOT_OPENED;
return 1;
}
#endif
/* Ïîëó÷àåì òåêóùåå âðåìÿ */
uint16_t fat_time = fat_pack_time();
uint16_t fat_date = fat_pack_date();
/* ×èòàåì ñåêòîð ñ çàïèñüþ */
if(sd_readBuf(fs_file.entry_sector)) return 1;
/* Ïîëó÷àåì óêàçàòåëü íà çàïèñü â êàòàëîãå */
uint8_t* entry = buf + (fs_file.entry_index % 16) * 32;
/* Îáíîâëÿåì âðåìÿ ïîñëåäíåé çàïèñè */
LD_uint16_t(entry + DIR_WrtTime) = fat_time;
LD_uint16_t(entry + DIR_WrtDate) = fat_date;
/* Åñëè âðåìÿ ñîçäàíèÿ íå óñòàíîâëåíî, óñòàíàâëèâàåì åãî */
if(LD_uint16_t(entry + DIR_CrtTime) == 0 && LD_uint16_t(entry + DIR_CrtDate) == 0)
{
LD_uint16_t(entry + DIR_CrtTime) = fat_time;
LD_uint16_t(entry + DIR_CrtDate) = fat_date;
}
/* Ñîõðàíÿåì èçìåíåíèÿ */
return sd_writeBuf(fs_file.entry_sector);
}
/**************************************************************************
* Óñòàíîâèòü êîíåö ôàéëà *
**************************************************************************/
uint8_t fs_write_eof()
{
/* Ïðîâåðêà îøèáîê ïðîãðàììèñòà */
#ifndef FS_DISABLE_CHECK
if(fs_file.opened != OPENED_FILE)
{
lastError = ERR_NOT_OPENED;
goto abort;
}
#endif
/* Êîððåêòèðóåì ëèáî FAT, ëèáî îïèñàòåëü ôàéëà. */
if(fs_file.ptr == 0)
{
/* Óäàëåì âñå êëàñòåðû ôàéëà */
fs_tmp = fs_file.entry_start_cluster;
fs_file.entry_start_cluster = 0;
}
else
{
/* Ýòîò êëàñòåð ôàéëà ïîñëåäíèé. */
fs_tmp = LAST_CLUSTER;
if(fs_setNextCluster(fs_file.cluster)) goto abort; /* fs_tmp áóäåò ñîäåðæàòü ñëåäóþùèé êëàñòåð, òàê êàê çàïèñûâàåòñÿ LAST_CLUSTER */
}
/* Óäàëåì âñå êëàñòåðû ôàéëà ïîñëå ýòîãî. (îíè ñîäåðæàòñÿ â fs_tmp); */
if(fs_freeChain()) goto abort;
/* Ñîõðàíÿåì äëíó è ïåðâûé êëàñòåð */
fs_file.size = fs_file.ptr;
fs_file.changed = 1;
if(!fs_saveFileLength()) return 0;
abort:
#ifndef FS_DISABLE_CHECK
fs_file.opened = OPENED_NONE;
#endif
return 1;
}
/**************************************************************************
* Çàïèñàòü â ôàéë *
**************************************************************************/
uint8_t fs_write(uint8_t* ptr, uint16_t len)
{
/* Ïðîâåðêà íà îøèáêè ïðîèñõîäèò â âûçûâàåìûõ ôóíêöèÿõ */
/* Êîíåö ôàéëà */
if(len == 0) return fs_write_eof();
fs_wtotal = len;
do
{
if(fs_write_start()) goto abort;
memcpy(fs_file_wbuf, ptr, fs_file_wlen);
ptr += fs_file_wlen;
if(fs_write_end()) goto abort;
}
while(fs_wtotal);
return 0;
abort:
return 1;
}
/**************************************************************************
* Ïåðåêëþ÷èòü ôàéëû *
**************************************************************************/
#ifndef FS_DISABLE_SWAP
void fs_swap()
{
/* Ýòî çàíèìàåò ìåíüøå ÏÇÓ, ÷åì òðè ôóíêöèè memcpy */
uint8_t t, *a = (uint8_t*)&fs_file, *b = (uint8_t*)&fs_secondFile, n = sizeof(File);
do
{
t=*a, *a=*b, *b=t;
++a;
++b;
}
while(--n);
}
#endif
/**************************************************************************
* Ðàñ÷åò ñâîáîäíîãî ìåñòà *
* *
* Ðåçóëüòàò â ïåðåìåííîé fs_tmp â ìåãàáàéòàõ *
* Ôóíêöèÿ çàêðûâàåò ôàéë *
**************************************************************************/
#ifndef FS_DISABLE_GETFREESPACE
uint8_t fs_getfree()
{
/* Ìû èñïîðòèì ïåðåìåííóþ fs_file.sector, ïîýòîìó çàêðûâàåì ôàéë */
fs_file.opened = OPENED_NONE;
/* Êîë-âî ñâîáîäíûõ êëàñòåðîâ áóäåò â fs_file.sector */
fs_file.sector = 0;
if(fs_allocCluster(1)) return 1;
/* Ïåðåñ÷åò â ìåãàáàéòû */
fs_tmp = ((fs_file.sector >> 10) + 1) / 2 * fs_csize;
return 0;
}
#endif
/**************************************************************************
* Ðàçìåð íàêîïèòåëÿ â ìåãàáàéòàõ *
**************************************************************************/
uint8_t fs_gettotal()
{
/* Ïðîâåðêà îøèáîê ïðîãðàììèñòà */
#ifndef FS_DISABLE_CHECK
if(fs_type == FS_ERROR)
{
lastError = ERR_NO_FILESYSTEM;
return 1;
}
#endif
fs_tmp = ((fs_n_fatent >> 10) + 1) / 2 * fs_csize;
return 0;
}
/**************************************************************************
* Ðàçìåð ôàéëà *
**************************************************************************/
uint8_t fs_getfilesize()
{
#ifndef FS_DISABLE_CHECK
if(fs_file.opened != OPENED_FILE)
{
lastError = ERR_NOT_OPENED;
return 1;
}
#endif
fs_tmp = fs_file.size;
return 0;
}
/**************************************************************************
* Óêàçàòåëü ÷òåíèÿ çàïèñè ôàéëà *
**************************************************************************/
uint8_t fs_tell()
{
#ifndef FS_DISABLE_CHECK
if(fs_file.opened != OPENED_FILE)
{
lastError = ERR_NOT_OPENED;
return 1;
}
#endif
fs_tmp = fs_file.ptr;
return 0;
}