Subversion Repositories NaviCtrl

Rev

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

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