Subversion Repositories NaviCtrl

Rev

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