Subversion Repositories NaviCtrl

Rev

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