Subversion Repositories NaviCtrl

Rev

Rev 427 | Rev 433 | 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
 
431 killagreg 1094
        // incomming pointers are useless?
88 killagreg 1095
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
41 ingob 1096
 
431 killagreg 1097
        // check sector range to be searched
1098
 
1099
        // no search area defined?
1100
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
1101
        {      
1102
                return(direntry_exist);
41 ingob 1103
        }
431 killagreg 1104
        //is search area the root?
1105
        else if(Partition.FirstRootDirSector == file->FirstSectorOfFirstCluster)
41 ingob 1106
        {
431 killagreg 1107
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR; // limit to  size of root 
1108
                file->DirectorySector = SECTOR_UNDEFINED; // if we have to search within the root, there is no corresponding directory entry available
41 ingob 1109
        }
431 killagreg 1110
        // is search area within the data cluster range?
1111
        else if((Partition.FirstDataSector <= file->FirstSectorOfFirstCluster) && (file->FirstSectorOfFirstCluster <= Partition.LastDataSector))
41 ingob 1112
        {
427 killagreg 1113
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max sectors before next cluster
431 killagreg 1114
                /*
1115
                //there must be a corresponding directory entry
1116
                if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1117
                {
431 killagreg 1118
                        return (direntry_exist);       
24 StephanB 1119
                }
431 killagreg 1120
                else // check directory entry
24 StephanB 1121
                {
431 killagreg 1122
                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1123
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1124
                        {
1125
                                Fat16_Deinit();
1126
                                return (direntry_exist);
1127
                        }
1128
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1129
                        switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
1130
                        {
1131
                                case SLOT_EMPTY:
1132
                                case SLOT_DELETED:
1133
                                        // the directrory pointer of this file points to a deleted or not existen directory
1134
                                        // therefore no file or subdirectory exist here
1135
                                        return(direntry_exist);
1136
                                        break;
1137
                                default:        // and is a real directory
1138
                                        if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1139
                                        {       // current file is not a directory therefore no file or subdirectory can be searched here
1140
                                                return(direntry_exist);
1141
                                        }
1142
                                        break;
1143
                        }
1144
                        // check that search area matches directory entry
1145
                        if(file->FirstSectorOfFirstCluster != Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster))
1146
                        {
1147
                                return (direntry_exist);        
1148
                        }
1149
 
1150
                } */
24 StephanB 1151
        }
431 killagreg 1152
        else return (direntry_exist); // bad sector range for search area
1153
 
41 ingob 1154
        // update current file data area position to start of first cluster
88 killagreg 1155
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1156
        file->SectorOfCurrCluster               = 0;
41 ingob 1157
        file->ByteOfCurrSector                  = 0;
24 StephanB 1158
 
41 ingob 1159
        do // loop over all data clusters of the current directory entry
88 killagreg 1160
        {
379 holgerb 1161
                dir_sector = 0;
41 ingob 1162
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1163
                {
41 ingob 1164
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1165
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1166
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
1167
                        {
1168
                                Fat16_Deinit();
431 killagreg 1169
                                return(direntry_exist);
41 ingob 1170
                        }
1171
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1172
                        // search all directory entries within that sector
1173
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1174
                        {   // check for existing dir entry
1175
                                switch((u8)dir[dir_entry].Name[0])
1176
                                {
1177
                                        case SLOT_EMPTY:
1178
                                        case SLOT_DELETED:
1179
                                                // ignore empty or deleted dir entries
1180
                                                break;
1181
                                        default:
1182
                                                // if existing check attributes before names are compared will safe performance
1183
                                                if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
1184
                                                // then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
1185
                                                i = 0;
1186
                                                while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
1187
                                                if (i < 10) break; // names does not match
1188
                                                // if dirname and attribute have matched
1189
                                                file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
88 killagreg 1190
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
41 ingob 1191
                                                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1192
                                                file->SectorOfCurrCluster = 0;
1193
                                                file->ByteOfCurrSector = 0;
1194
                                                file->DirectorySector = curr_sector; // current sector
1195
                                                file->DirectoryIndex  = dir_entry; // current direntry in current sector
88 killagreg 1196
                                                file->Size = dir[dir_entry].Size;
1197
                                                direntry_exist = 1; // mark as found
1198
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
41 ingob 1199
                                } // end of first byte of name check
1200
                        }
1201
                        dir_sector++; // search next sector
1202
                // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 1203
                }while((dir_sector < max_dir_sector) && (!direntry_exist));
1 ingob 1204
 
41 ingob 1205
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
88 killagreg 1206
                if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
41 ingob 1207
                {
1208
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1209
                }
431 killagreg 1210
        }while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no match has been found
41 ingob 1211
        return(direntry_exist);
1 ingob 1212
}
1213
 
1214
 
41 ingob 1215
/****************************************************************************************************************************************/
1216
/*      Function:               CreateDirectoryEntry(s8 *, u16, File_t *)                                                                                                                                                       */
1217
/*                                                                                                                                                                                                                                                                              */
1218
/*      Description:    This function looks for the next free position in the directory and creates an entry.                                                           */
1219
/*                                      The type of an directory entry is specified by the file attribute.                                                                                                      */
1220
/*                                                                                                                                                                                                                                                                              */
1221
/*      Returnvalue:    Return 0 on error                                                                                                                                                                                                       */
1222
/****************************************************************************************************************************************/
1223
u8 CreateDirectoryEntry(s8 *dirname, u8 attrib, File_t *file)
1 ingob 1224
{
41 ingob 1225
        u32 dir_sector, max_dir_sector, curr_sector;
1226
        u16 dir_entry   = 0;
1227
        u16 subdircluster, dircluster = 0;
1228
        u16 end_of_directory_not_reached = 0;
1229
        u8      i                       = 0;
88 killagreg 1230
        u8      retvalue        = 0;
41 ingob 1231
        DirEntry_t *dir;
1232
 
431 killagreg 1233
        // incomming pointers are useless?
1234
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(retvalue);
88 killagreg 1235
 
431 killagreg 1236
        // check sector range to be searched
88 killagreg 1237
 
431 killagreg 1238
        // no creation area defined?
1239
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
1240
        {      
1241
                return(retvalue);
41 ingob 1242
        }
431 killagreg 1243
        //is creation area the root?
1244
        else if(Partition.FirstRootDirSector == file->FirstSectorOfFirstCluster)
41 ingob 1245
        {
431 killagreg 1246
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;  // limit to  size of root 
1247
                file->DirectorySector = SECTOR_UNDEFINED; // if we have to search within the root, there is no corresponding directory entry available
41 ingob 1248
        }
431 killagreg 1249
        // is creation area within the data cluster range?
1250
        else if((Partition.FirstDataSector <= file->FirstSectorOfFirstCluster) && (file->FirstSectorOfFirstCluster <= Partition.LastDataSector))
41 ingob 1251
        {
431 killagreg 1252
                max_dir_sector = Partition.SectorsPerCluster;                                   // limit max sectors before next cluster
1253
                // there must be a corresponding directory entry
1254
                if(file->DirectorySector == SECTOR_UNDEFINED)
41 ingob 1255
                {
431 killagreg 1256
                        return (retvalue);     
88 killagreg 1257
                }
431 killagreg 1258
                else // check directory entry
41 ingob 1259
                {
431 killagreg 1260
                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1261
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read in the sector.
1262
                        {
1263
                                Fat16_Deinit();
1264
                                return (retvalue);
1265
                        }
1266
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1267
                        switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
1268
                        {
1269
                                case SLOT_EMPTY:
1270
                                case SLOT_DELETED:
1271
                                        // the directrory pointer of this file points to a deleted or not existen directory
1272
                                        // therefore no file or subdirectory exist here
1273
                                        return(retvalue);
1274
                                        break;
1275
                                default:        // and is a real directory
1276
                                        if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1277
                                        {       // current file is not a directory therefore no file or subdirectory can be created here
1278
                                                return(retvalue);
1279
                                        }
1280
                                        break;
1281
                        }
1282
                        // check that search area matches directory entry
1283
                        if(file->FirstSectorOfFirstCluster != Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster))
1284
                        {
1285
                                return (retvalue);      
1286
                        }
41 ingob 1287
                }
1288
        }
431 killagreg 1289
        else return(retvalue); // bad sector range for search area
88 killagreg 1290
 
431 killagreg 1291
        // if the new directory entry is a subdirectory
218 killagreg 1292
        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)
427 killagreg 1293
        {       // get a free cluster for its content
218 killagreg 1294
                subdircluster = FindNextFreeCluster(file);      // get the next free cluster on the disk and mark it as used.
1295
        }
1296
        else // a normal file
1297
        {       // has no data cluster after creation
1298
                subdircluster = CLUSTER_UNDEFINED;
1299
        }
1300
 
211 killagreg 1301
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1302
        file->SectorOfCurrCluster               = 0;
1303
        do // loop over all clusters of current directory
41 ingob 1304
        {
211 killagreg 1305
                dir_sector = 0; // reset sector counter within a new cluster
1306
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1307
                {
211 killagreg 1308
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
427 killagreg 1309
                        file->SectorInCache = curr_sector;                                                      // update the sector number of file cache.
211 killagreg 1310
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1 ingob 1311
                        {
211 killagreg 1312
                                Fat16_Deinit();
431 killagreg 1313
                                return(retvalue);
211 killagreg 1314
                        }
1315
 
1316
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1317
                        // search all directory entries of a sector
1318
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1319
                        {       // check if current direntry is available
1320
                                if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
1321
                                {       // a free direntry was found
1322
                                        for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i];            // Set dir name
1323
                                        dir[dir_entry].Attribute    = attrib;
1324
                                        dir[dir_entry].Res1 = 0;
1325
                                        dir[dir_entry].CreationTime10ms = (u8)(SystemTime.mSec/10);
1326
                                        dir[dir_entry].CreationTime     = FileTime(&SystemTime);
1327
                                        dir[dir_entry].CreationDate     = FileDate(&SystemTime);
1328
                                        dir[dir_entry].LastAccessDate = dir[dir_entry].CreationDate;
1329
                                        dir[dir_entry].Res2[0] = 0;
1330
                                        dir[dir_entry].Res2[1] = 0;
1331
                                        dir[dir_entry].ModTime = dir[dir_entry].CreationTime;
1332
                                        dir[dir_entry].ModDate = dir[dir_entry].CreationDate;
1333
                                        // Set the attribute of the new directoryentry.
1334
                                        dir[dir_entry].StartCluster = subdircluster;                                            // copy the location of the first datacluster to the directoryentry.
1335
                                        dir[dir_entry].Size             = 0;                                                                    // the new createted file has no content yet.
1336
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to card
1337
                                        {
1338
                                                Fat16_Deinit();
431 killagreg 1339
                                                return(retvalue);
211 killagreg 1340
                                        }
218 killagreg 1341
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster);  // Calculate absolute sectorposition of first datacluster.
211 killagreg 1342
                                        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;      // Start reading the file with the first sector of the first datacluster.
1343
                                        file->SectorOfCurrCluster               = 0;                                                            // reset sector of cureen cluster
1344
                                        file->ByteOfCurrSector                  = 0;                                                            // reset the byte location within the current sector
1345
                                        file->Attribute                                 = attrib;                                               // set file attribute to dir attribute
1346
                                        file->Size                                              = 0;                                                        // new file has no size
1347
                                        file->DirectorySector                   = curr_sector;
1348
                                        file->DirectoryIndex                    = dir_entry;
1349
                                        // prepare subdirectory data cluster
1350
                                        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)                           // if a new directory was created then initilize the data area
1351
                                        {
1352
                                                ClearCurrCluster(file); // fill cluster with zeros
1353
                                                file->SectorInCache = file->FirstSectorOfFirstCluster;
1354
                                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1355
                                                {
211 killagreg 1356
                                                        Fat16_Deinit();
431 killagreg 1357
                                                        return(retvalue);
41 ingob 1358
                                                }
211 killagreg 1359
                                                dir = (DirEntry_t *)file->Cache;
1360
                                                // create direntry "." to current dir
1361
                                                dir[0].Name[0] = 0x2E;
1362
                                                for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
1363
                                                dir[0].Attribute = ATTR_SUBDIRECTORY;
1364
                                                dir[0].StartCluster = subdircluster;
1365
                                                dir[0].Size = 0;
1366
                                                // create direntry ".." to the upper dir
1367
                                                dir[1].Name[0] = 0x2E;
1368
                                                dir[1].Name[1] = 0x2E;
1369
                                                for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
1370
                                                dir[1].Attribute = ATTR_SUBDIRECTORY;
1371
                                                dir[1].StartCluster = dircluster;
1372
                                                dir[1].Size = 0;
1373
                                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
88 killagreg 1374
                                                {
211 killagreg 1375
                                                        Fat16_Deinit();
431 killagreg 1376
                                                        return(retvalue);
211 killagreg 1377
                                                }
1378
                                        }
1379
                                        retvalue = 1;
1380
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
88 killagreg 1381
                                }
211 killagreg 1382
                        }
1383
                        dir_sector++; // search next sector
1384
                // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 1385
                }while((dir_sector < max_dir_sector) && (!retvalue));
88 killagreg 1386
 
211 killagreg 1387
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1388
                if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
1389
                {
1390
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1391
                }
368 holgerb 1392
        }while((end_of_directory_not_reached) && (!retvalue));
211 killagreg 1393
        // Perhaps we are at the end of the last cluster of a directory file and have no free direntry found.
1394
        // Then we would need to add a cluster to that file and create the new direntry there.
1395
        // This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
1396
        // within a subdirectory of root.
1397
 
41 ingob 1398
        return(retvalue);       // return 1 if file has been created otherwise return 0.
1 ingob 1399
}
1400
 
41 ingob 1401
/********************************************************************************************************************************************/
427 killagreg 1402
/*      Function:               u8 DeleteDirectoryEntry(File_t *file)                                                                                                                                                                   */
1403
/*      Description:    This function deletes the directoryentry of the file to be deleted from the filesystem                                                                  */
1404
/*                                                                                                                                                                                                                                      */
1405
/*                                                                                                                                                                                                                                                                                      */
1406
/*      Returnvalue:    1 on succes and 0 on error                                                                                                                                                                                              */
1407
/********************************************************************************************************************************************/
1408
u8 DeleteDirectoryEntry(File_t *file)
1409
{
1410
        DirEntry_t *DirectoryEntry = NULL;
1411
        u8 retval = 0;
1412
 
1413
        if((!Partition.IsValid) || (file == NULL)) return (retval);
431 killagreg 1414
        // valid directory sector?
1415
        if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.LastDataSector))
1416
        {
1417
                // try to  read the sector containing the directory entry of the file to be deleted 
1418
                if(SD_SUCCESS != SDC_GetSector((u32) file->DirectorySector,file->Cache)) return(retval);
1419
                // get access to the elements of the directoryentry
1420
                DirectoryEntry = (DirEntry_t *)file->Cache;
1421
                // delete the directoryentry
1422
                DirectoryEntry[file->DirectoryIndex].Name[0] = SLOT_DELETED;
1423
                DirectoryEntry[file->DirectoryIndex].Attribute = 0;
1424
                DirectoryEntry[file->DirectoryIndex].Size = 0;
1425
                // the file has been deleted from the directory, save the modified sector back to the filesystem 
1426
                if(SD_SUCCESS == SDC_PutSector((u32) file->DirectorySector,file->Cache)) retval = 1;
1427
        }
427 killagreg 1428
        return(retval);
1429
}
1430
 
1431
/********************************************************************************************************************************************/
41 ingob 1432
/*      Function:               FileExist(const s8* filename, u8 attribfilter, u8 attribmask, File_t *file);                                                                                    */
1433
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 1434
/*      Description:    This function looks for the specified file including its subdirectories.                                                                                                */
1435
/*                  If the file is found the Filepointer properties are updated.                                                                                                                        */
41 ingob 1436
/*                                                                                                                                                                                                                                                                                      */
1437
/*      Returnvalue:    1 if file is found else 0.                                                                                                                                                                                              */
1438
/********************************************************************************************************************************************/
1439
u8 FileExist(const s8* filename, const u8 attribfilter, const u8 attribmask, File_t *file)
1 ingob 1440
{
41 ingob 1441
        s8* path = 0;
1442
        s8* subpath = 0;
1443
        u8 af, am, file_exist = 0;
1444
        s8 dirname[12]; // 8+3 + temination character
1 ingob 1445
 
41 ingob 1446
        // if incomming pointers are useless return immediatly
1447
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1448
 
41 ingob 1449
        // trace along the filepath
427 killagreg 1450
        path = (s8*)filename;                                                           // start at the beginning of the filename string
431 killagreg 1451
        file->DirectoryIndex = 0;                                                       // start search at first dir entry of cluster
427 killagreg 1452
        if(path[0] == '/') // if a path begins  with a '/' the search starts at RootDirectory with file search
379 holgerb 1453
        {
431 killagreg 1454
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;         // start at RootDirectory with file search      
427 killagreg 1455
        }
1456
        else // if a path begins not with a '/' the search starts relative to the CWD
1457
        {
431 killagreg 1458
                file->FirstSectorOfFirstCluster = Partition.CurrentWorkingDirectory;
427 killagreg 1459
        }
41 ingob 1460
        // as long as the file was not found and the remaining path is not empty
368 holgerb 1461
        while((*path != 0) && !file_exist)
41 ingob 1462
        {       // separate dirname and subpath from filepath string
427 killagreg 1463
                subpath = SeperateFormatedDirName(path, dirname);
41 ingob 1464
                if(subpath != NULL)
88 killagreg 1465
                {
1466
                        if(*subpath == 0)
41 ingob 1467
                        {       // empty subpath indicates last element of dir chain
1468
                                af = attribfilter;
1469
                                am = attribmask;
1470
                        }
1471
                        else  // it must be a subdirectory and no volume label
1 ingob 1472
                        {
41 ingob 1473
                                af = ATTR_SUBDIRECTORY;
1474
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1475
                        }
1476
                        if(!DirectoryEntryExist(dirname, af, am, file))
1477
                        {
431 killagreg 1478
                                return(file_exist); // subdirectory does not exist
41 ingob 1479
                        }
88 killagreg 1480
                        else
1481
                        {
41 ingob 1482
                                if (*subpath == 0)
24 StephanB 1483
                                {
41 ingob 1484
                                        file_exist = 1; // last element of path chain was found with the given attribute filter
24 StephanB 1485
                                }
1 ingob 1486
                        }
1487
                }
41 ingob 1488
                else // error seperating the subpath
1 ingob 1489
                {
431 killagreg 1490
                        return(file_exist); // bad subdir format
1 ingob 1491
                }
41 ingob 1492
                path = subpath;
1493
                subpath = 0;
1 ingob 1494
        }
431 killagreg 1495
        return(file_exist);
1 ingob 1496
}
1497
 
24 StephanB 1498
 
41 ingob 1499
/********************************************************************************************************************************************/
1500
/*      Function:               FileCreate(const s8* filename, u8 attrib, File_t *file);                                                                                                                                */
1501
/*                                                                                                                                                                                                                                                                                      */
1502
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1503
/*                                      in the rootdirectory of the partition. If the file is found the Filepointer properties are                                                              */
88 killagreg 1504
/*                                      updated. If file or its subdirectories are not found they will be created                                                                                               */
41 ingob 1505
/*                                                                                                                                                                                                                                                                                      */
1506
/*      Returnvalue:    1 if file was created else 0.                                                                                                                                                                                   */
1507
/********************************************************************************************************************************************/
1508
u8 FileCreate(const s8* filename, const u8 attrib, File_t *file)
1509
{
1510
        s8 *path = 0;
1511
        s8 *subpath = 0;
1512
        u8 af, am, file_created = 0;
1513
        s8 dirname[12];
431 killagreg 1514
        s8 txt[60];
1515
        u8 i=0;
24 StephanB 1516
 
41 ingob 1517
        // if incomming pointers are useless return immediatly
427 killagreg 1518
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return(0);
1 ingob 1519
 
41 ingob 1520
        // trace along the filepath
427 killagreg 1521
        path = (s8*)filename;
1522
 
1523
        if(path[0] == '/') // if a path begins  with a '/' the search starts at RootDirectory with file search
1524
        {
431 killagreg 1525
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;         // start at RootDirectory with file search      
427 killagreg 1526
        }
1527
        else // if a path begins not with a '/' the search starts relative to the CWD
1528
        {
431 killagreg 1529
                file->FirstSectorOfFirstCluster = Partition.CurrentWorkingDirectory;
427 killagreg 1530
        }
41 ingob 1531
        file->DirectoryIndex = 0;
427 killagreg 1532
 
41 ingob 1533
        // as long as the file was not created and the remaining file path is not empty
368 holgerb 1534
        while((*path != 0) && !file_created)
41 ingob 1535
        {   // separate dirname and subpath from filepath string
427 killagreg 1536
                subpath = SeperateFormatedDirName(path, dirname);
41 ingob 1537
                if(subpath != NULL)
24 StephanB 1538
                {
88 killagreg 1539
                        if(*subpath == 0)
41 ingob 1540
                        {       // empty subpath indicates last element of dir chain
1541
                                af = ATTR_NONE;
1542
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;  // any file that is no subdir or volume label
24 StephanB 1543
                        }
427 killagreg 1544
                        else  // it must be a subdirectory but no volume label
24 StephanB 1545
                        {
41 ingob 1546
                                af = ATTR_SUBDIRECTORY;
1547
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
24 StephanB 1548
                        }
41 ingob 1549
                        if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
1550
                        {  // try to create subdir or file
1551
                                if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
1552
                                if(!CreateDirectoryEntry(dirname, af, file))
1553
                                {       // could not be created
88 killagreg 1554
                                        return(file_created);
1555
                                }
427 killagreg 1556
                                else if(*subpath == 0) file_created = 1; // last element of path chain was created
24 StephanB 1557
                        }
431 killagreg 1558
                        sprintf(txt+i, "s:%06d",file->FirstSectorOfFirstCluster);
1559
                        i+=8;
24 StephanB 1560
                }
41 ingob 1561
                else // error seperating the subpath
24 StephanB 1562
                {
431 killagreg 1563
                        return(file_created); // bad subdir format
24 StephanB 1564
                }
41 ingob 1565
                path = subpath;
427 killagreg 1566
                subpath = NULL;
41 ingob 1567
        }
431 killagreg 1568
        Debug(txt);
1569
        return(file_created);
24 StephanB 1570
}
1 ingob 1571
 
24 StephanB 1572
 
41 ingob 1573
/********************************************************************************************************************************************/
427 killagreg 1574
/*      Function:               void Slashing_Path(s8*)                                                                                                                                                                                                 */
1575
/*                                                                                                                                                                                                                                                                                      */
1576
/*      Description:    This function replaces all \ by / in the string pointed to by the argument                                                                              */
1577
/*                                                                                                                                                                                                                                      */
1578
/*                                                                                                                                                                                                                                                                                      */
1579
/*      Returnvalue:                                                                                                                                                                                                                                                    */
1580
/********************************************************************************************************************************************/
1581
void Slashing_Path(s8* path)
1582
{
1583
        s8 *cptr = path;
1584
        while(*cptr != 0 )
1585
        {
1586
                if(*cptr == '\\') *cptr = '/'; // replace \ by /
1587
                cptr++;
1588
        }
1589
}
1590
 
1591
/********************************************************************************************************************************************/
41 ingob 1592
/*      Function:               File_t * fopen_(s8* filename, s8 mode);                                                                                                                                                                 */
1593
/*                                                                                                                                                                                                                                                                                      */
1594
/*      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 1595
/*                                      corrosponding filepointer is returned. Only modes 'r' (reading), 'w' (writing) and 'a' (append) are implemented yet.    */
41 ingob 1596
/*                                                                                                                                                                                                                                                                                      */
1597
/*      Returnvalue:    The filepointer to the file or 0 if faild.                                                                                                                                                              */
1598
/********************************************************************************************************************************************/
427 killagreg 1599
File_t * fopen_(s8* const filename, const s8 mode)
88 killagreg 1600
{
41 ingob 1601
        File_t *file    = 0;
379 holgerb 1602
        s8 *cptr;
88 killagreg 1603
 
41 ingob 1604
        if((!Partition.IsValid) || (filename == 0)) return(file);
1605
 
1606
        // Look for an unused filepointer in the file pointer list?
1607
        file = LockFilePointer();
1608
        // if no unused file pointer was found return 0
1609
        if(file == NULL) return(file);
1610
 
1611
        // now we have found a free filepointer and claimed it
1612
        file->Mode                                              = mode;         // mode of fileoperation (read,write)
1613
        file->Attribute                                 = 0;            // the attribute of the file opened.
1614
 
427 killagreg 1615
        // bring the path into the correct syntax
1616
        Slashing_Path(filename);
379 holgerb 1617
        cptr = filename;
427 killagreg 1618
 
41 ingob 1619
        // check if a real file (no directory) to the given filename exist
88 killagreg 1620
        if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
41 ingob 1621
        {  // file exist
1622
                switch(mode)  // check mode
1 ingob 1623
                {
41 ingob 1624
                        case 'a':       // if mode is: append to file
1625
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1626
                                {       // file is marked as readonly --> do not open this file
1627
                                        fclose_(file);
1628
                                        file = NULL;
1629
                                }
1630
                                else
1631
                                {       // file is not marked as read only --> goto end of file
1632
                                        fseek_(file, 0, SEEK_END);              // point to the end of the file
1633
                                }
1634
                                break;
1635
                        case 'w':       // if mode is: write to file
1636
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1637
                                {       // file is marked as readonly --> do not open this file
1638
                                        fclose_(file);
1639
                                        file = NULL;
1640
                                }
1641
                                else
211 killagreg 1642
                                {       // file is not marked as read only
1643
                                        DirEntry_t * dir;
41 ingob 1644
                                        // free all clusters of that file
1645
                                        DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
211 killagreg 1646
                                        // update directory entry of that file
1647
                                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1648
                                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1649
                                        {
1650
                                                Fat16_Deinit();
1651
                                                return(NULL);
1652
                                        }
1653
                                        dir = (DirEntry_t *)file->Cache;                                                                // set pointer to directory
1654
                                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);        // set modification time
1655
                                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);        // set modification date
1656
                                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
427 killagreg 1657
                                        dir[file->DirectoryIndex].StartCluster = CLUSTER_UNDEFINED;             // update startcluster
211 killagreg 1658
                                        dir[file->DirectoryIndex].Size          = 0;
1659
                                        // write sector containing the direntry
1660
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1661
                                        {
1662
                                                Fat16_Deinit();
1663
                                                return(NULL);
1664
                                        }
1665
                                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1666
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1667
                                        file->SectorOfCurrCluster = 0;
1668
                                        file->ByteOfCurrSector = 0;
1669
                                        file->Size = 0;
1670
                                        file->Position = 0;
1671
                                        fseek_(file, 0, SEEK_SET);
1672
                                }
1673
                                break;
1674
                        case 'r':       // if mode is: read from file
88 killagreg 1675
                                // goto end of file
41 ingob 1676
                                fseek_(file, 0, SEEK_SET);
1677
                                break;
1678
                        default: // other modes are not supported
1679
                                fclose_(file);
1680
                                file = NULL;
24 StephanB 1681
                        break;
1 ingob 1682
                }
88 killagreg 1683
                return(file);
1 ingob 1684
        }
41 ingob 1685
        else // file does not exist
1686
        {
1687
                switch(mode)  // check mode
1688
                {
1689
                        case 'a':
1690
                        case 'w': // if mode is write or append
1691
                                // try to create the file
1692
                                if(!FileCreate(filename, ATTR_ARCHIVE, file))
1693
                                { // if it could not be created
1694
                                        fclose_(file);
1695
                                        file = NULL;
427 killagreg 1696
                                }
41 ingob 1697
                                break;
1698
                        case 'r': // else opened for 'r'
218 killagreg 1699
                        default:  // if unsupported mode
41 ingob 1700
                                fclose_(file);
1701
                                file = NULL;
88 killagreg 1702
                                break;
41 ingob 1703
                }
88 killagreg 1704
                return(file);
41 ingob 1705
        }
1706
        // we should never come to this point
1707
        fclose_(file);
1708
        file = NULL;
24 StephanB 1709
        return(file);
1710
}
1711
 
41 ingob 1712
/****************************************************************************************************************************************************/
427 killagreg 1713
/* Function:    s16 fseek_(File_t *, s32 *, u8)                                                                                                                                                                                                         */
1714
/*                                                                                                                                                                                                                                                                                                      */
1715
/* Description: This function sets the pointer of the stream relative to the position                                                                                                                           */
1716
/*                              specified by origin (SEEK_SET, SEEK_CUR, SEEK_END)                                                                                                                                                                      */
1717
/* Returnvalue: Is 0 if seek was successful                                                                                                                                                                                                                     */
1718
/****************************************************************************************************************************************************/
1719
s16 fseek_(File_t *file, s32 offset, s16 origin)
1720
{
1721
        s32             fposition       = 0;
1722
        s16     retvalue        = 1;
1723
        u32             byte_index       = 0;   // the byteindex within a sector
1724
        u32             sector_index  = 0;      // the  sectorindex within a cluster
1725
        u32     cluster_index = 0;      // the index of the cluster within the clusterchain inside the fat
1726
 
1727
        // check if the partition is valid
1728
        if((!Partition.IsValid) || (file == NULL)) return(retvalue);
1729
        switch(origin)
1730
        {
1731
                case SEEK_SET:                          // Fileposition relative to the beginning of the file.
1732
                        fposition = 0;
1733
                        break;
1734
                case SEEK_END:                          // Fileposition relative to the end of the file.
1735
                        fposition = (s32)file->Size;
1736
                        break;
1737
                case SEEK_CUR:                          // Fileposition relative to the current position of the file.
1738
                default:
1739
                        fposition = file->Position;
1740
                        break;
1741
        }
1742
 
1743
        // calculate the specified fileposition according to the selected mode
1744
        fposition += offset;
1745
        // is the fileposition within the file?
1746
        if((fposition >= 0) && (fposition <= (s32)file->Size))
1747
        {
1748
                // initialize the filepointer to start of the file
1749
                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1750
                file->SectorOfCurrCluster       = 0;
1751
                file->ByteOfCurrSector          = 0;
1752
                file->Position                          = 0;
1753
                // has the specified file at least one valid sector attached?
1754
                if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(retvalue);
1755
                // calculate the absolute number of the sector wich contains the fileposition we are looking for
1756
                sector_index = (u32) ((u32)fposition >> 9);      // 512 bytes per sector
1757
                // calculate the index of the cluster containing the specified sector
1758
                cluster_index = (u32) sector_index / Partition.SectorsPerCluster;
1759
                // the absolute sectornumber becomes relative to the beginning of the specified cluster
1760
                sector_index = (sector_index % Partition.SectorsPerCluster);
1761
                // calculate the index of the byteposition the fileposition points to
1762
                byte_index = (u32) fposition % 512;
1763
                // parse the fat till the calculated cluster has been reached
1764
                while(cluster_index--) GetNextCluster(file);
1765
                // set the filepointer to the specified sector and byteposition
1766
                file->SectorOfCurrCluster = (u8) sector_index;
1767
                file->ByteOfCurrSector = (u16) byte_index;
1768
                // the fileposition now equals the filepointer
1769
                file->Position = (u32)fposition;
1770
                // the specified fileposition has been reached
1771
                retvalue = 0;
1772
        }
1773
        return(retvalue);
1774
}
1775
 
1776
/****************************************************************************************************************************************************/
41 ingob 1777
/* Function:    fflush_(File *);                                                                                                                                                                                                                                        */
1778
/*                                                                                                                                                                                                                                                                                                      */
1779
/* Description: This function writes the data already in the buffer but not yet written to the file.                                                                                            */
1780
/*                                                                                                                                                                                                                                                                                                      */
1781
/* Returnvalue: 0 on success EOF on error                                                                                                                                                                                                                       */
1782
/****************************************************************************************************************************************************/
1783
s16     fflush_(File_t *file)
24 StephanB 1784
{
88 killagreg 1785
        DirEntry_t *dir;
1786
 
41 ingob 1787
        if((file == NULL) || (!Partition.IsValid)) return (EOF);
88 killagreg 1788
 
41 ingob 1789
        switch(file->Mode)
24 StephanB 1790
        {
41 ingob 1791
                case 'a':
1792
                case 'w':
88 killagreg 1793
                        if(file->ByteOfCurrSector > 0)                                                                          // has data been added to the file?
41 ingob 1794
                        {
88 killagreg 1795
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
41 ingob 1796
                                {
88 killagreg 1797
                                        Fat16_Deinit();
1798
                                        return(EOF);
1799
                                }
41 ingob 1800
                        }
1801
                        file->SectorInCache     = file->DirectorySector;
1802
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))                                       // read the directory entry for this file.
1803
                        {
1804
                                Fat16_Deinit();
88 killagreg 1805
                                return(EOF);
41 ingob 1806
                        }
88 killagreg 1807
 
41 ingob 1808
                        dir = (DirEntry_t *)file->Cache;
324 killagreg 1809
                        // update file size and modification time & date
211 killagreg 1810
                        dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);
1811
                        dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);
1812
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
41 ingob 1813
                        dir[file->DirectoryIndex].Size = file->Size;                                            // update file size
1814
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to sd-card
1815
                        {
1816
                                Fat16_Deinit();
1817
                                return(EOF);
1818
                        }
1819
                        break;
1820
                case 'r':
1821
                default:
211 killagreg 1822
                        // do nothing!
41 ingob 1823
                        return(EOF);
1824
                        break;
1825
 
24 StephanB 1826
        }
41 ingob 1827
        return(0);
24 StephanB 1828
}
1 ingob 1829
 
41 ingob 1830
/********************************************************************************************************************************************/
1831
/*      Function:               fgetc_(File *file);                                                                                                                                                                                                             */
1832
/*                                                                                                                                                                                                                                                                                      */
1833
/*      Description:    This function reads and returns one character from the specified file. Is the end of the actual sector reached the              */
1834
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1835
/*                                                                                                                                                                                                                                                                                      */
1836
/*      Returnvalue:    The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.                                   */
1837
/********************************************************************************************************************************************/
1838
s16 fgetc_(File_t *file)
88 killagreg 1839
{
41 ingob 1840
        s16 c = EOF;
1841
        u32 curr_sector;
88 killagreg 1842
 
41 ingob 1843
        if( (!Partition.IsValid) || (file == NULL)) return(c);
1844
        // if the end of the file is not reached, get the next character.
379 holgerb 1845
        if((0 < file->Size) && ((file->Position) < file->Size) )
1 ingob 1846
        {
41 ingob 1847
                curr_sector  = file->FirstSectorOfCurrCluster;          // calculate the sector of the next character to be read.
88 killagreg 1848
                curr_sector += file->SectorOfCurrCluster;
1849
 
41 ingob 1850
                if(file->SectorInCache != curr_sector)
1 ingob 1851
                {
41 ingob 1852
                        file->SectorInCache = curr_sector;
1853
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
1854
                        {
1855
                                Fat16_Deinit();
379 holgerb 1856
                                return(EOF);
88 killagreg 1857
                        }
1858
                }
41 ingob 1859
                c = (s16) file->Cache[file->ByteOfCurrSector];
1860
                file->Position++;                                                                       // increment file position
88 killagreg 1861
                file->ByteOfCurrSector++;                                                       // goto next byte in sector
41 ingob 1862
                if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if end of sector
24 StephanB 1863
                {
41 ingob 1864
                        file->ByteOfCurrSector = 0;                                             //  reset byte location
1865
                        file->SectorOfCurrCluster++;                                    //      next sector
1866
                        if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
24 StephanB 1867
                        {
88 killagreg 1868
 
41 ingob 1869
                                if(GetNextCluster(file))                                                                                // Sets the clusterpointer of the file to the next datacluster.
24 StephanB 1870
                                {
41 ingob 1871
                                        file->SectorOfCurrCluster = 0;                                                          // start reading new cluster at first sector of the cluster.
1872
                                }
1873
                                else // the last cluster was allready reached
1874
                                {
1875
                                        file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
1876
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
1877
                                }
1 ingob 1878
                        }
24 StephanB 1879
                }
1880
        }
41 ingob 1881
        return(c);
24 StephanB 1882
}
1883
 
41 ingob 1884
/********************************************************************************************************************************************/
1885
/*      Function:               fputc_( const s8 c, File *file);                                                                                                                                                                                */
1886
/*                                                                                                                                                                                                                                                                                      */
1887
/*      Description:    This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.                                 */
1888
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1889
/*                                                                                                                                                                                                                                                                                      */
1890
/*      Returnvalue:    The function returns the character written to the stream or EOF on error.                                                                                               */
1891
/********************************************************************************************************************************************/
1892
s16 fputc_(const s8 c, File_t *file)
88 killagreg 1893
{
41 ingob 1894
        u32 curr_sector  = 0;
88 killagreg 1895
 
41 ingob 1896
        if((!Partition.IsValid) || (file == NULL)) return(EOF);
211 killagreg 1897
        switch(file->Mode)
41 ingob 1898
        {
211 killagreg 1899
                case 'w':
1900
                case 'a':
1901
                        // If file position equals to file size, then the end of file has been reached.
1902
                        // In this case it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
1903
                        // and a new cluster should be appended.
427 killagreg 1904
                        // If the first sector of first cluster is unvalid, then the file claims no data clusters
211 killagreg 1905
                        // and size should be zero, therefore append a new Cluster too.
1906
                        if(((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) || (file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED))
1907
                        {
1908
                                if(CLUSTER_UNDEFINED == AppendCluster(file)) return(EOF);
1909
                        }
427 killagreg 1910
 
211 killagreg 1911
                        curr_sector  = file->FirstSectorOfCurrCluster;
1912
                        curr_sector += file->SectorOfCurrCluster;
1913
                        if(file->SectorInCache != curr_sector)
1914
                        {
1915
                                file->SectorInCache = curr_sector;
1916
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
24 StephanB 1917
                                {
211 killagreg 1918
                                        Fat16_Deinit();
1919
                                        return(EOF);
24 StephanB 1920
                                }
1 ingob 1921
                        }
427 killagreg 1922
 
379 holgerb 1923
                        file->Cache[file->ByteOfCurrSector] = (u8)c;            // write databyte into the buffer. The byte will be written to the device at once
211 killagreg 1924
                        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.
1925
                        file->Position++;                                                                       // the actual positon within the file.
1926
                        file->ByteOfCurrSector++;                                                       // goto next byte in sector
1927
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if the end of this sector is reached yet
1928
                        {       // save the sector to the sd-card
427 killagreg 1929
 
211 killagreg 1930
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1931
                                {
1932
                                        Fat16_Deinit();
1933
                                        return(EOF);
1934
                                }
1935
                                file->ByteOfCurrSector = 0;                                             //  reset byte location
1936
                                file->SectorOfCurrCluster++;                                    //      next sector
1937
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
1938
                                {
1939
                                        if(!GetNextCluster(file))                                                               // Sets the clusterpointer of the file to the next datacluster.
1940
                                        { // if current cluster was the last cluster of the file
1941
                                                if(!AppendCluster(file))                                                // append a new and free cluster at the end of the file.
1942
                                                {
1943
                                                        file->SectorOfCurrCluster--;                            // jump back to last sector of last cluster
1944
                                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;      // set byte location to 1 byte over sector len
1945
                                                        return(EOF);
1946
                                                }
1947
                                        }
1948
                                        else // next cluster
1949
                                        {
1950
                                                file->SectorOfCurrCluster = 0;                                                  // start reading new cluster at first sector of the cluster.
1951
                                        }
1952
                                }
88 killagreg 1953
                        }
211 killagreg 1954
                        break;
1955
                case 'r':
1956
                default:
1957
                        return(EOF);
1958
                        break;
1959
        } // EOF switch(file->Mode)
41 ingob 1960
        return(0);
24 StephanB 1961
}
1962
 
1963
 
41 ingob 1964
/****************************************************************************************************************************************/
1965
/*      Function:               fread_(void *buffer, s32 size, s32 count, File *File);                                                                                                                          */
1966
/*                                                                                                                                                                                                                                                                              */
1967
/*      Description:    This function reads count objects of the specified size                                                                                                                         */
1968
/*                                      from the actual position of the file to the specified buffer.                                                                                                           */
1969
/*                                                                                                                                                                                                                                                                              */
1970
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1971
/****************************************************************************************************************************************/
1972
u32 fread_(void *buffer, u32 size, u32 count, File_t *file)
1973
{
1974
        u32 object_cnt  = 0;                                                                                    // count the number of objects read from the file.
1975
        u32 object_size = 0;                                                                                    // count the number of bytes read from the actual object.
1976
        u8 *pbuff       = 0;                                                                                    // a pointer to the actual bufferposition.
1977
        u8 success      = 1;                                                                                    // no error occured during read operation to the file.
88 killagreg 1978
        s16 c;
24 StephanB 1979
 
41 ingob 1980
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
24 StephanB 1981
 
41 ingob 1982
        pbuff = (u8 *) buffer;                                                                                  // cast the void pointer to an u8 *
88 killagreg 1983
 
368 holgerb 1984
        while((object_cnt < count) && success)
24 StephanB 1985
        {
41 ingob 1986
                object_size = size;
368 holgerb 1987
                while((size > 0) && success)
41 ingob 1988
                {
1989
                        c = fgetc_(file);
1990
                        if(c != EOF)
1991
                        {
1992
                                *pbuff = (u8)c;                                                                         // read a byte from the buffer to the opened file.
1993
                                pbuff++;
1994
                                size--;
1995
                        }
1996
                        else // error or end of file reached
1997
                        {
88 killagreg 1998
                                success = 0;
41 ingob 1999
                        }
2000
                }
2001
                if(success) object_cnt++;
88 killagreg 2002
        }
41 ingob 2003
        return(object_cnt);                                                                                             // return the number of objects succesfully read from the file
1 ingob 2004
}
2005
 
24 StephanB 2006
 
41 ingob 2007
/****************************************************************************************************************************************/
2008
/*      Function:               fwrite_(void *buffer, s32 size, s32 count, File *file);                                                                                                                         */
2009
/*                                                                                                                                                                                                                                                                              */
2010
/*      Description:    This function writes count objects of the specified size                                                                                                                        */
2011
/*                                      from the buffer pointer to the actual position in the file.                                                                                                                     */
2012
/*                                                                                                                                                                                                                                                                              */
2013
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
2014
/****************************************************************************************************************************************/
2015
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file)
1 ingob 2016
{
41 ingob 2017
        u32 object_cnt  = 0;                                                                                                            // count the number of objects written to the file.
2018
        u32 object_size = 0;                                                                                                            // count the number of bytes written from the actual object.
2019
        u8 *pbuff           = 0;                                                                                                                // a pointer to the actual bufferposition.
2020
        u8 success      = 1;                                                                                                            // no error occured during write operation to the file.
88 killagreg 2021
        s16 c;
24 StephanB 2022
 
41 ingob 2023
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
211 killagreg 2024
        if(file->Mode == 'r') return (0); // opened read only
41 ingob 2025
        pbuff = (u8 *) buffer;                                                                                                          // cast the void pointer to an u8 *
88 killagreg 2026
 
368 holgerb 2027
        while((object_cnt < count) && success)
1 ingob 2028
        {
41 ingob 2029
                object_size = size;
368 holgerb 2030
                while((size > 0) && success)
1 ingob 2031
                {
427 killagreg 2032
                        c = fputc_(*pbuff, file);                                                                                       // write a byte from the buffer to the opened file.
41 ingob 2033
                        if(c != EOF)
24 StephanB 2034
                        {
41 ingob 2035
                                pbuff++;
2036
                                size--;
24 StephanB 2037
                        }
41 ingob 2038
                        else
24 StephanB 2039
                        {
41 ingob 2040
                                success = 0;
24 StephanB 2041
                        }
1 ingob 2042
                }
41 ingob 2043
                if(success) object_cnt++;
88 killagreg 2044
        }
2045
 
427 killagreg 2046
        return(object_cnt);             // return the number of objects succesfully written to the file
88 killagreg 2047
}
1 ingob 2048
 
24 StephanB 2049
 
41 ingob 2050
/****************************************************************************************************************************************/
2051
/*      Function:               fputs_(const s8 *string, File_t *File);                                                                                                                                                         */
2052
/*                                                                                                                                                                                                                                                                              */
2053
/*      Description:    This function writes a string to the specified file.                                                                                                                            */
2054
/*                                                                                                                                                                                                                                                                              */
2055
/*      Returnvalue:    The function returns a no negative value or EOF on error.                                                                                                                       */
2056
/****************************************************************************************************************************************/
89 killagreg 2057
s16 fputs_(s8 * const string, File_t * const file)
24 StephanB 2058
{
41 ingob 2059
        u8 i=0;
2060
        s16 c = 0;
88 killagreg 2061
 
211 killagreg 2062
        if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(EOF);
2063
        if(file->Mode == 'r') return(EOF);
368 holgerb 2064
        while((string[i] != 0)&& (c != EOF))
24 StephanB 2065
        {
41 ingob 2066
                c = fputc_(string[i], file);
2067
                i++;
24 StephanB 2068
        }
41 ingob 2069
        return(c);
24 StephanB 2070
}
2071
 
41 ingob 2072
/****************************************************************************************************************************************/
2073
/*      Function:               fgets_(s8 *, s16 , File_t *);                                                                                                                                                                           */
2074
/*                                                                                                                                                                                                                                                                              */
2075
/*      Description:    This function reads a string from the file to the specifies string.                                                                                             */
2076
/*                                                                                                                                                                                                                                                                              */
2077
/*      Returnvalue:    A pointer to the string read from the file or 0 on error.                                                                                                                       */
2078
/****************************************************************************************************************************************/
89 killagreg 2079
s8 * fgets_(s8 * const string, s16 const length, File_t * const file)
24 StephanB 2080
{
89 killagreg 2081
        s8 *pbuff;
2082
        s16 c = 0, bytecount;
88 killagreg 2083
 
89 killagreg 2084
        if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length < 1)) return (0);
2085
        bytecount = length;
2086
        pbuff = string;                                                         // set write pointer to start of string
368 holgerb 2087
        while(bytecount > 1)                                            // read the length-1 characters from the file to the string.
24 StephanB 2088
        {
41 ingob 2089
                c = fgetc_(file);                                               // read a character from the opened file.
2090
                switch(c)
1 ingob 2091
                {
89 killagreg 2092
                        case 0x0A:                                                      // new line
2093
                                *pbuff = 0;                                             // set string terminator
2094
                                return(string);                                 // return normal
88 killagreg 2095
 
41 ingob 2096
                        case EOF:
89 killagreg 2097
                                *pbuff = 0;                                             // set string terminator
2098
                                return(0);
2099
 
2100
                        default:
2101
                                *pbuff++ = (s8)c;                               // copy byte to string
2102
                                bytecount--;
88 killagreg 2103
                                break;
1 ingob 2104
                }
24 StephanB 2105
        }
89 killagreg 2106
        *pbuff = 0;     // set string terminator
41 ingob 2107
        return(string);
24 StephanB 2108
}
2109
 
41 ingob 2110
/****************************************************************************************************************************************/
427 killagreg 2111
/*      Function:               fclose_(File *file);                                                                                                                                                                                            */
2112
/*                                                                                                                                                                                                                                                                              */
2113
/*      Description:    This function closes the open file by writing the remaining data                                                                                                        */
2114
/*                                      from the buffer to the device and entering the filesize in the directory entry.                                                                         */
2115
/*                                                                                                                                                                                                                                                                              */
2116
/*      Returnvalue:    0 on success EOF on error                                                                                                                                                                                       */
2117
/****************************************************************************************************************************************/
2118
s16 fclose_(File_t *file)
2119
{
2120
        s16 returnvalue = EOF;
2121
 
2122
        if(file == NULL) return(returnvalue);
2123
        returnvalue = fflush_(file);
2124
        UnlockFilePointer(file);
2125
        return(returnvalue);
2126
}
2127
 
2128
 
2129
/****************************************************************************************************************************************/
41 ingob 2130
/*      Function:               fexist_(const u8*);                                                                                                                                                                                                     */
2131
/*                                                                                                                                                                                                                                                                              */
2132
/*      Description:    This function checks if a file already exist.                                                                                                                                           */
2133
/*                                                                                                                                                                                                                                                                              */
2134
/*      Returnvalue:    1 if the file exist else 0.                                                                                                                                                                                     */
2135
/****************************************************************************************************************************************/
89 killagreg 2136
u8 fexist_(s8 * const filename)
24 StephanB 2137
{
41 ingob 2138
        u8 exist = 0;
2139
        File_t *file = 0;
2140
        file = LockFilePointer();
2141
        exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
2142
        UnlockFilePointer(file);
2143
        return(exist);
1 ingob 2144
}
24 StephanB 2145
 
41 ingob 2146
/****************************************************************************************************************************************/
2147
/*      Function:               feof_(File_t *File);                                                                                                                                                                                            */
2148
/*                                                                                                                                                                                                                                                                              */
2149
/*      Description:    This function checks wether the end of the file has been reached.                                                                                                                                               */
2150
/*                                                                                                                                                                                                                                                                              */
2151
/*      Returnvalue:    0 if the end of the file was not reached otherwise 1.                                                                                                                                                                           */
2152
/****************************************************************************************************************************************/
2153
u8 feof_(File_t *file)
88 killagreg 2154
{
41 ingob 2155
        if(((file->Position)+1) < (file->Size))
24 StephanB 2156
        {
2157
                return(0);
2158
        }
88 killagreg 2159
        else
24 StephanB 2160
        {
88 killagreg 2161
                return(1);
24 StephanB 2162
        }
2163
}
41 ingob 2164
 
427 killagreg 2165
 
2166
/********************************************************************************************************************************************/
2167
/*      Function:               fdelete_(s8* filepath);                                                                                                                                                                                                 */
2168
/*                                                                                                                                                                                                                                                                                      */
2169
/*      Description:    This function deletes the file with the specified filename from the filesystem                                                                                  */
2170
/*                                                                                                                                                                                                                                      */
2171
/*                                                                                                                                                                                                                                                                                      */
2172
/*      Returnvalue:    1 : specified file deleted succesfully 0: specified file not found                                                                                                              */
2173
/********************************************************************************************************************************************/
2174
 
2175
u8 fdelete_(s8* const filepath)
2176
{
2177
        u8 retvalue = 0;
2178
        File_t file;
2179
 
2180
        if(filepath == NULL) return(0);
2181
        // correct filepath formatting
2182
        Slashing_Path(filepath);
431 killagreg 2183
        file.FirstSectorOfFirstCluster = SECTOR_UNDEFINED;              // First sector of the first cluster of the file.
2184
        file.FirstSectorOfCurrCluster = SECTOR_UNDEFINED;               // First sector of the cluster which is edited at the moment.
2185
        file.FirstSectorOfLastCluster = SECTOR_UNDEFINED;               // First sector of the last cluster of the file
2186
        file.SectorOfCurrCluster = SECTOR_UNDEFINED;                    // The sector within the current cluster.
2187
        file.ByteOfCurrSector = 0;                                                              // The byte location within the current sector.
2188
        file.Mode = 0;                                                                                  // Mode of fileoperation (read,write)
2189
        file.Size = 0;                                                                                  // The size of the opend file in bytes.
2190
        file.Position = 0;                                                                              // Pointer to a character within the file 0 < fileposition < filesize
2191
        file.DirectorySector = SECTOR_UNDEFINED;                                // the sectorposition where the directoryentry has been made.
2192
        file.DirectoryIndex = 0;                                                                // The index to the directoryentry within the specified sector.
2193
        file.Attribute = 0;                                                                             // The attribute of the file opened.
2194
        file.SectorInCache = SECTOR_UNDEFINED;                                  // The last sector read, which is still in the sector cache.
2195
        file.State = FSTATE_USED;                                                               // mark it as used
2196
 
427 killagreg 2197
        // if file is existent
2198
        if(FileExist(filepath, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, &file))
2199
        {
2200
                // and is not marked as readonly?
2201
                if((file.Attribute & ATTR_READONLY) != ATTR_READONLY)
2202
                {
2203
                        // try to delete the file content from the filesystem
2204
                        if(DeleteClusterChain(file.FirstSectorOfFirstCluster))
2205
                        {
2206
                                // and try delete the directory entry of the file
2207
                                retvalue = DeleteDirectoryEntry(&file);
2208
                        }      
2209
                }
2210
        }
2211
        return(retvalue);
2212
}
2213
 
210 killagreg 2214
/****************************************************************************************************************************************************/
2215
/* Function:    s8* FAT16_GetVolumeLabel(void)                                                                                                                                                                                                                  */
2216
/*                                                                                                                                                                                                                                                                                                      */
2217
/* Description: This function returns the volume label                                                                                                                                                                                          */
2218
/*                                                                                                                                                                                                                                                                                                      */
2219
/* Returnvalue: This function returns the pointer to the volume label or NULL if not found.                                                                                                                     */
2220
/****************************************************************************************************************************************************/
2221
s8* FAT16_GetVolumeLabel(void)
2222
{
2223
        s8              *pVolumeLabel = NULL;
2224
        u32             dir_sector, max_dir_sector, curr_sector;
2225
        u16     dir_entry = 0;
2226
        u8              i = 0;
41 ingob 2227
 
210 killagreg 2228
        DirEntry_t * dir;
2229
        File_t *file = NULL;
427 killagreg 2230
 
2231
        // if Partition is not valid return NULL
210 killagreg 2232
        if(!Partition.IsValid) return(pVolumeLabel);
2233
        // if Volume label was read before return it
2234
        if(Partition.VolumeLabel[0]!= '\0') return (Partition.VolumeLabel);
2235
        // try to catch a file pointer
2236
        file = LockFilePointer();
2237
        if(file == NULL) return(pVolumeLabel);
2238
        // search dir entries direct within the root directory area
2239
        file->DirectorySector = 0;
2240
        max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2241
        file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
427 killagreg 2242
 
210 killagreg 2243
        // update current file data area position to start of first cluster
2244
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
2245
        file->SectorOfCurrCluster               = 0;
2246
        file->ByteOfCurrSector                  = 0;
2247
 
2248
        dir_sector = 0; // reset sector counter within a new cluster
2249
        do // loop over all sectors of the root directory
2250
        {
2251
                curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
2252
                file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
2253
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
2254
                {
2255
                        Fat16_Deinit();
379 holgerb 2256
                        return(NULL);
210 killagreg 2257
                }
2258
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
2259
                // search all directory entries within that sector
2260
                for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
2261
                {   // check for existing dir entry
2262
                        switch((u8)dir[dir_entry].Name[0])
2263
                        {
2264
                                case SLOT_EMPTY:
2265
                                case SLOT_DELETED:
2266
                                        // ignore empty or deleted dir entries
2267
                                        break;
2268
                                default:
2269
                                        // check attributes for volume label
2270
                                        if ((dir[dir_entry].Attribute & ATTR_VOLUMELABEL) != ATTR_VOLUMELABEL) break; // attribute must match
2271
                                        // (first 11 characters include 8 chars of basename and 3 chars extension.)
2272
                                        for(i = 0; i<11;i++) Partition.VolumeLabel[i] = dir[dir_entry].Name[i];
2273
                                        Partition.VolumeLabel[11] = '\0'; // terminate string
2274
                                        file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
2275
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
2276
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
219 killagreg 2277
                                        file->SectorOfCurrCluster = 0;
2278
                                        file->ByteOfCurrSector = 0;
210 killagreg 2279
                                        file->DirectorySector = curr_sector; // current sector
2280
                                        file->DirectoryIndex  = dir_entry; // current direntry in current sector
2281
                                        file->Size = dir[dir_entry].Size;
2282
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
2283
                                        pVolumeLabel =  Partition.VolumeLabel;
2284
                        } // end of first byte of name check
2285
                }
2286
                dir_sector++; // search next sector
2287
        // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 2288
        }while((dir_sector < max_dir_sector) && (!pVolumeLabel));
210 killagreg 2289
 
2290
        UnlockFilePointer(file);
2291
        return(pVolumeLabel);
2292
}
379 holgerb 2293
 
2294
 
2295
/********************************************************************************************************************************************/
427 killagreg 2296
/*      Function:               u8 FindItem(Find_t);                                                                                                                                                                                                    */
379 holgerb 2297
/*                                                                                                                                                                                                                                                                                      */
2298
/*      Description:    This function looks for the item specified by global structure FindElement in the actual directory                                      */
2299
/*                                                                                                                                                                                                                                                              */
2300
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2301
/*      Returnvalue:    TRUE if an matching element was found                                                                                                                                                                   */
379 holgerb 2302
/********************************************************************************************************************************************/
2303
 
2304
u8 FindItem(Find_t *findelement)
2305
{
2306
        u16             index = 0;
2307
        u16             max_dir_sector = 0;
2308
        u16     end_of_directory_not_reached = 1;                                                                               // the directory has been read completely without a result.
2309
        u8              i = 0;
2310
        u8              readpointer = 0;
2311
        u8              writepointer = 0;
2312
        u8              retvalue = 0;
2313
        DirEntry_t      *DirectoryEntry;
2314
        File_t  file;
427 killagreg 2315
        SD_Result_t res=0;
379 holgerb 2316
 
2317
        file.FirstSectorOfCurrCluster   = findelement->fp.FirstSectorOfCurrCluster;
2318
        file.SectorOfCurrCluster        = findelement->fp.SectorOfCurrCluster;
2319
        index                                                   = findelement->fp.DirectoryIndex;
2320
 
2321
        // within the root directory area we can read sectors sequentially until the end of this area
2322
        if((Partition.FirstRootDirSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster < Partition.FirstDataSector))
2323
        {
2324
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2325
        }
2326
        // within the data clusters we can read sectors sequentially only within the cluster
2327
        else if((Partition.FirstDataSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster <= Partition.LastDataSector))
2328
        {
2329
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
2330
        }
2331
 
2332
        do
427 killagreg 2333
        {       // search the next 16 rootentries in this sector of the roordirectory.
2334
                res = SDC_GetSector(((u32) file.FirstSectorOfCurrCluster + (u32)file.SectorOfCurrCluster), file.Cache);                                         // Read the Rootdirectory.
2335
                if(res != SD_SUCCESS)
379 holgerb 2336
                {
2337
                        Fat16_Deinit();
2338
                        return(0);
2339
                }
427 killagreg 2340
 
379 holgerb 2341
                DirectoryEntry = (DirEntry_t *)file.Cache;
2342
 
427 killagreg 2343
                while((!retvalue)&&(index < 16))
379 holgerb 2344
                {
427 killagreg 2345
                        i = 0;
2346
                        if( (u8)DirectoryEntry[index].Name[0] != SLOT_DELETED)          // ignore deleted items.
379 holgerb 2347
                        {
427 killagreg 2348
                                while((i <= 10) && ( (DirectoryEntry[index].Name[i] == findelement->searchstring[i]) || (findelement->searchstring[i] == '*') || findelement->searchstring[i] == '?'))
379 holgerb 2349
                                {
2350
                                        i++;
2351
                                }
2352
                        }
427 killagreg 2353
                        if((DirectoryEntry[index].Attribute & 0x30) && (DirectoryEntry[index].Attribute & findelement->attribmask) && (i == 11))
379 holgerb 2354
                        {
427 killagreg 2355
                /* initialize the namestring with 0 */
2356
                        for(i = 0; i < 12; i++) findelement->name[i] = 0;
2357
                for(readpointer = 0; readpointer <= 10; readpointer++)
379 holgerb 2358
                                {
2359
                                        if((DirectoryEntry[index].Name[readpointer] != ' ') && (readpointer!=8))
2360
                                        {
2361
                                                findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2362
                                                writepointer++;
2363
                                        }
427 killagreg 2364
                                        else
379 holgerb 2365
                                        {
427 killagreg 2366
                                                if(DirectoryEntry[index].Attribute == ATTR_ARCHIVE)
379 holgerb 2367
                                                {
427 killagreg 2368
                                        if(readpointer < 8) readpointer = 8;
379 holgerb 2369
                                        if(DirectoryEntry[index].Name[readpointer] != ' ')
2370
                                        {
427 killagreg 2371
                                        findelement->name[writepointer] = '.';                                                  // then seperate the name and the extension by a '.' at index 8.
379 holgerb 2372
                                        writepointer++;
2373
                                        findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2374
                                        writepointer++;
2375
                                        }
2376
                                            else break;
2377
                                                }
2378
                            else break;
2379
                        }
2380
                                }
427 killagreg 2381
                                findelement->fp.FirstSectorOfFirstCluster = (u32) DirectoryEntry[index].StartCluster;
2382
                                findelement->fp.DirectoryIndex   = index;
379 holgerb 2383
                                findelement->fp.FirstSectorOfCurrCluster   = file.FirstSectorOfCurrCluster;
2384
                                findelement->fp.DirectorySector  = (file.FirstSectorOfCurrCluster + file.SectorOfCurrCluster);
2385
                                findelement->fp.SectorOfCurrCluster      = file.SectorOfCurrCluster;
2386
                findelement->fp.Size            = DirectoryEntry[index].Size;
2387
                                findelement->fp.Attribute               = DirectoryEntry[index].Attribute;
2388
                retvalue = 1;
427 killagreg 2389
                        }
379 holgerb 2390
                        /* search the next sector */
2391
                        index++;
2392
                }
2393
                /* this sector has been searched but we havn't found what we are looking for. Therefore we have to find the next sector */
2394
                if(!retvalue)                                                                                                                           // file not found in this sector so take next sector.
2395
                {
2396
                        /* in the next sector we start looking for the specified entry beginning at index 0 */
2397
                        index = 0;
2398
                        /* there are still sectors to be read within the cluster or within the linear addresspace of the rootdirectory */
427 killagreg 2399
                        if(file.SectorOfCurrCluster < max_dir_sector-1)  file.SectorOfCurrCluster++;
379 holgerb 2400
                        /* 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 2401
                        else if(Partition.FirstDataSector <= file.FirstSectorOfCurrCluster)
379 holgerb 2402
                        {
427 killagreg 2403
                                end_of_directory_not_reached = GetNextCluster(&file);
379 holgerb 2404
                        }
427 killagreg 2405
                        // within the rootdirectory we abort searching for elements after the maximun number of possible rootentries has beensearched
2406
                        else
2407
                        {
2408
                                end_of_directory_not_reached = 0;
2409
                        }
379 holgerb 2410
                }
2411
        }
2412
        while((end_of_directory_not_reached) && (!retvalue) );
2413
 
427 killagreg 2414
        return(retvalue);
379 holgerb 2415
}
2416
 
2417
 
2418
 
2419
 
2420
/********************************************************************************************************************************************/
2421
/*      Function:               findnext_(Find_t *);                                                                                                                                                                                                                    */
2422
/*                                                                                                                                                                                                                                                                                      */
2423
/*      Description:    This function looks for the next item in the specified directory with a matching filename and fileattributes specified  */
2424
/*                  by function findfirst()                                                                                                                                                                                                     */
2425
/*                                                                                                                                                                                                                                                                                      */
2426
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2427
/********************************************************************************************************************************************/
2428
u8 findnext_(Find_t * findelement)
2429
{
2430
        u8 itemfound = 0;
2431
        u8 index = 0;
2432
 
2433
        findelement->fp.DirectoryIndex++;
2434
 
2435
        /* before we start searching an element we clear the complete namestring within the structure FindElement */
427 killagreg 2436
        for(index = 0; index < 11; index++) findelement->name[index] = 0;
379 holgerb 2437
 
2438
        if(FindItem(findelement))
2439
        {
427 killagreg 2440
                itemfound = 1;
379 holgerb 2441
        }
2442
 
2443
        return(itemfound);
2444
}
2445
 
2446
 
2447
 
2448
/********************************************************************************************************************************************/
2449
/*      Function:               findfirst_(s8* filename, u8 attribmask, Find_t *);                                                                                                                                              */
2450
/*                                                                                                                                                                                                                                                                                      */
2451
/*      Description:    This function looks for the first item in the specified directory with a matching filename and fileattributes                   */
2452
/*                                      The filename of the element found is transformed from 8.3 to a string                                                                                                   */
2453
/*                                                                                                                                                                                                                                                                                      */
2454
/*                                                                                                                                                                                                                                                                                      */
2455
/*      Returnvalue:    (1) if Element was found. (0) if no valid element was found                                                                                                                     */
2456
/********************************************************************************************************************************************/
2457
u8 findfirst_(const s8* name, u8 attribmask, Find_t *findelement)
2458
{
2459
        u8 itemfound = 0;
427 killagreg 2460
        u8 index = 0;
379 holgerb 2461
 
2462
        /* initialize the FindElement structure */
427 killagreg 2463
        findelement->fp.FirstSectorOfFirstCluster = 0;                                  // First sector of the first cluster of the file.
2464
        findelement->fp.FirstSectorOfCurrCluster = Partition.CurrentWorkingDirectory;   // First sector of the cluster which is edited at the moment.
2465
        findelement->fp.SectorOfCurrCluster = 0;                                                // The sector within the current cluster.
379 holgerb 2466
        findelement->fp.ByteOfCurrSector = 0;                                                   // The byte location within the current sector.
2467
        findelement->fp.Size = 0;                                                                               // The size of the opend file in bytes.
2468
        findelement->fp.Position = 0;                                                                   // Pointer to a character within the file 0 < fileposition < filesize
427 killagreg 2469
        findelement->fp.DirectorySector = 0;                                                    // the sectorposition where the directoryentry has been made.
379 holgerb 2470
        findelement->fp.DirectoryIndex = 0;                                                             // The index to the directoryentry within the specified sector.
2471
        findelement->attribfilter = 0;
2472
        findelement->attribmask = attribmask;
427 killagreg 2473
        findelement->searchstring[0] = 0;                                                               // terminate string at the begin (=NULL)
379 holgerb 2474
 
427 killagreg 2475
        // bring it to the 8.3 format
2476
        if(NULL == SeperateFormatedDirName(name, findelement->searchstring)) return(0);
2477
 
2478
        //process the wildcards (*). After an * all following character are wildcards to
2479
        for(index = 0;index < 8;index++)
379 holgerb 2480
        {
2481
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2482
                if(findelement->searchstring[index] == '*')
2483
                {
2484
                        /*  */
427 killagreg 2485
                        while(++index < 8) findelement->searchstring[index] = '*';
379 holgerb 2486
                }
2487
        }
427 killagreg 2488
        for(index = 8;index < 11;index++)
2489
        {
379 holgerb 2490
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2491
                if(findelement->searchstring[index] == '*')
2492
                {
2493
                        /*  */
427 killagreg 2494
                        while(++index < 11) findelement->searchstring[index] = '*';
379 holgerb 2495
                }
2496
        }
427 killagreg 2497
 
379 holgerb 2498
        /* the value of ...DirectoryIndex will be incremented in findnext_() thererfore it has to be decremented in findfirst_() */
2499
        findelement->fp.DirectoryIndex--;
2500
        /* now lets search for the item within the direcory */
2501
        itemfound = findnext_(findelement);
2502
 
2503
        return(itemfound);
2504
}
2505
 
2506
/********************************************************************************************************************************************/
427 killagreg 2507
/* Function:    s8 *GetSubDirectory (s8 *dirpath, s8 *directory)                                                                                                                                                        */
379 holgerb 2508
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2509
/* Description: this function parses the dirpath string and copies the first directroy name to the location pointed to by directroy                     */
379 holgerb 2510
/*                                                                                                                                                                                                                                                                                      */
2511
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2512
/* returnvalue:  a pointer to the beginning of the next subdirectory or NULL                                                                                                                            */
379 holgerb 2513
/********************************************************************************************************************************************/
427 killagreg 2514
s8 * GetSubDirectory(s8 *dirpath, s8 *directory)
379 holgerb 2515
{
427 killagreg 2516
   s8 *cptr = dirpath;
2517
   s8 *dptr = directory;
2518
   s8 *remainingpath = NULL;
2519
 
379 holgerb 2520
   /* if the first character of the path is an '/' we go to the next character */
427 killagreg 2521
   if(*cptr == '/') cptr++;
379 holgerb 2522
   /* search end of path or subdirectory*/
2523
   while((*cptr != 0) && (*cptr != '/'))
2524
   {
427 killagreg 2525
      *dptr = *cptr;   // copy to directory string buffer
379 holgerb 2526
       dptr++;
2527
       cptr++;
427 killagreg 2528
   }
2529
   if(*cptr!=0) remainingpath = ++cptr; // return pointer to remaining path string
2530
   *dptr = 0; // terminate directory name string
379 holgerb 2531
 
427 killagreg 2532
   return(remainingpath);
379 holgerb 2533
}
2534
 
427 killagreg 2535
 
379 holgerb 2536
/********************************************************************************************************************************************/
427 killagreg 2537
/*      Function:               u8 chdir_(s8* const path);                                                                                                                                                                                              */
379 holgerb 2538
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2539
/*      Description:    This function changes the current working directory to the directory specified by the filepath                                                  */
2540
/*                  by function findfirst()                                                                                                                                                                                                     */
379 holgerb 2541
/*                                                                                                                                                                                                                                                                                      */
2542
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2543
/********************************************************************************************************************************************/
2544
 
427 killagreg 2545
u8 chdir_(s8* const path)
379 holgerb 2546
{
427 killagreg 2547
        u8              retvalue = 0;                                   // the value returned by this function
2548
        u32     ultemp = 0;                                             // temp. variable
2549
        s8      *dirpath = path;                                // pointer to the remaining path string
2550
        s8      dirname[64];                                    // a buffer containing the name of the subdirectory we are actually looking for
2551
        Find_t  fe;                                                             // The findelement needed for function findfirst to find the subdirectory entry
2552
        s8              tp[256];                                                // temporarily we remember the actual path until the operation has finished successfully
2553
        u32     tcwd = 0;                                               // temporarily we remember the actual current working directory
379 holgerb 2554
 
427 killagreg 2555
        if(path == NULL) return(0);                             // return immediately of no path is given
2556
        // correct filepath formatting
2557
        Slashing_Path(path);
379 holgerb 2558
 
427 killagreg 2559
        // lets remember the actual path and correspondig directory sector
2560
        strcpy(tp, Partition.PathToCwd);
2561
        tcwd = Partition.CurrentWorkingDirectory;
2562
 
2563
        if(path[0] == '/') // if the path is absolute we begin at the rootdirectory
2564
        {
2565
                strcpy(Partition.PathToCwd, "/");
2566
                Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
2567
        }
2568
        // parse through all the subdirectories within the path
2569
        do
2570
        {
2571
                dirpath = GetSubDirectory(dirpath, dirname); // get the name of the subdirectory we are looking for and the remainig path
2572
                if(dirname[0] == 0)             // if no directory name is available 
2573
                {
2574
                        retvalue = 1;                   // we are done
2575
                        break;                                  // break the loop
2576
                }      
2577
                // search for the next subdirectory within the path
2578
                if(findfirst_(dirname, ATTR_SUBDIRECTORY, &fe))
2579
                {
2580
                        // we try to change into the directory "..". Now we have to delete the last direntry from the path
2581
                        if(strcmp(dirname, "..") == 0) CWDPath_Pop();
2582
                        // we try to change into the actual directory so there's nothing todo
2583
                        else if(dirname[0] == '.') return(1);
2584
                        // otherwise we append the name of the directory we are changing in to the path
2585
                        else CWDPath_Push(dirname);
2586
                        // The startcluster within an directory entry specifies the position within the fat where the file or directory starts
2587
                        ultemp = (u32) fe.fp.FirstSectorOfFirstCluster;
2588
                        // do we have to change into the rootdirectory?
2589
                        if(ultemp)
2590
                        {
2591
                                // the first 2 entries are reserved for '.' and '..' 
2592
                                ultemp -= 2;
2593
                                // 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
2594
                                ultemp *= Partition.SectorsPerCluster;
2595
                                // at least we make the sectoraddress absolute by adding the relative address to the beginning of the datasection of the active partition
2596
                                ultemp += Partition.FirstDataSector;
2597
                                // the cwd now points to the specified directory
2598
                                Partition.CurrentWorkingDirectory = ultemp;
2599
                        }
2600
                        else // (=0) root directory 
2601
                        {
2602
                                // the cwd now points to the rootdirectory
2603
                                Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
2604
                        }
2605
                        retvalue = 1;
2606
                }
2607
                else // subdirectory not found
2608
                {
2609
                        retvalue = 0;           // no success tracing along the given directory chain
2610
                        break;                          // break the loop
2611
                }
2612
        }
2613
        while(dirpath != NULL);  // do this until all subdirectories have been found
2614
 
2615
        // if we could not change to the specified directory we restore the actual path 
2616
        if(!retvalue)
2617
        {
2618
                Partition.CurrentWorkingDirectory = tcwd;
2619
                strcpy(Partition.PathToCwd, tp);
2620
        }
2621
        return(retvalue);
379 holgerb 2622
}
2623
 
427 killagreg 2624
 
379 holgerb 2625
/********************************************************************************************************************************************/
427 killagreg 2626
/*      Function:               u8 rmdir_(s8* dname);                                                                                                                                                                                                           */
379 holgerb 2627
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2628
/*      Description:    This function deletes the directory with the specified filename from the filesystem                                                                             */
2629
/*                                                                                                                                                                                                                                      */
379 holgerb 2630
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2631
/*      Returnvalue:    1 : specified directory deleted succesfully 0: specified directory not found                                                                                    */
379 holgerb 2632
/********************************************************************************************************************************************/
2633
 
427 killagreg 2634
u8 rmdir_(s8* const dirpath)
379 holgerb 2635
{
427 killagreg 2636
        u8 retvalue = 0;
2637
        Find_t fe;
2638
        u32 cwd;
2639
        s8 path[256];
2640
        s8 *dn;
2641
        s8 *dp;
379 holgerb 2642
 
427 killagreg 2643
        if(dirpath == NULL) return(0);
2644
        // correct filepath formatting
2645
        Slashing_Path(dirpath);
379 holgerb 2646
 
427 killagreg 2647
    // remember the current workingdirectory
2648
        cwd = Partition.CurrentWorkingDirectory;
2649
 
2650
        // create local copy of the path
2651
        strcpy(path, dirpath);
2652
        // seperate the filepath from the last directory within the path that shall be deleted
2653
        // start searching for the name of the directory to be deleted from the beginning of the path
2654
        dn = path;
2655
        dp = path;
2656
        // search the complete path until the end of the string is found
2657
        while(*dn != 0) dn++;
2658
        // now check if the last directory whithin the path is terminated with an '/' and remove the '/' from the directoryname
2659
        if(*(dn-1) == '/') *--dn = 0;
2660
        // now find the beginning of the last directoryentry
2661
        while((*dn != '/') && (dn > path)) dn--;
2662
        // beginning of the last directory found
2663
        if(*dn == '/')
379 holgerb 2664
        {
427 killagreg 2665
                // remove the directoryname from the path by terminating the path with 0
2666
                *dn = 0;
2667
                // the dirname begins 1 character after the terminated path
2668
                dn++;
379 holgerb 2669
        }
427 killagreg 2670
        // we couldn't find a path before the directory to be deleted or no directoryname at all
379 holgerb 2671
        else
2672
        {
427 killagreg 2673
                // there is no path before the name of the directory to be deleted
2674
                if(dn == path)
2675
                {
2676
                        // if there is a name of a directory to be deleted?
2677
                        if(*dn == 0) return(0);
2678
                        // the directory to be deleted is within the actual directory therefore we don't have to change the directory before deleting the directory
2679
                        dp = NULL;
2680
                }
2681
 
379 holgerb 2682
        }
427 killagreg 2683
        // switch to the directory containing the directory to be deleted if neccessary
2684
        if(dp != NULL)
2685
        {
2686
                if(!chdir_(dp)) return(0);
2687
        }
2688
        // now we have to find the specified directory to be deleted
2689
        retvalue = findfirst_(dn, 0xff, &fe);
2690
        // was the specified directory found?
2691
        if(retvalue)
2692
        {
2693
                // before we delete the directory we check if the directory is empty
2694
                if(chdir_(dn))
2695
                {
2696
                        if(findfirst_("*.*", 0xff, &fe))
2697
                        {
2698
                                // within an directory that shall be deleted only the entries . and .. are allowed
2699
                                if((strncmp(fe.name, ".", 1) != 0) && (strncmp(fe.name, "..", 2) != 0)) retvalue = 0;
2700
                                while(findnext_(&fe))
2701
                                {
2702
                                        if((strncmp(fe.name, ".", 1) != 0) && (strncmp(fe.name, "..", 2) != 0)) retvalue = 0;
2703
                                }
2704
                        }
2705
                        chdir_("..");
2706
                }
2707
                // directory couldn't be entered, is a real file?
2708
                else
2709
                {
2710
                        retvalue = 0;
2711
                }
2712
                // specified directory is empty
2713
                if(retvalue)
2714
                {
2715
                        retvalue = 0;
2716
                        // 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
2717
                        if(findfirst_(dn, 0xff, &fe))
2718
                        {
431 killagreg 2719
                                Debug("found");
427 killagreg 2720
                                // try to clear the allocated clusters within the fat
2721
                                if(DeleteClusterChain(fe.fp.FirstSectorOfFirstCluster))
2722
                                {
2723
                                        // delete the directoryentry within the specified directory
2724
                                        if(DeleteDirectoryEntry(&(fe.fp))) retvalue = 1;
2725
                                }
2726
                        }
2727
                }
2728
        }
2729
 
2730
        // restore the actual path
2731
        Partition.CurrentWorkingDirectory = cwd;
2732
 
2733
        return(retvalue);
379 holgerb 2734
}
2735
 
427 killagreg 2736
 
379 holgerb 2737
/********************************************************************************************************************************************/
427 killagreg 2738
/*      Function:               mkdir_(s8* dirpath);                                                                                                                                                                                                    */
379 holgerb 2739
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2740
/*      Description:    This function creates the directory with the specified pathname in the filesystem                                                                               */
2741
/*                                                                                                                                                                                                                                      */
379 holgerb 2742
/*                                                                                                                                                                                                                                                                                      */
427 killagreg 2743
/*      Returnvalue:    1 : specified directory created succesfully 0: specified dir exist already                                                                                              */
379 holgerb 2744
/********************************************************************************************************************************************/
2745
 
427 killagreg 2746
u8 mkdir_(s8* const dirpath)
379 holgerb 2747
{
427 killagreg 2748
        u8 retvalue = 0;
2749
        File_t file;
379 holgerb 2750
 
427 killagreg 2751
        if(dirpath == NULL) return(0);
2752
        // correct filepath formatting
2753
        Slashing_Path(dirpath);
431 killagreg 2754
        file.FirstSectorOfFirstCluster = SECTOR_UNDEFINED;              // First sector of the first cluster of the file.
2755
        file.FirstSectorOfCurrCluster = SECTOR_UNDEFINED;               // First sector of the cluster which is edited at the moment.
2756
        file.FirstSectorOfLastCluster = SECTOR_UNDEFINED;               // First sector of the last cluster of the file
2757
        file.SectorOfCurrCluster = SECTOR_UNDEFINED;                    // The sector within the current cluster.
2758
        file.ByteOfCurrSector = 0;                                                              // The byte location within the current sector.
2759
        file.Mode = 0;                                                                                  // Mode of fileoperation (read,write)
2760
        file.Size = 0;                                                                                  // The size of the opend file in bytes.
2761
        file.Position = 0;                                                                              // Pointer to a character within the file 0 < fileposition < filesize
2762
        file.DirectorySector = SECTOR_UNDEFINED;                                // the sectorposition where the directoryentry has been made.
2763
        file.DirectoryIndex = 0;                                                                // The index to the directoryentry within the specified sector.
2764
        file.Attribute = 0;                                                                             // The attribute of the file opened.
2765
        file.SectorInCache = SECTOR_UNDEFINED;                                  // The last sector read, which is still in the sector cache.
2766
        file.State = FSTATE_USED;                                                               // mark it as used
427 killagreg 2767
        // if directory is not existent
2768
        if(!FileExist(dirpath, ATTR_SUBDIRECTORY, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, &file))
379 holgerb 2769
        {
427 killagreg 2770
                retvalue = FileCreate(dirpath, ATTR_SUBDIRECTORY, &file);
379 holgerb 2771
        }
427 killagreg 2772
        return(retvalue);
2773
}
379 holgerb 2774
 
427 killagreg 2775
 
2776
 
2777
 
2778
 
2779
 
2780