Subversion Repositories NaviCtrl

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
412 holgerb 1
/*#######################################################################################*/
2
/* !!! THIS IS NOT FREE SOFTWARE !!!                                                     */
3
/*#######################################################################################*/
4
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5
// + www.MikroKopter.com
6
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7
// + Software Nutzungsbedingungen (english version: see below)
8
// + der Fa. HiSystems GmbH, Flachsmeerstrasse 2, 26802 Moormerland - nachfolgend Lizenzgeber genannt -
9
// + Der Lizenzgeber räumt dem Kunden ein nicht-ausschließliches, zeitlich und räumlich* unbeschränktes Recht ein, die im den
10
// + Mikrocontroller verwendete Firmware für die Hardware Flight-Ctrl, Navi-Ctrl, BL-Ctrl, MK3Mag & PC-Programm MikroKopter-Tool 
11
// + - nachfolgend Software genannt - nur für private Zwecke zu nutzen.
12
// + Der Einsatz dieser Software ist nur auf oder mit Produkten des Lizenzgebers zulässig.
13
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14
// + Die vom Lizenzgeber gelieferte Software ist urheberrechtlich geschützt. Alle Rechte an der Software sowie an sonstigen im
15
// + Rahmen der Vertragsanbahnung und Vertragsdurchführung überlassenen Unterlagen stehen im Verhältnis der Vertragspartner ausschließlich dem Lizenzgeber zu.
16
// + Die in der Software enthaltenen Copyright-Vermerke, Markenzeichen, andere Rechtsvorbehalte, Seriennummern sowie
17
// + sonstige der Programmidentifikation dienenden Merkmale dürfen vom Kunden nicht verändert oder unkenntlich gemacht werden.
18
// + Der Kunde trifft angemessene Vorkehrungen für den sicheren Einsatz der Software. Er wird die Software gründlich auf deren
19
// + Verwendbarkeit zu dem von ihm beabsichtigten Zweck testen, bevor er diese operativ einsetzt.
20
// + Die Haftung des Lizenzgebers wird - soweit gesetzlich zulässig - begrenzt in Höhe des typischen und vorhersehbaren
21
// + Schadens. Die gesetzliche Haftung bei Personenschäden und nach dem Produkthaftungsgesetz bleibt unberührt. Dem Lizenzgeber steht jedoch der Einwand 
22
// + des Mitverschuldens offen.
23
// + Der Kunde trifft angemessene Vorkehrungen für den Fall, dass die Software ganz oder teilweise nicht ordnungsgemäß arbeitet.
24
// + Er wird die Software gründlich auf deren Verwendbarkeit zu dem von ihm beabsichtigten Zweck testen, bevor er diese operativ einsetzt.
25
// + Der Kunde wird er seine Daten vor Einsatz der Software nach dem Stand der Technik sichern.
26
// + Der Kunde ist darüber unterrichtet, dass der Lizenzgeber seine Daten im zur Vertragsdurchführung erforderlichen Umfang
27
// + und auf Grundlage der Datenschutzvorschriften erhebt, speichert, verarbeitet und, sofern notwendig, an Dritte übermittelt.
28
// + *) Die räumliche Nutzung bezieht sich nur auf den Einsatzort, nicht auf die Reichweite der programmierten Software.
29
// + #### ENDE DER NUTZUNGSBEDINGUNGEN ####'
30
// +  Hinweis: Informationen über erweiterte Nutzungsrechte (wie z.B. Nutzung für nicht-private Zwecke) sind auf Anfrage per Email an info(@)hisystems.de verfügbar.
31
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
32
// + Software LICENSING TERMS
33
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
34
// + of HiSystems GmbH, Flachsmeerstrasse 2, 26802 Moormerland, Germany - the Licensor -
35
// + The Licensor grants the customer a non-exclusive license to use the microcontroller firmware of the Flight-Ctrl, Navi-Ctrl, BL-Ctrl, and MK3Mag hardware 
36
// + (the Software) exclusively for private purposes. The License is unrestricted with respect to time and territory*.
37
// + The Software may only be used with the Licensor's products.
38
// + The Software provided by the Licensor is protected by copyright. With respect to the relationship between the parties to this
39
// + agreement, all rights pertaining to the Software and other documents provided during the preparation and execution of this
40
// + agreement shall be the property of the Licensor.
41
// + The information contained in the Software copyright notices, trademarks, other legal reservations, serial numbers and other
42
// + features that can be used to identify the program may not be altered or defaced by the customer.
43
// + The customer shall be responsible for taking reasonable precautions
44
// + for the safe use of the Software. The customer shall test the Software thoroughly regarding its suitability for the
45
// + intended purpose before implementing it for actual operation. The Licensor's liability shall be limited to the extent of typical and
46
// + foreseeable damage to the extent permitted by law, notwithstanding statutory liability for bodily injury and product
47
// + liability. However, the Licensor shall be entitled to the defense of contributory negligence.
48
// + The customer will take adequate precautions in the case, that the software is not working properly. The customer will test
49
// + the software for his purpose before any operational usage. The customer will backup his data before using the software.
50
// + The customer understands that the Licensor collects, stores and processes, and, where required, forwards, customer data
51
// + to third parties to the extent necessary for executing the agreement, subject to applicable data protection and privacy regulations.
52
// + *) The territory aspect only refers to the place where the Software is used, not its programmed range.
53
// + #### END OF LICENSING TERMS ####
54
// + Note: For information on license extensions (e.g. commercial use), please contact us at info(@)hisystems.de.
55
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
56
#include <stdio.h>
57
#include <string.h>
58
#include "91x_lib.h"
59
#include "timer1.h"
60
#include "fat16.h"
61
#include "sdc.h"
62
#include "uart1.h"
63
#include "main.h"
64
#include "logging.h"
65
 
66
 
67
//________________________________________________________________________________________________________________________________________
68
// Module name:                 fat16.c
69
// Compiler used:               avr-gcc 3.4.5
70
// Last Modifikation:   20.03.2010
71
// Version:                             2.10
72
// Authors:                             Stephan Busker & Gregor Stobrawa
73
// Description:                 Source files for FAT16 implementation with read and write-access
74
//                                              Copyright (C) 2008 Stephan Busker & Gregor Stobrawa
75
//........................................................................................................................................
76
// Functions:                   extern s16              Fat16_Init(void);
77
//                                              extern s16              Fat16_Deinit(void);
78
//                                              extern s8*              FAT16_GetVolumeLabel(void);
79
//                                              extern File_t * fopen_(const u8 *filename, const s8 mode);
80
//                                              extern s16              fclose_(File_t *File);
81
//                                              extern u8               fexist_(s8 * const filename);
82
//                                              extern s16              fflush_(File_t *File);
83
//                                              extern s16      fseek_(File_t *File, s32 offset, s16 origin);
84
//                                              extern s16              fgetc_(File_t *File);
85
//                                              extern s16              fputc_(u8 c, File_t *File);
86
//                                              extern u32              fread_(void *buffer, u32 size, u32 count, File_t *File);
87
//                                              extern u32              fwrite_(void *buffer, u32 size, u32 count, File_t *File);
88
//                                              extern s16              fputs_(const u8 *string, File_t *File);
89
//                                              extern u8 *     fgets_(u8 *string, s16 length, File_t *File);
90
//                                              extern u8               feof_(File_t * const file);
91
//........................................................................................................................................
92
// ext. functions:              extern SD_Result_t SDC_Init(void;)
93
//                                              extern SD_Result_t SDC_Deinit(void);
94
//                      extern SD_Result_t SDC_GetSector (u32,u8 *);
95
//                                              extern SD_Result_t SDC_PutSector (u32,u8 *);
96
//........................................................................................................................................
97
//
98
// URL:                                 www.Mikro-Control.de
99
// mailto:                              stephan.busker@mikro-control.de
100
//________________________________________________________________________________________________________________________________________
101
 
102
/*
103
FAT16 Drive Layout:
104
Description                                             Offset
105
Volume Boot Sector                                      Start of Partition
106
Fat Tables                                                      Start + # of Reserved Sectors
107
Root Directory Entry                            Start + # of Reserved + (# of Sectors Per FAT * 2)
108
Data Area (Starts with Cluster #2)      Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
109
*/
110
 
111
 
112
 
113
/*
114
________________________________________________________________________________________________________________________________________
115
 
116
        Structure of an partition entry
117
________________________________________________________________________________________________________________________________________
118
 
119
        Partition Entry is 16 bytes long
120
*/
121
typedef struct
122
{
123
        u8      PartitionState;                         // Current State of Partition (00h=Inactive, 80h=Active)
124
        u8      BeginningHead;                          // Beginning of Partition - Head
125
        u16     BeginningCylSec;                        // Beginning of Partition - Cylinder/Sector (See Below)
126
        u8      Type;                                           // Type of Partition (See List Below)
127
        u8      EndHead;                                        // End of Partition - Head
128
        u16     EndCylSec;                                      // End of Partition - Cylinder/Sector
129
        u32     NoSectorsBeforePartition;       // Number of Sectors between the MBR and the First Sector in the Partition
130
        u32     NoSectorsPartition      ;               // Number of Sectors in the Partition
131
} __attribute__((packed)) PartitionEntry_t;
132
 
133
 
134
 
135
/*
136
Coding of Cylinder/Sector words
137
 
138
Cylinder is 10 bits:  [7:0] at [15:8] and [9:8] at [7:6]
139
Sector is 5 bits:  [5:0] at [5:0]
140
*/
141
 
142
// Partition Types:
143
#define PART_TYPE_UNKNOWN                       0x00
144
#define PART_TYPE_FAT12                         0x01
145
#define PART_TYPE_XENIX                         0x02
146
#define PART_TYPE_FAT16_ST_32_MB        0x04
147
#define PART_TYPE_EXTDOS                        0x05
148
#define PART_TYPE_FAT16_LT_32_MB        0x06
149
#define PART_TYPE_NTFS                          0x07
150
#define PART_TYPE_FAT32                         0x0B
151
#define PART_TYPE_FAT32LBA                      0x0C
152
#define PART_TYPE_FAT16LBA                      0x0E
153
#define PART_TYPE_EXTDOSLBA                     0x0F
154
#define PART_TYPE_EISA                          0x12
155
#define PART_TYPE_ONTRACK                       0x33
156
#define PART_TYPE_NOVELL                        0x40
157
#define PART_TYPE_DYNAMIC                       0x42
158
#define PART_TYPE_PCIX                          0x4B
159
#define PART_TYPE_LINUX_SWAP            0x82
160
#define PART_TYPE_LINUX_NATIVE          0x83
161
#define PART_TYPE_LINUX_LVM                     0x8E
162
#define PART_TYPE_PHOENIXSAVE           0xA0
163
#define PART_TYPE_FREEBSD                       0xA5
164
#define PART_TYPE_OPENBSD                       0xA6
165
#define PART_TYPE_NETNBSD                       0xA9
166
#define PART_TYPE_CPM                           0xDB
167
#define PART_TYPE_DBFS                          0xE0
168
#define PART_TYPE_BBT                           0xFF
169
 
170
 
171
/*
172
________________________________________________________________________________________________________________________________________
173
 
174
        Structure of the MasterBootRecord
175
________________________________________________________________________________________________________________________________________
176
 
177
        Master Boot Record is 512 bytes long
178
        The Master Boot Record is the same for pretty much all Operating Systems.
179
        It is located on the first Sector of the Hard Drive, at Cylinder 0, Head 0, Sector 1
180
*/
181
typedef struct
182
{
183
        u8                              ExecutableCode[446];    // 446 bytes for machine start code
184
        PartitionEntry_t        PartitionEntry1;                // 16 bytes for partition entry 1
185
        PartitionEntry_t        PartitionEntry2;                // 16 bytes for partition entry 2
186
        PartitionEntry_t        PartitionEntry3;                // 16 bytes for partition entry 3
187
        PartitionEntry_t        PartitionEntry4;                // 16 bytes for partition entry 4
188
        u16                                     ExecutableMarker;               // BIOS-Signature (0x55 0xAA)
189
} __attribute__((packed)) MBR_Entry_t;
190
 
191
 
192
/*
193
________________________________________________________________________________________________________________________________________
194
 
195
        Structure of the VolumeBootRecord
196
________________________________________________________________________________________________________________________________________
197
 
198
        The Volume Boot Record is 512 bytes long
199
        This information is located in the first sector of every partition.
200
*/
201
typedef struct
202
{
203
        u8  JumpCode[3];                        // Jump Code + NOP
204
        s8  OEMName[8];                         // OEM Name
205
        u16 BytesPerSector;                     // Bytes Per Sector
206
        u8  SectorsPerCluster;          // Sectors Per Cluster
207
        u16 ReservedSectors;            // Reserved Sectors
208
        u8  NoFATCopies;                        // Number of Copies of FAT
209
        u16 MaxRootEntries;                     // Maximum Root Directory Entries
210
        u16 NoSectorsInPartSml32MB;     // Number of Sectors in Partition Smaller than 32 MB
211
        u8  MediaDescriptor;            // Media Descriptor (0xF8 for Hard Disks)
212
        u16 SectorsPerFAT;                      // Sectors Per FAT
213
        u16 SectorsPerTrack;            // Sectors Per Track
214
        u16 NoHeads;                            // Number of Heads
215
        u32 NoHiddenSectors;            // Number of Hidden Sectors     in Partition
216
        u32 NoSectors;                          // Number of Sectors in Partition
217
        u16     DriveNo;                                // Logical Drive Number of Partition
218
        u8  ExtendedSig;                        // Extended Signature (0x29)
219
        u32 SerialNo;                           // Serial Number of the Partition
220
        s8  VolumeName[11];                     // Volume Name of the Partititon
221
        s8  FATName[8];                         // FAT Name (FAT16)
222
        u8  ExecutableCode[446];        // 446 bytes for machine start code
223
        u16 ExecutableMarker;           // Executable Marker (0x55 0xAA)
224
} __attribute__((packed)) VBR_Entry_t;
225
 
226
 
227
 
228
/*
229
________________________________________________________________________________________________________________________________________
230
 
231
        Structure of an directory entry
232
________________________________________________________________________________________________________________________________________
233
 
234
        Directory entry is 32 bytes.
235
*/
236
typedef struct
237
{
238
        s8      Name[8];                                        // 8 bytes name, padded with spaces.
239
        u8      Extension[3];                           // 3 bytes extension, padded with spaces.
240
        u8      Attribute;                                      // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
241
        u8  Res1;                                               // should be zero
242
        u8  CreationTime10ms;                   // subsecond resolution of creation time
243
        u16 CreationTime;                               // Time of creation h:m:s
244
        u16 CreationDate;                               // Date of creation Y.M.D
245
        u16 LastAccessDate;             // The date where the file was last accessed
246
        u8      Res2[2];                                    // should be zero
247
        u16 ModTime;                                    // date of last write access
248
        u16 ModDate;                                    // date of last write access to the file or directory.
249
        u16 StartCluster;                               // first cluster of the file or directory.
250
        u32 Size;                                               // size of the file or directory in bytes.
251
}  __attribute__((packed)) DirEntry_t;
252
 
253
#define SLOT_EMPTY              0x00    // slot has never been used
254
#define SLOT_E5                 0x05    // the real value is 0xe5
255
#define SLOT_DELETED            0xE5    // file in this slot deleted
256
 
257
#define ATTR_NONE               0x00    // normal file
258
#define ATTR_READONLY           0x01    // file is readonly
259
#define ATTR_HIDDEN                     0x02    // file is hidden
260
#define ATTR_SYSTEM                     0x04    // file is a system file
261
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
262
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
263
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
264
#define ATTR_ARCHIVE            0x20    // file is new or modified
265
 
266
 
267
/*
268
________________________________________________________________________________________________________________________________________
269
 
270
        Structure of an entry within the fileallocationtable.
271
________________________________________________________________________________________________________________________________________
272
*/
273
typedef struct
274
{
275
        u16  NextCluster;                               // the next cluster of the file.
276
} __attribute__((packed)) Fat16Entry_t;
277
 
278
// secial fat entries
279
#define FAT16_CLUSTER_FREE                      0x0000
280
#define FAT16_CLUSTER_RESERVED          0x0001
281
#define FAT16_CLUSTER_USED_MIN          0x0002
282
#define FAT16_CLUSTER_USED_MAX          0xFFEF
283
#define FAT16_CLUSTER_ROOTDIR_MIN       0xFFF0
284
#define FAT16_CLUSTER_ROOTDIR_MAX       0xFFF6
285
#define FAT16_CLUSTER_BAD                       0xFFF7
286
#define FAT16_CLUSTER_LAST_MIN          0xFFF8
287
#define FAT16_CLUSTER_LAST_MAX          0xFFFF
288
 
289
/*****************************************************************************************************************************************/
290
/*                                                                                                                                                                                                                                                                               */
291
/*      Global variables needed for read- or write-acces to the FAT16- filesystem.                                                                                                                       */
292
/*                                                                                                                                                                                                                                                                               */
293
/*****************************************************************************************************************************************/
294
 
295
#define MBR_SECTOR                                      0x00    // the masterboot record is located in sector 0.
296
#define DIRENTRY_SIZE                           32              //bytes
297
#define DIRENTRIES_PER_SECTOR           BYTES_PER_SECTOR/DIRENTRY_SIZE
298
#define FAT16_BYTES                                     2
299
#define FAT16_ENTRIES_PER_SECTOR        BYTES_PER_SECTOR/FAT16_BYTES
300
 
301
#define SECTOR_UNDEFINED        0x00000000L
302
#define CLUSTER_UNDEFINED       0x0000
303
 
304
#define FSTATE_UNUSED   0
305
#define FSTATE_USED             1
306
 
307
typedef struct
308
{
309
        u8      IsValid;                                // 0 means invalid, else valid
310
        u8      SectorsPerCluster;              // how many sectors does a cluster contain?
311
        u8      FatCopies;                              // Numbers of copies of the FAT
312
        u16     MaxRootEntries;                 // Possible number of entries in the root directory.
313
        u16     SectorsPerFat;                  // how many sectors does a fat16 contain?
314
        u32 FirstFatSector;                     // sector of the start of the fat
315
        u32 FirstRootDirSector;         // sector of the rootdirectory
316
        u32 FirstDataSector;            // sector of the first cluster containing data (cluster2).
317
        u32 LastDataSector;                     // the last data sector of the partition
318
        u8  VolumeLabel[12];        // the volume label
319
        u32     CurrentWorkingDirectory;// A pointer to the directory we are actual using 
320
        s8      PathToCwd[256];                 // a string containing the complete path to the current working directory                               
321
}   __attribute__((packed)) Partition_t;
322
 
323
Partition_t     Partition;              // Structure holds partition information
324
 
325
File_t FilePointer[FILE_MAX_OPEN];      // Allocate Memmoryspace for each filepointer used.
326
 
327
 
328
 
329
 
330
/****************************************************************************************************************************************/
331
/*      Function:               FileDate(DateTime_t *);                                                                                                                                                                                         */
332
/*                                                                                                                                                                                                                                                                              */
333
/*      Description:    This function calculates the DOS date from a pointer to a time structure.                                                                                       */
334
/*                                                                                                                                                                                                                                                                              */
335
/*      Returnvalue:    Returns the DOS date.                                                                                                                                                                                           */
336
/****************************************************************************************************************************************/
337
u16 FileDate(DateTime_t * pTimeStruct)
338
{
339
        u16 date = 0;
340
        if(pTimeStruct == NULL)   return date;
341
        if(!(pTimeStruct->Valid)) return date;
342
 
343
        date |= (0x007F & (u16)(pTimeStruct->Year - 1980))<<9; // set year
344
        date |= (0x000F & (u16)(pTimeStruct->Month))<<5; // set month
345
        date |= (0x001F & (u16)(pTimeStruct->Day));
346
        return date;
347
}
348
 
349
/****************************************************************************************************************************************/
350
/*      Function:               FileTime(DateTime_t *);                                                                                                                                                                                         */
351
/*                                                                                                                                                                                                                                                                              */
352
/*      Description:    This function calculates the DOS time from a pointer to a time structure.                                                                                       */
353
/*                                                                                                                                                                                                                                                                              */
354
/*      Returnvalue:    Returns the DOS time.                                                                                                                                                                                           */
355
/****************************************************************************************************************************************/
356
 
357
u16 FileTime(DateTime_t * pTimeStruct)
358
{
359
        u16 time = 0;
360
        if(pTimeStruct == NULL)   return time;
361
        if(!(pTimeStruct->Valid)) return time;
362
 
363
        time |= (0x001F & (u16)(pTimeStruct->Hour))<<11;
364
        time |= (0x003F & (u16)(pTimeStruct->Min))<<5;
365
        time |= (0x001F & (u16)(pTimeStruct->Sec/2));
366
        return time;
367
}
368
 
369
/****************************************************************************************************************************************/
370
/*      Function:               LockFilePointer();                                                                                                                                                                                                      */
371
/*                                                                                                                                                                                                                                                                              */
372
/*      Description:    This function trys to lock a free file pointer.                                                                                                                                         */
373
/*                                                                                                                                                                                                                                                                              */
374
/*      Returnvalue:    Returns the Filepointer on success or 0.                                                                                                                                                        */
375
/****************************************************************************************************************************************/
376
File_t * LockFilePointer(void)
377
{
378
        u8 i;
379
        File_t * File = 0;
380
        for(i = 0; i < FILE_MAX_OPEN; i++)
381
        {
382
                if(FilePointer[i].State == FSTATE_UNUSED)               // found an unused one
383
                {
384
                        File = &FilePointer[i];                                         // set pointer to that entry
385
                        FilePointer[i].State = FSTATE_USED;                     // mark it as used
386
                        break;
387
                }
388
        }
389
        return(File);
390
}
391
 
392
/****************************************************************************************************************************************/
393
/*      Function:               UnlockFilePointer(file_t *);                                                                                                                                                                            */
394
/*                                                                                                                                                                                                                                                                              */
395
/*      Description:    This function trys to unlock a file pointer.                                                                                                                                            */
396
/*                                                                                                                                                                                                                                                                              */
397
/*      Returnvalue:    Returns 1 if file pointer was freed else 0.                                                                                                                                                     */
398
/****************************************************************************************************************************************/
399
u8 UnlockFilePointer(File_t * file)
400
{
401
        u8 cnt;
402
        if(file == NULL) return(0);
403
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
404
        {
405
                if(&FilePointer[cnt] == file)                                           // filepointer to be freed found?
406
                {
407
                        file->State = FSTATE_UNUSED;
408
                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;                     // Sectorpointer to the first sector of the first datacluster of the file.
409
                        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;                     // Pointer to the cluster which is edited at the moment.
410
                        file->SectorOfCurrCluster               = 0;                    // The sector which is edited at the moment (cluster_pointer + sector_index).
411
                        file->ByteOfCurrSector                  = 0;                    // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
412
                        file->Mode                                              = 0;                    // mode of fileoperation (read,write)
413
                        file->Size                                              = 0;                    // the size of the opend file in bytes.
414
                        file->Position                                  = 0;                    // pointer to a character within the file 0 < fileposition < filesize
415
                        file->SectorInCache                     = SECTOR_UNDEFINED;                     // the last sector read, wich is still in the sectorbuffer.
416
                        file->DirectorySector                   = SECTOR_UNDEFINED;                     // the sectorposition where the directoryentry has been made.
417
                        file->DirectoryIndex                    = 0;                    // the index to the directoryentry within the specified sector.
418
                        file->Attribute                                 = 0;                    // the attribute of the file opened.
419
                        file = NULL;
420
                        return(1);
421
                }
422
        }
423
        return(0);
424
}
425
 
426
/****************************************************************************************************************************************/
427
/*      Function:               SeperateDirName(s8*, s8*);                                                                                                                                                                              */
428
/*                                                                                                                                                                                                                                                                              */
429
/*      Description:    This function seperates the first dirname from filepath and brings them                                                                                         */
430
/*                                      into the needed format ('test.txt' -> 'TEST    TXT')                                                                                                                            */
431
/*                                      The subpath is the pointer to the remaining substring of the filepath                                                                                           */
432
/*                                                                                                                                                                                                                                                                              */
433
/*      Returnvalue:    Return NULL on error or pointer to subpath                                                                                                                                                                                                      */
434
/****************************************************************************************************************************************/
435
s8* SeperateDirName(const s8 *filepath, s8 *dirname)
436
{
437
        s8* subpath = NULL;
438
        u8 readpointer  = 0;
439
        u8 writepointer = 0;
440
 
441
        // search subpath from beginning of filepath
442
        subpath = NULL;
443
        readpointer     = 0;
444
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
445
        while(subpath == NULL)  // search the filepath until a subpath was found.
446
        {
447
                if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/')))    // if '/' found or end of filepath reached
448
                {
449
                        subpath = (s8*)&filepath[readpointer];                          // store the position of the first "/" found after the beginning of the filenpath
450
                }
451
                readpointer++;
452
        }
453
 
454
        // clear dirname with spaces
455
        dirname[11] = 0; // terminate dirname
456
        for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
457
 
458
        // handle the special dirnames "." and ".." seperately
459
        readpointer = 0;
460
        if(filepath[0] == '/') readpointer++;
461
        // if we are trying to enter directories "." or ".." 
462
        if(filepath[readpointer] == '.')
463
        {
464
                // directory '.'
465
                if(filepath[readpointer+1] == 0)
466
                {
467
                        dirname[0] = '.';
468
                        return((s8*)&filepath[readpointer]);
469
                }
470
                // directory '..'               
471
                if((filepath[readpointer+1] == '.') &&  (filepath[readpointer+2] == 0))
472
                {
473
                        dirname[0] = '.';
474
                        dirname[1] = '.';
475
                        return((s8*)&filepath[readpointer]);
476
                }
477
        }
478
 
479
        writepointer = 0;
480
        // start seperating the dirname from the filepath.
481
        readpointer = 0;
482
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
483
        while( &filepath[readpointer] < subpath)
484
        {
485
                if(writepointer >= 11) return(NULL);            // dirname to long
486
                if(filepath[readpointer] == '.')                        // seperating dirname and extension.
487
                {
488
                        if(writepointer <= 8)
489
                        {
490
                                readpointer++;                                          // next character in filename
491
                                writepointer = 8;                                       // jump to start of extension
492
                        }
493
                        else return(NULL);                                              // dirbasename to long
494
                }
495
                else
496
                {
497
                        if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
498
                        {
499
                                dirname[writepointer] = (filepath[readpointer] - 0x20);                                 // all characters must be upper case.
500
                        }
501
                        else
502
                        {
503
                                dirname[writepointer] = filepath[readpointer];
504
                        }
505
                        readpointer++;
506
                        writepointer++;
507
                }
508
        }
509
        return(subpath);
510
}
511
 
512
 
513
/**************************************************************************************************************************************+*/
514
/*      Function:       Fat16ClusterToSector( u16 cluster);                                                                                                                                                                             */
515
/*                                                                                                                                                                                                                                                                              */
516
/*      Description:    This function converts a cluster number given by the fat to the corresponding                                                                           */
517
/*                                      sector that points to the start of the data area that is represented by the cluster number.                                                     */
518
/*                                                                                                                                                                                                                                                                              */
519
/*      Returnvalue: The sector number with the data area of the given cluster                                                                                                                          */
520
/****************************************************************************************************************************************/
521
u32     Fat16ClusterToSector(u16 cluster)
522
{
523
        if(!Partition.IsValid) return SECTOR_UNDEFINED;
524
        if ((cluster < 2) || (cluster == CLUSTER_UNDEFINED))
525
        {
526
                return SECTOR_UNDEFINED;
527
        }
528
        else
529
        {
530
                return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector     is represented by the 2nd cluster
531
        }
532
}
533
 
534
/****************************************************************************************************************************************/
535
/*      Function:       SectorToFat16Cluster( u32 sector);                                                                                                                                                                              */
536
/*                                                                                                                                                                                                                                                                              */
537
/*      Description:    This function converts a given sector number given to the corresponding                                                                                         */
538
/*                                      cluster number in the fat that represents this data area.                                                                                                                       */
539
/*                                                                                                                                                                                                                                                                              */
540
/*      Returnvalue: The cluster number representing the data area of the sector.                                                                                                                       */
541
/****************************************************************************************************************************************/
542
u16     SectorToFat16Cluster(u32 sector)
543
{
544
        if(!Partition.IsValid) return CLUSTER_UNDEFINED;
545
        if((sector == SECTOR_UNDEFINED) || (sector < Partition.FirstDataSector)) return CLUSTER_UNDEFINED;
546
        else return ((u16)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
547
}
548
 
549
 
550
/****************************************************************************************************************************************/
551
/*      Function:       Fat16_IsValid(void);                                                                                                                                                                                                    */
552
/*                                                                                                                                                                                                                                                                              */
553
/*      Description:    This function return the Fat 16 filesystem state                                                                                                                                        */
554
/*                                                                                                                                                                                                                                                                              */
555
/*      Returnvalue: The function returns "1" on success                                                                                                                                                                        */
556
/****************************************************************************************************************************************/
557
u8 Fat16_IsValid(void)
558
{
559
        return(Partition.IsValid);
560
}
561
 
562
/****************************************************************************************************************************************/
563
/*      Function:       Fat16_Deinit(void);                                                                                                                                                                                                             */
564
/*                                                                                                                                                                                                                                                                              */
565
/*      Description:    This function uninitializes the fat 16 api                                                                                                                                                      */
566
/*                                                                                                                                                                                                                                                                              */
567
/*      Returnvalue: The function returns "0" on success                                                                                                                                                                        */
568
/****************************************************************************************************************************************/
569
u8 Fat16_Deinit(void)
570
{
571
        s16 returnvalue = 0;
572
        u8 cnt;
573
 
574
        UART1_PutString("\r\n FAT16 deinit...");
575
        // declare the filepointers as unused.
576
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
577
        {      
578
                UnlockFilePointer(&FilePointer[cnt]);
579
        }
580
        returnvalue = SDC_Deinit();                     // uninitialize interface to sd-card
581
        Partition.IsValid = 0;  // mark data in partition structure as invalid
582
        Partition.VolumeLabel[0]='\0';
583
        UART1_PutString("ok");
584
        if(SD_WatchDog > 2000) SD_WatchDog = 2000;
585
        SD_LoggingError = 100;
586
        return(returnvalue);
587
}
588
 
589
/****************************************************************************************************************************************/
590
/*      Function:               Fat16_Init(void);                                                                                                                                                                                                       */
591
/*                                                                                                                                                                                                                                                                          */
592
/*      Description:    This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdir    */
593
/*                                      and stores the information in global variables.                                                                                                                                     */
594
/*                                                                                                                                                                                                                                                                          */
595
/*      Returnvalue:    The function returns "0" if the filesystem is initialized.                                                                                                                      */
596
/****************************************************************************************************************************************/
597
u8 Fat16_Init(void)
598
{
599
    u8  cnt     = 0;
600
        u32     partitionfirstsector;
601
        VBR_Entry_t *VBR;
602
        MBR_Entry_t *MBR;
603
        File_t *file;
604
        u8 result = 0;
605
 
606
        UART1_PutString("\r\n FAT16 init...");
607
        Partition.IsValid = 0;
608
        // declare the filepointers as unused.
609
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
610
        {
611
                UnlockFilePointer(&FilePointer[cnt]);
612
        }
613
        // set current file pinter to first position in list
614
        file = &FilePointer[0];
615
 
616
        // try to initialize the sd-card.
617
        if(SD_SUCCESS != SDC_Init())
618
        {
619
                UART1_PutString("SD-Card could not be initialized.");
620
                result = 1;
621
                goto end;
622
        }
623
 
624
        // SD-Card is initialized successfully
625
        if(SD_SUCCESS != SDC_GetSector((u32)MBR_SECTOR,file->Cache))    // Read the MasterBootRecord
626
        {
627
                UART1_PutString("Error reading the MBR.");
628
                result = 2;
629
                goto end;
630
        }
631
        MBR = (MBR_Entry_t *)file->Cache;                                               // Enter the MBR using the structure MBR_Entry_t.
632
        if((MBR->PartitionEntry1.Type == PART_TYPE_FAT16_ST_32_MB) ||
633
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16_LT_32_MB) ||
634
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16LBA))
635
        {
636
                // get sector offset 1st partition
637
                partitionfirstsector = MBR->PartitionEntry1.NoSectorsBeforePartition;
638
                // Start of Partition is the Volume Boot Sector
639
                if(SD_SUCCESS != SDC_GetSector(partitionfirstsector,file->Cache)) // Read the volume boot record
640
                {
641
                        UART1_PutString("Error reading the VBR.");
642
                        result = 3;
643
                        goto end;
644
                }
645
        }
646
        else  // maybe the medium has no partition assuming sector 0 is the vbr
647
        {
648
                partitionfirstsector = 0;
649
        }
650
 
651
        VBR = (VBR_Entry_t *) file->Cache;                                              // Enter the VBR using the structure VBR_Entry_t.
652
        if(VBR->BytesPerSector != BYTES_PER_SECTOR)
653
        {
654
                UART1_PutString("VBR: Sector size not supported.");
655
                result = 4;
656
                goto end;
657
        }
658
        Partition.SectorsPerCluster             = VBR->SectorsPerCluster;                       // Number of sectors per cluster. Depends on the memorysize of the sd-card.
659
        Partition.FatCopies                     = VBR->NoFATCopies;                                     // Number of fatcopies.
660
        Partition.MaxRootEntries                = VBR->MaxRootEntries;                          // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
661
        Partition.SectorsPerFat                 = VBR->SectorsPerFAT;                           // The number of sectors per FAT                                // copy volume label
662
        Partition.VolumeLabel[0] = '\0';                                                                        // set string terminator
663
 
664
        /* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */
665
        // Calculate the position of the FileAllocationTable:
666
        // Start + # of Reserved Sectors
667
        Partition.FirstFatSector        =   (u32)(partitionfirstsector + (u32)(VBR->ReservedSectors));
668
        // Calculate the position of the Rootdirectory:
669
        // Start + # of Reserved Sectors + (# of Sectors Per FAT * # of FAT Copies)
670
        Partition.FirstRootDirSector    =   Partition.FirstFatSector + (u32)((u32)Partition.SectorsPerFat*(u32)Partition.FatCopies);
671
        // Calculate the position of the first datacluster:
672
        // Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
673
        Partition.FirstDataSector       =   Partition.FirstRootDirSector + (u32)(Partition.MaxRootEntries>>4);  // assuming 512 Byte Per Sector
674
        // Calculate the last data sector
675
        if(VBR->NoSectors == 0)
676
        {
677
                UART1_PutString("VBR: Bad number of sectors.");
678
                result = 5;
679
                goto end;
680
        }
681
        Partition.LastDataSector = Partition.FirstDataSector + VBR->NoSectors - 1;
682
        // check for FAT16 in VBR of first partition
683
        if(!((VBR->FATName[0]=='F') && (VBR->FATName[1]=='A') && (VBR->FATName[2]=='T') && (VBR->FATName[3]=='1')&&(VBR->FATName[4]=='6')))
684
        {
685
                UART1_PutString("VBR: Partition ist not FAT16 type.");
686
                result = 6;
687
                goto end;
688
        }
689
        Partition.IsValid = 1; // mark data in partition structure as valid
690
        Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
691
        strcpy(Partition.PathToCwd,"/");       
692
        result = 0;
693
        end:
694
        if(result != 0) Fat16_Deinit();
695
        else UART1_PutString("ok");
696
        return(result);
697
}
698
 
699
 
700
 
701
/****************************************************************************************************************************************/
702
/* Function:    ClearCurrCluster(File_t*);                                                                                                                                                                                      */
703
/*                                                                                                                                                                                                                                                                              */
704
/* Description: This function fills the current cluster with 0.                                                                                                                                                 */
705
/*                                                                                                                                                                                                                                                                              */
706
/* Returnvalue: The function returns 1 on success else 0.                                                                                                                                                               */
707
/****************************************************************************************************************************************/
708
u8 ClearCurrCluster(File_t * file)
709
{
710
        u8 retvalue = 1;
711
        u32 i;
712
 
713
        if((!Partition.IsValid) || (file == NULL)) return(0);
714
 
715
        for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
716
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return (0); // nothing to do 
717
        for(i = 0; i < Partition.SectorsPerCluster; i++)
718
        {
719
                file->SectorInCache = file->FirstSectorOfCurrCluster + i;
720
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
721
                {
722
                        Fat16_Deinit();
723
                        return(0);
724
                }
725
        }
726
        return(retvalue);
727
}
728
 
729
/*****************************************************************************************************************************************/
730
/* Function:    GetNextCluster(File_t* );                                                                                                                                                                                        */
731
/*                                                                                                                                                                                                                                                                               */
732
/* Description: This function finds the next datacluster of the file specified with File *File.                                                                                  */
733
/*                                                                                                                                                                                                                                                                               */
734
/* Returnvalue: The function returns the next cluster or 0 if the last cluster has already reached.                                                                                                      */
735
/*****************************************************************************************************************************************/
736
u16 GetNextCluster(File_t * file)
737
{
738
        u16 cluster = CLUSTER_UNDEFINED;
739
        u32 fat_byte_offset, sector, byte;
740
        Fat16Entry_t * fat;
741
 
742
        if((!Partition.IsValid) || (file == NULL)) return(cluster);
743
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(cluster);
744
        // if sector is within the data area
745
        if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
746
        {
747
                // determine current file cluster
748
                cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);
749
                // calculate byte offset in the fat for corresponding entry
750
                fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
751
                // calculate the sector that contains the current cluster within the fat
752
                sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
753
                // calculate byte offset of the current cluster within that fat sector
754
                byte = fat_byte_offset % BYTES_PER_SECTOR;
755
                // read this sector to the file cache
756
                if(file->SectorInCache != sector)
757
                {
758
                        file->SectorInCache = sector;                                           // update sector stored in buffer
759
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
760
                        {
761
                                Fat16_Deinit();
762
                                return (CLUSTER_UNDEFINED);
763
                        }
764
                }
765
                // read the next cluster from cache
766
                fat = (Fat16Entry_t *)(&(file->Cache[byte]));
767
                cluster = fat->NextCluster;
768
                // if no next cluster exist
769
                if(FAT16_CLUSTER_LAST_MIN <= cluster)
770
                {
771
                         cluster = CLUSTER_UNDEFINED; // next cluster is undefined
772
                }
773
                else
774
                {
775
                        file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
776
                        file->SectorOfCurrCluster = 0;
777
                        file->ByteOfCurrSector = 0;
778
                }
779
        }
780
        return(cluster);
781
}
782
 
783
 
784
 
785
/****************************************************************************************************************************************/
786
/* Function:    FindNextFreeCluster(File_t *);                                                                                                                                                                          */
787
/*                                                                                                                                                                                                                                                                              */
788
/* Description: This function looks in the fat to find the next free cluster                                                                                                                    */
789
/*                                                                                                                                                                                                                                                                              */
790
/* Returnvalue: The function returns the cluster number of the next free cluster found within the fat.                                                                  */
791
/****************************************************************************************************************************************/
792
u16 FindNextFreeCluster(File_t *file)
793
{
794
        u32 fat_sector;                                 // current sector within the fat relative to the first sector of the fat.
795
        u32     curr_sector;                            // current sector
796
        u16     fat_entry;                                      // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
797
        u16     free_cluster    = CLUSTER_UNDEFINED;    // next free cluster number.
798
        Fat16Entry_t * fat;
799
 
800
        if((!Partition.IsValid) || (file == NULL)) return(0);
801
 
802
        // start searching for an empty cluster at the beginning of the fat.
803
        fat_sector = 0;
804
        do
805
        {
806
                curr_sector = Partition.FirstFatSector + fat_sector;    // calculate sector to read
807
                file->SectorInCache = curr_sector;                                              // upate the sector number of file cache.
808
                if( SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))              // read sector of fat from sd-card.
809
                {
810
                        Fat16_Deinit();
811
                        return(CLUSTER_UNDEFINED);
812
                }
813
 
814
                fat = (Fat16Entry_t *)file->Cache;                                              // set fat pointer to file cache
815
 
816
                for(fat_entry = 0; fat_entry < FAT16_ENTRIES_PER_SECTOR; fat_entry++)                                           // look for an free cluster at all entries in this sector of the fat.
817
                {
818
                        if(fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE)            // empty cluster found!!
819
                        {
820
                                fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX;    // mark this fat-entry as used
821
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // and save the sector at the sd-card.
822
                                {
823
                                        Fat16_Deinit();
824
                                        return(CLUSTER_UNDEFINED);
825
                                }
826
                                free_cluster = (u16)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (u32)fat_entry);
827
                                fat_entry = FAT16_ENTRIES_PER_SECTOR;                                   // terminate the search for a free cluster in this sector.
828
                        }
829
                }
830
                fat_sector++;                                                                                                   // continue the search in next fat sector
831
        // repeat until the end of the fat is  reached and no free cluster has been found so far
832
        }while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
833
        return(free_cluster);
834
}
835
 
836
 
837
/****************************************************************************************************************************************************/
838
/* Function:    s16 fseek_(File_t *, s32 *, u8)                                                                                                                                                                                                         */
839
/*                                                                                                                                                                                                                                                                                                      */
840
/* Description: This function sets the pointer of the stream relative to the position                                                                                                                           */
841
/*                              specified by origin (SEEK_SET, SEEK_CUR, SEEK_END)                                                                                                                                                                      */
842
/* Returnvalue: Is 0 if seek was successful                                                                                                                                                                                                                     */
843
/****************************************************************************************************************************************************/
844
s16 fseek_(File_t *file, s32 offset, s16 origin)
845
{
846
        s32             fposition       = 0;
847
        s16     retvalue        = 1;
848
 
849
        // the byteindex within a sector 
850
        u32             byte_index       = 0;                  
851
        // the  sectorindex within a cluster                                                                    
852
        u32             sector_index  = 0;
853
        // the index of the cluster within the clusterchain inside the fat                                                                                                      
854
        u32     cluster_index = 0;                                                                                                     
855
 
856
        // check if the partition is valid      
857
        if((!Partition.IsValid) || (file == NULL)) return(retvalue);
858
//......................................................
859
        if(origin == SEEK_SET)                                                                                                          // Fileposition relative to the beginning of the file.
860
        {
861
                fposition = 0;
862
        }      
863
//......................................................
864
        else if(origin == SEEK_END)                                                                                                     // Fileposition relative to the end of the file.
865
        {
866
                fposition  = (s32) file->Size;
867
        }      
868
//......................................................
869
        else if(origin == SEEK_CUR)                                                                                                     // Fileposition relative to the current position of the file.
870
        {
871
                fposition = (s32)file->Position;
872
        }      
873
 
874
        // calculate the specified fileposition according to the selected mode
875
        fposition += offset;                                                                                                            // Die Absolute Dateiposition welche durch fseek angesprungen werden soll.
876
        // is the fileposition within the file?
877
        if((fposition >= 0) && (fposition <= (s32)file->Size))                                          // Ist die berechnete Dateiposition innerhalb der geöffneten Datei?
878
        {
879
                // initialize the filepointer
880
                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
881
                file->SectorOfCurrCluster       = 0;
882
                file->ByteOfCurrSector          = 0;
883
                file->Position                          = 0;
884
                // has the specified file at least one valid sector attached?
885
                if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(retvalue);
886
                // calculate the absolute number of the sector wich contains the fileposition we are looking for
887
                sector_index = (u32) ((u32)fposition >> 9);
888
                // calculate the index of the cluster containing the specified sector
889
                cluster_index = (u32) sector_index / Partition.SectorsPerCluster;      
890
                // the absolute sectornumber becomes relative to the beginning of the specified cluster
891
                sector_index = (sector_index % Partition.SectorsPerCluster);           
892
                // calculate the index of the byteposition the fileposition points to
893
                byte_index = (u32) fposition % 512;
894
                // parse the fat till the calculated cluster has been reached
895
                while(cluster_index--) GetNextCluster(file);
896
                // set the filepointer to the specified sector and byteposition
897
                file->SectorOfCurrCluster = (u8) sector_index;
898
                file->ByteOfCurrSector = (u16) byte_index;
899
                // the fileposition now equals the filepointer
900
                file->Position = (u32)fposition;       
901
                // the specified fileposition has been reached
902
                retvalue = 0;                                                                                  
903
        }      
904
        return(retvalue);
905
}
906
 
907
 
908
/****************************************************************************************************************************************/
909
/* Function:    u16 DeleteClusterChain(File *file);                                                                                                                                                                             */
910
/*                                                                                                                                                                                                                                                                              */
911
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited.                                                                  */
912
/*                                                                                                                                                                                                                                                                              */
913
/****************************************************************************************************************************************/
914
u8 DeleteClusterChain(u16 StartCluster)
915
{
916
        u16 cluster;
917
        u32 fat_byte_offset, sector, byte;
918
        Fat16Entry_t * fat;
919
        u8 buffer[BYTES_PER_SECTOR];
920
        u32 sector_in_buffer = 0;
921
        u8 repeat = 0;
922
 
923
        if(!Partition.IsValid) return(0);
924
        if(StartCluster == CLUSTER_UNDEFINED) return(0);
925
        cluster = StartCluster; // init chain trace
926
        // if start cluster is no real cluster
927
    if(FAT16_CLUSTER_LAST_MIN <= cluster) return 1;
928
 
929
        // calculate byte offset in the fat for corresponding entry
930
        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
931
        // calculate the sector that contains the current cluster within the fat
932
        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
933
        // calculate byte offset of the current cluster within that fat sector
934
        byte = fat_byte_offset % BYTES_PER_SECTOR;
935
        do
936
        {
937
                if(sector != sector_in_buffer)
938
                {
939
                        // read this sector to buffer
940
                        sector_in_buffer = sector;
941
                        if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0;     // read sector from sd-card
942
                }
943
                // read the next cluster from cache
944
                fat = (Fat16Entry_t *)(&(buffer[byte]));
945
                cluster = fat->NextCluster;
946
                fat->NextCluster =      FAT16_CLUSTER_FREE; // mark current cluster as free
947
 
948
                if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) )
949
                {
950
                        repeat = 1;
951
                        // calculate sector byte and byte offset in the fat for the next cluster
952
                        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
953
                        // calculate the sector that contains the current cluster within the fat
954
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
955
                        // calculate byte offset of the current cluster within that fat sector
956
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
957
                }
958
                else repeat = 0;
959
 
960
                // if new sector is not the sector in buffer or the last cluster in the chain was traced
961
                if((sector != sector_in_buffer) || !repeat)
962
                {       // write sector in buffer
963
                        if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer))
964
                        {
965
                                Fat16_Deinit();
966
                                return(0);
967
                        }
968
                }
969
        }
970
        while(repeat);
971
 
972
        return 1;
973
}
974
 
975
 
976
/****************************************************************************************************************************************/
977
/* Function:    u16 AppendCluster(File *file);                                                                                                                                                                                  */
978
/*                                                                                                                                                                                                                                                                              */
979
/* Description: This function looks in the fat to find the next free cluster and appends it to the file.                                                                */
980
/*                                                                                                                                                                                                                                                                              */
981
/* Returnvalue: The function returns the appened cluster number or CLUSTER_UNDEFINED of no cluster was appended.                                                */
982
/****************************************************************************************************************************************/
983
 
984
u16 AppendCluster(File_t *file)
985
{
986
        u16 last_cluster, new_cluster = CLUSTER_UNDEFINED;
987
        u32 fat_byte_offset, sector, byte;
988
        Fat16Entry_t * fat;
989
 
990
        if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
991
 
992
        new_cluster = FindNextFreeCluster(file);        // the next free cluster found on the disk.
993
        if(new_cluster != CLUSTER_UNDEFINED)
994
        {       // A free cluster was found and can be added to the end of the file.
995
                fseek_(file, 0, SEEK_END);                                                                                                      // jump to the end of the file
996
                last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);            // determine current file cluster
997
                if(last_cluster != CLUSTER_UNDEFINED)
998
                {
999
                        // update FAT entry of last cluster
1000
                        fat_byte_offset = ((u32)last_cluster)<<1;
1001
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
1002
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
1003
                        // read the sector containing the last cluster of the file
1004
                        if(file->SectorInCache != sector)
1005
                        {
1006
                                file->SectorInCache = sector;   // update sector stored in buffer
1007
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
1008
                                {
1009
                                        Fat16_Deinit();
1010
                                        return(0);
1011
                                }
1012
                        }
1013
                        fat = (Fat16Entry_t *)(&(file->Cache[byte]));
1014
                        fat->NextCluster = new_cluster;                                                 // append the free cluster to the end of the file in the FAT.
1015
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // save the modified sector to the FAT.
1016
                        {
1017
                                Fat16_Deinit();
1018
                                return(0);
1019
                        }
1020
                }
1021
                else // last cluster of the file is undefined
1022
                {   // then the new cluster must be the first one of the file
1023
                    // and its cluster number must be set in the direntry
1024
                        DirEntry_t * dir;
1025
                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1026
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1027
                        {
1028
                                Fat16_Deinit();
1029
                                return(CLUSTER_UNDEFINED);
1030
                        }
1031
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1032
                        dir[file->DirectoryIndex].Res1 = 0;
1033
                        dir[file->DirectoryIndex].Res2[0] = 0;
1034
                        dir[file->DirectoryIndex].Res2[1] = 0;
1035
                        dir[file->DirectoryIndex].StartCluster = new_cluster;           // update startcluster 
1036
                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);// set time
1037
                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);// and date of modification
1038
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1039
                        dir[file->DirectoryIndex].Size          = 0;
1040
                        // write sector containing the direntry
1041
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1042
                        {
1043
                                Fat16_Deinit();
1044
                                return(CLUSTER_UNDEFINED);
1045
                        }
1046
                        // update file info     
1047
                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(new_cluster);
1048
                        file->Size = 0;
1049
                        file->Position = 0;
1050
                }
1051
                // update file pointes
1052
                file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
1053
                file->SectorOfCurrCluster = 0;
1054
                file->ByteOfCurrSector = 0;
1055
        }
1056
        return(new_cluster);
1057
}
1058
 
1059
 
1060
/****************************************************************************************************************************************************/
1061
/* Function:    DirectoryEntryExist(s8 *, u8, u8, File_t *)                                                                                                                                                                                     */
1062
/*                                                                                                                                                                                                                                                                                                      */
1063
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached                     */
1064
/*                                                                                                                                                                                                                                                                                                      */
1065
/* Returnvalue: This function returns 1 if the directory entry specified was found.                                                                                                                                     */
1066
/****************************************************************************************************************************************************/
1067
u8 DirectoryEntryExist(s8 *dirname, u8 attribfilter, u8 attribmask, File_t *file)
1068
{
1069
        u32             dir_sector, max_dir_sector, curr_sector;
1070
        u16     dir_entry = 0;
1071
 
1072
        u16     end_of_directory_not_reached = 0;
1073
        u8              i = 0;
1074
        u8      direntry_exist = 0;
1075
        DirEntry_t * dir;
1076
 
1077
        // if incomming pointers are useless return immediatly
1078
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
1079
 
1080
        // dir entries can be searched only in filesclusters that have
1081
        // a corresponding dir entry with adir-flag set in its attribute
1082
        // or direct within the root directory area
1083
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
1084
        // no current directory exist therefore assume searching in the root
1085
        if(file->DirectorySector == SECTOR_UNDEFINED)
1086
        {
1087
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1088
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1089
        }
1090
        // within the root directory area we can read sectors sequentially until the end of this area
1091
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1092
        {
1093
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1094
        }
1095
        // within the data clusters we can read sectors sequentially only within the cluster
1096
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1097
        {
1098
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
1099
        }
1100
        else return (direntry_exist); // bad sector range for directory sector of the file
1101
        // if search area is not defined yet
1102
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
1103
        {
1104
                // check if the directory entry of current file is existent and has the dir-flag set
1105
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1106
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1107
                {
1108
                        Fat16_Deinit();
1109
                        return(0);
1110
                }
1111
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1112
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
1113
                {
1114
                        case SLOT_EMPTY:
1115
                        case SLOT_DELETED:
1116
                                // the directrory pointer of this file points to a deleted or not existen directory
1117
                                // therefore no file or subdirectory can be created
1118
                                return (direntry_exist);
1119
                                break;
1120
                        default:        // and is a real directory
1121
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1122
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1123
                                        return (direntry_exist);
1124
                                }
1125
                                break;
1126
                }
1127
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster);
1128
        }
1129
 
1130
        // update current file data area position to start of first cluster
1131
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1132
        file->SectorOfCurrCluster               = 0;
1133
        file->ByteOfCurrSector                  = 0;
1134
 
1135
        do // loop over all data clusters of the current directory entry
1136
        {
1137
                dir_sector = 0;
1138
                do // loop over all sectors of a cluster or all sectors of the root directory
1139
                {
1140
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1141
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1142
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
1143
                        {
1144
                                Fat16_Deinit();
1145
                                return(0);
1146
                        }
1147
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1148
                        // search all directory entries within that sector
1149
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1150
                        {   // check for existing dir entry
1151
                                switch((u8)dir[dir_entry].Name[0])
1152
                                {
1153
                                        case SLOT_EMPTY:
1154
                                        case SLOT_DELETED:
1155
                                                // ignore empty or deleted dir entries
1156
                                                break;
1157
                                        default:
1158
                                                // if existing check attributes before names are compared will safe performance
1159
                                                if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
1160
                                                // then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
1161
                                                i = 0;
1162
                                                while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
1163
                                                if (i < 10) break; // names does not match
1164
                                                // if dirname and attribute have matched
1165
                                                file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
1166
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
1167
                                                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1168
                                                file->SectorOfCurrCluster = 0;
1169
                                                file->ByteOfCurrSector = 0;
1170
                                                file->DirectorySector = curr_sector; // current sector
1171
                                                file->DirectoryIndex  = dir_entry; // current direntry in current sector
1172
                                                file->Size = dir[dir_entry].Size;
1173
                                                direntry_exist = 1; // mark as found
1174
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
1175
                                } // end of first byte of name check
1176
                        }
1177
                        dir_sector++; // search next sector
1178
                // stop if we reached the end of the cluster or the end of the root dir
1179
                }while((dir_sector < max_dir_sector) && (!direntry_exist));
1180
 
1181
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1182
                if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
1183
                {
1184
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1185
                }
1186
        }while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
1187
        return(direntry_exist);
1188
}
1189
 
1190
 
1191
/****************************************************************************************************************************************/
1192
/*      Function:               CreateDirectoryEntry(s8 *, u16, File_t *)                                                                                                                                                       */
1193
/*                                                                                                                                                                                                                                                                              */
1194
/*      Description:    This function looks for the next free position in the directory and creates an entry.                                                           */
1195
/*                                      The type of an directory entry is specified by the file attribute.                                                                                                      */
1196
/*                                                                                                                                                                                                                                                                              */
1197
/*      Returnvalue:    Return 0 on error                                                                                                                                                                                                       */
1198
/****************************************************************************************************************************************/
1199
u8 CreateDirectoryEntry(s8 *dirname, u8 attrib, File_t *file)
1200
{
1201
        u32 dir_sector, max_dir_sector, curr_sector;
1202
        u16 dir_entry   = 0;
1203
        u16 subdircluster, dircluster = 0;
1204
        u16 end_of_directory_not_reached = 0;
1205
        u8      i                       = 0;
1206
        u8      retvalue        = 0;
1207
        DirEntry_t *dir;
1208
 
1209
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
1210
        // It is not checked here that the dir entry that should be created is already existent!
1211
 
1212
        // Dir entries can be created only in file-clusters that have
1213
        // the dir-flag set in its attribute or within the root directory
1214
 
1215
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
1216
        // no current directory exist therefore assume creating in the root
1217
        if(file->DirectorySector == SECTOR_UNDEFINED)
1218
        {
1219
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1220
                dircluster = 0;
1221
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1222
        }
1223
        // within the root directory area we can read sectors sequentially until the end of this area
1224
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1225
        {
1226
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1227
        }
1228
        // within the data clusters we can read sectors sequentially only within the cluster
1229
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1230
        {
1231
                max_dir_sector = Partition.SectorsPerCluster;
1232
        }
1233
        else return (retvalue); // bad sector range for directory sector of the file
1234
        // if search area is not defined yet
1235
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
1236
        {
1237
            // check if the directory entry of current file is existent and has the dir-flag set
1238
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1239
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1240
                {
1241
                        Fat16_Deinit();
1242
                        return(0);
1243
                }
1244
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1245
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
1246
                {
1247
                        case SLOT_EMPTY:
1248
                        case SLOT_DELETED:
1249
                                return (retvalue);
1250
                                break;
1251
                        default:        // and is a real directory
1252
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1253
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1254
                                        return (retvalue);
1255
                                }
1256
                                break;
1257
                }
1258
                dircluster = dir[file->DirectoryIndex].StartCluster;
1259
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
1260
        }
1261
 
1262
        // if the new direntry is a subdirectory
1263
        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)
1264
        {       // get a free clutser for its content
1265
                subdircluster = FindNextFreeCluster(file);      // get the next free cluster on the disk and mark it as used.
1266
        }
1267
        else // a normal file
1268
        {       // has no data cluster after creation
1269
                subdircluster = CLUSTER_UNDEFINED;
1270
        }
1271
 
1272
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1273
        file->SectorOfCurrCluster               = 0;
1274
        do // loop over all clusters of current directory
1275
        {
1276
                dir_sector = 0; // reset sector counter within a new cluster
1277
                do // loop over all sectors of a cluster or all sectors of the root directory
1278
                {
1279
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1280
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1281
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1282
                        {
1283
                                Fat16_Deinit();
1284
                                return(0);
1285
                        }
1286
 
1287
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1288
                        // search all directory entries of a sector
1289
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1290
                        {       // check if current direntry is available
1291
                                if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
1292
                                {       // a free direntry was found
1293
                                        for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i];            // Set dir name
1294
                                        dir[dir_entry].Attribute    = attrib;
1295
                                        dir[dir_entry].Res1 = 0;
1296
                                        dir[dir_entry].CreationTime10ms = (u8)(SystemTime.mSec/10);
1297
                                        dir[dir_entry].CreationTime     = FileTime(&SystemTime);
1298
                                        dir[dir_entry].CreationDate     = FileDate(&SystemTime);
1299
                                        dir[dir_entry].LastAccessDate = dir[dir_entry].CreationDate;
1300
                                        dir[dir_entry].Res2[0] = 0;
1301
                                        dir[dir_entry].Res2[1] = 0;
1302
                                        dir[dir_entry].ModTime = dir[dir_entry].CreationTime;
1303
                                        dir[dir_entry].ModDate = dir[dir_entry].CreationDate;
1304
                                        // Set the attribute of the new directoryentry.
1305
                                        dir[dir_entry].StartCluster = subdircluster;                                            // copy the location of the first datacluster to the directoryentry.
1306
                                        dir[dir_entry].Size             = 0;                                                                    // the new createted file has no content yet.
1307
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to card
1308
                                        {
1309
                                                Fat16_Deinit();
1310
                                                return(0);
1311
                                        }
1312
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster);  // Calculate absolute sectorposition of first datacluster.
1313
                                        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;      // Start reading the file with the first sector of the first datacluster.
1314
                                        file->SectorOfCurrCluster               = 0;                                                            // reset sector of cureen cluster
1315
                                        file->ByteOfCurrSector                  = 0;                                                            // reset the byte location within the current sector
1316
                                        file->Attribute                                 = attrib;                                               // set file attribute to dir attribute
1317
                                        file->Size                                              = 0;                                                        // new file has no size
1318
                                        file->DirectorySector                   = curr_sector;
1319
                                        file->DirectoryIndex                    = dir_entry;
1320
                                        // prepare subdirectory data cluster
1321
                                        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)                           // if a new directory was created then initilize the data area
1322
                                        {
1323
                                                ClearCurrCluster(file); // fill cluster with zeros
1324
                                                file->SectorInCache = file->FirstSectorOfFirstCluster;
1325
                                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1326
                                                {
1327
                                                        Fat16_Deinit();
1328
                                                        return(0);
1329
                                                }
1330
                                                dir = (DirEntry_t *)file->Cache;
1331
                                                // create direntry "." to current dir
1332
                                                dir[0].Name[0] = 0x2E;
1333
                                                for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
1334
                                                dir[0].Attribute = ATTR_SUBDIRECTORY;
1335
                                                dir[0].StartCluster = subdircluster;
1336
                                                dir[0].Size = 0;
1337
                                                // create direntry ".." to the upper dir
1338
                                                dir[1].Name[0] = 0x2E;
1339
                                                dir[1].Name[1] = 0x2E;
1340
                                                for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
1341
                                                dir[1].Attribute = ATTR_SUBDIRECTORY;
1342
                                                dir[1].StartCluster = dircluster;
1343
                                                dir[1].Size = 0;
1344
                                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
1345
                                                {
1346
                                                        Fat16_Deinit();
1347
                                                        return(0);
1348
                                                }
1349
                                        }
1350
                                        retvalue = 1;
1351
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
1352
                                }
1353
                        }
1354
                        dir_sector++; // search next sector
1355
                // stop if we reached the end of the cluster or the end of the root dir
1356
                }while((dir_sector < max_dir_sector) && (!retvalue));
1357
 
1358
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1359
                if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
1360
                {
1361
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1362
                }
1363
        }while((end_of_directory_not_reached) && (!retvalue));
1364
        // Perhaps we are at the end of the last cluster of a directory file and have no free direntry found.
1365
        // Then we would need to add a cluster to that file and create the new direntry there.
1366
        // This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
1367
        // within a subdirectory of root.
1368
 
1369
        return(retvalue);       // return 1 if file has been created otherwise return 0.
1370
}
1371
 
1372
/********************************************************************************************************************************************/
1373
/*      Function:               FileExist(const s8* filename, u8 attribfilter, u8 attribmask, File_t *file);                                                                                    */
1374
/*                                                                                                                                                                                                                                                                                      */
1375
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1376
/*                                      in the rootdirectory of the drive. If the file is found the Filepointer properties are                                                                  */
1377
/*                                      updated.                                                                                                                                                                                                                                */
1378
/*                                                                                                                                                                                                                                                                                      */
1379
/*      Returnvalue:    1 if file is found else 0.                                                                                                                                                                                              */
1380
/********************************************************************************************************************************************/
1381
u8 FileExist(const s8* filename, const u8 attribfilter, const u8 attribmask, File_t *file)
1382
{
1383
        s8* path = 0;
1384
        s8* subpath = 0;
1385
        u8 af, am, file_exist = 0;
1386
        s8 dirname[12]; // 8+3 + temination character
1387
 
1388
        // if incomming pointers are useless return immediatly
1389
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1390
 
1391
        // trace along the filepath
1392
        path = (s8*)filename;                                                           // start a the beginning of the filename string
1393
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1394
        file->DirectoryIndex = 0;
1395
        /* if a path begins with a '/' at index 0 the search starts at the rootdirectory otherwise we will start relative to the cwd */
1396
        if(path[0] != '/')
1397
        {
1398
                /* is the current working directory the rootdirectory? */
1399
                if(Partition.CurrentWorkingDirectory == Partition.FirstRootDirSector) file->DirectorySector = 0;
1400
                /* otherwise we are working in an subdirectory */
1401
                else file->DirectorySector = Partition.CurrentWorkingDirectory;
1402
        }
1403
        // as long as the file was not found and the remaining path is not empty
1404
        while((*path != 0) && !file_exist)
1405
        {       // separate dirname and subpath from filepath string
1406
                subpath = SeperateDirName(path, dirname);
1407
                if(subpath != NULL)
1408
                {
1409
                        if(*subpath == 0)
1410
                        {       // empty subpath indicates last element of dir chain
1411
                                af = attribfilter;
1412
                                am = attribmask;
1413
                        }
1414
                        else  // it must be a subdirectory and no volume label
1415
                        {
1416
                                af = ATTR_SUBDIRECTORY;
1417
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1418
                        }
1419
                        if(!DirectoryEntryExist(dirname, af, am, file))
1420
                        {
1421
                                return (file_exist); // subdirectory does not exist
1422
                        }
1423
                        else
1424
                        {
1425
                                if (*subpath == 0)
1426
                                {
1427
                                        file_exist = 1; // last element of path chain was found with the given attribute filter
1428
                                }
1429
                        }
1430
                }
1431
                else // error seperating the subpath
1432
                {
1433
                        return file_exist; // bad subdir format
1434
                }
1435
                path = subpath;
1436
                subpath = 0;
1437
        }
1438
        return (file_exist);
1439
}
1440
 
1441
 
1442
/********************************************************************************************************************************************/
1443
/*      Function:               FileCreate(const s8* filename, u8 attrib, File_t *file);                                                                                                                                */
1444
/*                                                                                                                                                                                                                                                                                      */
1445
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1446
/*                                      in the rootdirectory of the partition. If the file is found the Filepointer properties are                                                              */
1447
/*                                      updated. If file or its subdirectories are not found they will be created                                                                                               */
1448
/*                                                                                                                                                                                                                                                                                      */
1449
/*      Returnvalue:    1 if file was created else 0.                                                                                                                                                                                   */
1450
/********************************************************************************************************************************************/
1451
u8 FileCreate(const s8* filename, const u8 attrib, File_t *file)
1452
{
1453
        s8 *path = 0;
1454
        s8 *subpath = 0;
1455
        u8 af, am, file_created = 0;
1456
        s8 dirname[12];
1457
 
1458
        // if incomming pointers are useless return immediatly
1459
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1460
 
1461
        // trace along the filepath
1462
        path = (s8*)filename;                                                                   // start a the beginning of the filename string
1463
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1464
        file->DirectoryIndex = 0;
1465
        // as long as the file was not created and the remaining file path is not empty
1466
        while((*path != 0) && !file_created)
1467
        {   // separate dirname and subpath from filepath string
1468
                subpath = SeperateDirName(path, dirname);
1469
                if(subpath != NULL)
1470
                {
1471
                        if(*subpath == 0)
1472
                        {       // empty subpath indicates last element of dir chain
1473
                                af = ATTR_NONE;
1474
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;  // any file that is no subdir or volume label
1475
                        }
1476
                        else  // it must be a subdirectory and no volume label
1477
                        {
1478
                                af = ATTR_SUBDIRECTORY;
1479
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1480
                        }
1481
                        if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
1482
                        {  // try to create subdir or file
1483
                                if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
1484
                                if(!CreateDirectoryEntry(dirname, af, file))
1485
                                {       // could not be created
1486
                                        return(file_created);
1487
                                }
1488
                                else if (*subpath == 0) file_created = 1; // last element of path chain was created
1489
                        }
1490
                }
1491
                else // error seperating the subpath
1492
                {
1493
                        return file_created; // bad subdir format
1494
                }
1495
                path = subpath;
1496
                subpath = 0;
1497
        }
1498
        return (file_created);
1499
}
1500
 
1501
 
1502
/********************************************************************************************************************************************/
1503
/*      Function:               File_t * fopen_(s8* filename, s8 mode);                                                                                                                                                                 */
1504
/*                                                                                                                                                                                                                                                                                      */
1505
/*      Description:    This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the    */
1506
/*                                      corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet.                                             */
1507
/*                                                                                                                                                                                                                                                                                      */
1508
/*      Returnvalue:    The filepointer to the file or 0 if faild.                                                                                                                                                              */
1509
/********************************************************************************************************************************************/
1510
File_t * fopen_(s8 * const filename, const s8 mode)
1511
{
1512
        File_t *file    = 0;
1513
        s8 *cptr;
1514
 
1515
        if((!Partition.IsValid) || (filename == 0)) return(file);
1516
 
1517
        // Look for an unused filepointer in the file pointer list?
1518
        file = LockFilePointer();
1519
        // if no unused file pointer was found return 0
1520
        if(file == NULL) return(file);
1521
 
1522
        // now we have found a free filepointer and claimed it
1523
        // so let initiate its property values
1524
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;             // Sectorpointer to the first sector of the first datacluster of the file.
1525
        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;             // Pointer to the cluster which is edited at the moment.
1526
        file->SectorOfCurrCluster               = 0;            // The sector which is edited at the moment (cluster_pointer + sector_index).
1527
        file->ByteOfCurrSector                  = 0;            // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
1528
        file->Mode                                              = mode;         // mode of fileoperation (read,write)
1529
        file->Size                                              = 0;            // the size of the opened file in bytes.
1530
        file->Position                                  = 0;            // pointer to a byte within the file 0 < fileposition < filesize
1531
        file->SectorInCache                             = SECTOR_UNDEFINED;             // the last sector read, wich is still in the sectorbuffer.
1532
        file->DirectorySector                   = SECTOR_UNDEFINED;             // the sectorposition where the directoryentry has been made.
1533
        file->DirectoryIndex                    = 0;            // the index to the directoryentry within the specified sector.
1534
        file->Attribute                                 = 0;            // the attribute of the file opened.
1535
 
1536
        // bring the path into the correct syntax 
1537
        cptr = filename;
1538
        // search the whole string 
1539
        while(*cptr != 0)
1540
        {
1541
                // replace all '\' by '/'
1542
                if(*cptr == '\\') *cptr = '/';
1543
                cptr++;
1544
        }
1545
        // check if a real file (no directory) to the given filename exist
1546
        if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
1547
        {  // file exist
1548
                switch(mode)  // check mode
1549
                {
1550
                        case 'a':       // if mode is: append to file
1551
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1552
                                {       // file is marked as readonly --> do not open this file
1553
                                        fclose_(file);
1554
                                        file = NULL;
1555
                                }
1556
                                else
1557
                                {       // file is not marked as read only --> goto end of file
1558
                                        fseek_(file, 0, SEEK_END);              // point to the end of the file
1559
                                }
1560
                                break;
1561
                        case 'w':       // if mode is: write to file
1562
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1563
                                {       // file is marked as readonly --> do not open this file
1564
                                        fclose_(file);
1565
                                        file = NULL;
1566
                                }
1567
                                else
1568
                                {       // file is not marked as read only
1569
                                        DirEntry_t * dir;
1570
                                        // free all clusters of that file
1571
                                        DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
1572
                                        // update directory entry of that file
1573
                                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1574
                                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1575
                                        {
1576
                                                Fat16_Deinit();
1577
                                                return(NULL);
1578
                                        }
1579
                                        dir = (DirEntry_t *)file->Cache;                                                                // set pointer to directory
1580
                                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);        // set modification time
1581
                                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);        // set modification date
1582
                                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1583
                                        dir[file->DirectoryIndex].StartCluster = CLUSTER_UNDEFINED;             // update startcluster 
1584
                                        dir[file->DirectoryIndex].Size          = 0;
1585
                                        // write sector containing the direntry
1586
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1587
                                        {
1588
                                                Fat16_Deinit();
1589
                                                return(NULL);
1590
                                        }
1591
                                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
1592
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1593
                                        file->SectorOfCurrCluster = 0;
1594
                                        file->ByteOfCurrSector = 0;
1595
                                        file->Size = 0;
1596
                                        file->Position = 0;
1597
                                        fseek_(file, 0, SEEK_SET);
1598
                                }
1599
                                break;
1600
                        case 'r':       // if mode is: read from file
1601
                                // goto end of file
1602
                                fseek_(file, 0, SEEK_SET);
1603
                                break;
1604
                        default: // other modes are not supported
1605
                                fclose_(file);
1606
                                file = NULL;
1607
                        break;
1608
                }
1609
                return(file);
1610
        }
1611
        else // file does not exist
1612
        {
1613
                switch(mode)  // check mode
1614
                {
1615
                        case 'a':
1616
                        case 'w': // if mode is write or append
1617
                                // try to create the file
1618
                                if(!FileCreate(filename, ATTR_ARCHIVE, file))
1619
                                { // if it could not be created
1620
                                        fclose_(file);
1621
                                        file = NULL;
1622
                                }
1623
                                break;
1624
                        case 'r': // else opened for 'r'
1625
                        default:  // if unsupported mode
1626
                                fclose_(file);
1627
                                file = NULL;
1628
                                break;
1629
                }
1630
                return(file);
1631
        }
1632
        // we should never come to this point
1633
        fclose_(file);
1634
        file = NULL;
1635
        return(file);
1636
}
1637
 
1638
/****************************************************************************************************************************************************/
1639
/* Function:    fflush_(File *);                                                                                                                                                                                                                                        */
1640
/*                                                                                                                                                                                                                                                                                                      */
1641
/* Description: This function writes the data already in the buffer but not yet written to the file.                                                                                            */
1642
/*                                                                                                                                                                                                                                                                                                      */
1643
/* Returnvalue: 0 on success EOF on error                                                                                                                                                                                                                       */
1644
/****************************************************************************************************************************************************/
1645
s16     fflush_(File_t *file)
1646
{
1647
        DirEntry_t *dir;
1648
 
1649
        if((file == NULL) || (!Partition.IsValid)) return (EOF);
1650
 
1651
        switch(file->Mode)
1652
        {
1653
                case 'a':
1654
                case 'w':
1655
                        if(file->ByteOfCurrSector > 0)                                                                          // has data been added to the file?
1656
                        {
1657
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
1658
                                {
1659
                                        Fat16_Deinit();
1660
                                        return(EOF);
1661
                                }
1662
                        }
1663
                        file->SectorInCache     = file->DirectorySector;
1664
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))                                       // read the directory entry for this file.
1665
                        {
1666
                                Fat16_Deinit();
1667
                                return(EOF);
1668
                        }
1669
 
1670
                        dir = (DirEntry_t *)file->Cache;
1671
                        // update file size and modification time & date
1672
                        dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);
1673
                        dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);
1674
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1675
                        dir[file->DirectoryIndex].Size = file->Size;                                            // update file size
1676
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to sd-card
1677
                        {
1678
                                Fat16_Deinit();
1679
                                return(EOF);
1680
                        }
1681
                        break;
1682
                case 'r':
1683
                default:
1684
                        // do nothing!
1685
                        return(EOF);
1686
                        break;
1687
 
1688
        }
1689
        return(0);
1690
}
1691
 
1692
/****************************************************************************************************************************************/
1693
/*      Function:               fclose_(File *file);                                                                                                                                                                                            */
1694
/*                                                                                                                                                                                                                                                                              */
1695
/*      Description:    This function closes the open file by writing the remaining data                                                                                                        */
1696
/*                                      from the buffer to the device and entering the filesize in the directory entry.                                                                         */
1697
/*                                                                                                                                                                                                                                                                              */
1698
/*      Returnvalue:    0 on success EOF on error                                                                                                                                                                                       */
1699
/****************************************************************************************************************************************/
1700
s16 fclose_(File_t *file)
1701
{
1702
        s16 returnvalue = EOF;
1703
 
1704
        if(file == NULL) return(returnvalue);
1705
        returnvalue = fflush_(file);
1706
        UnlockFilePointer(file);
1707
        return(returnvalue);
1708
}
1709
 
1710
/********************************************************************************************************************************************/
1711
/*      Function:               fgetc_(File *file);                                                                                                                                                                                                             */
1712
/*                                                                                                                                                                                                                                                                                      */
1713
/*      Description:    This function reads and returns one character from the specified file. Is the end of the actual sector reached the              */
1714
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1715
/*                                                                                                                                                                                                                                                                                      */
1716
/*      Returnvalue:    The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.                                   */
1717
/********************************************************************************************************************************************/
1718
s16 fgetc_(File_t *file)
1719
{
1720
        s16 c = EOF;
1721
        u32 curr_sector;
1722
 
1723
        if( (!Partition.IsValid) || (file == NULL)) return(c);
1724
        // if the end of the file is not reached, get the next character.
1725
        if((0 < file->Size) && ((file->Position) < file->Size) )
1726
        {
1727
                curr_sector  = file->FirstSectorOfCurrCluster;          // calculate the sector of the next character to be read.
1728
                curr_sector += file->SectorOfCurrCluster;
1729
 
1730
                if(file->SectorInCache != curr_sector)
1731
                {
1732
                        file->SectorInCache = curr_sector;
1733
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
1734
                        {
1735
                                Fat16_Deinit();
1736
                                return(EOF);
1737
                        }
1738
                }
1739
                c = (s16) file->Cache[file->ByteOfCurrSector];
1740
                file->Position++;                                                                       // increment file position
1741
                file->ByteOfCurrSector++;                                                       // goto next byte in sector
1742
                if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if end of sector
1743
                {
1744
                        file->ByteOfCurrSector = 0;                                             //  reset byte location
1745
                        file->SectorOfCurrCluster++;                                    //      next sector
1746
                        if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
1747
                        {
1748
 
1749
                                if(GetNextCluster(file))                                                                                // Sets the clusterpointer of the file to the next datacluster.
1750
                                {
1751
                                        file->SectorOfCurrCluster = 0;                                                          // start reading new cluster at first sector of the cluster.
1752
                                }
1753
                                else // the last cluster was allready reached
1754
                                {
1755
                                        file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
1756
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
1757
                                }
1758
                        }
1759
                }
1760
        }
1761
        return(c);
1762
}
1763
 
1764
/********************************************************************************************************************************************/
1765
/*      Function:               fputc_( const s8 c, File *file);                                                                                                                                                                                */
1766
/*                                                                                                                                                                                                                                                                                      */
1767
/*      Description:    This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.                                 */
1768
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1769
/*                                                                                                                                                                                                                                                                                      */
1770
/*      Returnvalue:    The function returns the character written to the stream or EOF on error.                                                                                               */
1771
/********************************************************************************************************************************************/
1772
s16 fputc_(const s8 c, File_t *file)
1773
{
1774
        u32 curr_sector  = 0;
1775
 
1776
        if((!Partition.IsValid) || (file == NULL)) return(EOF);
1777
        switch(file->Mode)
1778
        {
1779
                case 'w':
1780
                case 'a':
1781
                        // If file position equals to file size, then the end of file has been reached.
1782
                        // In this case it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
1783
                        // and a new cluster should be appended.
1784
                        // If the first sector of first cluster is unvalid, then the file claims no data clusters 
1785
                        // and size should be zero, therefore append a new Cluster too.
1786
                        if(((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) || (file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED))
1787
                        {
1788
                                if(CLUSTER_UNDEFINED == AppendCluster(file)) return(EOF);
1789
                        }
1790
 
1791
                        curr_sector  = file->FirstSectorOfCurrCluster;
1792
                        curr_sector += file->SectorOfCurrCluster;
1793
                        if(file->SectorInCache != curr_sector)
1794
                        {
1795
                                file->SectorInCache = curr_sector;
1796
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
1797
                                {
1798
                                        Fat16_Deinit();
1799
                                        return(EOF);
1800
                                }
1801
                        }
1802
 
1803
                        file->Cache[file->ByteOfCurrSector] = (u8)c;            // write databyte into the buffer. The byte will be written to the device at once
1804
                        if(file->Size == file->Position) file->Size++;          // a character has been written to the file so the size is incremented only when the character has been added at the end of the file.
1805
                        file->Position++;                                                                       // the actual positon within the file.
1806
                        file->ByteOfCurrSector++;                                                       // goto next byte in sector
1807
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if the end of this sector is reached yet
1808
                        {       // save the sector to the sd-card
1809
 
1810
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1811
                                {
1812
                                        Fat16_Deinit();
1813
                                        return(EOF);
1814
                                }
1815
                                file->ByteOfCurrSector = 0;                                             //  reset byte location
1816
                                file->SectorOfCurrCluster++;                                    //      next sector
1817
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
1818
                                {
1819
                                        if(!GetNextCluster(file))                                                               // Sets the clusterpointer of the file to the next datacluster.
1820
                                        { // if current cluster was the last cluster of the file
1821
                                                if(!AppendCluster(file))                                                // append a new and free cluster at the end of the file.
1822
                                                {
1823
                                                        file->SectorOfCurrCluster--;                            // jump back to last sector of last cluster
1824
                                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;      // set byte location to 1 byte over sector len
1825
                                                        return(EOF);
1826
                                                }
1827
                                        }
1828
                                        else // next cluster
1829
                                        {
1830
                                                file->SectorOfCurrCluster = 0;                                                  // start reading new cluster at first sector of the cluster.
1831
                                        }
1832
                                }
1833
                        }
1834
                        break;
1835
                case 'r':
1836
                default:
1837
                        return(EOF);
1838
                        break;
1839
        } // EOF switch(file->Mode)
1840
        return(0);
1841
}
1842
 
1843
 
1844
/****************************************************************************************************************************************/
1845
/*      Function:               fread_(void *buffer, s32 size, s32 count, File *File);                                                                                                                          */
1846
/*                                                                                                                                                                                                                                                                              */
1847
/*      Description:    This function reads count objects of the specified size                                                                                                                         */
1848
/*                                      from the actual position of the file to the specified buffer.                                                                                                           */
1849
/*                                                                                                                                                                                                                                                                              */
1850
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1851
/****************************************************************************************************************************************/
1852
u32 fread_(void *buffer, u32 size, u32 count, File_t *file)
1853
{
1854
        u32 object_cnt  = 0;                                                                                    // count the number of objects read from the file.
1855
        u32 object_size = 0;                                                                                    // count the number of bytes read from the actual object.
1856
        u8 *pbuff       = 0;                                                                                    // a pointer to the actual bufferposition.
1857
        u8 success      = 1;                                                                                    // no error occured during read operation to the file.
1858
        s16 c;
1859
 
1860
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
1861
 
1862
        pbuff = (u8 *) buffer;                                                                                  // cast the void pointer to an u8 *
1863
 
1864
        while((object_cnt < count) && success)
1865
        {
1866
                object_size = size;
1867
                while((size > 0) && success)
1868
                {
1869
                        c = fgetc_(file);
1870
                        if(c != EOF)
1871
                        {
1872
                                *pbuff = (u8)c;                                                                         // read a byte from the buffer to the opened file.
1873
                                pbuff++;
1874
                                size--;
1875
                        }
1876
                        else // error or end of file reached
1877
                        {
1878
                                success = 0;
1879
                        }
1880
                }
1881
                if(success) object_cnt++;
1882
        }
1883
        return(object_cnt);                                                                                             // return the number of objects succesfully read from the file
1884
}
1885
 
1886
 
1887
/****************************************************************************************************************************************/
1888
/*      Function:               fwrite_(void *buffer, s32 size, s32 count, File *file);                                                                                                                         */
1889
/*                                                                                                                                                                                                                                                                              */
1890
/*      Description:    This function writes count objects of the specified size                                                                                                                        */
1891
/*                                      from the buffer pointer to the actual position in the file.                                                                                                                     */
1892
/*                                                                                                                                                                                                                                                                              */
1893
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1894
/****************************************************************************************************************************************/
1895
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file)
1896
{
1897
        u32 object_cnt  = 0;                                                                                                            // count the number of objects written to the file.
1898
        u32 object_size = 0;                                                                                                            // count the number of bytes written from the actual object.
1899
        u8 *pbuff           = 0;                                                                                                                // a pointer to the actual bufferposition.
1900
        u8 success      = 1;                                                                                                            // no error occured during write operation to the file.
1901
        s16 c;
1902
 
1903
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
1904
        if(file->Mode == 'r') return (0); // opened read only
1905
        pbuff = (u8 *) buffer;                                                                                                          // cast the void pointer to an u8 *
1906
 
1907
        while((object_cnt < count) && success)
1908
        {
1909
                object_size = size;
1910
                while((size > 0) && success)
1911
                {
1912
                        c = fputc_(*pbuff, file);                                                                               // write a byte from the buffer to the opened file.
1913
                        if(c != EOF)
1914
                        {
1915
                                pbuff++;
1916
                                size--;
1917
                        }
1918
                        else
1919
                        {
1920
                                success = 0;
1921
                        }
1922
                }
1923
                if(success) object_cnt++;
1924
        }
1925
 
1926
        return(object_cnt);                                                                                                                             // return the number of objects succesfully written to the file
1927
}
1928
 
1929
 
1930
/****************************************************************************************************************************************/
1931
/*      Function:               fputs_(const s8 *string, File_t *File);                                                                                                                                                         */
1932
/*                                                                                                                                                                                                                                                                              */
1933
/*      Description:    This function writes a string to the specified file.                                                                                                                            */
1934
/*                                                                                                                                                                                                                                                                              */
1935
/*      Returnvalue:    The function returns a no negative value or EOF on error.                                                                                                                       */
1936
/****************************************************************************************************************************************/
1937
s16 fputs_(s8 * const string, File_t * const file)
1938
{
1939
        u8 i=0;
1940
        s16 c = 0;
1941
 
1942
        if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(EOF);
1943
        if(file->Mode == 'r') return(EOF);
1944
        while((string[i] != 0)&& (c != EOF))
1945
        {
1946
                c = fputc_(string[i], file);
1947
                i++;
1948
        }
1949
        return(c);
1950
}
1951
 
1952
/****************************************************************************************************************************************/
1953
/*      Function:               fgets_(s8 *, s16 , File_t *);                                                                                                                                                                           */
1954
/*                                                                                                                                                                                                                                                                              */
1955
/*      Description:    This function reads a string from the file to the specifies string.                                                                                             */
1956
/*                                                                                                                                                                                                                                                                              */
1957
/*      Returnvalue:    A pointer to the string read from the file or 0 on error.                                                                                                                       */
1958
/****************************************************************************************************************************************/
1959
s8 * fgets_(s8 * const string, s16 const length, File_t * const file)
1960
{
1961
        s8 *pbuff;
1962
        s16 c = 0, bytecount;
1963
 
1964
        if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length < 1)) return (0);
1965
        bytecount = length;
1966
        pbuff = string;                                                         // set write pointer to start of string
1967
        while(bytecount > 1)                                            // read the length-1 characters from the file to the string.
1968
        {
1969
                c = fgetc_(file);                                               // read a character from the opened file.
1970
                switch(c)
1971
                {
1972
                        case 0x0A:                                                      // new line
1973
                                *pbuff = 0;                                             // set string terminator
1974
                                return(string);                                 // return normal
1975
 
1976
                        case EOF:
1977
                                *pbuff = 0;                                             // set string terminator
1978
                                return(0);
1979
 
1980
                        default:
1981
                                *pbuff++ = (s8)c;                               // copy byte to string
1982
                                bytecount--;
1983
                                break;
1984
                }
1985
        }
1986
        *pbuff = 0;     // set string terminator
1987
        return(string);
1988
}
1989
 
1990
/****************************************************************************************************************************************/
1991
/*      Function:               fexist_(const u8*);                                                                                                                                                                                                     */
1992
/*                                                                                                                                                                                                                                                                              */
1993
/*      Description:    This function checks if a file already exist.                                                                                                                                           */
1994
/*                                                                                                                                                                                                                                                                              */
1995
/*      Returnvalue:    1 if the file exist else 0.                                                                                                                                                                                     */
1996
/****************************************************************************************************************************************/
1997
u8 fexist_(s8 * const filename)
1998
{
1999
        u8 exist = 0;
2000
        File_t *file = 0;
2001
        file = LockFilePointer();
2002
        exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
2003
        UnlockFilePointer(file);
2004
        return(exist);
2005
}
2006
 
2007
/****************************************************************************************************************************************/
2008
/*      Function:               feof_(File_t *File);                                                                                                                                                                                            */
2009
/*                                                                                                                                                                                                                                                                              */
2010
/*      Description:    This function checks wether the end of the file has been reached.                                                                                                                                               */
2011
/*                                                                                                                                                                                                                                                                              */
2012
/*      Returnvalue:    0 if the end of the file was not reached otherwise 1.                                                                                                                                                                           */
2013
/****************************************************************************************************************************************/
2014
u8 feof_(File_t *file)
2015
{
2016
        if(((file->Position)+1) < (file->Size))
2017
        {
2018
                return(0);
2019
        }
2020
        else
2021
        {
2022
                return(1);
2023
        }
2024
}
2025
 
2026
/****************************************************************************************************************************************************/
2027
/* Function:    s8* FAT16_GetVolumeLabel(void)                                                                                                                                                                                                                  */
2028
/*                                                                                                                                                                                                                                                                                                      */
2029
/* Description: This function returns the volume label                                                                                                                                                                                          */
2030
/*                                                                                                                                                                                                                                                                                                      */
2031
/* Returnvalue: This function returns the pointer to the volume label or NULL if not found.                                                                                                                     */
2032
/****************************************************************************************************************************************************/
2033
s8* FAT16_GetVolumeLabel(void)
2034
{
2035
        s8              *pVolumeLabel = NULL;
2036
        u32             dir_sector, max_dir_sector, curr_sector;
2037
        u16     dir_entry = 0;
2038
        u8              i = 0;
2039
 
2040
        DirEntry_t * dir;
2041
        File_t *file = NULL;
2042
 
2043
        // if Partition is not valud return NULL
2044
        if(!Partition.IsValid) return(pVolumeLabel);
2045
        // if Volume label was read before return it
2046
        if(Partition.VolumeLabel[0]!= '\0') return (Partition.VolumeLabel);
2047
        // try to catch a file pointer
2048
        file = LockFilePointer();
2049
        if(file == NULL) return(pVolumeLabel);
2050
        // search dir entries direct within the root directory area
2051
        file->DirectorySector = 0;
2052
        max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2053
        file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
2054
 
2055
        // update current file data area position to start of first cluster
2056
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
2057
        file->SectorOfCurrCluster               = 0;
2058
        file->ByteOfCurrSector                  = 0;
2059
 
2060
        dir_sector = 0; // reset sector counter within a new cluster
2061
        do // loop over all sectors of the root directory
2062
        {
2063
                curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
2064
                file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
2065
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
2066
                {
2067
                        Fat16_Deinit();
2068
                        return(NULL);
2069
                }
2070
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
2071
                // search all directory entries within that sector
2072
                for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
2073
                {   // check for existing dir entry
2074
                        switch((u8)dir[dir_entry].Name[0])
2075
                        {
2076
                                case SLOT_EMPTY:
2077
                                case SLOT_DELETED:
2078
                                        // ignore empty or deleted dir entries
2079
                                        break;
2080
                                default:
2081
                                        // check attributes for volume label
2082
                                        if ((dir[dir_entry].Attribute & ATTR_VOLUMELABEL) != ATTR_VOLUMELABEL) break; // attribute must match
2083
                                        // (first 11 characters include 8 chars of basename and 3 chars extension.)
2084
                                        for(i = 0; i<11;i++) Partition.VolumeLabel[i] = dir[dir_entry].Name[i];
2085
                                        Partition.VolumeLabel[11] = '\0'; // terminate string
2086
                                        file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
2087
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
2088
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
2089
                                        file->SectorOfCurrCluster = 0;
2090
                                        file->ByteOfCurrSector = 0;
2091
                                        file->DirectorySector = curr_sector; // current sector
2092
                                        file->DirectoryIndex  = dir_entry; // current direntry in current sector
2093
                                        file->Size = dir[dir_entry].Size;
2094
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
2095
                                        pVolumeLabel =  Partition.VolumeLabel;
2096
                        } // end of first byte of name check
2097
                }
2098
                dir_sector++; // search next sector
2099
        // stop if we reached the end of the cluster or the end of the root dir
2100
        }while((dir_sector < max_dir_sector) && (!pVolumeLabel));
2101
 
2102
        UnlockFilePointer(file);
2103
        return(pVolumeLabel);
2104
}
2105
 
2106
 
2107
 
2108
#define ATTR_NONE               0x00    // normal file
2109
#define ATTR_READONLY           0x01    // file is readonly
2110
#define ATTR_HIDDEN                     0x02    // file is hidden
2111
#define ATTR_SYSTEM                     0x04    // file is a system file
2112
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2113
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2114
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2115
#define ATTR_ARCHIVE            0x20    // file is new or modified
2116
 
2117
 
2118
/********************************************************************************************************************************************/
2119
/*      Function:               u8 FindItem(Find_t);                                                                                                                                                                                                                    */
2120
/*                                                                                                                                                                                                                                                                                      */
2121
/*      Description:    This function looks for the item specified by global structure FindElement in the actual directory                                      */
2122
/*                                                                                                                                                                                                                                                              */
2123
/*                                                                                                                                                                                                                                                                                      */
2124
/*      Returnvalue:    TRUE if an matching element was found                                                                                                                                                                           */
2125
/********************************************************************************************************************************************/
2126
 
2127
u8 FindItem(Find_t *findelement)
2128
{
2129
        u16             index = 0;
2130
        u16             max_dir_sector = 0;
2131
        u16     end_of_directory_not_reached = 1;                                                                               // the directory has been read completely without a result.
2132
        u8              i = 0;
2133
        u8              readpointer = 0;
2134
        u8              writepointer = 0;
2135
        u8              retvalue = 0;
2136
        DirEntry_t      *DirectoryEntry;
2137
        File_t  file;
2138
 
2139
        file.FirstSectorOfCurrCluster   = findelement->fp.FirstSectorOfCurrCluster;
2140
        file.SectorOfCurrCluster        = findelement->fp.SectorOfCurrCluster;
2141
        index                                                   = findelement->fp.DirectoryIndex;
2142
 
2143
        // within the root directory area we can read sectors sequentially until the end of this area
2144
        if((Partition.FirstRootDirSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster < Partition.FirstDataSector))
2145
        {
2146
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2147
        }
2148
        // within the data clusters we can read sectors sequentially only within the cluster
2149
        else if((Partition.FirstDataSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster <= Partition.LastDataSector))
2150
        {
2151
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
2152
        }
2153
 
2154
        do
2155
        {                                                                                                                                                               // search the next 16 rootentries in this sector of the roordirectory.          
2156
                if(SD_SUCCESS != SDC_GetSector(((u32) file.FirstSectorOfCurrCluster + (u32)file.SectorOfCurrCluster), file.Cache));                                             // Read the Rootdirectory.
2157
                {
2158
                        Fat16_Deinit();
2159
                        return(0);
2160
                }
2161
 
2162
                DirectoryEntry = (DirEntry_t *)file.Cache;
2163
 
2164
                while((!retvalue)&&(index<16))
2165
                {
2166
                        i=0;                   
2167
                        if((u8) DirectoryEntry[index].Name[0] != 0xe5)                                                          // ignore deleted items.
2168
                        {
2169
                                while((i<=10)&&((DirectoryEntry[index].Name[i] == findelement->searchstring[i]) || (findelement->searchstring[i]=='*') || findelement->searchstring[i]=='?'))
2170
                                {
2171
                                        i++;
2172
                                }
2173
                        }
2174
                        if((DirectoryEntry[index].Attribute <= 0x30) && (DirectoryEntry[index].Attribute & findelement->attribmask) && (i==11))
2175
                        {
2176
                for(readpointer=0;readpointer<=10;readpointer++)
2177
                                {
2178
                                        if((DirectoryEntry[index].Name[readpointer] != ' ') && (readpointer!=8))
2179
                                        {
2180
                                                findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2181
                                                writepointer++;
2182
                                        }
2183
                                        else  
2184
                                        {
2185
                                                if(DirectoryEntry[index].Attribute == ATTR_ARCHIVE)                                            
2186
                                                {
2187
                                        if(readpointer < 8) readpointer=8;
2188
                                        if(DirectoryEntry[index].Name[readpointer] != ' ')
2189
                                        {
2190
                                        findelement->name[writepointer] = '.';                                                  // then seperate the name and the extension by a '.' at index 8.                                                
2191
                                        writepointer++;
2192
                                        findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2193
                                        writepointer++;
2194
                                        }
2195
                                            else break;
2196
                                                }
2197
                            else break;
2198
                        }
2199
                        /* terminate the namestring with 0 for debugpurposes*/
2200
                        findelement->name[12] = 0;
2201
                                }
2202
                                findelement->fp.FirstSectorOfFirstCluster = (u32) DirectoryEntry[index].StartCluster;                                                  
2203
                                findelement->fp.DirectoryIndex   = index;              
2204
                                findelement->fp.FirstSectorOfCurrCluster   = file.FirstSectorOfCurrCluster;
2205
                                findelement->fp.DirectorySector  = (file.FirstSectorOfCurrCluster + file.SectorOfCurrCluster);
2206
                                findelement->fp.SectorOfCurrCluster      = file.SectorOfCurrCluster;
2207
                findelement->fp.Size            = DirectoryEntry[index].Size;
2208
                                findelement->fp.Attribute               = DirectoryEntry[index].Attribute;
2209
                retvalue = 1;
2210
                        }                      
2211
                        /* search the next sector */
2212
                        index++;
2213
                }
2214
                /* this sector has been searched but we havn't found what we are looking for. Therefore we have to find the next sector */
2215
                if(!retvalue)                                                                                                                           // file not found in this sector so take next sector.
2216
                {
2217
                        /* in the next sector we start looking for the specified entry beginning at index 0 */
2218
                        index = 0;
2219
                        /* there are still sectors to be read within the cluster or within the linear addresspace of the rootdirectory */
2220
                        if(file.SectorOfCurrCluster < max_dir_sector-1)  file.SectorOfCurrCluster++; else end_of_directory_not_reached = 0;
2221
                        /* if we are looking for an directoryentry outside the rootdirectory and have reached the end of the cluster we have to get the next one */
2222
                        if(Partition.FirstDataSector <= file.FirstSectorOfCurrCluster)
2223
                        {
2224
                                end_of_directory_not_reached = GetNextCluster(&file);
2225
                        }
2226
                }
2227
        }
2228
        while((end_of_directory_not_reached) && (!retvalue) );
2229
 
2230
        return(retvalue);      
2231
}
2232
 
2233
 
2234
 
2235
 
2236
/********************************************************************************************************************************************/
2237
/*      Function:               findnext_(Find_t *);                                                                                                                                                                                                                    */
2238
/*                                                                                                                                                                                                                                                                                      */
2239
/*      Description:    This function looks for the next item in the specified directory with a matching filename and fileattributes specified  */
2240
/*                  by function findfirst()                                                                                                                                                                                                     */
2241
/*                                                                                                                                                                                                                                                                                      */
2242
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2243
/********************************************************************************************************************************************/
2244
u8 findnext_(Find_t * findelement)
2245
{
2246
        u8 itemfound = 0;
2247
        u8 index = 0;
2248
 
2249
        findelement->fp.DirectoryIndex++;
2250
 
2251
        /* before we start searching an element we clear the complete namestring within the structure FindElement */
2252
        for(index=0;index<11;index++) findelement->name[index] = 0;
2253
 
2254
        if(FindItem(findelement))
2255
        {
2256
                itemfound = 1;         
2257
        }
2258
 
2259
        return(itemfound);
2260
}
2261
 
2262
 
2263
 
2264
/********************************************************************************************************************************************/
2265
/*      Function:               findfirst_(s8* filename, u8 attribmask, Find_t *);                                                                                                                                              */
2266
/*                                                                                                                                                                                                                                                                                      */
2267
/*      Description:    This function looks for the first item in the specified directory with a matching filename and fileattributes                   */
2268
/*                                      The filename of the element found is transformed from 8.3 to a string                                                                                                   */
2269
/*                                                                                                                                                                                                                                                                                      */
2270
/*                                                                                                                                                                                                                                                                                      */
2271
/*      Returnvalue:    (1) if Element was found. (0) if no valid element was found                                                                                                                     */
2272
/********************************************************************************************************************************************/
2273
u8 findfirst_(const s8* name, u8 attribmask, Find_t *findelement)
2274
{
2275
        u8 itemfound = 0;
2276
        u8 index = 0;  
2277
 
2278
        /* initialize the FindElement structure */
2279
        findelement->fp.FirstSectorOfFirstCluster = 0;  // First sector of the first cluster of the file.
2280
        findelement->fp.FirstSectorOfCurrCluster = Partition.CurrentWorkingDirectory;                                   // First sector of the cluster which is edited at the moment.
2281
        findelement->fp.SectorOfCurrCluster = 0;                                                        // The sector within the current cluster.
2282
        findelement->fp.ByteOfCurrSector = 0;                                                   // The byte location within the current sector.
2283
        findelement->fp.Size = 0;                                                                               // The size of the opend file in bytes.
2284
        findelement->fp.Position = 0;                                                                   // Pointer to a character within the file 0 < fileposition < filesize
2285
        findelement->fp.DirectorySector = 0;                                                            // the sectorposition where the directoryentry has been made.
2286
        findelement->fp.DirectoryIndex = 0;                                                             // The index to the directoryentry within the specified sector.
2287
        findelement->attribfilter = 0;
2288
        findelement->attribmask = attribmask;
2289
        findelement->searchstring[0]=0;
2290
 
2291
        /* seperate the name of the element to be found from the filepath and bring it to the 8.3*/
2292
        SeperateDirName(name, findelement->searchstring);
2293
        /* after the name of the element is in 8.3 we process the wildcards (*). After an * all following character are wildcards to */
2294
        for(index=0;index<8;index++)
2295
        {
2296
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2297
                if(findelement->searchstring[index] == '*')
2298
                {
2299
                        /*  */
2300
                        while(++index <8) findelement->searchstring[index] = '*';
2301
                }
2302
        }
2303
        for(index=8;index<11;index++)
2304
        {                                                                                                                                                                                                                                        
2305
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2306
                if(findelement->searchstring[index] == '*')
2307
                {
2308
                        /*  */
2309
                        while(++index <11) findelement->searchstring[index] = '*';
2310
                }
2311
        }
2312
 
2313
        /* the value of ...DirectoryIndex will be incremented in findnext_() thererfore it has to be decremented in findfirst_() */
2314
        findelement->fp.DirectoryIndex--;
2315
        /* now lets search for the item within the direcory */
2316
        itemfound = findnext_(findelement);
2317
 
2318
        return(itemfound);
2319
}
2320
 
2321
 
2322
/********************************************************************************************************************************************/
2323
/*      Function:               u8 GetDirCount(s8* filepath);                                                                                                                                                                                   */
2324
/*                                                                                                                                                                                                                                                                                      */
2325
/*      Description:    This function counts the number of subdirectories the dirpath contains                                                                                                  */
2326
/*                                                                                                                                                                                                                                                              */
2327
/*                                                                                                                                                                                                                                                                                      */
2328
/*      Returnvalue:    then number of subdirectories within the specified path                                                                                                                                 */
2329
/********************************************************************************************************************************************/
2330
u8 GetDirCount(u8 *dirpath)
2331
{
2332
   u8 i=0;
2333
   u8 cnt=0;
2334
 
2335
   while(dirpath[i] != 0 )
2336
   {
2337
      if(dirpath[i]=='/')
2338
      {  
2339
         if(dirpath[i+1]!=0) cnt++;                                            // ignore last'/'
2340
      }
2341
      i++;  
2342
   }
2343
   i=0;  
2344
   return(cnt);
2345
}
2346
 
2347
 
2348
/********************************************************************************************************************************************/
2349
/* Funtion:     char *GetSubDirectory (char *dirpath, char *directory)                                                                                                                                          */
2350
/*                                                                                                                                                                                                                                                                                      */
2351
/* Description: this function returns a pointer to the beginning of the next subdirectory or NULL                                                                                       */
2352
/*                                                                                                                                                                                                                                                                                      */
2353
/*                                                                                                                                                                                                                                                                                      */
2354
/* returnvalue:   number of subdirectories in the filepath                                                                                                                                                                      */
2355
/********************************************************************************************************************************************/
2356
u8 * GetSubDirectory(u8 *dirpath, u8 *directory)
2357
{
2358
   u8 *cptr = dirpath;
2359
   u8 *dptr = directory;
2360
   u8 *retvalue = NULL;
2361
 
2362
   /* if the first character of the path is an '/' we go to the next character */
2363
   if(*cptr == '/') cptr++;
2364
   /* search end of path or subdirectory*/
2365
   while((*cptr != 0) && (*cptr != '/'))
2366
   {
2367
      *dptr = *cptr;
2368
       dptr++;
2369
       cptr++;
2370
   }  
2371
   if(*cptr!=0) retvalue = ++cptr;
2372
   *dptr = 0;
2373
 
2374
   return(retvalue);
2375
}
2376
 
2377
/********************************************************************************************************************************************/
2378
/*      Function:               s8 *GetPath(void);                                                                                                                                                                                                              */
2379
/*                                                                                                                                                                                                                                                                                      */
2380
/*      Description:    This function function returns a pointer to the absolute path of the active partition                                                                   */
2381
/*                                                                                                                                                                                                                                      */
2382
/*                                                                                                                                                                                                                                                                                      */
2383
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2384
/********************************************************************************************************************************************/
2385
 
2386
s8 *GetPath(void)
2387
{
2388
        return(Partition.PathToCwd);
2389
}
2390
 
2391
/********************************************************************************************************************************************/
2392
/*      Function:               void SetPathToRoot(void);                                                                                                                                                                                                       */
2393
/*                                                                                                                                                                                                                                                                                      */
2394
/*      Description:    This function sets the path to the rootdirectory                                                                                                                                                */
2395
/*                                                                                                                                                                                                                                      */
2396
/*                                                                                                                                                                                                                                                                                      */
2397
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2398
/********************************************************************************************************************************************/
2399
 
2400
void SetPathToRoot(void)
2401
{
2402
        /* lets point to the rootdirectory */
2403
        strcpy(Partition.PathToCwd, "/");      
2404
}
2405
 
2406
/********************************************************************************************************************************************/
2407
/*      Function:               void AppendDirToPath(s8* directory);                                                                                                                                                                                    */
2408
/*                                                                                                                                                                                                                                                                                      */
2409
/*      Description:    This function function appends the name of an directory to the Path to the CWD                                                                                  */
2410
/*                                                                                                                                                                                                                                      */
2411
/*                                                                                                                                                                                                                                                                                      */
2412
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2413
/********************************************************************************************************************************************/
2414
 
2415
void AppendDirToPath(s8* directory)
2416
{
2417
        /* append the name of the directory to the path */
2418
        strcat(Partition.PathToCwd, directory);
2419
        /* append a '/' after the directoryname */
2420
        strcat(Partition.PathToCwd, "/");
2421
}
2422
 
2423
/********************************************************************************************************************************************/
2424
/*      Function:               RemoveLastDirFromPath(void);                                                                                                                                                                                    */
2425
/*                                                                                                                                                                                                                                                                                      */
2426
/*      Description:    This function removes the last directory from the path to the cwd                                                                                                               */
2427
/*                                                                                                                                                                                                                                      */
2428
/*                                                                                                                                                                                                                                                                                      */
2429
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2430
/********************************************************************************************************************************************/
2431
 
2432
void RemoveLastDirFromPath(void)
2433
{
2434
        /* a pointer to the beginning of the absolute path to the cwd */
2435
        s8 * cptr = Partition.PathToCwd;
2436
        /* lets find the end of the path to the cwd */
2437
        while(*cptr != 0 ) cptr++;
2438
        /* if the path is terminated with an '/' */
2439
        if((*(cptr-1)) == '/') *(cptr-1)=0;    
2440
        /* now lets find the beginning of the last directorientry */
2441
        while((*cptr != '/' ) && cptr > Partition.PathToCwd) cptr--;
2442
        /* is there one subdirectory left within the path? */
2443
        if(cptr > Partition.PathToCwd)
2444
        {
2445
                /* we delete the direntry by terminating the path with 0 */
2446
                *cptr = 0;
2447
        }
2448
        /* there is no subdirectory left within the path. Therefore we create the root instead. */
2449
        else
2450
        {
2451
                *cptr = '/';
2452
                *(cptr+1) = 0;
2453
        }
2454
}
2455
 
2456
/********************************************************************************************************************************************/
2457
/*      Function:               chdir_(s8* filepath);                                                                                                                                                                                                   */
2458
/*                                                                                                                                                                                                                                                                                      */
2459
/*      Description:    This function changed the current working directory to the directory specified by the filepath                                                  */
2460
/*                  by function findfirst()                                                                                                                                                                                                     */
2461
/*                                                                                                                                                                                                                                                                                      */
2462
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2463
/********************************************************************************************************************************************/
2464
/*                                                                         
2465
#define ATTR_NONE               0x00    // normal file
2466
#define ATTR_READONLY           0x01    // file is readonly
2467
#define ATTR_HIDDEN                     0x02    // file is hidden
2468
#define ATTR_SYSTEM                     0x04    // file is a system file
2469
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2470
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2471
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2472
#define ATTR_ARCHIVE            0x20    // file is new or modified
2473
*/
2474
 
2475
u8 chdir_(s8 *path)
2476
{
2477
        u8              retvalue = 0;                                   // the value returned by this function
2478
        u32     ultemp = 0;                                             // temp. variable
2479
        u8     *directory = path;                               // pointer to a directoryname within the path
2480
        u8      dircount = 0;                                   // the number of subdirectoryentries within the path
2481
        u8      cache[64];                                              // a buffer containing the name of the subdirectory we are actually looking for
2482
        Find_t  fe;                                                             // The findelement needed for function findfirst to find the subdirectoryentry
2483
        s8              tp[256];                                                // temporarily we remember the actual path until the operation has finished successfully
2484
        u32     cwdt = 0;
2485
        s8     *cptr;
2486
 
2487
        /* bring the path into the correct syntax */
2488
        cptr = path;
2489
        /* search the whole string */
2490
        while(*cptr != 0 )
2491
        {
2492
                if(*cptr == '\\') *cptr = '/';
2493
                cptr++;
2494
        }
2495
        /* lets remember the actual path */
2496
        strcpy(tp, Partition.PathToCwd);
2497
        cwdt = Partition.CurrentWorkingDirectory;
2498
        /* how many subdirectories are there within the path? */
2499
        dircount = GetDirCount(path);  
2500
        /* if the path is absolute we begin at the rootdirectory */
2501
        if(path[0] == '/')
2502
        {
2503
                strcpy(Partition.PathToCwd, "/");
2504
                Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
2505
                /* if there is no other pathinformation we only switch to the rootdirectory. So theres nothing left todo.*/
2506
                if(!dircount) return(1);
2507
        }
2508
        /* now we parse through all the subdirectories within the path */
2509
        do
2510
        {  
2511
                /* until all the subdirectories within the path have been processed */
2512
        if(dircount) dircount--;
2513
                /* this is the name of the next subdirectory we are looking for */             
2514
            directory = GetSubDirectory(directory, cache);  
2515
                /* search for the next subdirectory within the path */
2516
                if(findfirst_(cache, ATTR_SUBDIRECTORY, &fe))
2517
                {
2518
                        /* we try to change into the directory "..". Now we have to delete the last direntry from the path */
2519
                        if(strcmp(cache,"..") == 0) RemoveLastDirFromPath();
2520
                        /* we try to change into the actual directory so there's nothing todo */
2521
                        else if(cache[0] == '.') return(1);
2522
                        /* otherwise we append the name of the directory we are changing in to the path */
2523
                        else AppendDirToPath(cache);
2524
                        /* The startcluster within an directoryentry specifies the position within the fat where the file or directory starts */
2525
                        ultemp = (u32) fe.fp.FirstSectorOfFirstCluster;
2526
                        /* the first 2 entries are reserved for '.' and '..' */
2527
                        ultemp -= 2;
2528
                        /* now we have to transform the position within the fat into the corrosponding sectoraddress relative to the beginning of the datasection of the active partition*/
2529
                        ultemp *= Partition.SectorsPerCluster;
2530
                        /* at least we make the sectoraddress absolute by adding the relative address to the beginning of the datasection of the active partition */
2531
                        ultemp += Partition.FirstDataSector;
2532
                        /* the cwd now points to the specified directory */
2533
                        Partition.CurrentWorkingDirectory = ultemp;
2534
                        /* we found the folder specified by the foldername */
2535
                        retvalue = 1;
2536
                }
2537
        }
2538
        /* do this until all subdirectories have been found or a subdirectory is missing */
2539
        while(dircount && retvalue );
2540
 
2541
        /* if we could not change to the specified directory we restore the actual path */
2542
        if(!retvalue)
2543
        {
2544
                Partition.CurrentWorkingDirectory = cwdt;                                                  
2545
                strcpy(Partition.PathToCwd, tp);
2546
        }
2547
        return(retvalue);      
2548
}