Subversion Repositories NaviCtrl

Rev

Rev 385 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 ingob 1
/*#######################################################################################*/
2
/* !!! THIS IS NOT FREE SOFTWARE !!!                                                     */
3
/*#######################################################################################*/
4
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5
// + www.MikroKopter.com
6
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 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.
1 ingob 13
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 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.
1 ingob 31
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 32
// + Software LICENSING TERMS
1 ingob 33
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 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.
1 ingob 55
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41 ingob 56
#include <stdio.h>
379 holgerb 57
#include <string.h>
41 ingob 58
#include "91x_lib.h"
119 killagreg 59
#include "timer1.h"
41 ingob 60
#include "fat16.h"
61
#include "sdc.h"
62
#include "uart1.h"
379 holgerb 63
#include "main.h"
385 holgerb 64
#include "logging.h"
379 holgerb 65
 
383 holgerb 66
 
1 ingob 67
//________________________________________________________________________________________________________________________________________
88 killagreg 68
// Module name:                 fat16.c
1 ingob 69
// Compiler used:               avr-gcc 3.4.5
211 killagreg 70
// Last Modifikation:   20.03.2010
71
// Version:                             2.10
88 killagreg 72
// Authors:                             Stephan Busker & Gregor Stobrawa
41 ingob 73
// Description:                 Source files for FAT16 implementation with read and write-access
74
//                                              Copyright (C) 2008 Stephan Busker & Gregor Stobrawa
1 ingob 75
//........................................................................................................................................
41 ingob 76
// Functions:                   extern s16              Fat16_Init(void);
88 killagreg 77
//                                              extern s16              Fat16_Deinit(void);
211 killagreg 78
//                                              extern s8*              FAT16_GetVolumeLabel(void);
41 ingob 79
//                                              extern File_t * fopen_(const u8 *filename, const s8 mode);
80
//                                              extern s16              fclose_(File_t *File);
211 killagreg 81
//                                              extern u8               fexist_(s8 * const filename);
41 ingob 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);
88 killagreg 86
//                                              extern u32              fread_(void *buffer, u32 size, u32 count, File_t *File);
41 ingob 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);
211 killagreg 90
//                                              extern u8               feof_(File_t * const file);
1 ingob 91
//........................................................................................................................................
41 ingob 92
// ext. functions:              extern SD_Result_t SDC_Init(void;)
93
//                                              extern SD_Result_t SDC_Deinit(void);
88 killagreg 94
//                      extern SD_Result_t SDC_GetSector (u32,u8 *);
41 ingob 95
//                                              extern SD_Result_t SDC_PutSector (u32,u8 *);
1 ingob 96
//........................................................................................................................................
97
//
98
// URL:                                 www.Mikro-Control.de
99
// mailto:                              stephan.busker@mikro-control.de
100
//________________________________________________________________________________________________________________________________________
101
 
41 ingob 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
*/
1 ingob 110
 
111
 
379 holgerb 112
 
41 ingob 113
/*
114
________________________________________________________________________________________________________________________________________
88 killagreg 115
 
116
        Structure of an partition entry
41 ingob 117
________________________________________________________________________________________________________________________________________
1 ingob 118
 
41 ingob 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
88 killagreg 131
} __attribute__((packed)) PartitionEntry_t;
1 ingob 132
 
379 holgerb 133
 
134
 
41 ingob 135
/*
136
Coding of Cylinder/Sector words
1 ingob 137
 
41 ingob 138
Cylinder is 10 bits:  [7:0] at [15:8] and [9:8] at [7:6]
88 killagreg 139
Sector is 5 bits:  [5:0] at [5:0]
41 ingob 140
*/
1 ingob 141
 
41 ingob 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
1 ingob 169
 
170
 
41 ingob 171
/*
172
________________________________________________________________________________________________________________________________________
88 killagreg 173
 
174
        Structure of the MasterBootRecord
41 ingob 175
________________________________________________________________________________________________________________________________________
1 ingob 176
 
41 ingob 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
{
88 killagreg 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;
1 ingob 190
 
191
 
41 ingob 192
/*
193
________________________________________________________________________________________________________________________________________
88 killagreg 194
 
195
        Structure of the VolumeBootRecord
41 ingob 196
________________________________________________________________________________________________________________________________________
24 StephanB 197
 
41 ingob 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
88 killagreg 204
        s8  OEMName[8];                         // OEM Name
41 ingob 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
88 killagreg 209
        u16 MaxRootEntries;                     // Maximum Root Directory Entries
41 ingob 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)
88 killagreg 222
        u8  ExecutableCode[446];        // 446 bytes for machine start code
223
        u16 ExecutableMarker;           // Executable Marker (0x55 0xAA)
224
} __attribute__((packed)) VBR_Entry_t;
1 ingob 225
 
226
 
227
 
41 ingob 228
/*
229
________________________________________________________________________________________________________________________________________
230
 
88 killagreg 231
        Structure of an directory entry
41 ingob 232
________________________________________________________________________________________________________________________________________
233
 
234
        Directory entry is 32 bytes.
235
*/
236
typedef struct
1 ingob 237
{
41 ingob 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)
211 killagreg 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.
41 ingob 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;
1 ingob 252
 
41 ingob 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
1 ingob 256
 
41 ingob 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
24 StephanB 265
 
266
 
41 ingob 267
/*
268
________________________________________________________________________________________________________________________________________
88 killagreg 269
 
270
        Structure of an entry within the fileallocationtable.
41 ingob 271
________________________________________________________________________________________________________________________________________
272
*/
273
typedef struct
274
{
275
        u16  NextCluster;                               // the next cluster of the file.
276
} __attribute__((packed)) Fat16Entry_t;
1 ingob 277
 
41 ingob 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
 
88 killagreg 289
/*****************************************************************************************************************************************/
41 ingob 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
 
211 killagreg 301
#define SECTOR_UNDEFINED        0x00000000L
302
#define CLUSTER_UNDEFINED       0x0000
303
 
88 killagreg 304
#define FSTATE_UNUSED   0
41 ingob 305
#define FSTATE_USED             1
306
 
307
typedef struct
1 ingob 308
{
41 ingob 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
379 holgerb 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;
1 ingob 322
 
379 holgerb 323
Partition_t     Partition;              // Structure holds partition information
1 ingob 324
 
41 ingob 325
File_t FilePointer[FILE_MAX_OPEN];      // Allocate Memmoryspace for each filepointer used.
1 ingob 326
 
41 ingob 327
 
379 holgerb 328
 
329
 
41 ingob 330
/****************************************************************************************************************************************/
211 killagreg 331
/*      Function:               FileDate(DateTime_t *);                                                                                                                                                                                         */
41 ingob 332
/*                                                                                                                                                                                                                                                                              */
211 killagreg 333
/*      Description:    This function calculates the DOS date from a pointer to a time structure.                                                                                       */
41 ingob 334
/*                                                                                                                                                                                                                                                                              */
211 killagreg 335
/*      Returnvalue:    Returns the DOS date.                                                                                                                                                                                           */
41 ingob 336
/****************************************************************************************************************************************/
211 killagreg 337
u16 FileDate(DateTime_t * pTimeStruct)
338
{
339
        u16 date = 0;
340
        if(pTimeStruct == NULL)   return date;
341
        if(!(pTimeStruct->Valid)) return date;
41 ingob 342
 
211 killagreg 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)
1 ingob 358
{
211 killagreg 359
        u16 time = 0;
360
        if(pTimeStruct == NULL)   return time;
361
        if(!(pTimeStruct->Valid)) return time;
24 StephanB 362
 
211 killagreg 363
        time |= (0x001F & (u16)(pTimeStruct->Hour))<<11;
364
        time |= (0x003F & (u16)(pTimeStruct->Min))<<5;
365
        time |= (0x001F & (u16)(pTimeStruct->Sec/2));
366
        return time;
1 ingob 367
}
368
 
41 ingob 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)
1 ingob 377
{
41 ingob 378
        u8 i;
379
        File_t * File = 0;
380
        for(i = 0; i < FILE_MAX_OPEN; i++)
1 ingob 381
        {
88 killagreg 382
                if(FilePointer[i].State == FSTATE_UNUSED)               // found an unused one
1 ingob 383
                {
88 killagreg 384
                        File = &FilePointer[i];                                         // set pointer to that entry
41 ingob 385
                        FilePointer[i].State = FSTATE_USED;                     // mark it as used
386
                        break;
1 ingob 387
                }
41 ingob 388
        }
389
        return(File);
1 ingob 390
}
391
 
41 ingob 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)
1 ingob 400
{
41 ingob 401
        u8 cnt;
402
        if(file == NULL) return(0);
403
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 404
        {
41 ingob 405
                if(&FilePointer[cnt] == file)                                           // filepointer to be freed found?
1 ingob 406
                {
88 killagreg 407
                        file->State = FSTATE_UNUSED;
211 killagreg 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.
41 ingob 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
211 killagreg 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.
41 ingob 417
                        file->DirectoryIndex                    = 0;                    // the index to the directoryentry within the specified sector.
418
                        file->Attribute                                 = 0;                    // the attribute of the file opened.
88 killagreg 419
                        file = NULL;
41 ingob 420
                        return(1);
1 ingob 421
                }
41 ingob 422
        }
423
        return(0);
424
}
1 ingob 425
 
41 ingob 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')                                                                                                                            */
210 killagreg 431
/*                                      The subpath is the pointer to the remaining substring of the filepath                                                                                           */
41 ingob 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;
1 ingob 440
 
88 killagreg 441
        // search subpath from beginning of filepath
41 ingob 442
        subpath = NULL;
443
        readpointer     = 0;
444
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
368 holgerb 445
        while(subpath == NULL)  // search the filepath until a subpath was found.
1 ingob 446
        {
88 killagreg 447
                if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/')))    // if '/' found or end of filepath reached
448
                {
41 ingob 449
                        subpath = (s8*)&filepath[readpointer];                          // store the position of the first "/" found after the beginning of the filenpath
450
                }
451
                readpointer++;
452
        }
1 ingob 453
 
41 ingob 454
        // clear dirname with spaces
455
        dirname[11] = 0; // terminate dirname
456
        for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
379 holgerb 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
 
41 ingob 479
        writepointer = 0;
480
        // start seperating the dirname from the filepath.
481
        readpointer = 0;
482
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
368 holgerb 483
        while( &filepath[readpointer] < subpath)
1 ingob 484
        {
41 ingob 485
                if(writepointer >= 11) return(NULL);            // dirname to long
486
                if(filepath[readpointer] == '.')                        // seperating dirname and extension.
1 ingob 487
                {
41 ingob 488
                        if(writepointer <= 8)
1 ingob 489
                        {
41 ingob 490
                                readpointer++;                                          // next character in filename
491
                                writepointer = 8;                                       // jump to start of extension
1 ingob 492
                        }
88 killagreg 493
                        else return(NULL);                                              // dirbasename to long
41 ingob 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
                        }
1 ingob 501
                        else
502
                        {
41 ingob 503
                                dirname[writepointer] = filepath[readpointer];
88 killagreg 504
                        }
41 ingob 505
                        readpointer++;
506
                        writepointer++;
1 ingob 507
                }
41 ingob 508
        }
88 killagreg 509
        return(subpath);
1 ingob 510
}
511
 
512
 
41 ingob 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
{
211 killagreg 523
        if(!Partition.IsValid) return SECTOR_UNDEFINED;
218 killagreg 524
        if ((cluster < 2) || (cluster == CLUSTER_UNDEFINED))
211 killagreg 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
        }
41 ingob 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
{
211 killagreg 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);
41 ingob 547
}
548
 
549
 
550
/****************************************************************************************************************************************/
210 killagreg 551
/*      Function:       Fat16_IsValid(void);                                                                                                                                                                                                    */
90 killagreg 552
/*                                                                                                                                                                                                                                                                              */
210 killagreg 553
/*      Description:    This function return the Fat 16 filesystem state                                                                                                                                        */
90 killagreg 554
/*                                                                                                                                                                                                                                                                              */
555
/*      Returnvalue: The function returns "1" on success                                                                                                                                                                        */
556
/****************************************************************************************************************************************/
557
u8 Fat16_IsValid(void)
558
{
559
        return(Partition.IsValid);
560
}
561
 
562
/****************************************************************************************************************************************/
41 ingob 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;
146 killagreg 573
 
574
        UART1_PutString("\r\n FAT16 deinit...");
41 ingob 575
        // declare the filepointers as unused.
576
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
324 killagreg 577
        {      
578
                UnlockFilePointer(&FilePointer[cnt]);
1 ingob 579
        }
324 killagreg 580
        returnvalue = SDC_Deinit();                     // uninitialize interface to sd-card
41 ingob 581
        Partition.IsValid = 0;  // mark data in partition structure as invalid
210 killagreg 582
        Partition.VolumeLabel[0]='\0';
146 killagreg 583
        UART1_PutString("ok");
385 holgerb 584
        if(SD_WatchDog > 2000) SD_WatchDog = 2000;
585
        SD_LoggingError = 100;
41 ingob 586
        return(returnvalue);
1 ingob 587
}
588
 
41 ingob 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)
88 killagreg 598
{
41 ingob 599
    u8  cnt     = 0;
600
        u32     partitionfirstsector;
88 killagreg 601
        VBR_Entry_t *VBR;
41 ingob 602
        MBR_Entry_t *MBR;
603
        File_t *file;
604
        u8 result = 0;
1 ingob 605
 
110 killagreg 606
        UART1_PutString("\r\n FAT16 init...");
41 ingob 607
        Partition.IsValid = 0;
608
        // declare the filepointers as unused.
609
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 610
        {
211 killagreg 611
                UnlockFilePointer(&FilePointer[cnt]);
1 ingob 612
        }
41 ingob 613
        // set current file pinter to first position in list
88 killagreg 614
        file = &FilePointer[0];
615
 
211 killagreg 616
        // try to initialize the sd-card.
88 killagreg 617
        if(SD_SUCCESS != SDC_Init())
618
        {
110 killagreg 619
                UART1_PutString("SD-Card could not be initialized.");
41 ingob 620
                result = 1;
88 killagreg 621
                goto end;
41 ingob 622
        }
1 ingob 623
 
41 ingob 624
        // SD-Card is initialized successfully
625
        if(SD_SUCCESS != SDC_GetSector((u32)MBR_SECTOR,file->Cache))    // Read the MasterBootRecord
1 ingob 626
        {
110 killagreg 627
                UART1_PutString("Error reading the MBR.");
41 ingob 628
                result = 2;
88 killagreg 629
                goto end;
1 ingob 630
        }
41 ingob 631
        MBR = (MBR_Entry_t *)file->Cache;                                               // Enter the MBR using the structure MBR_Entry_t.
88 killagreg 632
        if((MBR->PartitionEntry1.Type == PART_TYPE_FAT16_ST_32_MB) ||
41 ingob 633
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16_LT_32_MB) ||
634
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16LBA))
1 ingob 635
        {
41 ingob 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
1 ingob 640
                {
110 killagreg 641
                        UART1_PutString("Error reading the VBR.");
41 ingob 642
                        result = 3;
88 killagreg 643
                        goto end;
644
                }
1 ingob 645
        }
41 ingob 646
        else  // maybe the medium has no partition assuming sector 0 is the vbr
647
        {
648
                partitionfirstsector = 0;
649
        }
88 killagreg 650
 
41 ingob 651
        VBR = (VBR_Entry_t *) file->Cache;                                              // Enter the VBR using the structure VBR_Entry_t.
652
        if(VBR->BytesPerSector != BYTES_PER_SECTOR)
653
        {
110 killagreg 654
                UART1_PutString("VBR: Sector size not supported.");
41 ingob 655
                result = 4;
88 killagreg 656
                goto end;
41 ingob 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).
210 killagreg 661
        Partition.SectorsPerFat                 = VBR->SectorsPerFAT;                           // The number of sectors per FAT                                // copy volume label
662
        Partition.VolumeLabel[0] = '\0';                                                                        // set string terminator
41 ingob 663
 
664
        /* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */
88 killagreg 665
        // Calculate the position of the FileAllocationTable:
41 ingob 666
        // Start + # of Reserved Sectors
88 killagreg 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)
41 ingob 670
        Partition.FirstRootDirSector    =   Partition.FirstFatSector + (u32)((u32)Partition.SectorsPerFat*(u32)Partition.FatCopies);
671
        // Calculate the position of the first datacluster:
88 killagreg 672
        // Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
41 ingob 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
        {
110 killagreg 677
                UART1_PutString("VBR: Bad number of sectors.");
41 ingob 678
                result = 5;
88 killagreg 679
                goto end;
41 ingob 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
        {
110 killagreg 685
                UART1_PutString("VBR: Partition ist not FAT16 type.");
41 ingob 686
                result = 6;
687
                goto end;
688
        }
689
        Partition.IsValid = 1; // mark data in partition structure as valid
379 holgerb 690
        Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
691
        strcpy(Partition.PathToCwd,"/");       
41 ingob 692
        result = 0;
693
        end:
694
        if(result != 0) Fat16_Deinit();
110 killagreg 695
        else UART1_PutString("ok");
88 killagreg 696
        return(result);
1 ingob 697
}
698
 
699
 
41 ingob 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)
1 ingob 709
{
41 ingob 710
        u8 retvalue = 1;
711
        u32 i;
88 killagreg 712
 
41 ingob 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
211 killagreg 716
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return (0); // nothing to do 
41 ingob 717
        for(i = 0; i < Partition.SectorsPerCluster; i++)
1 ingob 718
        {
41 ingob 719
                file->SectorInCache = file->FirstSectorOfCurrCluster + i;
720
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
721
                {
88 killagreg 722
                        Fat16_Deinit();
379 holgerb 723
                        return(0);
41 ingob 724
                }
1 ingob 725
        }
88 killagreg 726
        return(retvalue);
1 ingob 727
}
728
 
41 ingob 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)
1 ingob 737
{
211 killagreg 738
        u16 cluster = CLUSTER_UNDEFINED;
41 ingob 739
        u32 fat_byte_offset, sector, byte;
740
        Fat16Entry_t * fat;
88 killagreg 741
 
41 ingob 742
        if((!Partition.IsValid) || (file == NULL)) return(cluster);
211 killagreg 743
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(cluster);
41 ingob 744
        // if sector is within the data area
745
        if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
1 ingob 746
        {
41 ingob 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)
1 ingob 757
                {
41 ingob 758
                        file->SectorInCache = sector;                                           // update sector stored in buffer
759
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
24 StephanB 760
                        {
41 ingob 761
                                Fat16_Deinit();
379 holgerb 762
                                return (CLUSTER_UNDEFINED);
88 killagreg 763
                        }
764
                }
41 ingob 765
                // read the next cluster from cache
766
                fat = (Fat16Entry_t *)(&(file->Cache[byte]));
767
                cluster = fat->NextCluster;
211 killagreg 768
                // if no next cluster exist
41 ingob 769
                if(FAT16_CLUSTER_LAST_MIN <= cluster)
770
                {
211 killagreg 771
                         cluster = CLUSTER_UNDEFINED; // next cluster is undefined
1 ingob 772
                }
24 StephanB 773
                else
774
                {
41 ingob 775
                        file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
776
                        file->SectorOfCurrCluster = 0;
777
                        file->ByteOfCurrSector = 0;
24 StephanB 778
                }
88 killagreg 779
        }
41 ingob 780
        return(cluster);
1 ingob 781
}
782
 
783
 
379 holgerb 784
 
41 ingob 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)
1 ingob 793
{
41 ingob 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).
211 killagreg 797
        u16     free_cluster    = CLUSTER_UNDEFINED;    // next free cluster number.
41 ingob 798
        Fat16Entry_t * fat;
88 killagreg 799
 
41 ingob 800
        if((!Partition.IsValid) || (file == NULL)) return(0);
24 StephanB 801
 
41 ingob 802
        // start searching for an empty cluster at the beginning of the fat.
88 killagreg 803
        fat_sector = 0;
804
        do
1 ingob 805
        {
41 ingob 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();
379 holgerb 811
                        return(CLUSTER_UNDEFINED);
41 ingob 812
                }
813
 
814
                fat = (Fat16Entry_t *)file->Cache;                                              // set fat pointer to file cache
815
 
88 killagreg 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.
41 ingob 817
                {
818
                        if(fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE)            // empty cluster found!!
88 killagreg 819
                        {
820
                                fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX;    // mark this fat-entry as used
41 ingob 821
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // and save the sector at the sd-card.
822
                                {
823
                                        Fat16_Deinit();
379 holgerb 824
                                        return(CLUSTER_UNDEFINED);
41 ingob 825
                                }
88 killagreg 826
                                free_cluster = (u16)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (u32)fat_entry);
41 ingob 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
88 killagreg 831
        // repeat until the end of the fat is  reached and no free cluster has been found so far
368 holgerb 832
        }while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
41 ingob 833
        return(free_cluster);
1 ingob 834
}
835
 
836
 
41 ingob 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)                                                                                                                                                                      */
380 holgerb 842
/* Returnvalue: Is 0 if seek was successful                                                                                                                                                                                                                     */
41 ingob 843
/****************************************************************************************************************************************************/
844
s16 fseek_(File_t *file, s32 offset, s16 origin)
1 ingob 845
{
41 ingob 846
        s32             fposition       = 0;
847
        s16     retvalue        = 1;
88 killagreg 848
 
380 holgerb 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      
211 killagreg 857
        if((!Partition.IsValid) || (file == NULL)) return(retvalue);
380 holgerb 858
//......................................................
859
        if(origin == SEEK_SET)                                                                                                          // Fileposition relative to the beginning of the file.
41 ingob 860
        {
380 holgerb 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
        }      
41 ingob 873
 
380 holgerb 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?
1 ingob 878
        {
380 holgerb 879
                // initialize the filepointer
41 ingob 880
                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
881
                file->SectorOfCurrCluster       = 0;
882
                file->ByteOfCurrSector          = 0;
883
                file->Position                          = 0;
380 holgerb 884
                // has the specified file at least one valid sector attached?
211 killagreg 885
                if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(retvalue);
380 holgerb 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
        }      
1 ingob 904
        return(retvalue);
905
}
906
 
41 ingob 907
/****************************************************************************************************************************************/
908
/* Function:    u16 DeleteClusterChain(File *file);                                                                                                                                                                             */
909
/*                                                                                                                                                                                                                                                                              */
910
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited.                                                                  */
911
/*                                                                                                                                                                                                                                                                              */
912
/****************************************************************************************************************************************/
913
u8 DeleteClusterChain(u16 StartCluster)
1 ingob 914
{
88 killagreg 915
        u16 cluster;
41 ingob 916
        u32 fat_byte_offset, sector, byte;
917
        Fat16Entry_t * fat;
918
        u8 buffer[BYTES_PER_SECTOR];
919
        u32 sector_in_buffer = 0;
920
        u8 repeat = 0;
921
 
211 killagreg 922
        if(!Partition.IsValid) return(0);
923
        if(StartCluster == CLUSTER_UNDEFINED) return(0);
210 killagreg 924
        cluster = StartCluster; // init chain trace
211 killagreg 925
        // if start cluster is no real cluster
926
    if(FAT16_CLUSTER_LAST_MIN <= cluster) return 1;
41 ingob 927
 
928
        // calculate byte offset in the fat for corresponding entry
929
        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
930
        // calculate the sector that contains the current cluster within the fat
931
        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
932
        // calculate byte offset of the current cluster within that fat sector
933
        byte = fat_byte_offset % BYTES_PER_SECTOR;
88 killagreg 934
        do
1 ingob 935
        {
41 ingob 936
                if(sector != sector_in_buffer)
1 ingob 937
                {
41 ingob 938
                        // read this sector to buffer
939
                        sector_in_buffer = sector;
940
                        if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0;     // read sector from sd-card
88 killagreg 941
                }
41 ingob 942
                // read the next cluster from cache
943
                fat = (Fat16Entry_t *)(&(buffer[byte]));
944
                cluster = fat->NextCluster;
211 killagreg 945
                fat->NextCluster =      FAT16_CLUSTER_FREE; // mark current cluster as free
946
 
947
                if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) )
948
                {
949
                        repeat = 1;
950
                        // calculate sector byte and byte offset in the fat for the next cluster
951
                        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
952
                        // calculate the sector that contains the current cluster within the fat
953
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
954
                        // calculate byte offset of the current cluster within that fat sector
955
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
956
                }
41 ingob 957
                else repeat = 0;
958
 
959
                // if new sector is not the sector in buffer or the last cluster in the chain was traced
960
                if((sector != sector_in_buffer) || !repeat)
961
                {       // write sector in buffer
210 killagreg 962
                        if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer))
146 killagreg 963
                        {
964
                                Fat16_Deinit();
211 killagreg 965
                                return(0);
146 killagreg 966
                        }
1 ingob 967
                }
41 ingob 968
        }
368 holgerb 969
        while(repeat);
41 ingob 970
 
971
        return 1;
1 ingob 972
}
973
 
974
 
41 ingob 975
/****************************************************************************************************************************************/
976
/* Function:    u16 AppendCluster(File *file);                                                                                                                                                                                  */
977
/*                                                                                                                                                                                                                                                                              */
978
/* Description: This function looks in the fat to find the next free cluster and appends it to the file.                                                                */
979
/*                                                                                                                                                                                                                                                                              */
211 killagreg 980
/* Returnvalue: The function returns the appened cluster number or CLUSTER_UNDEFINED of no cluster was appended.                                                */
41 ingob 981
/****************************************************************************************************************************************/
982
u16 AppendCluster(File_t *file)
1 ingob 983
{
211 killagreg 984
        u16 last_cluster, new_cluster = CLUSTER_UNDEFINED;
41 ingob 985
        u32 fat_byte_offset, sector, byte;
986
        Fat16Entry_t * fat;
88 killagreg 987
 
387 StephanB 988
 
41 ingob 989
        if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
1 ingob 990
 
41 ingob 991
        new_cluster = FindNextFreeCluster(file);        // the next free cluster found on the disk.
211 killagreg 992
        if(new_cluster != CLUSTER_UNDEFINED)
387 StephanB 993
        {       // A free cluster was found and can be added to the end of the file.            
994
                // is there at least one cluster appended to the file?
995
                if(file->FirstSectorOfLastCluster == CLUSTER_UNDEFINED)
996
                {
997
                        fseek_(file, 0, SEEK_END);                                                                                                      // jump to the end of the file
998
                        // remember the first sector of the last cluster
999
                        file->FirstSectorOfLastCluster = file->FirstSectorOfCurrCluster;
1000
                        last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);            // determine current file cluster
1001
                }
1002
                else
1003
                {
1004
                        last_cluster = SectorToFat16Cluster(file->FirstSectorOfLastCluster);            // determine current file cluster
1005
                }
1006
 
211 killagreg 1007
                if(last_cluster != CLUSTER_UNDEFINED)
41 ingob 1008
                {
211 killagreg 1009
                        // update FAT entry of last cluster
1010
                        fat_byte_offset = ((u32)last_cluster)<<1;
1011
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
1012
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
1013
                        // read the sector containing the last cluster of the file
1014
                        if(file->SectorInCache != sector)
41 ingob 1015
                        {
211 killagreg 1016
                                file->SectorInCache = sector;   // update sector stored in buffer
1017
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
1018
                                {
1019
                                        Fat16_Deinit();
1020
                                        return(0);
1021
                                }
1022
                        }
1023
                        fat = (Fat16Entry_t *)(&(file->Cache[byte]));
1024
                        fat->NextCluster = new_cluster;                                                 // append the free cluster to the end of the file in the FAT.
1025
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // save the modified sector to the FAT.
1026
                        {
41 ingob 1027
                                Fat16_Deinit();
211 killagreg 1028
                                return(0);
88 killagreg 1029
                        }
387 StephanB 1030
                        // now the new cluster appended to the fat is the last cluster
1031
                        file->FirstSectorOfLastCluster = Fat16ClusterToSector(new_cluster);
88 killagreg 1032
                }
211 killagreg 1033
                else // last cluster of the file is undefined
1034
                {   // then the new cluster must be the first one of the file
1035
                    // and its cluster number must be set in the direntry
1036
                        DirEntry_t * dir;
1037
                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1038
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1039
                        {
1040
                                Fat16_Deinit();
1041
                                return(CLUSTER_UNDEFINED);
1042
                        }
1043
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1044
                        dir[file->DirectoryIndex].Res1 = 0;
1045
                        dir[file->DirectoryIndex].Res2[0] = 0;
1046
                        dir[file->DirectoryIndex].Res2[1] = 0;
1047
                        dir[file->DirectoryIndex].StartCluster = new_cluster;           // update startcluster 
1048
                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);// set time
1049
                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);// and date of modification
1050
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1051
                        dir[file->DirectoryIndex].Size          = 0;
1052
                        // write sector containing the direntry
1053
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1054
                        {
1055
                                Fat16_Deinit();
1056
                                return(CLUSTER_UNDEFINED);
1057
                        }
1058
                        // update file info     
1059
                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(new_cluster);
387 StephanB 1060
                        file->FirstSectorOfLastCluster = file->FirstSectorOfFirstCluster;
211 killagreg 1061
                        file->Size = 0;
1062
                        file->Position = 0;
41 ingob 1063
                }
211 killagreg 1064
                // update file pointes
41 ingob 1065
                file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
1066
                file->SectorOfCurrCluster = 0;
1067
                file->ByteOfCurrSector = 0;
1068
        }
1069
        return(new_cluster);
1 ingob 1070
}
1071
 
380 holgerb 1072
 
41 ingob 1073
/****************************************************************************************************************************************************/
1074
/* Function:    DirectoryEntryExist(s8 *, u8, u8, File_t *)                                                                                                                                                                                     */
1075
/*                                                                                                                                                                                                                                                                                                      */
1076
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached                     */
1077
/*                                                                                                                                                                                                                                                                                                      */
1078
/* Returnvalue: This function returns 1 if the directory entry specified was found.                                                                                                                                     */
1079
/****************************************************************************************************************************************************/
1080
u8 DirectoryEntryExist(s8 *dirname, u8 attribfilter, u8 attribmask, File_t *file)
1081
{
1082
        u32             dir_sector, max_dir_sector, curr_sector;
1083
        u16     dir_entry = 0;
24 StephanB 1084
 
41 ingob 1085
        u16     end_of_directory_not_reached = 0;
1086
        u8              i = 0;
1087
        u8      direntry_exist = 0;
1088
        DirEntry_t * dir;
24 StephanB 1089
 
41 ingob 1090
        // if incomming pointers are useless return immediatly
88 killagreg 1091
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
41 ingob 1092
 
88 killagreg 1093
        // dir entries can be searched only in filesclusters that have
1094
        // a corresponding dir entry with adir-flag set in its attribute
41 ingob 1095
        // or direct within the root directory area
211 killagreg 1096
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1097
        // no current directory exist therefore assume searching in the root
211 killagreg 1098
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1099
        {
41 ingob 1100
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1101
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1102
        }
1103
        // within the root directory area we can read sectors sequentially until the end of this area
1104
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1105
        {
1106
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1107
        }
88 killagreg 1108
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1109
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1110
        {
1111
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
1112
        }
1113
        else return (direntry_exist); // bad sector range for directory sector of the file
1114
        // if search area is not defined yet
211 killagreg 1115
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1116
        {
1117
                // check if the directory entry of current file is existent and has the dir-flag set
1118
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1119
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
24 StephanB 1120
                {
41 ingob 1121
                        Fat16_Deinit();
379 holgerb 1122
                        return(0);
24 StephanB 1123
                }
41 ingob 1124
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
211 killagreg 1125
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
24 StephanB 1126
                {
41 ingob 1127
                        case SLOT_EMPTY:
1128
                        case SLOT_DELETED:
1129
                                // the directrory pointer of this file points to a deleted or not existen directory
1130
                                // therefore no file or subdirectory can be created
1131
                                return (direntry_exist);
1132
                                break;
88 killagreg 1133
                        default:        // and is a real directory
41 ingob 1134
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1135
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1136
                                        return (direntry_exist);
1137
                                }
1138
                                break;
24 StephanB 1139
                }
41 ingob 1140
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster);
24 StephanB 1141
        }
1142
 
41 ingob 1143
        // update current file data area position to start of first cluster
88 killagreg 1144
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1145
        file->SectorOfCurrCluster               = 0;
41 ingob 1146
        file->ByteOfCurrSector                  = 0;
24 StephanB 1147
 
41 ingob 1148
        do // loop over all data clusters of the current directory entry
88 killagreg 1149
        {
379 holgerb 1150
                dir_sector = 0;
41 ingob 1151
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1152
                {
41 ingob 1153
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1154
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1155
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
1156
                        {
1157
                                Fat16_Deinit();
379 holgerb 1158
                                return(0);
41 ingob 1159
                        }
1160
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1161
                        // search all directory entries within that sector
1162
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1163
                        {   // check for existing dir entry
1164
                                switch((u8)dir[dir_entry].Name[0])
1165
                                {
1166
                                        case SLOT_EMPTY:
1167
                                        case SLOT_DELETED:
1168
                                                // ignore empty or deleted dir entries
1169
                                                break;
1170
                                        default:
1171
                                                // if existing check attributes before names are compared will safe performance
1172
                                                if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
1173
                                                // then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
1174
                                                i = 0;
1175
                                                while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
1176
                                                if (i < 10) break; // names does not match
1177
                                                // if dirname and attribute have matched
1178
                                                file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
88 killagreg 1179
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
41 ingob 1180
                                                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1181
                                                file->SectorOfCurrCluster = 0;
1182
                                                file->ByteOfCurrSector = 0;
1183
                                                file->DirectorySector = curr_sector; // current sector
1184
                                                file->DirectoryIndex  = dir_entry; // current direntry in current sector
88 killagreg 1185
                                                file->Size = dir[dir_entry].Size;
1186
                                                direntry_exist = 1; // mark as found
1187
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
41 ingob 1188
                                } // end of first byte of name check
1189
                        }
1190
                        dir_sector++; // search next sector
1191
                // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 1192
                }while((dir_sector < max_dir_sector) && (!direntry_exist));
1 ingob 1193
 
41 ingob 1194
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
88 killagreg 1195
                if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
41 ingob 1196
                {
1197
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1198
                }
368 holgerb 1199
        }while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
41 ingob 1200
        return(direntry_exist);
1 ingob 1201
}
1202
 
1203
 
41 ingob 1204
/****************************************************************************************************************************************/
1205
/*      Function:               CreateDirectoryEntry(s8 *, u16, File_t *)                                                                                                                                                       */
1206
/*                                                                                                                                                                                                                                                                              */
1207
/*      Description:    This function looks for the next free position in the directory and creates an entry.                                                           */
1208
/*                                      The type of an directory entry is specified by the file attribute.                                                                                                      */
1209
/*                                                                                                                                                                                                                                                                              */
1210
/*      Returnvalue:    Return 0 on error                                                                                                                                                                                                       */
1211
/****************************************************************************************************************************************/
1212
u8 CreateDirectoryEntry(s8 *dirname, u8 attrib, File_t *file)
1 ingob 1213
{
41 ingob 1214
        u32 dir_sector, max_dir_sector, curr_sector;
1215
        u16 dir_entry   = 0;
1216
        u16 subdircluster, dircluster = 0;
1217
        u16 end_of_directory_not_reached = 0;
1218
        u8      i                       = 0;
88 killagreg 1219
        u8      retvalue        = 0;
41 ingob 1220
        DirEntry_t *dir;
1221
 
1222
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
1223
        // It is not checked here that the dir entry that should be created is already existent!
88 killagreg 1224
 
1225
        // Dir entries can be created only in file-clusters that have
41 ingob 1226
        // the dir-flag set in its attribute or within the root directory
88 killagreg 1227
 
211 killagreg 1228
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1229
        // no current directory exist therefore assume creating in the root
211 killagreg 1230
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1231
        {
41 ingob 1232
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1233
                dircluster = 0;
1234
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1235
        }
1236
        // within the root directory area we can read sectors sequentially until the end of this area
1237
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1238
        {
1239
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1240
        }
88 killagreg 1241
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1242
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1243
        {
1244
                max_dir_sector = Partition.SectorsPerCluster;
1245
        }
88 killagreg 1246
        else return (retvalue); // bad sector range for directory sector of the file
41 ingob 1247
        // if search area is not defined yet
211 killagreg 1248
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1249
        {
1250
            // check if the directory entry of current file is existent and has the dir-flag set
1251
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
88 killagreg 1252
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1253
                {
1254
                        Fat16_Deinit();
379 holgerb 1255
                        return(0);
88 killagreg 1256
                }
41 ingob 1257
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
218 killagreg 1258
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
41 ingob 1259
                {
1260
                        case SLOT_EMPTY:
1261
                        case SLOT_DELETED:
1262
                                return (retvalue);
1263
                                break;
88 killagreg 1264
                        default:        // and is a real directory
41 ingob 1265
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1266
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1267
                                        return (retvalue);
1268
                                }
1269
                                break;
1270
                }
1271
                dircluster = dir[file->DirectoryIndex].StartCluster;
88 killagreg 1272
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
41 ingob 1273
        }
88 killagreg 1274
 
218 killagreg 1275
        // if the new direntry is a subdirectory
1276
        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)
1277
        {       // get a free clutser for its content
1278
                subdircluster = FindNextFreeCluster(file);      // get the next free cluster on the disk and mark it as used.
1279
        }
1280
        else // a normal file
1281
        {       // has no data cluster after creation
1282
                subdircluster = CLUSTER_UNDEFINED;
1283
        }
1284
 
211 killagreg 1285
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1286
        file->SectorOfCurrCluster               = 0;
1287
        do // loop over all clusters of current directory
41 ingob 1288
        {
211 killagreg 1289
                dir_sector = 0; // reset sector counter within a new cluster
1290
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1291
                {
211 killagreg 1292
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1293
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1294
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1 ingob 1295
                        {
211 killagreg 1296
                                Fat16_Deinit();
379 holgerb 1297
                                return(0);
211 killagreg 1298
                        }
1299
 
1300
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1301
                        // search all directory entries of a sector
1302
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1303
                        {       // check if current direntry is available
1304
                                if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
1305
                                {       // a free direntry was found
1306
                                        for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i];            // Set dir name
1307
                                        dir[dir_entry].Attribute    = attrib;
1308
                                        dir[dir_entry].Res1 = 0;
1309
                                        dir[dir_entry].CreationTime10ms = (u8)(SystemTime.mSec/10);
1310
                                        dir[dir_entry].CreationTime     = FileTime(&SystemTime);
1311
                                        dir[dir_entry].CreationDate     = FileDate(&SystemTime);
1312
                                        dir[dir_entry].LastAccessDate = dir[dir_entry].CreationDate;
1313
                                        dir[dir_entry].Res2[0] = 0;
1314
                                        dir[dir_entry].Res2[1] = 0;
1315
                                        dir[dir_entry].ModTime = dir[dir_entry].CreationTime;
1316
                                        dir[dir_entry].ModDate = dir[dir_entry].CreationDate;
1317
                                        // Set the attribute of the new directoryentry.
1318
                                        dir[dir_entry].StartCluster = subdircluster;                                            // copy the location of the first datacluster to the directoryentry.
1319
                                        dir[dir_entry].Size             = 0;                                                                    // the new createted file has no content yet.
1320
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to card
1321
                                        {
1322
                                                Fat16_Deinit();
379 holgerb 1323
                                                return(0);
211 killagreg 1324
                                        }
218 killagreg 1325
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster);  // Calculate absolute sectorposition of first datacluster.
211 killagreg 1326
                                        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;      // Start reading the file with the first sector of the first datacluster.
1327
                                        file->SectorOfCurrCluster               = 0;                                                            // reset sector of cureen cluster
1328
                                        file->ByteOfCurrSector                  = 0;                                                            // reset the byte location within the current sector
1329
                                        file->Attribute                                 = attrib;                                               // set file attribute to dir attribute
1330
                                        file->Size                                              = 0;                                                        // new file has no size
1331
                                        file->DirectorySector                   = curr_sector;
1332
                                        file->DirectoryIndex                    = dir_entry;
1333
                                        // prepare subdirectory data cluster
1334
                                        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)                           // if a new directory was created then initilize the data area
1335
                                        {
1336
                                                ClearCurrCluster(file); // fill cluster with zeros
1337
                                                file->SectorInCache = file->FirstSectorOfFirstCluster;
1338
                                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1339
                                                {
211 killagreg 1340
                                                        Fat16_Deinit();
379 holgerb 1341
                                                        return(0);
41 ingob 1342
                                                }
211 killagreg 1343
                                                dir = (DirEntry_t *)file->Cache;
1344
                                                // create direntry "." to current dir
1345
                                                dir[0].Name[0] = 0x2E;
1346
                                                for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
1347
                                                dir[0].Attribute = ATTR_SUBDIRECTORY;
1348
                                                dir[0].StartCluster = subdircluster;
1349
                                                dir[0].Size = 0;
1350
                                                // create direntry ".." to the upper dir
1351
                                                dir[1].Name[0] = 0x2E;
1352
                                                dir[1].Name[1] = 0x2E;
1353
                                                for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
1354
                                                dir[1].Attribute = ATTR_SUBDIRECTORY;
1355
                                                dir[1].StartCluster = dircluster;
1356
                                                dir[1].Size = 0;
1357
                                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
88 killagreg 1358
                                                {
211 killagreg 1359
                                                        Fat16_Deinit();
379 holgerb 1360
                                                        return(0);
211 killagreg 1361
                                                }
1362
                                        }
1363
                                        retvalue = 1;
1364
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
88 killagreg 1365
                                }
211 killagreg 1366
                        }
1367
                        dir_sector++; // search next sector
1368
                // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 1369
                }while((dir_sector < max_dir_sector) && (!retvalue));
88 killagreg 1370
 
211 killagreg 1371
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1372
                if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
1373
                {
1374
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1375
                }
368 holgerb 1376
        }while((end_of_directory_not_reached) && (!retvalue));
211 killagreg 1377
        // Perhaps we are at the end of the last cluster of a directory file and have no free direntry found.
1378
        // Then we would need to add a cluster to that file and create the new direntry there.
1379
        // This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
1380
        // within a subdirectory of root.
1381
 
41 ingob 1382
        return(retvalue);       // return 1 if file has been created otherwise return 0.
1 ingob 1383
}
1384
 
41 ingob 1385
/********************************************************************************************************************************************/
1386
/*      Function:               FileExist(const s8* filename, u8 attribfilter, u8 attribmask, File_t *file);                                                                                    */
1387
/*                                                                                                                                                                                                                                                                                      */
1388
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1389
/*                                      in the rootdirectory of the drive. If the file is found the Filepointer properties are                                                                  */
1390
/*                                      updated.                                                                                                                                                                                                                                */
1391
/*                                                                                                                                                                                                                                                                                      */
1392
/*      Returnvalue:    1 if file is found else 0.                                                                                                                                                                                              */
1393
/********************************************************************************************************************************************/
1394
u8 FileExist(const s8* filename, const u8 attribfilter, const u8 attribmask, File_t *file)
1 ingob 1395
{
41 ingob 1396
        s8* path = 0;
1397
        s8* subpath = 0;
1398
        u8 af, am, file_exist = 0;
1399
        s8 dirname[12]; // 8+3 + temination character
1 ingob 1400
 
41 ingob 1401
        // if incomming pointers are useless return immediatly
1402
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1403
 
41 ingob 1404
        // trace along the filepath
1405
        path = (s8*)filename;                                                           // start a the beginning of the filename string
1406
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
88 killagreg 1407
        file->DirectoryIndex = 0;
379 holgerb 1408
        /* if a path begins with a '/' at index 0 the search starts at the rootdirectory otherwise we will start relative to the cwd */
1409
        if(path[0] != '/')
1410
        {
1411
                /* is the current working directory the rootdirectory? */
1412
                if(Partition.CurrentWorkingDirectory == Partition.FirstRootDirSector) file->DirectorySector = 0;
1413
                /* otherwise we are working in an subdirectory */
1414
                else file->DirectorySector = Partition.CurrentWorkingDirectory;
1415
        }
41 ingob 1416
        // as long as the file was not found and the remaining path is not empty
368 holgerb 1417
        while((*path != 0) && !file_exist)
41 ingob 1418
        {       // separate dirname and subpath from filepath string
1419
                subpath = SeperateDirName(path, dirname);
1420
                if(subpath != NULL)
88 killagreg 1421
                {
1422
                        if(*subpath == 0)
41 ingob 1423
                        {       // empty subpath indicates last element of dir chain
1424
                                af = attribfilter;
1425
                                am = attribmask;
1426
                        }
1427
                        else  // it must be a subdirectory and no volume label
1 ingob 1428
                        {
41 ingob 1429
                                af = ATTR_SUBDIRECTORY;
1430
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1431
                        }
1432
                        if(!DirectoryEntryExist(dirname, af, am, file))
1433
                        {
1434
                                return (file_exist); // subdirectory does not exist
1435
                        }
88 killagreg 1436
                        else
1437
                        {
41 ingob 1438
                                if (*subpath == 0)
24 StephanB 1439
                                {
41 ingob 1440
                                        file_exist = 1; // last element of path chain was found with the given attribute filter
24 StephanB 1441
                                }
1 ingob 1442
                        }
1443
                }
41 ingob 1444
                else // error seperating the subpath
1 ingob 1445
                {
41 ingob 1446
                        return file_exist; // bad subdir format
1 ingob 1447
                }
41 ingob 1448
                path = subpath;
1449
                subpath = 0;
1 ingob 1450
        }
41 ingob 1451
        return (file_exist);
1 ingob 1452
}
1453
 
24 StephanB 1454
 
41 ingob 1455
/********************************************************************************************************************************************/
1456
/*      Function:               FileCreate(const s8* filename, u8 attrib, File_t *file);                                                                                                                                */
1457
/*                                                                                                                                                                                                                                                                                      */
1458
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1459
/*                                      in the rootdirectory of the partition. If the file is found the Filepointer properties are                                                              */
88 killagreg 1460
/*                                      updated. If file or its subdirectories are not found they will be created                                                                                               */
41 ingob 1461
/*                                                                                                                                                                                                                                                                                      */
1462
/*      Returnvalue:    1 if file was created else 0.                                                                                                                                                                                   */
1463
/********************************************************************************************************************************************/
1464
u8 FileCreate(const s8* filename, const u8 attrib, File_t *file)
1465
{
1466
        s8 *path = 0;
1467
        s8 *subpath = 0;
1468
        u8 af, am, file_created = 0;
1469
        s8 dirname[12];
24 StephanB 1470
 
41 ingob 1471
        // if incomming pointers are useless return immediatly
1472
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1473
 
41 ingob 1474
        // trace along the filepath
1475
        path = (s8*)filename;                                                                   // start a the beginning of the filename string
1476
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1477
        file->DirectoryIndex = 0;
1478
        // as long as the file was not created and the remaining file path is not empty
368 holgerb 1479
        while((*path != 0) && !file_created)
41 ingob 1480
        {   // separate dirname and subpath from filepath string
1481
                subpath = SeperateDirName(path, dirname);
1482
                if(subpath != NULL)
24 StephanB 1483
                {
88 killagreg 1484
                        if(*subpath == 0)
41 ingob 1485
                        {       // empty subpath indicates last element of dir chain
1486
                                af = ATTR_NONE;
1487
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;  // any file that is no subdir or volume label
24 StephanB 1488
                        }
41 ingob 1489
                        else  // it must be a subdirectory and no volume label
24 StephanB 1490
                        {
41 ingob 1491
                                af = ATTR_SUBDIRECTORY;
1492
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
24 StephanB 1493
                        }
41 ingob 1494
                        if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
1495
                        {  // try to create subdir or file
1496
                                if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
1497
                                if(!CreateDirectoryEntry(dirname, af, file))
1498
                                {       // could not be created
88 killagreg 1499
                                        return(file_created);
1500
                                }
41 ingob 1501
                                else if (*subpath == 0) file_created = 1; // last element of path chain was created
24 StephanB 1502
                        }
1503
                }
41 ingob 1504
                else // error seperating the subpath
24 StephanB 1505
                {
41 ingob 1506
                        return file_created; // bad subdir format
24 StephanB 1507
                }
41 ingob 1508
                path = subpath;
1509
                subpath = 0;
1510
        }
1511
        return (file_created);
24 StephanB 1512
}
1 ingob 1513
 
24 StephanB 1514
 
41 ingob 1515
/********************************************************************************************************************************************/
1516
/*      Function:               File_t * fopen_(s8* filename, s8 mode);                                                                                                                                                                 */
1517
/*                                                                                                                                                                                                                                                                                      */
1518
/*      Description:    This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the    */
1519
/*                                      corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet.                                             */
1520
/*                                                                                                                                                                                                                                                                                      */
1521
/*      Returnvalue:    The filepointer to the file or 0 if faild.                                                                                                                                                              */
1522
/********************************************************************************************************************************************/
89 killagreg 1523
File_t * fopen_(s8 * const filename, const s8 mode)
88 killagreg 1524
{
41 ingob 1525
        File_t *file    = 0;
379 holgerb 1526
        s8 *cptr;
88 killagreg 1527
 
41 ingob 1528
        if((!Partition.IsValid) || (filename == 0)) return(file);
1529
 
1530
        // Look for an unused filepointer in the file pointer list?
1531
        file = LockFilePointer();
1532
        // if no unused file pointer was found return 0
1533
        if(file == NULL) return(file);
1534
 
1535
        // now we have found a free filepointer and claimed it
1536
        // so let initiate its property values
211 killagreg 1537
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;             // Sectorpointer to the first sector of the first datacluster of the file.
1538
        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;             // Pointer to the cluster which is edited at the moment.
41 ingob 1539
        file->SectorOfCurrCluster               = 0;            // The sector which is edited at the moment (cluster_pointer + sector_index).
1540
        file->ByteOfCurrSector                  = 0;            // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
1541
        file->Mode                                              = mode;         // mode of fileoperation (read,write)
1542
        file->Size                                              = 0;            // the size of the opened file in bytes.
1543
        file->Position                                  = 0;            // pointer to a byte within the file 0 < fileposition < filesize
211 killagreg 1544
        file->SectorInCache                             = SECTOR_UNDEFINED;             // the last sector read, wich is still in the sectorbuffer.
1545
        file->DirectorySector                   = SECTOR_UNDEFINED;             // the sectorposition where the directoryentry has been made.
41 ingob 1546
        file->DirectoryIndex                    = 0;            // the index to the directoryentry within the specified sector.
1547
        file->Attribute                                 = 0;            // the attribute of the file opened.
1548
 
379 holgerb 1549
        // bring the path into the correct syntax 
1550
        cptr = filename;
1551
        // search the whole string 
1552
        while(*cptr != 0)
1553
        {
1554
                // replace all '\' by '/'
1555
                if(*cptr == '\\') *cptr = '/';
1556
                cptr++;
1557
        }
41 ingob 1558
        // check if a real file (no directory) to the given filename exist
88 killagreg 1559
        if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
41 ingob 1560
        {  // file exist
1561
                switch(mode)  // check mode
1 ingob 1562
                {
41 ingob 1563
                        case 'a':       // if mode is: append to file
1564
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1565
                                {       // file is marked as readonly --> do not open this file
1566
                                        fclose_(file);
1567
                                        file = NULL;
1568
                                }
1569
                                else
1570
                                {       // file is not marked as read only --> goto end of file
1571
                                        fseek_(file, 0, SEEK_END);              // point to the end of the file
1572
                                }
1573
                                break;
1574
                        case 'w':       // if mode is: write to file
1575
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1576
                                {       // file is marked as readonly --> do not open this file
1577
                                        fclose_(file);
1578
                                        file = NULL;
1579
                                }
1580
                                else
211 killagreg 1581
                                {       // file is not marked as read only
1582
                                        DirEntry_t * dir;
41 ingob 1583
                                        // free all clusters of that file
1584
                                        DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
211 killagreg 1585
                                        // update directory entry of that file
1586
                                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1587
                                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1588
                                        {
1589
                                                Fat16_Deinit();
1590
                                                return(NULL);
1591
                                        }
1592
                                        dir = (DirEntry_t *)file->Cache;                                                                // set pointer to directory
1593
                                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);        // set modification time
1594
                                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);        // set modification date
1595
                                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1596
                                        dir[file->DirectoryIndex].StartCluster = CLUSTER_UNDEFINED;             // update startcluster 
1597
                                        dir[file->DirectoryIndex].Size          = 0;
1598
                                        // write sector containing the direntry
1599
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1600
                                        {
1601
                                                Fat16_Deinit();
1602
                                                return(NULL);
1603
                                        }
1604
                                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1605
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1606
                                        file->SectorOfCurrCluster = 0;
1607
                                        file->ByteOfCurrSector = 0;
1608
                                        file->Size = 0;
1609
                                        file->Position = 0;
1610
                                        fseek_(file, 0, SEEK_SET);
1611
                                }
1612
                                break;
1613
                        case 'r':       // if mode is: read from file
88 killagreg 1614
                                // goto end of file
41 ingob 1615
                                fseek_(file, 0, SEEK_SET);
1616
                                break;
1617
                        default: // other modes are not supported
1618
                                fclose_(file);
1619
                                file = NULL;
24 StephanB 1620
                        break;
1 ingob 1621
                }
88 killagreg 1622
                return(file);
1 ingob 1623
        }
41 ingob 1624
        else // file does not exist
1625
        {
1626
                switch(mode)  // check mode
1627
                {
1628
                        case 'a':
1629
                        case 'w': // if mode is write or append
1630
                                // try to create the file
1631
                                if(!FileCreate(filename, ATTR_ARCHIVE, file))
1632
                                { // if it could not be created
1633
                                        fclose_(file);
1634
                                        file = NULL;
379 holgerb 1635
                                }
41 ingob 1636
                                break;
1637
                        case 'r': // else opened for 'r'
218 killagreg 1638
                        default:  // if unsupported mode
41 ingob 1639
                                fclose_(file);
1640
                                file = NULL;
88 killagreg 1641
                                break;
41 ingob 1642
                }
88 killagreg 1643
                return(file);
41 ingob 1644
        }
1645
        // we should never come to this point
1646
        fclose_(file);
1647
        file = NULL;
24 StephanB 1648
        return(file);
1649
}
1650
 
41 ingob 1651
/****************************************************************************************************************************************************/
1652
/* Function:    fflush_(File *);                                                                                                                                                                                                                                        */
1653
/*                                                                                                                                                                                                                                                                                                      */
1654
/* Description: This function writes the data already in the buffer but not yet written to the file.                                                                                            */
1655
/*                                                                                                                                                                                                                                                                                                      */
1656
/* Returnvalue: 0 on success EOF on error                                                                                                                                                                                                                       */
1657
/****************************************************************************************************************************************************/
1658
s16     fflush_(File_t *file)
24 StephanB 1659
{
88 killagreg 1660
        DirEntry_t *dir;
1661
 
41 ingob 1662
        if((file == NULL) || (!Partition.IsValid)) return (EOF);
88 killagreg 1663
 
41 ingob 1664
        switch(file->Mode)
24 StephanB 1665
        {
41 ingob 1666
                case 'a':
1667
                case 'w':
88 killagreg 1668
                        if(file->ByteOfCurrSector > 0)                                                                          // has data been added to the file?
41 ingob 1669
                        {
88 killagreg 1670
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
41 ingob 1671
                                {
88 killagreg 1672
                                        Fat16_Deinit();
1673
                                        return(EOF);
1674
                                }
41 ingob 1675
                        }
1676
                        file->SectorInCache     = file->DirectorySector;
1677
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))                                       // read the directory entry for this file.
1678
                        {
1679
                                Fat16_Deinit();
88 killagreg 1680
                                return(EOF);
41 ingob 1681
                        }
88 killagreg 1682
 
41 ingob 1683
                        dir = (DirEntry_t *)file->Cache;
324 killagreg 1684
                        // update file size and modification time & date
211 killagreg 1685
                        dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);
1686
                        dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);
1687
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
41 ingob 1688
                        dir[file->DirectoryIndex].Size = file->Size;                                            // update file size
1689
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to sd-card
1690
                        {
1691
                                Fat16_Deinit();
1692
                                return(EOF);
1693
                        }
1694
                        break;
1695
                case 'r':
1696
                default:
211 killagreg 1697
                        // do nothing!
41 ingob 1698
                        return(EOF);
1699
                        break;
1700
 
24 StephanB 1701
        }
41 ingob 1702
        return(0);
24 StephanB 1703
}
1 ingob 1704
 
41 ingob 1705
/****************************************************************************************************************************************/
1706
/*      Function:               fclose_(File *file);                                                                                                                                                                                            */
1707
/*                                                                                                                                                                                                                                                                              */
1708
/*      Description:    This function closes the open file by writing the remaining data                                                                                                        */
1709
/*                                      from the buffer to the device and entering the filesize in the directory entry.                                                                         */
1710
/*                                                                                                                                                                                                                                                                              */
1711
/*      Returnvalue:    0 on success EOF on error                                                                                                                                                                                       */
1712
/****************************************************************************************************************************************/
1713
s16 fclose_(File_t *file)
24 StephanB 1714
{
41 ingob 1715
        s16 returnvalue = EOF;
24 StephanB 1716
 
41 ingob 1717
        if(file == NULL) return(returnvalue);
1718
        returnvalue = fflush_(file);
1719
        UnlockFilePointer(file);
1720
        return(returnvalue);
24 StephanB 1721
}
1722
 
41 ingob 1723
/********************************************************************************************************************************************/
1724
/*      Function:               fgetc_(File *file);                                                                                                                                                                                                             */
1725
/*                                                                                                                                                                                                                                                                                      */
1726
/*      Description:    This function reads and returns one character from the specified file. Is the end of the actual sector reached the              */
1727
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1728
/*                                                                                                                                                                                                                                                                                      */
1729
/*      Returnvalue:    The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.                                   */
1730
/********************************************************************************************************************************************/
1731
s16 fgetc_(File_t *file)
88 killagreg 1732
{
41 ingob 1733
        s16 c = EOF;
1734
        u32 curr_sector;
88 killagreg 1735
 
41 ingob 1736
        if( (!Partition.IsValid) || (file == NULL)) return(c);
1737
        // if the end of the file is not reached, get the next character.
379 holgerb 1738
        if((0 < file->Size) && ((file->Position) < file->Size) )
1 ingob 1739
        {
41 ingob 1740
                curr_sector  = file->FirstSectorOfCurrCluster;          // calculate the sector of the next character to be read.
88 killagreg 1741
                curr_sector += file->SectorOfCurrCluster;
1742
 
41 ingob 1743
                if(file->SectorInCache != curr_sector)
1 ingob 1744
                {
41 ingob 1745
                        file->SectorInCache = curr_sector;
1746
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
1747
                        {
1748
                                Fat16_Deinit();
379 holgerb 1749
                                return(EOF);
88 killagreg 1750
                        }
1751
                }
41 ingob 1752
                c = (s16) file->Cache[file->ByteOfCurrSector];
1753
                file->Position++;                                                                       // increment file position
88 killagreg 1754
                file->ByteOfCurrSector++;                                                       // goto next byte in sector
41 ingob 1755
                if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if end of sector
24 StephanB 1756
                {
41 ingob 1757
                        file->ByteOfCurrSector = 0;                                             //  reset byte location
1758
                        file->SectorOfCurrCluster++;                                    //      next sector
1759
                        if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
24 StephanB 1760
                        {
88 killagreg 1761
 
41 ingob 1762
                                if(GetNextCluster(file))                                                                                // Sets the clusterpointer of the file to the next datacluster.
24 StephanB 1763
                                {
41 ingob 1764
                                        file->SectorOfCurrCluster = 0;                                                          // start reading new cluster at first sector of the cluster.
1765
                                }
1766
                                else // the last cluster was allready reached
1767
                                {
1768
                                        file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
1769
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
1770
                                }
1 ingob 1771
                        }
24 StephanB 1772
                }
1773
        }
41 ingob 1774
        return(c);
24 StephanB 1775
}
1776
 
41 ingob 1777
/********************************************************************************************************************************************/
1778
/*      Function:               fputc_( const s8 c, File *file);                                                                                                                                                                                */
1779
/*                                                                                                                                                                                                                                                                                      */
1780
/*      Description:    This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.                                 */
1781
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1782
/*                                                                                                                                                                                                                                                                                      */
1783
/*      Returnvalue:    The function returns the character written to the stream or EOF on error.                                                                                               */
1784
/********************************************************************************************************************************************/
1785
s16 fputc_(const s8 c, File_t *file)
88 killagreg 1786
{
41 ingob 1787
        u32 curr_sector  = 0;
88 killagreg 1788
 
41 ingob 1789
        if((!Partition.IsValid) || (file == NULL)) return(EOF);
211 killagreg 1790
        switch(file->Mode)
41 ingob 1791
        {
211 killagreg 1792
                case 'w':
1793
                case 'a':
1794
                        // If file position equals to file size, then the end of file has been reached.
1795
                        // In this case it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
1796
                        // and a new cluster should be appended.
1797
                        // If the first sector of first cluster is unvalid, then the file claims no data clusters 
1798
                        // and size should be zero, therefore append a new Cluster too.
1799
                        if(((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) || (file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED))
1800
                        {
1801
                                if(CLUSTER_UNDEFINED == AppendCluster(file)) return(EOF);
1802
                        }
1803
 
1804
                        curr_sector  = file->FirstSectorOfCurrCluster;
1805
                        curr_sector += file->SectorOfCurrCluster;
1806
                        if(file->SectorInCache != curr_sector)
1807
                        {
1808
                                file->SectorInCache = curr_sector;
1809
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
24 StephanB 1810
                                {
211 killagreg 1811
                                        Fat16_Deinit();
1812
                                        return(EOF);
24 StephanB 1813
                                }
1 ingob 1814
                        }
379 holgerb 1815
 
1816
                        file->Cache[file->ByteOfCurrSector] = (u8)c;            // write databyte into the buffer. The byte will be written to the device at once
211 killagreg 1817
                        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.
1818
                        file->Position++;                                                                       // the actual positon within the file.
1819
                        file->ByteOfCurrSector++;                                                       // goto next byte in sector
1820
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if the end of this sector is reached yet
1821
                        {       // save the sector to the sd-card
383 holgerb 1822
 
211 killagreg 1823
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1824
                                {
1825
                                        Fat16_Deinit();
1826
                                        return(EOF);
1827
                                }
1828
                                file->ByteOfCurrSector = 0;                                             //  reset byte location
1829
                                file->SectorOfCurrCluster++;                                    //      next sector
1830
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
1831
                                {
1832
                                        if(!GetNextCluster(file))                                                               // Sets the clusterpointer of the file to the next datacluster.
1833
                                        { // if current cluster was the last cluster of the file
1834
                                                if(!AppendCluster(file))                                                // append a new and free cluster at the end of the file.
1835
                                                {
1836
                                                        file->SectorOfCurrCluster--;                            // jump back to last sector of last cluster
1837
                                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;      // set byte location to 1 byte over sector len
1838
                                                        return(EOF);
1839
                                                }
1840
                                        }
1841
                                        else // next cluster
1842
                                        {
1843
                                                file->SectorOfCurrCluster = 0;                                                  // start reading new cluster at first sector of the cluster.
1844
                                        }
1845
                                }
88 killagreg 1846
                        }
211 killagreg 1847
                        break;
1848
                case 'r':
1849
                default:
1850
                        return(EOF);
1851
                        break;
1852
        } // EOF switch(file->Mode)
41 ingob 1853
        return(0);
24 StephanB 1854
}
1855
 
1856
 
41 ingob 1857
/****************************************************************************************************************************************/
1858
/*      Function:               fread_(void *buffer, s32 size, s32 count, File *File);                                                                                                                          */
1859
/*                                                                                                                                                                                                                                                                              */
1860
/*      Description:    This function reads count objects of the specified size                                                                                                                         */
1861
/*                                      from the actual position of the file to the specified buffer.                                                                                                           */
1862
/*                                                                                                                                                                                                                                                                              */
1863
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1864
/****************************************************************************************************************************************/
1865
u32 fread_(void *buffer, u32 size, u32 count, File_t *file)
1866
{
1867
        u32 object_cnt  = 0;                                                                                    // count the number of objects read from the file.
1868
        u32 object_size = 0;                                                                                    // count the number of bytes read from the actual object.
1869
        u8 *pbuff       = 0;                                                                                    // a pointer to the actual bufferposition.
1870
        u8 success      = 1;                                                                                    // no error occured during read operation to the file.
88 killagreg 1871
        s16 c;
24 StephanB 1872
 
41 ingob 1873
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
24 StephanB 1874
 
41 ingob 1875
        pbuff = (u8 *) buffer;                                                                                  // cast the void pointer to an u8 *
88 killagreg 1876
 
368 holgerb 1877
        while((object_cnt < count) && success)
24 StephanB 1878
        {
41 ingob 1879
                object_size = size;
368 holgerb 1880
                while((size > 0) && success)
41 ingob 1881
                {
1882
                        c = fgetc_(file);
1883
                        if(c != EOF)
1884
                        {
1885
                                *pbuff = (u8)c;                                                                         // read a byte from the buffer to the opened file.
1886
                                pbuff++;
1887
                                size--;
1888
                        }
1889
                        else // error or end of file reached
1890
                        {
88 killagreg 1891
                                success = 0;
41 ingob 1892
                        }
1893
                }
1894
                if(success) object_cnt++;
88 killagreg 1895
        }
41 ingob 1896
        return(object_cnt);                                                                                             // return the number of objects succesfully read from the file
1 ingob 1897
}
1898
 
24 StephanB 1899
 
41 ingob 1900
/****************************************************************************************************************************************/
1901
/*      Function:               fwrite_(void *buffer, s32 size, s32 count, File *file);                                                                                                                         */
1902
/*                                                                                                                                                                                                                                                                              */
1903
/*      Description:    This function writes count objects of the specified size                                                                                                                        */
1904
/*                                      from the buffer pointer to the actual position in the file.                                                                                                                     */
1905
/*                                                                                                                                                                                                                                                                              */
1906
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1907
/****************************************************************************************************************************************/
1908
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file)
1 ingob 1909
{
41 ingob 1910
        u32 object_cnt  = 0;                                                                                                            // count the number of objects written to the file.
1911
        u32 object_size = 0;                                                                                                            // count the number of bytes written from the actual object.
1912
        u8 *pbuff           = 0;                                                                                                                // a pointer to the actual bufferposition.
1913
        u8 success      = 1;                                                                                                            // no error occured during write operation to the file.
88 killagreg 1914
        s16 c;
24 StephanB 1915
 
41 ingob 1916
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
211 killagreg 1917
        if(file->Mode == 'r') return (0); // opened read only
41 ingob 1918
        pbuff = (u8 *) buffer;                                                                                                          // cast the void pointer to an u8 *
88 killagreg 1919
 
368 holgerb 1920
        while((object_cnt < count) && success)
1 ingob 1921
        {
41 ingob 1922
                object_size = size;
368 holgerb 1923
                while((size > 0) && success)
1 ingob 1924
                {
41 ingob 1925
                        c = fputc_(*pbuff, file);                                                                               // write a byte from the buffer to the opened file.
1926
                        if(c != EOF)
24 StephanB 1927
                        {
41 ingob 1928
                                pbuff++;
1929
                                size--;
24 StephanB 1930
                        }
41 ingob 1931
                        else
24 StephanB 1932
                        {
41 ingob 1933
                                success = 0;
24 StephanB 1934
                        }
1 ingob 1935
                }
41 ingob 1936
                if(success) object_cnt++;
88 killagreg 1937
        }
1938
 
41 ingob 1939
        return(object_cnt);                                                                                                                             // return the number of objects succesfully written to the file
88 killagreg 1940
}
1 ingob 1941
 
24 StephanB 1942
 
41 ingob 1943
/****************************************************************************************************************************************/
1944
/*      Function:               fputs_(const s8 *string, File_t *File);                                                                                                                                                         */
1945
/*                                                                                                                                                                                                                                                                              */
1946
/*      Description:    This function writes a string to the specified file.                                                                                                                            */
1947
/*                                                                                                                                                                                                                                                                              */
1948
/*      Returnvalue:    The function returns a no negative value or EOF on error.                                                                                                                       */
1949
/****************************************************************************************************************************************/
89 killagreg 1950
s16 fputs_(s8 * const string, File_t * const file)
24 StephanB 1951
{
41 ingob 1952
        u8 i=0;
1953
        s16 c = 0;
88 killagreg 1954
 
211 killagreg 1955
        if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(EOF);
1956
        if(file->Mode == 'r') return(EOF);
368 holgerb 1957
        while((string[i] != 0)&& (c != EOF))
24 StephanB 1958
        {
41 ingob 1959
                c = fputc_(string[i], file);
1960
                i++;
24 StephanB 1961
        }
41 ingob 1962
        return(c);
24 StephanB 1963
}
1964
 
41 ingob 1965
/****************************************************************************************************************************************/
1966
/*      Function:               fgets_(s8 *, s16 , File_t *);                                                                                                                                                                           */
1967
/*                                                                                                                                                                                                                                                                              */
1968
/*      Description:    This function reads a string from the file to the specifies string.                                                                                             */
1969
/*                                                                                                                                                                                                                                                                              */
1970
/*      Returnvalue:    A pointer to the string read from the file or 0 on error.                                                                                                                       */
1971
/****************************************************************************************************************************************/
89 killagreg 1972
s8 * fgets_(s8 * const string, s16 const length, File_t * const file)
24 StephanB 1973
{
89 killagreg 1974
        s8 *pbuff;
1975
        s16 c = 0, bytecount;
88 killagreg 1976
 
89 killagreg 1977
        if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length < 1)) return (0);
1978
        bytecount = length;
1979
        pbuff = string;                                                         // set write pointer to start of string
368 holgerb 1980
        while(bytecount > 1)                                            // read the length-1 characters from the file to the string.
24 StephanB 1981
        {
41 ingob 1982
                c = fgetc_(file);                                               // read a character from the opened file.
1983
                switch(c)
1 ingob 1984
                {
89 killagreg 1985
                        case 0x0A:                                                      // new line
1986
                                *pbuff = 0;                                             // set string terminator
1987
                                return(string);                                 // return normal
88 killagreg 1988
 
41 ingob 1989
                        case EOF:
89 killagreg 1990
                                *pbuff = 0;                                             // set string terminator
1991
                                return(0);
1992
 
1993
                        default:
1994
                                *pbuff++ = (s8)c;                               // copy byte to string
1995
                                bytecount--;
88 killagreg 1996
                                break;
1 ingob 1997
                }
24 StephanB 1998
        }
89 killagreg 1999
        *pbuff = 0;     // set string terminator
41 ingob 2000
        return(string);
24 StephanB 2001
}
2002
 
41 ingob 2003
/****************************************************************************************************************************************/
2004
/*      Function:               fexist_(const u8*);                                                                                                                                                                                                     */
2005
/*                                                                                                                                                                                                                                                                              */
2006
/*      Description:    This function checks if a file already exist.                                                                                                                                           */
2007
/*                                                                                                                                                                                                                                                                              */
2008
/*      Returnvalue:    1 if the file exist else 0.                                                                                                                                                                                     */
2009
/****************************************************************************************************************************************/
89 killagreg 2010
u8 fexist_(s8 * const filename)
24 StephanB 2011
{
41 ingob 2012
        u8 exist = 0;
2013
        File_t *file = 0;
2014
        file = LockFilePointer();
2015
        exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
2016
        UnlockFilePointer(file);
2017
        return(exist);
1 ingob 2018
}
24 StephanB 2019
 
41 ingob 2020
/****************************************************************************************************************************************/
2021
/*      Function:               feof_(File_t *File);                                                                                                                                                                                            */
2022
/*                                                                                                                                                                                                                                                                              */
2023
/*      Description:    This function checks wether the end of the file has been reached.                                                                                                                                               */
2024
/*                                                                                                                                                                                                                                                                              */
2025
/*      Returnvalue:    0 if the end of the file was not reached otherwise 1.                                                                                                                                                                           */
2026
/****************************************************************************************************************************************/
2027
u8 feof_(File_t *file)
88 killagreg 2028
{
41 ingob 2029
        if(((file->Position)+1) < (file->Size))
24 StephanB 2030
        {
2031
                return(0);
2032
        }
88 killagreg 2033
        else
24 StephanB 2034
        {
88 killagreg 2035
                return(1);
24 StephanB 2036
        }
2037
}
41 ingob 2038
 
210 killagreg 2039
/****************************************************************************************************************************************************/
2040
/* Function:    s8* FAT16_GetVolumeLabel(void)                                                                                                                                                                                                                  */
2041
/*                                                                                                                                                                                                                                                                                                      */
2042
/* Description: This function returns the volume label                                                                                                                                                                                          */
2043
/*                                                                                                                                                                                                                                                                                                      */
2044
/* Returnvalue: This function returns the pointer to the volume label or NULL if not found.                                                                                                                     */
2045
/****************************************************************************************************************************************************/
2046
s8* FAT16_GetVolumeLabel(void)
2047
{
2048
        s8              *pVolumeLabel = NULL;
2049
        u32             dir_sector, max_dir_sector, curr_sector;
2050
        u16     dir_entry = 0;
2051
        u8              i = 0;
41 ingob 2052
 
210 killagreg 2053
        DirEntry_t * dir;
2054
        File_t *file = NULL;
2055
 
2056
        // if Partition is not valud return NULL
2057
        if(!Partition.IsValid) return(pVolumeLabel);
2058
        // if Volume label was read before return it
2059
        if(Partition.VolumeLabel[0]!= '\0') return (Partition.VolumeLabel);
2060
        // try to catch a file pointer
2061
        file = LockFilePointer();
2062
        if(file == NULL) return(pVolumeLabel);
2063
        // search dir entries direct within the root directory area
2064
        file->DirectorySector = 0;
2065
        max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2066
        file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
2067
 
2068
        // update current file data area position to start of first cluster
2069
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
2070
        file->SectorOfCurrCluster               = 0;
2071
        file->ByteOfCurrSector                  = 0;
2072
 
2073
        dir_sector = 0; // reset sector counter within a new cluster
2074
        do // loop over all sectors of the root directory
2075
        {
2076
                curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
2077
                file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
2078
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
2079
                {
2080
                        Fat16_Deinit();
379 holgerb 2081
                        return(NULL);
210 killagreg 2082
                }
2083
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
2084
                // search all directory entries within that sector
2085
                for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
2086
                {   // check for existing dir entry
2087
                        switch((u8)dir[dir_entry].Name[0])
2088
                        {
2089
                                case SLOT_EMPTY:
2090
                                case SLOT_DELETED:
2091
                                        // ignore empty or deleted dir entries
2092
                                        break;
2093
                                default:
2094
                                        // check attributes for volume label
2095
                                        if ((dir[dir_entry].Attribute & ATTR_VOLUMELABEL) != ATTR_VOLUMELABEL) break; // attribute must match
2096
                                        // (first 11 characters include 8 chars of basename and 3 chars extension.)
2097
                                        for(i = 0; i<11;i++) Partition.VolumeLabel[i] = dir[dir_entry].Name[i];
2098
                                        Partition.VolumeLabel[11] = '\0'; // terminate string
2099
                                        file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
2100
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
2101
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
219 killagreg 2102
                                        file->SectorOfCurrCluster = 0;
2103
                                        file->ByteOfCurrSector = 0;
210 killagreg 2104
                                        file->DirectorySector = curr_sector; // current sector
2105
                                        file->DirectoryIndex  = dir_entry; // current direntry in current sector
2106
                                        file->Size = dir[dir_entry].Size;
2107
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
2108
                                        pVolumeLabel =  Partition.VolumeLabel;
2109
                        } // end of first byte of name check
2110
                }
2111
                dir_sector++; // search next sector
2112
        // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 2113
        }while((dir_sector < max_dir_sector) && (!pVolumeLabel));
210 killagreg 2114
 
2115
        UnlockFilePointer(file);
2116
        return(pVolumeLabel);
2117
}
379 holgerb 2118
 
2119
 
2120
 
2121
#define ATTR_NONE               0x00    // normal file
2122
#define ATTR_READONLY           0x01    // file is readonly
2123
#define ATTR_HIDDEN                     0x02    // file is hidden
2124
#define ATTR_SYSTEM                     0x04    // file is a system file
2125
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2126
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2127
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2128
#define ATTR_ARCHIVE            0x20    // file is new or modified
2129
 
2130
 
2131
/********************************************************************************************************************************************/
2132
/*      Function:               u8 FindItem(Find_t);                                                                                                                                                                                                                    */
2133
/*                                                                                                                                                                                                                                                                                      */
2134
/*      Description:    This function looks for the item specified by global structure FindElement in the actual directory                                      */
2135
/*                                                                                                                                                                                                                                                              */
2136
/*                                                                                                                                                                                                                                                                                      */
2137
/*      Returnvalue:    TRUE if an matching element was found                                                                                                                                                                           */
2138
/********************************************************************************************************************************************/
2139
 
2140
u8 FindItem(Find_t *findelement)
2141
{
2142
        u16             index = 0;
2143
        u16             max_dir_sector = 0;
2144
        u16     end_of_directory_not_reached = 1;                                                                               // the directory has been read completely without a result.
2145
        u8              i = 0;
2146
        u8              readpointer = 0;
2147
        u8              writepointer = 0;
2148
        u8              retvalue = 0;
2149
        DirEntry_t      *DirectoryEntry;
2150
        File_t  file;
2151
 
2152
        file.FirstSectorOfCurrCluster   = findelement->fp.FirstSectorOfCurrCluster;
2153
        file.SectorOfCurrCluster        = findelement->fp.SectorOfCurrCluster;
2154
        index                                                   = findelement->fp.DirectoryIndex;
2155
 
2156
        // within the root directory area we can read sectors sequentially until the end of this area
2157
        if((Partition.FirstRootDirSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster < Partition.FirstDataSector))
2158
        {
2159
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2160
        }
2161
        // within the data clusters we can read sectors sequentially only within the cluster
2162
        else if((Partition.FirstDataSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster <= Partition.LastDataSector))
2163
        {
2164
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
2165
        }
2166
 
2167
        do
2168
        {                                                                                                                                                               // search the next 16 rootentries in this sector of the roordirectory.          
2169
                if(SD_SUCCESS != SDC_GetSector(((u32) file.FirstSectorOfCurrCluster + (u32)file.SectorOfCurrCluster), file.Cache));                                             // Read the Rootdirectory.
2170
                {
2171
                        Fat16_Deinit();
2172
                        return(0);
2173
                }
2174
 
2175
                DirectoryEntry = (DirEntry_t *)file.Cache;
2176
 
2177
                while((!retvalue)&&(index<16))
2178
                {
2179
                        i=0;                   
2180
                        if((u8) DirectoryEntry[index].Name[0] != 0xe5)                                                          // ignore deleted items.
2181
                        {
2182
                                while((i<=10)&&((DirectoryEntry[index].Name[i] == findelement->searchstring[i]) || (findelement->searchstring[i]=='*') || findelement->searchstring[i]=='?'))
2183
                                {
2184
                                        i++;
2185
                                }
2186
                        }
2187
                        if((DirectoryEntry[index].Attribute <= 0x30) && (DirectoryEntry[index].Attribute & findelement->attribmask) && (i==11))
2188
                        {
2189
                for(readpointer=0;readpointer<=10;readpointer++)
2190
                                {
2191
                                        if((DirectoryEntry[index].Name[readpointer] != ' ') && (readpointer!=8))
2192
                                        {
2193
                                                findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2194
                                                writepointer++;
2195
                                        }
2196
                                        else  
2197
                                        {
2198
                                                if(DirectoryEntry[index].Attribute == ATTR_ARCHIVE)                                            
2199
                                                {
2200
                                        if(readpointer < 8) readpointer=8;
2201
                                        if(DirectoryEntry[index].Name[readpointer] != ' ')
2202
                                        {
2203
                                        findelement->name[writepointer] = '.';                                                  // then seperate the name and the extension by a '.' at index 8.                                                
2204
                                        writepointer++;
2205
                                        findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2206
                                        writepointer++;
2207
                                        }
2208
                                            else break;
2209
                                                }
2210
                            else break;
2211
                        }
2212
                        /* terminate the namestring with 0 for debugpurposes*/
2213
                        findelement->name[12] = 0;
2214
                                }
2215
                                findelement->fp.FirstSectorOfFirstCluster = (u32) DirectoryEntry[index].StartCluster;                                                  
2216
                                findelement->fp.DirectoryIndex   = index;              
2217
                                findelement->fp.FirstSectorOfCurrCluster   = file.FirstSectorOfCurrCluster;
2218
                                findelement->fp.DirectorySector  = (file.FirstSectorOfCurrCluster + file.SectorOfCurrCluster);
2219
                                findelement->fp.SectorOfCurrCluster      = file.SectorOfCurrCluster;
2220
                findelement->fp.Size            = DirectoryEntry[index].Size;
2221
                                findelement->fp.Attribute               = DirectoryEntry[index].Attribute;
2222
                retvalue = 1;
2223
                        }                      
2224
                        /* search the next sector */
2225
                        index++;
2226
                }
2227
                /* this sector has been searched but we havn't found what we are looking for. Therefore we have to find the next sector */
2228
                if(!retvalue)                                                                                                                           // file not found in this sector so take next sector.
2229
                {
2230
                        /* in the next sector we start looking for the specified entry beginning at index 0 */
2231
                        index = 0;
2232
                        /* there are still sectors to be read within the cluster or within the linear addresspace of the rootdirectory */
2233
                        if(file.SectorOfCurrCluster < max_dir_sector-1)  file.SectorOfCurrCluster++; else end_of_directory_not_reached = 0;
2234
                        /* 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 */
2235
                        if(Partition.FirstDataSector <= file.FirstSectorOfCurrCluster)
2236
                        {
2237
                                end_of_directory_not_reached = GetNextCluster(&file);
2238
                        }
2239
                }
2240
        }
2241
        while((end_of_directory_not_reached) && (!retvalue) );
2242
 
2243
        return(retvalue);      
2244
}
2245
 
2246
 
2247
 
2248
 
2249
/********************************************************************************************************************************************/
2250
/*      Function:               findnext_(Find_t *);                                                                                                                                                                                                                    */
2251
/*                                                                                                                                                                                                                                                                                      */
2252
/*      Description:    This function looks for the next item in the specified directory with a matching filename and fileattributes specified  */
2253
/*                  by function findfirst()                                                                                                                                                                                                     */
2254
/*                                                                                                                                                                                                                                                                                      */
2255
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2256
/********************************************************************************************************************************************/
2257
u8 findnext_(Find_t * findelement)
2258
{
2259
        u8 itemfound = 0;
2260
        u8 index = 0;
2261
 
2262
        findelement->fp.DirectoryIndex++;
2263
 
2264
        /* before we start searching an element we clear the complete namestring within the structure FindElement */
2265
        for(index=0;index<11;index++) findelement->name[index] = 0;
2266
 
2267
        if(FindItem(findelement))
2268
        {
2269
                itemfound = 1;         
2270
        }
2271
 
2272
        return(itemfound);
2273
}
2274
 
2275
 
2276
 
2277
/********************************************************************************************************************************************/
2278
/*      Function:               findfirst_(s8* filename, u8 attribmask, Find_t *);                                                                                                                                              */
2279
/*                                                                                                                                                                                                                                                                                      */
2280
/*      Description:    This function looks for the first item in the specified directory with a matching filename and fileattributes                   */
2281
/*                                      The filename of the element found is transformed from 8.3 to a string                                                                                                   */
2282
/*                                                                                                                                                                                                                                                                                      */
2283
/*                                                                                                                                                                                                                                                                                      */
2284
/*      Returnvalue:    (1) if Element was found. (0) if no valid element was found                                                                                                                     */
2285
/********************************************************************************************************************************************/
2286
u8 findfirst_(const s8* name, u8 attribmask, Find_t *findelement)
2287
{
2288
        u8 itemfound = 0;
2289
        u8 index = 0;  
2290
 
2291
        /* initialize the FindElement structure */
2292
        findelement->fp.FirstSectorOfFirstCluster = 0;  // First sector of the first cluster of the file.
2293
        findelement->fp.FirstSectorOfCurrCluster = Partition.CurrentWorkingDirectory;                                   // First sector of the cluster which is edited at the moment.
2294
        findelement->fp.SectorOfCurrCluster = 0;                                                        // The sector within the current cluster.
2295
        findelement->fp.ByteOfCurrSector = 0;                                                   // The byte location within the current sector.
2296
        findelement->fp.Size = 0;                                                                               // The size of the opend file in bytes.
2297
        findelement->fp.Position = 0;                                                                   // Pointer to a character within the file 0 < fileposition < filesize
2298
        findelement->fp.DirectorySector = 0;                                                            // the sectorposition where the directoryentry has been made.
2299
        findelement->fp.DirectoryIndex = 0;                                                             // The index to the directoryentry within the specified sector.
2300
        findelement->attribfilter = 0;
2301
        findelement->attribmask = attribmask;
2302
        findelement->searchstring[0]=0;
2303
 
2304
        /* seperate the name of the element to be found from the filepath and bring it to the 8.3*/
2305
        SeperateDirName(name, findelement->searchstring);
2306
        /* after the name of the element is in 8.3 we process the wildcards (*). After an * all following character are wildcards to */
2307
        for(index=0;index<8;index++)
2308
        {
2309
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2310
                if(findelement->searchstring[index] == '*')
2311
                {
2312
                        /*  */
2313
                        while(++index <8) findelement->searchstring[index] = '*';
2314
                }
2315
        }
2316
        for(index=8;index<11;index++)
2317
        {                                                                                                                                                                                                                                        
2318
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2319
                if(findelement->searchstring[index] == '*')
2320
                {
2321
                        /*  */
2322
                        while(++index <11) findelement->searchstring[index] = '*';
2323
                }
2324
        }
2325
 
2326
        /* the value of ...DirectoryIndex will be incremented in findnext_() thererfore it has to be decremented in findfirst_() */
2327
        findelement->fp.DirectoryIndex--;
2328
        /* now lets search for the item within the direcory */
2329
        itemfound = findnext_(findelement);
2330
 
2331
        return(itemfound);
2332
}
2333
 
2334
 
2335
/********************************************************************************************************************************************/
2336
/*      Function:               u8 GetDirCount(s8* filepath);                                                                                                                                                                                   */
2337
/*                                                                                                                                                                                                                                                                                      */
2338
/*      Description:    This function counts the number of subdirectories the dirpath contains                                                                                                  */
2339
/*                                                                                                                                                                                                                                                              */
2340
/*                                                                                                                                                                                                                                                                                      */
2341
/*      Returnvalue:    then number of subdirectories within the specified path                                                                                                                                 */
2342
/********************************************************************************************************************************************/
2343
u8 GetDirCount(u8 *dirpath)
2344
{
2345
   u8 i=0;
2346
   u8 cnt=0;
2347
 
2348
   while(dirpath[i] != 0 )
2349
   {
2350
      if(dirpath[i]=='/')
2351
      {  
2352
         if(dirpath[i+1]!=0) cnt++;                                            // ignore last'/'
2353
      }
2354
      i++;  
2355
   }
2356
   i=0;  
2357
   return(cnt);
2358
}
2359
 
2360
 
2361
/********************************************************************************************************************************************/
2362
/* Funtion:     char *GetSubDirectory (char *dirpath, char *directory)                                                                                                                                          */
2363
/*                                                                                                                                                                                                                                                                                      */
2364
/* Description: this function returns a pointer to the beginning of the next subdirectory or NULL                                                                                       */
2365
/*                                                                                                                                                                                                                                                                                      */
2366
/*                                                                                                                                                                                                                                                                                      */
2367
/* returnvalue:   number of subdirectories in the filepath                                                                                                                                                                      */
2368
/********************************************************************************************************************************************/
2369
u8 * GetSubDirectory(u8 *dirpath, u8 *directory)
2370
{
2371
   u8 *cptr = dirpath;
2372
   u8 *dptr = directory;
2373
   u8 *retvalue = NULL;
2374
 
2375
   /* if the first character of the path is an '/' we go to the next character */
2376
   if(*cptr == '/') cptr++;
2377
   /* search end of path or subdirectory*/
2378
   while((*cptr != 0) && (*cptr != '/'))
2379
   {
2380
      *dptr = *cptr;
2381
       dptr++;
2382
       cptr++;
2383
   }  
2384
   if(*cptr!=0) retvalue = ++cptr;
2385
   *dptr = 0;
2386
 
2387
   return(retvalue);
2388
}
2389
 
2390
/********************************************************************************************************************************************/
2391
/*      Function:               s8 *GetPath(void);                                                                                                                                                                                                              */
2392
/*                                                                                                                                                                                                                                                                                      */
2393
/*      Description:    This function function returns a pointer to the absolute path of the active partition                                                                   */
2394
/*                                                                                                                                                                                                                                      */
2395
/*                                                                                                                                                                                                                                                                                      */
2396
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2397
/********************************************************************************************************************************************/
2398
 
2399
s8 *GetPath(void)
2400
{
2401
        return(Partition.PathToCwd);
2402
}
2403
 
2404
/********************************************************************************************************************************************/
2405
/*      Function:               void SetPathToRoot(void);                                                                                                                                                                                                       */
2406
/*                                                                                                                                                                                                                                                                                      */
2407
/*      Description:    This function sets the path to the rootdirectory                                                                                                                                                */
2408
/*                                                                                                                                                                                                                                      */
2409
/*                                                                                                                                                                                                                                                                                      */
2410
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2411
/********************************************************************************************************************************************/
2412
 
2413
void SetPathToRoot(void)
2414
{
2415
        /* lets point to the rootdirectory */
2416
        strcpy(Partition.PathToCwd, "/");      
2417
}
2418
 
2419
/********************************************************************************************************************************************/
2420
/*      Function:               void AppendDirToPath(s8* directory);                                                                                                                                                                                    */
2421
/*                                                                                                                                                                                                                                                                                      */
2422
/*      Description:    This function function appends the name of an directory to the Path to the CWD                                                                                  */
2423
/*                                                                                                                                                                                                                                      */
2424
/*                                                                                                                                                                                                                                                                                      */
2425
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2426
/********************************************************************************************************************************************/
2427
 
2428
void AppendDirToPath(s8* directory)
2429
{
2430
        /* append the name of the directory to the path */
2431
        strcat(Partition.PathToCwd, directory);
2432
        /* append a '/' after the directoryname */
2433
        strcat(Partition.PathToCwd, "/");
2434
}
2435
 
2436
/********************************************************************************************************************************************/
2437
/*      Function:               RemoveLastDirFromPath(void);                                                                                                                                                                                    */
2438
/*                                                                                                                                                                                                                                                                                      */
2439
/*      Description:    This function removes the last directory from the path to the cwd                                                                                                               */
2440
/*                                                                                                                                                                                                                                      */
2441
/*                                                                                                                                                                                                                                                                                      */
2442
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2443
/********************************************************************************************************************************************/
2444
 
2445
void RemoveLastDirFromPath(void)
2446
{
2447
        /* a pointer to the beginning of the absolute path to the cwd */
2448
        s8 * cptr = Partition.PathToCwd;
2449
        /* lets find the end of the path to the cwd */
2450
        while(*cptr != 0 ) cptr++;
2451
        /* if the path is terminated with an '/' */
2452
        if((*(cptr-1)) == '/') *(cptr-1)=0;    
2453
        /* now lets find the beginning of the last directorientry */
2454
        while((*cptr != '/' ) && cptr > Partition.PathToCwd) cptr--;
2455
        /* is there one subdirectory left within the path? */
2456
        if(cptr > Partition.PathToCwd)
2457
        {
2458
                /* we delete the direntry by terminating the path with 0 */
2459
                *cptr = 0;
2460
        }
2461
        /* there is no subdirectory left within the path. Therefore we create the root instead. */
2462
        else
2463
        {
2464
                *cptr = '/';
2465
                *(cptr+1) = 0;
2466
        }
2467
}
2468
 
2469
/********************************************************************************************************************************************/
2470
/*      Function:               chdir_(s8* filepath);                                                                                                                                                                                                   */
2471
/*                                                                                                                                                                                                                                                                                      */
2472
/*      Description:    This function changed the current working directory to the directory specified by the filepath                                                  */
2473
/*                  by function findfirst()                                                                                                                                                                                                     */
2474
/*                                                                                                                                                                                                                                                                                      */
2475
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2476
/********************************************************************************************************************************************/
2477
/*                                                                         
2478
#define ATTR_NONE               0x00    // normal file
2479
#define ATTR_READONLY           0x01    // file is readonly
2480
#define ATTR_HIDDEN                     0x02    // file is hidden
2481
#define ATTR_SYSTEM                     0x04    // file is a system file
2482
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2483
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2484
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2485
#define ATTR_ARCHIVE            0x20    // file is new or modified
2486
*/
2487
 
2488
u8 chdir_(s8 *path)
2489
{
2490
        u8              retvalue = 0;                                   // the value returned by this function
2491
        u32     ultemp = 0;                                             // temp. variable
2492
        u8     *directory = path;                               // pointer to a directoryname within the path
2493
        u8      dircount = 0;                                   // the number of subdirectoryentries within the path
2494
        u8      cache[64];                                              // a buffer containing the name of the subdirectory we are actually looking for
2495
        Find_t  fe;                                                             // The findelement needed for function findfirst to find the subdirectoryentry
2496
        s8              tp[256];                                                // temporarily we remember the actual path until the operation has finished successfully
2497
        u32     cwdt = 0;
2498
        s8     *cptr;
2499
 
2500
        /* bring the path into the correct syntax */
2501
        cptr = path;
2502
        /* search the whole string */
2503
        while(*cptr != 0 )
2504
        {
2505
                if(*cptr == '\\') *cptr = '/';
2506
                cptr++;
2507
        }
2508
        /* lets remember the actual path */
2509
        strcpy(tp, Partition.PathToCwd);
2510
        cwdt = Partition.CurrentWorkingDirectory;
2511
        /* how many subdirectories are there within the path? */
2512
        dircount = GetDirCount(path);  
2513
        /* if the path is absolute we begin at the rootdirectory */
2514
        if(path[0] == '/')
2515
        {
2516
                strcpy(Partition.PathToCwd, "/");
2517
                Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
2518
                /* if there is no other pathinformation we only switch to the rootdirectory. So theres nothing left todo.*/
2519
                if(!dircount) return(1);
2520
        }
2521
        /* now we parse through all the subdirectories within the path */
2522
        do
2523
        {  
2524
                /* until all the subdirectories within the path have been processed */
2525
        if(dircount) dircount--;
2526
                /* this is the name of the next subdirectory we are looking for */             
2527
            directory = GetSubDirectory(directory, cache);  
2528
                /* search for the next subdirectory within the path */
2529
                if(findfirst_(cache, ATTR_SUBDIRECTORY, &fe))
2530
                {
2531
                        /* we try to change into the directory "..". Now we have to delete the last direntry from the path */
2532
                        if(strcmp(cache,"..") == 0) RemoveLastDirFromPath();
2533
                        /* we try to change into the actual directory so there's nothing todo */
2534
                        else if(cache[0] == '.') return(1);
2535
                        /* otherwise we append the name of the directory we are changing in to the path */
2536
                        else AppendDirToPath(cache);
2537
                        /* The startcluster within an directoryentry specifies the position within the fat where the file or directory starts */
2538
                        ultemp = (u32) fe.fp.FirstSectorOfFirstCluster;
2539
                        /* the first 2 entries are reserved for '.' and '..' */
2540
                        ultemp -= 2;
2541
                        /* 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*/
2542
                        ultemp *= Partition.SectorsPerCluster;
2543
                        /* at least we make the sectoraddress absolute by adding the relative address to the beginning of the datasection of the active partition */
2544
                        ultemp += Partition.FirstDataSector;
2545
                        /* the cwd now points to the specified directory */
2546
                        Partition.CurrentWorkingDirectory = ultemp;
2547
                        /* we found the folder specified by the foldername */
2548
                        retvalue = 1;
2549
                }
2550
        }
2551
        /* do this until all subdirectories have been found or a subdirectory is missing */
2552
        while(dircount && retvalue );
2553
 
2554
        /* if we could not change to the specified directory we restore the actual path */
2555
        if(!retvalue)
2556
        {
2557
                Partition.CurrentWorkingDirectory = cwdt;                                                  
2558
                strcpy(Partition.PathToCwd, tp);
2559
        }
2560
        return(retvalue);      
2561
}