Subversion Repositories NaviCtrl

Rev

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