Subversion Repositories NaviCtrl

Rev

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

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