Dual CANbus monitor and instrumentation cluster. Presently tuned for the Nissan Leaf EV.

Dependencies:   SPI_TFTx2_ILI9341 TFT_fonts TOUCH_TFTx2_ILI9341 mbed

Fork of CANary_corrupt by Tick Tock

After adding the LPC1768 platform, import as a program and do not select the "update to latest revision" box

User Guide

Eagle Schematic and Board design

/media/uploads/TickTock/canaryr6.zip

/media/uploads/TickTock/canary_sch.jpg

/media/uploads/TickTock/canaryr6brd.jpg

For LCD Rev 1.01:

/media/uploads/TickTock/lcdsch.jpg

For VCD Rev 2.00:

/media/uploads/TickTock/lcdr2.jpg

Parts List

qtyinstancepart #packagesupplierDescription
1BAT3Vhttp://www.ebay.com/itm/10x-CR2032-SMD-Battery-Holder-for-CR2032-Battery-/180938057979?pt=LH_DefaultDomain_0&hash=item2a20bfa8fbLithium 2032 coin battery holder
4C1-C4ECST1DC106R6032Tantalium capacitor 10uF
3FC1-FC3ZF1-20-01-T-WThttp://www.samtec.com/cable-systems/idc-ffc/ffc/zero-insertion.aspx20 conductor 1mm pitch flex cable connector (optional)
1FJ-20-R-08.00-4http://www.samtec.com/cable-systems/idc-ffc/ffc/zero-insertion.aspx8\" 20 conductor 1mm pitch flex connector, end reversed (optional)
2H1-H4(DON'T populate H1-H4 headers - solder mbed directly)
1H5http://www.ebay.com/itm/221186042943?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l26491x12 .1\" pitch header (optional)
1H62x6 .1\" pitch header (optional)
2IC1,IC2VP230LMDSOP8http://www.ebay.com/itm/130488665247?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649canbus transciever
1IC3LM1117-5VSOT2235V regulator
5JP*2 pin .1\" jumper header
1mbedLPC1768http://www.ebay.com/itm/200830573509?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2649mbed uC
2Q1,Q22N2222SOT23General purpose NPN transistor
1R1R393M120639K resistor
1R2R103M120610K resistor
4R4-R6R102M12061K resistor
1R3R500M120650 Ohm resistor
2TR1-TR5ZJYS81R5-2PL51TG01http://www.digikey.com/product-detail/en/ZJYS81R5-2PL51T-G01/445-2223-1-ND/765232CM Choke
1Z11N5340BGC1702-15http://www.ebay.com/itm/150878122425?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l26496V, 5W Zener Diode
1Z1DC-DC conveterhttp://www.ebay.com/itm/251142727849?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l264912V-7V, 3W DC-DC converter
1X1USBhttp://www.ebay.com/itm/New-Vertical-USB-2-0-A-pcb-connector-socket-USB-A-Type-/300553895292?pt=LH_DefaultDomain_0&hash=item45fa687d7cvertical USB connector
2LCD0,LCD1TFThttp://www.mikroe.com/add-on-boards/display/tft-proto/320x240 LCD with touch screen
1E0Enclosurehttp://www.shapeways.com/model/1077799/canary.html?li=user-profile&materialId=63d printed enclosure

Assembly

1) LCD Displays

I found ribbon cable is a nice way to organize the wires to the displays. There are two versions of the display and each must be wired differently. The original project used HW REV. 1.01. For that version, you'll need 12 conductors and I connected them in the following order:

1LED+
2LED-
3RST
4SDI
5WR/SCLK
6CS
7X+
8X-
9Y+
10Y-
11VDD
12GND

If, instead, you have HW REV 2.0, you will need 13 conductors with the following order:

1LED+
2LED-
3RST
4SDI
5RS (SCLK)
6WR (DC)
7CS
8X+
9X-
10Y+
11Y-
12VDD
13GND

First I connected all the GND connections (2 GND & IM0, IM1, IM3 for REV1.01 or 2 GND, RD, & IM0 for REV2.00). Do not connect the bottom GND until you have the ribbon cable connected. After making all the ribbon cable connections (connecting the GND of the ribbon cable to the bottom GND pad), solder the GND bar from the previous step to the back of the bottom GND connection. Finally, make a connection from the back side 3.3V pin to IM2 for REV1.01 or to IM1,IM2,&IM3 for REV2.00. Take a break and repeat for the second display.

Examples of REV1.01 boards:

/media/uploads/TickTock/lcdtop.jpg /media/uploads/TickTock/lcdbot.jpg

Examples of REV2.00:

/media/uploads/TickTock/rev2front.jpg /media/uploads/TickTock/rev2back.jpg

Once the two displays are complete combine all wires except CS0, CS1, X+, X-, Y+, and Y-. Connect X- of the left display to X+ of the right. Similarly connect Y- of the left display to Y+ of the right. Insulate any exposed wires.

2) PCB

Refer to the schematics to place all the components on the board. If you plan to install into the CANary 3D enclosure, DO NOT install the battery holder or the socket for the mbed and, instead, connect two wires to the VB and GND pads nearby. You will have to install the battery holder against the back wall to avoid interfering with the right-hand display and the mbed will have to be directly soldered. I have not found a socket with a low enough profile to fit in the space provided (depth of enclosure is limited by the space behind the center console). Also, I recommend keeping as much lead as possible on the Zener diode (bending it as shown to clear the back wall). Although it is operating well within parameters, the Zener gets quite hot during extended operation and the leads help dissipate the heat and keep it away from the PCB and other components.Update: Several Zeners have failed resulting in damage to some users boards so I recommend using a DC-DC converter instead to bring the 12V down to 7V.

/media/uploads/TickTock/pcbtop.jpg /media/uploads/TickTock/pcbbot.jpg

Once the PCB is populated, solder the LCDs to the PCB. CS0 connects to the right display and CS1 connects to the left. /media/uploads/TickTock/brddis.jpg

Update: The Zener diodes tended to fail after a few months so I am recommending removing them and replacing with a DC-DC converter. This will run cooler and waste less energy, too. To install, remove the left display panel to gain access to the Zener. From there, the Zener can be removed and it's pads used to connect to the DC-DC converter. I recommend setting the output voltage on the bench before installing since the trim pot is tricky to reach once installed. Set it to 7V. The input can be connected to the left pad previously occupied by the zener and the output can connect to the right. GND(-) can be connected to the bottom right pad on the 2x6 header below the flex cable connector. Make sure the GND wire lies flat so it doesn't interfere with the connection of the flex cable. /media/uploads/TickTock/dcdcinst2.jpg

Once soldered in place, the DC-DC converter can easily be mounted to the back wall with double sided tape above the battery holder. /media/uploads/TickTock/dcdcinst3.jpg

3) Testing

1)First step is to buzz out all connections from the LCDs to the pins in the main board
2)Next check the touch screen connections. On the main board, place an Ohm meter across X+ and X-. You should read 700 Ohms. Repeat for Y+ and Y-. Then test the resistance from X+ to Y+. With nothing touching the screens, it should read >100K Ohms and <1K when touching either screen.
3)When all connections are checked, solder in the mbed. Download and install the touch2 program http://mbed.org/users/TickTock/code/touch2/ to test the basic operation of the mbed and touch screens.
tips:
Touch screen is sensitive - excess flux on X+,X-,Y+,Y- connection on mbed can result in flakey operation
If touch is not working, double-check the LCD0_CS and LCD1_CS are not swapped. LCD0_CS must connect to the CS of the LCD that has X- & Y- connected to the mbed. LCD1_CS must connect to the CS of the LCD that has X+ & Y+ connected to the mbed.
4)Once touch2 works, it is time to connect to the OBD connector. I highly recommend double checking all connections from the OBD to the PCB with the cable in place before connecting to the Leaf. Buzz out all the pins in the OBS to make sure none are shorting to each other, Check that the 12V goes to the Zener (and nothing else) and the switched 12V to the resistor divider (and nothing else). Test the ground connection properly connects to ground and nothing else.
5)Once you are confident there are no shorts or wrong connections from the OBD connector, take a deep breath and plug it into your leaf. Touch2 program should come up and function. Unplug and install the latest CANary firmware. If you have the REV2.00 LCD boards, you will need to edit the precompile.h file in the TOUCH_TFTx2_w9341 library and set USE_ILI9341 to 1. Test all features before installing into the enclosure (gids, cellpair, menu system, logging) since installing and removing from the enclosure is a PITA.

/media/uploads/TickTock/pcbdone.jpg /media/uploads/TickTock/functioning.jpg

4) Enclosure

The 3D printer leaves a lot of powder behind - I used a strong spray of water to get it out of all the cracks. The enclosure comes with a rather rough finish. I recommend convincing yourself you like it, then simply lightly sand then paint before assembly. Sanding is very difficult - the nylon is very nicely fused and doesn't want to sand. I tried sandblasting and that didn't work either. I had some limited success with filler and then sanding, but only on the outside - it is too difficult to sand the face. /media/uploads/TickTock/enclosure.jpg

5) Final Assembly

Make sure you are well rested with lots of patience before attempting assembly. It is a puzzle figuring out how to get both displays and the PCB in place. Enclosure was too expensive for me to keep iterating to optimize for assembly. I ended up snipping the thin display posts shorter and using various tools to push the displays into place. Also, some USB connectors are taller than others. If you have one of the taller ones, you will have to deflect the back wall a bit while inserting the PCB (being careful not to bend the housing) to get it to it's opening in the back wall. Do use a screw in the provided post to secure the PCB as USB insertion will otherwise dislodge it.

I added an additional safety line which wraps around the center post to prevent the enclosure from becoming a projectile in the event of an accident. /media/uploads/TickTock/safety.jpg Installed: /media/uploads/TickTock/installed.jpg

Committer:
TickTock
Date:
Sun Jun 30 19:52:38 2013 +0000
Branch:
Metric
Revision:
110:ffddff3ad2f2
Parent:
109:3e6f0e8fca0d
Got battery and trip logs working.  Fixed canlog to append (was overwriting previous data).

Who changed what in which revision?

UserRevisionLine numberNew contents of line
TickTock 109:3e6f0e8fca0d 1 /*----------------------------------------------------------------------------/
TickTock 109:3e6f0e8fca0d 2 / FatFs - FAT file system module R0.07e (C)ChaN, 2009
TickTock 109:3e6f0e8fca0d 3 /-----------------------------------------------------------------------------/
TickTock 109:3e6f0e8fca0d 4 / FatFs module is a generic FAT file system module for small embedded systems.
TickTock 109:3e6f0e8fca0d 5 / This is a free software that opened for education, research and commercial
TickTock 109:3e6f0e8fca0d 6 / developments under license policy of following trems.
TickTock 109:3e6f0e8fca0d 7 /
TickTock 109:3e6f0e8fca0d 8 / Copyright (C) 2009, ChaN, all right reserved.
TickTock 109:3e6f0e8fca0d 9 /
TickTock 109:3e6f0e8fca0d 10 / * The FatFs module is a free software and there is NO WARRANTY.
TickTock 109:3e6f0e8fca0d 11 / * No restriction on use. You can use, modify and redistribute it for
TickTock 109:3e6f0e8fca0d 12 / personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
TickTock 109:3e6f0e8fca0d 13 / * Redistributions of source code must retain the above copyright notice.
TickTock 109:3e6f0e8fca0d 14 /
TickTock 109:3e6f0e8fca0d 15 /-----------------------------------------------------------------------------/
TickTock 109:3e6f0e8fca0d 16 / Feb 26,'06 R0.00 Prototype.
TickTock 109:3e6f0e8fca0d 17 /
TickTock 109:3e6f0e8fca0d 18 / Apr 29,'06 R0.01 First stable version.
TickTock 109:3e6f0e8fca0d 19 /
TickTock 109:3e6f0e8fca0d 20 / Jun 01,'06 R0.02 Added FAT12 support.
TickTock 109:3e6f0e8fca0d 21 / Removed unbuffered mode.
TickTock 109:3e6f0e8fca0d 22 / Fixed a problem on small (<32M) patition.
TickTock 109:3e6f0e8fca0d 23 / Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
TickTock 109:3e6f0e8fca0d 24 /
TickTock 109:3e6f0e8fca0d 25 / Sep 22,'06 R0.03 Added f_rename().
TickTock 109:3e6f0e8fca0d 26 / Changed option _FS_MINIMUM to _FS_MINIMIZE.
TickTock 109:3e6f0e8fca0d 27 / Dec 11,'06 R0.03a Improved cluster scan algolithm to write files fast.
TickTock 109:3e6f0e8fca0d 28 / Fixed f_mkdir() creates incorrect directory on FAT32.
TickTock 109:3e6f0e8fca0d 29 /
TickTock 109:3e6f0e8fca0d 30 / Feb 04,'07 R0.04 Supported multiple drive system.
TickTock 109:3e6f0e8fca0d 31 / Changed some interfaces for multiple drive system.
TickTock 109:3e6f0e8fca0d 32 / Changed f_mountdrv() to f_mount().
TickTock 109:3e6f0e8fca0d 33 / Added f_mkfs().
TickTock 109:3e6f0e8fca0d 34 / Apr 01,'07 R0.04a Supported multiple partitions on a plysical drive.
TickTock 109:3e6f0e8fca0d 35 / Added a capability of extending file size to f_lseek().
TickTock 109:3e6f0e8fca0d 36 / Added minimization level 3.
TickTock 109:3e6f0e8fca0d 37 / Fixed an endian sensitive code in f_mkfs().
TickTock 109:3e6f0e8fca0d 38 / May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
TickTock 109:3e6f0e8fca0d 39 / Added FSInfo support.
TickTock 109:3e6f0e8fca0d 40 / Fixed DBCS name can result FR_INVALID_NAME.
TickTock 109:3e6f0e8fca0d 41 / Fixed short seek (<= csize) collapses the file object.
TickTock 109:3e6f0e8fca0d 42 /
TickTock 109:3e6f0e8fca0d 43 / Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
TickTock 109:3e6f0e8fca0d 44 / Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
TickTock 109:3e6f0e8fca0d 45 / Fixed f_mkdir() on FAT32 creates incorrect directory.
TickTock 109:3e6f0e8fca0d 46 / Feb 03,'08 R0.05a Added f_truncate() and f_utime().
TickTock 109:3e6f0e8fca0d 47 / Fixed off by one error at FAT sub-type determination.
TickTock 109:3e6f0e8fca0d 48 / Fixed btr in f_read() can be mistruncated.
TickTock 109:3e6f0e8fca0d 49 / Fixed cached sector is not flushed when create and close
TickTock 109:3e6f0e8fca0d 50 / without write.
TickTock 109:3e6f0e8fca0d 51 /
TickTock 109:3e6f0e8fca0d 52 / Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
TickTock 109:3e6f0e8fca0d 53 / Improved performance of f_lseek() on moving to the same
TickTock 109:3e6f0e8fca0d 54 / or following cluster.
TickTock 109:3e6f0e8fca0d 55 /
TickTock 109:3e6f0e8fca0d 56 / Apr 01,'09 R0.07 Merged Tiny-FatFs as a buffer configuration option.
TickTock 109:3e6f0e8fca0d 57 / Added long file name support.
TickTock 109:3e6f0e8fca0d 58 / Added multiple code page support.
TickTock 109:3e6f0e8fca0d 59 / Added re-entrancy for multitask operation.
TickTock 109:3e6f0e8fca0d 60 / Added auto cluster size selection to f_mkfs().
TickTock 109:3e6f0e8fca0d 61 / Added rewind option to f_readdir().
TickTock 109:3e6f0e8fca0d 62 / Changed result code of critical errors.
TickTock 109:3e6f0e8fca0d 63 / Renamed string functions to avoid name collision.
TickTock 109:3e6f0e8fca0d 64 / Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
TickTock 109:3e6f0e8fca0d 65 / Added multiple sector size support.
TickTock 109:3e6f0e8fca0d 66 / Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error.
TickTock 109:3e6f0e8fca0d 67 / Fixed wrong cache control in f_lseek().
TickTock 109:3e6f0e8fca0d 68 / Added relative path feature.
TickTock 109:3e6f0e8fca0d 69 / Added f_chdir() and f_chdrive().
TickTock 109:3e6f0e8fca0d 70 / Added proper case conversion to extended char.
TickTock 109:3e6f0e8fca0d 71 / Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
TickTock 109:3e6f0e8fca0d 72 / Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
TickTock 109:3e6f0e8fca0d 73 / Fixed name matching error on the 13 char boundary.
TickTock 109:3e6f0e8fca0d 74 / Added a configuration option, _LFN_UNICODE.
TickTock 109:3e6f0e8fca0d 75 / Changed f_readdir() to return the SFN with always upper
TickTock 109:3e6f0e8fca0d 76 / case on non-LFN cfg.
TickTock 109:3e6f0e8fca0d 77 /---------------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 78
TickTock 109:3e6f0e8fca0d 79 #include "ff.h" /* FatFs configurations and declarations */
TickTock 109:3e6f0e8fca0d 80 #include "diskio.h" /* Declarations of low level disk I/O functions */
TickTock 109:3e6f0e8fca0d 81
TickTock 109:3e6f0e8fca0d 82 /*--------------------------------------------------------------------------
TickTock 109:3e6f0e8fca0d 83
TickTock 109:3e6f0e8fca0d 84 Module Private Definitions
TickTock 109:3e6f0e8fca0d 85
TickTock 109:3e6f0e8fca0d 86 ---------------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 87
TickTock 109:3e6f0e8fca0d 88 #if _FATFS != 0x007E
TickTock 109:3e6f0e8fca0d 89 #error Wrong include file (ff.h).
TickTock 109:3e6f0e8fca0d 90 #endif
TickTock 109:3e6f0e8fca0d 91
TickTock 109:3e6f0e8fca0d 92 #if _FS_REENTRANT
TickTock 109:3e6f0e8fca0d 93 #if _USE_LFN == 1
TickTock 109:3e6f0e8fca0d 94 #error Static LFN work area must not be used in re-entrant configuration.
TickTock 109:3e6f0e8fca0d 95 #endif
TickTock 109:3e6f0e8fca0d 96 #define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; }
TickTock 109:3e6f0e8fca0d 97 #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; }
TickTock 109:3e6f0e8fca0d 98
TickTock 109:3e6f0e8fca0d 99 #else
TickTock 109:3e6f0e8fca0d 100 #define ENTER_FF(fs)
TickTock 109:3e6f0e8fca0d 101 #define LEAVE_FF(fs, res) return res
TickTock 109:3e6f0e8fca0d 102
TickTock 109:3e6f0e8fca0d 103 #endif
TickTock 109:3e6f0e8fca0d 104
TickTock 109:3e6f0e8fca0d 105 #define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); }
TickTock 109:3e6f0e8fca0d 106
TickTock 109:3e6f0e8fca0d 107 #ifndef NULL
TickTock 109:3e6f0e8fca0d 108 #define NULL 0
TickTock 109:3e6f0e8fca0d 109 #endif
TickTock 109:3e6f0e8fca0d 110
TickTock 109:3e6f0e8fca0d 111 /* Name status flags */
TickTock 109:3e6f0e8fca0d 112 #define NS 11 /* Offset of name status byte */
TickTock 109:3e6f0e8fca0d 113 #define NS_LOSS 0x01 /* Out of 8.3 format */
TickTock 109:3e6f0e8fca0d 114 #define NS_LFN 0x02 /* Force to create LFN entry */
TickTock 109:3e6f0e8fca0d 115 #define NS_LAST 0x04 /* Last segment */
TickTock 109:3e6f0e8fca0d 116 #define NS_BODY 0x08 /* Lower case flag (body) */
TickTock 109:3e6f0e8fca0d 117 #define NS_EXT 0x10 /* Lower case flag (ext) */
TickTock 109:3e6f0e8fca0d 118 #define NS_DOT 0x20 /* Dot entry */
TickTock 109:3e6f0e8fca0d 119
TickTock 109:3e6f0e8fca0d 120
TickTock 109:3e6f0e8fca0d 121
TickTock 109:3e6f0e8fca0d 122
TickTock 109:3e6f0e8fca0d 123 /*--------------------------------------------------------------------------
TickTock 109:3e6f0e8fca0d 124
TickTock 109:3e6f0e8fca0d 125 Private Work Area
TickTock 109:3e6f0e8fca0d 126
TickTock 109:3e6f0e8fca0d 127 ---------------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 128
TickTock 109:3e6f0e8fca0d 129 #if _DRIVES < 1 || _DRIVES > 9
TickTock 109:3e6f0e8fca0d 130 #error Number of drives must be 1-9.
TickTock 109:3e6f0e8fca0d 131 #endif
TickTock 109:3e6f0e8fca0d 132 static
TickTock 109:3e6f0e8fca0d 133 FATFS *FatFs[_DRIVES]; /* Pointer to the file system objects (logical drives) */
TickTock 109:3e6f0e8fca0d 134
TickTock 109:3e6f0e8fca0d 135 static
TickTock 109:3e6f0e8fca0d 136 WORD Fsid; /* File system mount ID */
TickTock 109:3e6f0e8fca0d 137
TickTock 109:3e6f0e8fca0d 138 #if _FS_RPATH
TickTock 109:3e6f0e8fca0d 139 static
TickTock 109:3e6f0e8fca0d 140 BYTE Drive; /* Current drive */
TickTock 109:3e6f0e8fca0d 141 #endif
TickTock 109:3e6f0e8fca0d 142
TickTock 109:3e6f0e8fca0d 143
TickTock 109:3e6f0e8fca0d 144 #if _USE_LFN == 1 /* LFN with static LFN working buffer */
TickTock 109:3e6f0e8fca0d 145 static
TickTock 109:3e6f0e8fca0d 146 WCHAR LfnBuf[_MAX_LFN + 1];
TickTock 109:3e6f0e8fca0d 147 #define NAMEBUF(sp,lp) BYTE sp[12]; WCHAR *lp = LfnBuf
TickTock 109:3e6f0e8fca0d 148 #define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp
TickTock 109:3e6f0e8fca0d 149
TickTock 109:3e6f0e8fca0d 150 #elif _USE_LFN > 1 /* LFN with dynamic LFN working buffer */
TickTock 109:3e6f0e8fca0d 151 #define NAMEBUF(sp,lp) BYTE sp[12]; WCHAR lbuf[_MAX_LFN + 1], *lp = lbuf
TickTock 109:3e6f0e8fca0d 152 #define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp
TickTock 109:3e6f0e8fca0d 153
TickTock 109:3e6f0e8fca0d 154 #else /* No LFN */
TickTock 109:3e6f0e8fca0d 155 #define NAMEBUF(sp,lp) BYTE sp[12]
TickTock 109:3e6f0e8fca0d 156 #define INITBUF(dj,sp,lp) dj.fn = sp
TickTock 109:3e6f0e8fca0d 157
TickTock 109:3e6f0e8fca0d 158 #endif
TickTock 109:3e6f0e8fca0d 159
TickTock 109:3e6f0e8fca0d 160
TickTock 109:3e6f0e8fca0d 161
TickTock 109:3e6f0e8fca0d 162
TickTock 109:3e6f0e8fca0d 163 /*--------------------------------------------------------------------------
TickTock 109:3e6f0e8fca0d 164
TickTock 109:3e6f0e8fca0d 165 Module Private Functions
TickTock 109:3e6f0e8fca0d 166
TickTock 109:3e6f0e8fca0d 167 ---------------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 168
TickTock 109:3e6f0e8fca0d 169
TickTock 109:3e6f0e8fca0d 170 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 171 /* String functions */
TickTock 109:3e6f0e8fca0d 172 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 173
TickTock 109:3e6f0e8fca0d 174 /* Copy memory to memory */
TickTock 109:3e6f0e8fca0d 175 static
TickTock 109:3e6f0e8fca0d 176 void mem_cpy (void* dst, const void* src, int cnt) {
TickTock 109:3e6f0e8fca0d 177 char *d = (char*)dst;
TickTock 109:3e6f0e8fca0d 178 const char *s = (const char *)src;
TickTock 109:3e6f0e8fca0d 179 while (cnt--) *d++ = *s++;
TickTock 109:3e6f0e8fca0d 180 }
TickTock 109:3e6f0e8fca0d 181
TickTock 109:3e6f0e8fca0d 182 /* Fill memory */
TickTock 109:3e6f0e8fca0d 183 static
TickTock 109:3e6f0e8fca0d 184 void mem_set (void* dst, int val, int cnt) {
TickTock 109:3e6f0e8fca0d 185 char *d = (char*)dst;
TickTock 109:3e6f0e8fca0d 186 while (cnt--) *d++ = (char)val;
TickTock 109:3e6f0e8fca0d 187 }
TickTock 109:3e6f0e8fca0d 188
TickTock 109:3e6f0e8fca0d 189 /* Compare memory to memory */
TickTock 109:3e6f0e8fca0d 190 static
TickTock 109:3e6f0e8fca0d 191 int mem_cmp (const void* dst, const void* src, int cnt) {
TickTock 109:3e6f0e8fca0d 192 const char *d = (const char *)dst, *s = (const char *)src;
TickTock 109:3e6f0e8fca0d 193 int r = 0;
TickTock 109:3e6f0e8fca0d 194 while (cnt-- && (r = *d++ - *s++) == 0) ;
TickTock 109:3e6f0e8fca0d 195 return r;
TickTock 109:3e6f0e8fca0d 196 }
TickTock 109:3e6f0e8fca0d 197
TickTock 109:3e6f0e8fca0d 198 /* Check if chr is contained in the string */
TickTock 109:3e6f0e8fca0d 199 static
TickTock 109:3e6f0e8fca0d 200 int chk_chr (const char* str, int chr) {
TickTock 109:3e6f0e8fca0d 201 while (*str && *str != chr) str++;
TickTock 109:3e6f0e8fca0d 202 return *str;
TickTock 109:3e6f0e8fca0d 203 }
TickTock 109:3e6f0e8fca0d 204
TickTock 109:3e6f0e8fca0d 205
TickTock 109:3e6f0e8fca0d 206
TickTock 109:3e6f0e8fca0d 207 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 208 /* Request/Release grant to access the volume */
TickTock 109:3e6f0e8fca0d 209 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 210 #if _FS_REENTRANT
TickTock 109:3e6f0e8fca0d 211
TickTock 109:3e6f0e8fca0d 212 static
TickTock 109:3e6f0e8fca0d 213 BOOL lock_fs (
TickTock 109:3e6f0e8fca0d 214 FATFS *fs /* File system object */
TickTock 109:3e6f0e8fca0d 215 )
TickTock 109:3e6f0e8fca0d 216 {
TickTock 109:3e6f0e8fca0d 217 return ff_req_grant(fs->sobj);
TickTock 109:3e6f0e8fca0d 218 }
TickTock 109:3e6f0e8fca0d 219
TickTock 109:3e6f0e8fca0d 220
TickTock 109:3e6f0e8fca0d 221 static
TickTock 109:3e6f0e8fca0d 222 void unlock_fs (
TickTock 109:3e6f0e8fca0d 223 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 224 FRESULT res /* Result code to be returned */
TickTock 109:3e6f0e8fca0d 225 )
TickTock 109:3e6f0e8fca0d 226 {
TickTock 109:3e6f0e8fca0d 227 if (res != FR_NOT_ENABLED &&
TickTock 109:3e6f0e8fca0d 228 res != FR_INVALID_DRIVE &&
TickTock 109:3e6f0e8fca0d 229 res != FR_INVALID_OBJECT &&
TickTock 109:3e6f0e8fca0d 230 res != FR_TIMEOUT) {
TickTock 109:3e6f0e8fca0d 231 ff_rel_grant(fs->sobj);
TickTock 109:3e6f0e8fca0d 232 }
TickTock 109:3e6f0e8fca0d 233 }
TickTock 109:3e6f0e8fca0d 234 #endif
TickTock 109:3e6f0e8fca0d 235
TickTock 109:3e6f0e8fca0d 236
TickTock 109:3e6f0e8fca0d 237
TickTock 109:3e6f0e8fca0d 238 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 239 /* Change window offset */
TickTock 109:3e6f0e8fca0d 240 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 241
TickTock 109:3e6f0e8fca0d 242 static
TickTock 109:3e6f0e8fca0d 243 FRESULT move_window (
TickTock 109:3e6f0e8fca0d 244 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 245 DWORD sector /* Sector number to make apperance in the fs->win[] */
TickTock 109:3e6f0e8fca0d 246 ) /* Move to zero only writes back dirty window */
TickTock 109:3e6f0e8fca0d 247 {
TickTock 109:3e6f0e8fca0d 248 DWORD wsect;
TickTock 109:3e6f0e8fca0d 249
TickTock 109:3e6f0e8fca0d 250
TickTock 109:3e6f0e8fca0d 251 wsect = fs->winsect;
TickTock 109:3e6f0e8fca0d 252 if (wsect != sector) { /* Changed current window */
TickTock 109:3e6f0e8fca0d 253 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 254 if (fs->wflag) { /* Write back dirty window if needed */
TickTock 109:3e6f0e8fca0d 255 if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 256 return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 257 fs->wflag = 0;
TickTock 109:3e6f0e8fca0d 258 if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */
TickTock 109:3e6f0e8fca0d 259 BYTE nf;
TickTock 109:3e6f0e8fca0d 260 for (nf = fs->n_fats; nf > 1; nf--) { /* Refrect the change to all FAT copies */
TickTock 109:3e6f0e8fca0d 261 wsect += fs->sects_fat;
TickTock 109:3e6f0e8fca0d 262 disk_write(fs->drive, fs->win, wsect, 1);
TickTock 109:3e6f0e8fca0d 263 }
TickTock 109:3e6f0e8fca0d 264 }
TickTock 109:3e6f0e8fca0d 265 }
TickTock 109:3e6f0e8fca0d 266 #endif
TickTock 109:3e6f0e8fca0d 267 if (sector) {
TickTock 109:3e6f0e8fca0d 268 if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 269 return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 270 fs->winsect = sector;
TickTock 109:3e6f0e8fca0d 271 }
TickTock 109:3e6f0e8fca0d 272 }
TickTock 109:3e6f0e8fca0d 273
TickTock 109:3e6f0e8fca0d 274 return FR_OK;
TickTock 109:3e6f0e8fca0d 275 }
TickTock 109:3e6f0e8fca0d 276
TickTock 109:3e6f0e8fca0d 277
TickTock 109:3e6f0e8fca0d 278
TickTock 109:3e6f0e8fca0d 279
TickTock 109:3e6f0e8fca0d 280 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 281 /* Clean-up cached data */
TickTock 109:3e6f0e8fca0d 282 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 283 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 284 static
TickTock 109:3e6f0e8fca0d 285 FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */
TickTock 109:3e6f0e8fca0d 286 FATFS *fs /* File system object */
TickTock 109:3e6f0e8fca0d 287 )
TickTock 109:3e6f0e8fca0d 288 {
TickTock 109:3e6f0e8fca0d 289 FRESULT res;
TickTock 109:3e6f0e8fca0d 290
TickTock 109:3e6f0e8fca0d 291
TickTock 109:3e6f0e8fca0d 292 res = move_window(fs, 0);
TickTock 109:3e6f0e8fca0d 293 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 294 /* Update FSInfo sector if needed */
TickTock 109:3e6f0e8fca0d 295 if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
TickTock 109:3e6f0e8fca0d 296 fs->winsect = 0;
TickTock 109:3e6f0e8fca0d 297 mem_set(fs->win, 0, 512);
TickTock 109:3e6f0e8fca0d 298 ST_WORD(fs->win+BS_55AA, 0xAA55);
TickTock 109:3e6f0e8fca0d 299 ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
TickTock 109:3e6f0e8fca0d 300 ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
TickTock 109:3e6f0e8fca0d 301 ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
TickTock 109:3e6f0e8fca0d 302 ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
TickTock 109:3e6f0e8fca0d 303 disk_write(fs->drive, fs->win, fs->fsi_sector, 1);
TickTock 109:3e6f0e8fca0d 304 fs->fsi_flag = 0;
TickTock 109:3e6f0e8fca0d 305 }
TickTock 109:3e6f0e8fca0d 306 /* Make sure that no pending write process in the physical drive */
TickTock 109:3e6f0e8fca0d 307 if (disk_ioctl(fs->drive, CTRL_SYNC, (void*)NULL) != RES_OK)
TickTock 109:3e6f0e8fca0d 308 res = FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 309 }
TickTock 109:3e6f0e8fca0d 310
TickTock 109:3e6f0e8fca0d 311 return res;
TickTock 109:3e6f0e8fca0d 312 }
TickTock 109:3e6f0e8fca0d 313 #endif
TickTock 109:3e6f0e8fca0d 314
TickTock 109:3e6f0e8fca0d 315
TickTock 109:3e6f0e8fca0d 316
TickTock 109:3e6f0e8fca0d 317
TickTock 109:3e6f0e8fca0d 318 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 319 /* FAT access - Read value of a FAT entry */
TickTock 109:3e6f0e8fca0d 320 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 321
TickTock 109:3e6f0e8fca0d 322
TickTock 109:3e6f0e8fca0d 323 DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Interal error, Else:Cluster status */
TickTock 109:3e6f0e8fca0d 324 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 325 DWORD clst /* Cluster# to get the link information */
TickTock 109:3e6f0e8fca0d 326 )
TickTock 109:3e6f0e8fca0d 327 {
TickTock 109:3e6f0e8fca0d 328 UINT wc, bc;
TickTock 109:3e6f0e8fca0d 329 DWORD fsect;
TickTock 109:3e6f0e8fca0d 330
TickTock 109:3e6f0e8fca0d 331
TickTock 109:3e6f0e8fca0d 332 if (clst < 2 || clst >= fs->max_clust) /* Range check */
TickTock 109:3e6f0e8fca0d 333 return 1;
TickTock 109:3e6f0e8fca0d 334
TickTock 109:3e6f0e8fca0d 335 fsect = fs->fatbase;
TickTock 109:3e6f0e8fca0d 336 switch (fs->fs_type) {
TickTock 109:3e6f0e8fca0d 337 case FS_FAT12 :
TickTock 109:3e6f0e8fca0d 338 bc = clst; bc += bc / 2;
TickTock 109:3e6f0e8fca0d 339 if (move_window(fs, fsect + (bc / SS(fs)))) break;
TickTock 109:3e6f0e8fca0d 340 wc = fs->win[bc & (SS(fs) - 1)]; bc++;
TickTock 109:3e6f0e8fca0d 341 if (move_window(fs, fsect + (bc / SS(fs)))) break;
TickTock 109:3e6f0e8fca0d 342 wc |= (WORD)fs->win[bc & (SS(fs) - 1)] << 8;
TickTock 109:3e6f0e8fca0d 343 return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
TickTock 109:3e6f0e8fca0d 344
TickTock 109:3e6f0e8fca0d 345 case FS_FAT16 :
TickTock 109:3e6f0e8fca0d 346 if (move_window(fs, fsect + (clst / (SS(fs) / 2)))) break;
TickTock 109:3e6f0e8fca0d 347 return LD_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)]);
TickTock 109:3e6f0e8fca0d 348
TickTock 109:3e6f0e8fca0d 349 case FS_FAT32 :
TickTock 109:3e6f0e8fca0d 350 if (move_window(fs, fsect + (clst / (SS(fs) / 4)))) break;
TickTock 109:3e6f0e8fca0d 351 return LD_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF;
TickTock 109:3e6f0e8fca0d 352 }
TickTock 109:3e6f0e8fca0d 353
TickTock 109:3e6f0e8fca0d 354 return 0xFFFFFFFF; /* An error occured at the disk I/O layer */
TickTock 109:3e6f0e8fca0d 355 }
TickTock 109:3e6f0e8fca0d 356
TickTock 109:3e6f0e8fca0d 357
TickTock 109:3e6f0e8fca0d 358
TickTock 109:3e6f0e8fca0d 359
TickTock 109:3e6f0e8fca0d 360 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 361 /* FAT access - Change value of a FAT entry */
TickTock 109:3e6f0e8fca0d 362 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 363 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 364
TickTock 109:3e6f0e8fca0d 365 FRESULT put_fat (
TickTock 109:3e6f0e8fca0d 366 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 367 DWORD clst, /* Cluster# to be changed in range of 2 to fs->max_clust - 1 */
TickTock 109:3e6f0e8fca0d 368 DWORD val /* New value to mark the cluster */
TickTock 109:3e6f0e8fca0d 369 )
TickTock 109:3e6f0e8fca0d 370 {
TickTock 109:3e6f0e8fca0d 371 UINT bc;
TickTock 109:3e6f0e8fca0d 372 BYTE *p;
TickTock 109:3e6f0e8fca0d 373 DWORD fsect;
TickTock 109:3e6f0e8fca0d 374 FRESULT res;
TickTock 109:3e6f0e8fca0d 375
TickTock 109:3e6f0e8fca0d 376
TickTock 109:3e6f0e8fca0d 377 if (clst < 2 || clst >= fs->max_clust) { /* Range check */
TickTock 109:3e6f0e8fca0d 378 res = FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 379
TickTock 109:3e6f0e8fca0d 380 } else {
TickTock 109:3e6f0e8fca0d 381 fsect = fs->fatbase;
TickTock 109:3e6f0e8fca0d 382 switch (fs->fs_type) {
TickTock 109:3e6f0e8fca0d 383 case FS_FAT12 :
TickTock 109:3e6f0e8fca0d 384 bc = clst; bc += bc / 2;
TickTock 109:3e6f0e8fca0d 385 res = move_window(fs, fsect + (bc / SS(fs)));
TickTock 109:3e6f0e8fca0d 386 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 387 p = &fs->win[bc & (SS(fs) - 1)];
TickTock 109:3e6f0e8fca0d 388 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
TickTock 109:3e6f0e8fca0d 389 bc++;
TickTock 109:3e6f0e8fca0d 390 fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 391 res = move_window(fs, fsect + (bc / SS(fs)));
TickTock 109:3e6f0e8fca0d 392 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 393 p = &fs->win[bc & (SS(fs) - 1)];
TickTock 109:3e6f0e8fca0d 394 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
TickTock 109:3e6f0e8fca0d 395 break;
TickTock 109:3e6f0e8fca0d 396
TickTock 109:3e6f0e8fca0d 397 case FS_FAT16 :
TickTock 109:3e6f0e8fca0d 398 res = move_window(fs, fsect + (clst / (SS(fs) / 2)));
TickTock 109:3e6f0e8fca0d 399 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 400 ST_WORD(&fs->win[((WORD)clst * 2) & (SS(fs) - 1)], (WORD)val);
TickTock 109:3e6f0e8fca0d 401 break;
TickTock 109:3e6f0e8fca0d 402
TickTock 109:3e6f0e8fca0d 403 case FS_FAT32 :
TickTock 109:3e6f0e8fca0d 404 res = move_window(fs, fsect + (clst / (SS(fs) / 4)));
TickTock 109:3e6f0e8fca0d 405 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 406 ST_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)], val);
TickTock 109:3e6f0e8fca0d 407 break;
TickTock 109:3e6f0e8fca0d 408
TickTock 109:3e6f0e8fca0d 409 default :
TickTock 109:3e6f0e8fca0d 410 res = FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 411 }
TickTock 109:3e6f0e8fca0d 412 fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 413 }
TickTock 109:3e6f0e8fca0d 414
TickTock 109:3e6f0e8fca0d 415 return res;
TickTock 109:3e6f0e8fca0d 416 }
TickTock 109:3e6f0e8fca0d 417 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 418
TickTock 109:3e6f0e8fca0d 419
TickTock 109:3e6f0e8fca0d 420
TickTock 109:3e6f0e8fca0d 421
TickTock 109:3e6f0e8fca0d 422 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 423 /* FAT handling - Remove a cluster chain */
TickTock 109:3e6f0e8fca0d 424 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 425 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 426 static
TickTock 109:3e6f0e8fca0d 427 FRESULT remove_chain (
TickTock 109:3e6f0e8fca0d 428 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 429 DWORD clst /* Cluster# to remove a chain from */
TickTock 109:3e6f0e8fca0d 430 )
TickTock 109:3e6f0e8fca0d 431 {
TickTock 109:3e6f0e8fca0d 432 FRESULT res;
TickTock 109:3e6f0e8fca0d 433 DWORD nxt;
TickTock 109:3e6f0e8fca0d 434
TickTock 109:3e6f0e8fca0d 435
TickTock 109:3e6f0e8fca0d 436 if (clst < 2 || clst >= fs->max_clust) { /* Check the range of cluster# */
TickTock 109:3e6f0e8fca0d 437 res = FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 438
TickTock 109:3e6f0e8fca0d 439 } else {
TickTock 109:3e6f0e8fca0d 440 res = FR_OK;
TickTock 109:3e6f0e8fca0d 441 while (clst < fs->max_clust) { /* Not a last link? */
TickTock 109:3e6f0e8fca0d 442 nxt = get_fat(fs, clst); /* Get cluster status */
TickTock 109:3e6f0e8fca0d 443 if (nxt == 0) break; /* Empty cluster? */
TickTock 109:3e6f0e8fca0d 444 if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */
TickTock 109:3e6f0e8fca0d 445 if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */
TickTock 109:3e6f0e8fca0d 446 res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
TickTock 109:3e6f0e8fca0d 447 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 448 if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
TickTock 109:3e6f0e8fca0d 449 fs->free_clust++;
TickTock 109:3e6f0e8fca0d 450 fs->fsi_flag = 1;
TickTock 109:3e6f0e8fca0d 451 }
TickTock 109:3e6f0e8fca0d 452 clst = nxt; /* Next cluster */
TickTock 109:3e6f0e8fca0d 453 }
TickTock 109:3e6f0e8fca0d 454 }
TickTock 109:3e6f0e8fca0d 455
TickTock 109:3e6f0e8fca0d 456 return res;
TickTock 109:3e6f0e8fca0d 457 }
TickTock 109:3e6f0e8fca0d 458 #endif
TickTock 109:3e6f0e8fca0d 459
TickTock 109:3e6f0e8fca0d 460
TickTock 109:3e6f0e8fca0d 461
TickTock 109:3e6f0e8fca0d 462
TickTock 109:3e6f0e8fca0d 463 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 464 /* FAT handling - Stretch or Create a cluster chain */
TickTock 109:3e6f0e8fca0d 465 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 466 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 467 static
TickTock 109:3e6f0e8fca0d 468 DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
TickTock 109:3e6f0e8fca0d 469 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 470 DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
TickTock 109:3e6f0e8fca0d 471 )
TickTock 109:3e6f0e8fca0d 472 {
TickTock 109:3e6f0e8fca0d 473 DWORD cs, ncl, scl, mcl;
TickTock 109:3e6f0e8fca0d 474
TickTock 109:3e6f0e8fca0d 475
TickTock 109:3e6f0e8fca0d 476 mcl = fs->max_clust;
TickTock 109:3e6f0e8fca0d 477 if (clst == 0) { /* Create new chain */
TickTock 109:3e6f0e8fca0d 478 scl = fs->last_clust; /* Get suggested start point */
TickTock 109:3e6f0e8fca0d 479 if (scl == 0 || scl >= mcl) scl = 1;
TickTock 109:3e6f0e8fca0d 480 }
TickTock 109:3e6f0e8fca0d 481 else { /* Stretch existing chain */
TickTock 109:3e6f0e8fca0d 482 cs = get_fat(fs, clst); /* Check the cluster status */
TickTock 109:3e6f0e8fca0d 483 if (cs < 2) return 1; /* It is an invalid cluster */
TickTock 109:3e6f0e8fca0d 484 if (cs < mcl) return cs; /* It is already followed by next cluster */
TickTock 109:3e6f0e8fca0d 485 scl = clst;
TickTock 109:3e6f0e8fca0d 486 }
TickTock 109:3e6f0e8fca0d 487
TickTock 109:3e6f0e8fca0d 488 ncl = scl; /* Start cluster */
TickTock 109:3e6f0e8fca0d 489 for (;;) {
TickTock 109:3e6f0e8fca0d 490 ncl++; /* Next cluster */
TickTock 109:3e6f0e8fca0d 491 if (ncl >= mcl) { /* Wrap around */
TickTock 109:3e6f0e8fca0d 492 ncl = 2;
TickTock 109:3e6f0e8fca0d 493 if (ncl > scl) return 0; /* No free custer */
TickTock 109:3e6f0e8fca0d 494 }
TickTock 109:3e6f0e8fca0d 495 cs = get_fat(fs, ncl); /* Get the cluster status */
TickTock 109:3e6f0e8fca0d 496 if (cs == 0) break; /* Found a free cluster */
TickTock 109:3e6f0e8fca0d 497 if (cs == 0xFFFFFFFF || cs == 1)/* An error occured */
TickTock 109:3e6f0e8fca0d 498 return cs;
TickTock 109:3e6f0e8fca0d 499 if (ncl == scl) return 0; /* No free custer */
TickTock 109:3e6f0e8fca0d 500 }
TickTock 109:3e6f0e8fca0d 501
TickTock 109:3e6f0e8fca0d 502 if (put_fat(fs, ncl, 0x0FFFFFFF)) /* Mark the new cluster "in use" */
TickTock 109:3e6f0e8fca0d 503 return 0xFFFFFFFF;
TickTock 109:3e6f0e8fca0d 504 if (clst != 0) { /* Link it to the previous one if needed */
TickTock 109:3e6f0e8fca0d 505 if (put_fat(fs, clst, ncl))
TickTock 109:3e6f0e8fca0d 506 return 0xFFFFFFFF;
TickTock 109:3e6f0e8fca0d 507 }
TickTock 109:3e6f0e8fca0d 508
TickTock 109:3e6f0e8fca0d 509 fs->last_clust = ncl; /* Update FSINFO */
TickTock 109:3e6f0e8fca0d 510 if (fs->free_clust != 0xFFFFFFFF) {
TickTock 109:3e6f0e8fca0d 511 fs->free_clust--;
TickTock 109:3e6f0e8fca0d 512 fs->fsi_flag = 1;
TickTock 109:3e6f0e8fca0d 513 }
TickTock 109:3e6f0e8fca0d 514
TickTock 109:3e6f0e8fca0d 515 return ncl; /* Return new cluster number */
TickTock 109:3e6f0e8fca0d 516 }
TickTock 109:3e6f0e8fca0d 517 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 518
TickTock 109:3e6f0e8fca0d 519
TickTock 109:3e6f0e8fca0d 520
TickTock 109:3e6f0e8fca0d 521
TickTock 109:3e6f0e8fca0d 522 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 523 /* Get sector# from cluster# */
TickTock 109:3e6f0e8fca0d 524 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 525
TickTock 109:3e6f0e8fca0d 526
TickTock 109:3e6f0e8fca0d 527 DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
TickTock 109:3e6f0e8fca0d 528 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 529 DWORD clst /* Cluster# to be converted */
TickTock 109:3e6f0e8fca0d 530 )
TickTock 109:3e6f0e8fca0d 531 {
TickTock 109:3e6f0e8fca0d 532 clst -= 2;
TickTock 109:3e6f0e8fca0d 533 if (clst >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */
TickTock 109:3e6f0e8fca0d 534 return clst * fs->csize + fs->database;
TickTock 109:3e6f0e8fca0d 535 }
TickTock 109:3e6f0e8fca0d 536
TickTock 109:3e6f0e8fca0d 537
TickTock 109:3e6f0e8fca0d 538
TickTock 109:3e6f0e8fca0d 539
TickTock 109:3e6f0e8fca0d 540 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 541 /* Directory handling - Seek directory index */
TickTock 109:3e6f0e8fca0d 542 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 543
TickTock 109:3e6f0e8fca0d 544 static
TickTock 109:3e6f0e8fca0d 545 FRESULT dir_seek (
TickTock 109:3e6f0e8fca0d 546 eDIR *dj, /* Pointer to directory object */
TickTock 109:3e6f0e8fca0d 547 WORD idx /* Directory index number */
TickTock 109:3e6f0e8fca0d 548 )
TickTock 109:3e6f0e8fca0d 549 {
TickTock 109:3e6f0e8fca0d 550 DWORD clst;
TickTock 109:3e6f0e8fca0d 551 WORD ic;
TickTock 109:3e6f0e8fca0d 552
TickTock 109:3e6f0e8fca0d 553
TickTock 109:3e6f0e8fca0d 554 dj->index = idx;
TickTock 109:3e6f0e8fca0d 555 clst = dj->sclust;
TickTock 109:3e6f0e8fca0d 556 if (clst == 1 || clst >= dj->fs->max_clust) /* Check start cluster range */
TickTock 109:3e6f0e8fca0d 557 return FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 558 if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
TickTock 109:3e6f0e8fca0d 559 clst = dj->fs->dirbase;
TickTock 109:3e6f0e8fca0d 560
TickTock 109:3e6f0e8fca0d 561 if (clst == 0) { /* Static table */
TickTock 109:3e6f0e8fca0d 562 dj->clust = clst;
TickTock 109:3e6f0e8fca0d 563 if (idx >= dj->fs->n_rootdir) /* Index is out of range */
TickTock 109:3e6f0e8fca0d 564 return FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 565 dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32); /* Sector# */
TickTock 109:3e6f0e8fca0d 566 }
TickTock 109:3e6f0e8fca0d 567 else { /* Dynamic table */
TickTock 109:3e6f0e8fca0d 568 ic = SS(dj->fs) / 32 * dj->fs->csize; /* Entries per cluster */
TickTock 109:3e6f0e8fca0d 569 while (idx >= ic) { /* Follow cluster chain */
TickTock 109:3e6f0e8fca0d 570 clst = get_fat(dj->fs, clst); /* Get next cluster */
TickTock 109:3e6f0e8fca0d 571 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */
TickTock 109:3e6f0e8fca0d 572 if (clst < 2 || clst >= dj->fs->max_clust) /* Reached to end of table or int error */
TickTock 109:3e6f0e8fca0d 573 return FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 574 idx -= ic;
TickTock 109:3e6f0e8fca0d 575 }
TickTock 109:3e6f0e8fca0d 576 dj->clust = clst;
TickTock 109:3e6f0e8fca0d 577 dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32); /* Sector# */
TickTock 109:3e6f0e8fca0d 578 }
TickTock 109:3e6f0e8fca0d 579
TickTock 109:3e6f0e8fca0d 580 dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */
TickTock 109:3e6f0e8fca0d 581
TickTock 109:3e6f0e8fca0d 582 return FR_OK; /* Seek succeeded */
TickTock 109:3e6f0e8fca0d 583 }
TickTock 109:3e6f0e8fca0d 584
TickTock 109:3e6f0e8fca0d 585
TickTock 109:3e6f0e8fca0d 586
TickTock 109:3e6f0e8fca0d 587
TickTock 109:3e6f0e8fca0d 588 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 589 /* Directory handling - Move directory index next */
TickTock 109:3e6f0e8fca0d 590 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 591
TickTock 109:3e6f0e8fca0d 592 static
TickTock 109:3e6f0e8fca0d 593 FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */
TickTock 109:3e6f0e8fca0d 594 eDIR *dj, /* Pointer to directory object */
TickTock 109:3e6f0e8fca0d 595 BOOL streach /* FALSE: Do not streach table, TRUE: Streach table if needed */
TickTock 109:3e6f0e8fca0d 596 )
TickTock 109:3e6f0e8fca0d 597 {
TickTock 109:3e6f0e8fca0d 598 DWORD clst;
TickTock 109:3e6f0e8fca0d 599 WORD i;
TickTock 109:3e6f0e8fca0d 600
TickTock 109:3e6f0e8fca0d 601
TickTock 109:3e6f0e8fca0d 602 i = dj->index + 1;
TickTock 109:3e6f0e8fca0d 603 if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
TickTock 109:3e6f0e8fca0d 604 return FR_NO_FILE;
TickTock 109:3e6f0e8fca0d 605
TickTock 109:3e6f0e8fca0d 606 if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */
TickTock 109:3e6f0e8fca0d 607 dj->sect++; /* Next sector */
TickTock 109:3e6f0e8fca0d 608
TickTock 109:3e6f0e8fca0d 609 if (dj->clust == 0) { /* Static table */
TickTock 109:3e6f0e8fca0d 610 if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
TickTock 109:3e6f0e8fca0d 611 return FR_NO_FILE;
TickTock 109:3e6f0e8fca0d 612 }
TickTock 109:3e6f0e8fca0d 613 else { /* Dynamic table */
TickTock 109:3e6f0e8fca0d 614 if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
TickTock 109:3e6f0e8fca0d 615 clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
TickTock 109:3e6f0e8fca0d 616 if (clst <= 1) return FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 617 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 618 if (clst >= dj->fs->max_clust) { /* When it reached end of dynamic table */
TickTock 109:3e6f0e8fca0d 619 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 620 BYTE c;
TickTock 109:3e6f0e8fca0d 621 if (!streach) return FR_NO_FILE; /* When do not streach, report EOT */
TickTock 109:3e6f0e8fca0d 622 clst = create_chain(dj->fs, dj->clust); /* Streach cluster chain */
TickTock 109:3e6f0e8fca0d 623 if (clst == 0) return FR_DENIED; /* No free cluster */
TickTock 109:3e6f0e8fca0d 624 if (clst == 1) return FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 625 if (clst == 0xFFFFFFFF) return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 626 /* Clean-up streached table */
TickTock 109:3e6f0e8fca0d 627 if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */
TickTock 109:3e6f0e8fca0d 628 mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
TickTock 109:3e6f0e8fca0d 629 dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
TickTock 109:3e6f0e8fca0d 630 for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */
TickTock 109:3e6f0e8fca0d 631 dj->fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 632 if (move_window(dj->fs, 0)) return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 633 dj->fs->winsect++;
TickTock 109:3e6f0e8fca0d 634 }
TickTock 109:3e6f0e8fca0d 635 dj->fs->winsect -= c; /* Rewind window address */
TickTock 109:3e6f0e8fca0d 636 #else
TickTock 109:3e6f0e8fca0d 637 return FR_NO_FILE; /* Report EOT */
TickTock 109:3e6f0e8fca0d 638 #endif
TickTock 109:3e6f0e8fca0d 639 }
TickTock 109:3e6f0e8fca0d 640 dj->clust = clst; /* Initialize data for new cluster */
TickTock 109:3e6f0e8fca0d 641 dj->sect = clust2sect(dj->fs, clst);
TickTock 109:3e6f0e8fca0d 642 }
TickTock 109:3e6f0e8fca0d 643 }
TickTock 109:3e6f0e8fca0d 644 }
TickTock 109:3e6f0e8fca0d 645
TickTock 109:3e6f0e8fca0d 646 dj->index = i;
TickTock 109:3e6f0e8fca0d 647 dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32;
TickTock 109:3e6f0e8fca0d 648
TickTock 109:3e6f0e8fca0d 649 return FR_OK;
TickTock 109:3e6f0e8fca0d 650 }
TickTock 109:3e6f0e8fca0d 651
TickTock 109:3e6f0e8fca0d 652
TickTock 109:3e6f0e8fca0d 653
TickTock 109:3e6f0e8fca0d 654
TickTock 109:3e6f0e8fca0d 655 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 656 /* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */
TickTock 109:3e6f0e8fca0d 657 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 658 #if _USE_LFN
TickTock 109:3e6f0e8fca0d 659 static
TickTock 109:3e6f0e8fca0d 660 const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */
TickTock 109:3e6f0e8fca0d 661
TickTock 109:3e6f0e8fca0d 662
TickTock 109:3e6f0e8fca0d 663 static
TickTock 109:3e6f0e8fca0d 664 BOOL cmp_lfn ( /* TRUE:Matched, FALSE:Not matched */
TickTock 109:3e6f0e8fca0d 665 WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
TickTock 109:3e6f0e8fca0d 666 BYTE *dir /* Pointer to the directory entry containing a part of LFN */
TickTock 109:3e6f0e8fca0d 667 )
TickTock 109:3e6f0e8fca0d 668 {
TickTock 109:3e6f0e8fca0d 669 int i, s;
TickTock 109:3e6f0e8fca0d 670 WCHAR wc, uc;
TickTock 109:3e6f0e8fca0d 671
TickTock 109:3e6f0e8fca0d 672
TickTock 109:3e6f0e8fca0d 673 i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Get offset in the LFN buffer */
TickTock 109:3e6f0e8fca0d 674 s = 0; wc = 1;
TickTock 109:3e6f0e8fca0d 675 do {
TickTock 109:3e6f0e8fca0d 676 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
TickTock 109:3e6f0e8fca0d 677 if (wc) { /* Last char has not been processed */
TickTock 109:3e6f0e8fca0d 678 wc = ff_wtoupper(uc); /* Convert it to upper case */
TickTock 109:3e6f0e8fca0d 679 if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
TickTock 109:3e6f0e8fca0d 680 return FALSE; /* Not matched */
TickTock 109:3e6f0e8fca0d 681 } else {
TickTock 109:3e6f0e8fca0d 682 if (uc != 0xFFFF) return FALSE; /* Check filler */
TickTock 109:3e6f0e8fca0d 683 }
TickTock 109:3e6f0e8fca0d 684 } while (++s < 13); /* Repeat until all chars in the entry are checked */
TickTock 109:3e6f0e8fca0d 685
TickTock 109:3e6f0e8fca0d 686 if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i]) /* Last segment matched but different length */
TickTock 109:3e6f0e8fca0d 687 return FALSE;
TickTock 109:3e6f0e8fca0d 688
TickTock 109:3e6f0e8fca0d 689 return TRUE; /* The part of LFN matched */
TickTock 109:3e6f0e8fca0d 690 }
TickTock 109:3e6f0e8fca0d 691
TickTock 109:3e6f0e8fca0d 692
TickTock 109:3e6f0e8fca0d 693
TickTock 109:3e6f0e8fca0d 694 static
TickTock 109:3e6f0e8fca0d 695 BOOL pick_lfn ( /* TRUE:Succeeded, FALSE:Buffer overflow */
TickTock 109:3e6f0e8fca0d 696 WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
TickTock 109:3e6f0e8fca0d 697 BYTE *dir /* Pointer to the directory entry */
TickTock 109:3e6f0e8fca0d 698 )
TickTock 109:3e6f0e8fca0d 699 {
TickTock 109:3e6f0e8fca0d 700 int i, s;
TickTock 109:3e6f0e8fca0d 701 WCHAR wc, uc;
TickTock 109:3e6f0e8fca0d 702
TickTock 109:3e6f0e8fca0d 703
TickTock 109:3e6f0e8fca0d 704 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
TickTock 109:3e6f0e8fca0d 705
TickTock 109:3e6f0e8fca0d 706 s = 0; wc = 1;
TickTock 109:3e6f0e8fca0d 707 do {
TickTock 109:3e6f0e8fca0d 708 uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */
TickTock 109:3e6f0e8fca0d 709 if (wc) { /* Last char has not been processed */
TickTock 109:3e6f0e8fca0d 710 if (i >= _MAX_LFN) return FALSE; /* Buffer overflow? */
TickTock 109:3e6f0e8fca0d 711 lfnbuf[i++] = wc = uc; /* Store it */
TickTock 109:3e6f0e8fca0d 712 } else {
TickTock 109:3e6f0e8fca0d 713 if (uc != 0xFFFF) return FALSE; /* Check filler */
TickTock 109:3e6f0e8fca0d 714 }
TickTock 109:3e6f0e8fca0d 715 } while (++s < 13); /* Read all character in the entry */
TickTock 109:3e6f0e8fca0d 716
TickTock 109:3e6f0e8fca0d 717 if (dir[LDIR_Ord] & 0x40) { /* Put terminator if it is the last LFN part */
TickTock 109:3e6f0e8fca0d 718 if (i >= _MAX_LFN) return FALSE; /* Buffer overflow? */
TickTock 109:3e6f0e8fca0d 719 lfnbuf[i] = 0;
TickTock 109:3e6f0e8fca0d 720 }
TickTock 109:3e6f0e8fca0d 721
TickTock 109:3e6f0e8fca0d 722 return TRUE;
TickTock 109:3e6f0e8fca0d 723 }
TickTock 109:3e6f0e8fca0d 724
TickTock 109:3e6f0e8fca0d 725
TickTock 109:3e6f0e8fca0d 726 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 727 static
TickTock 109:3e6f0e8fca0d 728 void fit_lfn (
TickTock 109:3e6f0e8fca0d 729 const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
TickTock 109:3e6f0e8fca0d 730 BYTE *dir, /* Pointer to the directory entry */
TickTock 109:3e6f0e8fca0d 731 BYTE ord, /* LFN order (1-20) */
TickTock 109:3e6f0e8fca0d 732 BYTE sum /* SFN sum */
TickTock 109:3e6f0e8fca0d 733 )
TickTock 109:3e6f0e8fca0d 734 {
TickTock 109:3e6f0e8fca0d 735 int i, s;
TickTock 109:3e6f0e8fca0d 736 WCHAR wc;
TickTock 109:3e6f0e8fca0d 737
TickTock 109:3e6f0e8fca0d 738
TickTock 109:3e6f0e8fca0d 739 dir[LDIR_Chksum] = sum; /* Set check sum */
TickTock 109:3e6f0e8fca0d 740 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
TickTock 109:3e6f0e8fca0d 741 dir[LDIR_Type] = 0;
TickTock 109:3e6f0e8fca0d 742 ST_WORD(dir+LDIR_FstClusLO, 0);
TickTock 109:3e6f0e8fca0d 743
TickTock 109:3e6f0e8fca0d 744 i = (ord - 1) * 13; /* Get offset in the LFN buffer */
TickTock 109:3e6f0e8fca0d 745 s = wc = 0;
TickTock 109:3e6f0e8fca0d 746 do {
TickTock 109:3e6f0e8fca0d 747 if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */
TickTock 109:3e6f0e8fca0d 748 ST_WORD(dir+LfnOfs[s], wc); /* Put it */
TickTock 109:3e6f0e8fca0d 749 if (!wc) wc = 0xFFFF; /* Padding chars following last char */
TickTock 109:3e6f0e8fca0d 750 } while (++s < 13);
TickTock 109:3e6f0e8fca0d 751 if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40; /* Bottom LFN part is the start of LFN sequence */
TickTock 109:3e6f0e8fca0d 752 dir[LDIR_Ord] = ord; /* Set the LFN order */
TickTock 109:3e6f0e8fca0d 753 }
TickTock 109:3e6f0e8fca0d 754
TickTock 109:3e6f0e8fca0d 755 #endif
TickTock 109:3e6f0e8fca0d 756 #endif
TickTock 109:3e6f0e8fca0d 757
TickTock 109:3e6f0e8fca0d 758
TickTock 109:3e6f0e8fca0d 759
TickTock 109:3e6f0e8fca0d 760 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 761 /* Create numbered name */
TickTock 109:3e6f0e8fca0d 762 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 763 #if _USE_LFN
TickTock 109:3e6f0e8fca0d 764 void gen_numname (
TickTock 109:3e6f0e8fca0d 765 BYTE *dst, /* Pointer to genartated SFN */
TickTock 109:3e6f0e8fca0d 766 const BYTE *src, /* Pointer to source SFN to be modified */
TickTock 109:3e6f0e8fca0d 767 const WCHAR *lfn, /* Pointer to LFN */
TickTock 109:3e6f0e8fca0d 768 WORD num /* Sequense number */
TickTock 109:3e6f0e8fca0d 769 )
TickTock 109:3e6f0e8fca0d 770 {
TickTock 109:3e6f0e8fca0d 771 char ns[8];
TickTock 109:3e6f0e8fca0d 772 int i, j;
TickTock 109:3e6f0e8fca0d 773
TickTock 109:3e6f0e8fca0d 774
TickTock 109:3e6f0e8fca0d 775 mem_cpy(dst, src, 11);
TickTock 109:3e6f0e8fca0d 776
TickTock 109:3e6f0e8fca0d 777 if (num > 5) { /* On many collisions, generate a hash number instead of sequencial number */
TickTock 109:3e6f0e8fca0d 778 do num = (num >> 1) + (num << 15) + (WORD)*lfn++; while (*lfn);
TickTock 109:3e6f0e8fca0d 779 }
TickTock 109:3e6f0e8fca0d 780
TickTock 109:3e6f0e8fca0d 781 /* itoa */
TickTock 109:3e6f0e8fca0d 782 i = 7;
TickTock 109:3e6f0e8fca0d 783 do {
TickTock 109:3e6f0e8fca0d 784 ns[i--] = (num % 10) + '0';
TickTock 109:3e6f0e8fca0d 785 num /= 10;
TickTock 109:3e6f0e8fca0d 786 } while (num);
TickTock 109:3e6f0e8fca0d 787 ns[i] = '~';
TickTock 109:3e6f0e8fca0d 788
TickTock 109:3e6f0e8fca0d 789 /* Append the number */
TickTock 109:3e6f0e8fca0d 790 for (j = 0; j < i && dst[j] != ' '; j++) {
TickTock 109:3e6f0e8fca0d 791 if (IsDBCS1(dst[j])) {
TickTock 109:3e6f0e8fca0d 792 if (j == i - 1) break;
TickTock 109:3e6f0e8fca0d 793 j++;
TickTock 109:3e6f0e8fca0d 794 }
TickTock 109:3e6f0e8fca0d 795 }
TickTock 109:3e6f0e8fca0d 796 do {
TickTock 109:3e6f0e8fca0d 797 dst[j++] = (i < 8) ? ns[i++] : ' ';
TickTock 109:3e6f0e8fca0d 798 } while (j < 8);
TickTock 109:3e6f0e8fca0d 799 }
TickTock 109:3e6f0e8fca0d 800 #endif
TickTock 109:3e6f0e8fca0d 801
TickTock 109:3e6f0e8fca0d 802
TickTock 109:3e6f0e8fca0d 803
TickTock 109:3e6f0e8fca0d 804
TickTock 109:3e6f0e8fca0d 805 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 806 /* Calculate sum of an SFN */
TickTock 109:3e6f0e8fca0d 807 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 808 #if _USE_LFN
TickTock 109:3e6f0e8fca0d 809 static
TickTock 109:3e6f0e8fca0d 810 BYTE sum_sfn (
TickTock 109:3e6f0e8fca0d 811 const BYTE *dir /* Ptr to directory entry */
TickTock 109:3e6f0e8fca0d 812 )
TickTock 109:3e6f0e8fca0d 813 {
TickTock 109:3e6f0e8fca0d 814 BYTE sum = 0;
TickTock 109:3e6f0e8fca0d 815 int n = 11;
TickTock 109:3e6f0e8fca0d 816
TickTock 109:3e6f0e8fca0d 817 do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
TickTock 109:3e6f0e8fca0d 818 return sum;
TickTock 109:3e6f0e8fca0d 819 }
TickTock 109:3e6f0e8fca0d 820 #endif
TickTock 109:3e6f0e8fca0d 821
TickTock 109:3e6f0e8fca0d 822
TickTock 109:3e6f0e8fca0d 823
TickTock 109:3e6f0e8fca0d 824
TickTock 109:3e6f0e8fca0d 825 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 826 /* Directory handling - Find an object in the directory */
TickTock 109:3e6f0e8fca0d 827 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 828
TickTock 109:3e6f0e8fca0d 829 static
TickTock 109:3e6f0e8fca0d 830 FRESULT dir_find (
TickTock 109:3e6f0e8fca0d 831 eDIR *dj /* Pointer to the directory object linked to the file name */
TickTock 109:3e6f0e8fca0d 832 )
TickTock 109:3e6f0e8fca0d 833 {
TickTock 109:3e6f0e8fca0d 834 FRESULT res;
TickTock 109:3e6f0e8fca0d 835 BYTE c, *dir;
TickTock 109:3e6f0e8fca0d 836 #if _USE_LFN
TickTock 109:3e6f0e8fca0d 837 BYTE a, ord, sum;
TickTock 109:3e6f0e8fca0d 838 #endif
TickTock 109:3e6f0e8fca0d 839
TickTock 109:3e6f0e8fca0d 840 res = dir_seek(dj, 0); /* Rewind directory object */
TickTock 109:3e6f0e8fca0d 841 if (res != FR_OK) return res;
TickTock 109:3e6f0e8fca0d 842
TickTock 109:3e6f0e8fca0d 843 #if _USE_LFN
TickTock 109:3e6f0e8fca0d 844 ord = sum = 0xFF;
TickTock 109:3e6f0e8fca0d 845 #endif
TickTock 109:3e6f0e8fca0d 846 do {
TickTock 109:3e6f0e8fca0d 847 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 848 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 849 dir = dj->dir; /* Ptr to the directory entry of current index */
TickTock 109:3e6f0e8fca0d 850 c = dir[DIR_Name];
TickTock 109:3e6f0e8fca0d 851 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
TickTock 109:3e6f0e8fca0d 852 #if _USE_LFN /* LFN configuration */
TickTock 109:3e6f0e8fca0d 853 a = dir[DIR_Attr] & AM_MASK;
TickTock 109:3e6f0e8fca0d 854 if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
TickTock 109:3e6f0e8fca0d 855 ord = 0xFF;
TickTock 109:3e6f0e8fca0d 856 } else {
TickTock 109:3e6f0e8fca0d 857 if (a == AM_LFN) { /* An LFN entry is found */
TickTock 109:3e6f0e8fca0d 858 if (dj->lfn) {
TickTock 109:3e6f0e8fca0d 859 if (c & 0x40) { /* Is it start of LFN sequence? */
TickTock 109:3e6f0e8fca0d 860 sum = dir[LDIR_Chksum];
TickTock 109:3e6f0e8fca0d 861 c &= 0xBF; ord = c; /* LFN start order */
TickTock 109:3e6f0e8fca0d 862 dj->lfn_idx = dj->index;
TickTock 109:3e6f0e8fca0d 863 }
TickTock 109:3e6f0e8fca0d 864 /* Check validity of the LFN entry and compare it with given name */
TickTock 109:3e6f0e8fca0d 865 ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
TickTock 109:3e6f0e8fca0d 866 }
TickTock 109:3e6f0e8fca0d 867 } else { /* An SFN entry is found */
TickTock 109:3e6f0e8fca0d 868 if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */
TickTock 109:3e6f0e8fca0d 869 ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */
TickTock 109:3e6f0e8fca0d 870 if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */
TickTock 109:3e6f0e8fca0d 871 }
TickTock 109:3e6f0e8fca0d 872 }
TickTock 109:3e6f0e8fca0d 873 #else /* Non LFN configuration */
TickTock 109:3e6f0e8fca0d 874 if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
TickTock 109:3e6f0e8fca0d 875 break;
TickTock 109:3e6f0e8fca0d 876 #endif
TickTock 109:3e6f0e8fca0d 877 res = dir_next(dj, FALSE); /* Next entry */
TickTock 109:3e6f0e8fca0d 878 } while (res == FR_OK);
TickTock 109:3e6f0e8fca0d 879
TickTock 109:3e6f0e8fca0d 880 return res;
TickTock 109:3e6f0e8fca0d 881 }
TickTock 109:3e6f0e8fca0d 882
TickTock 109:3e6f0e8fca0d 883
TickTock 109:3e6f0e8fca0d 884
TickTock 109:3e6f0e8fca0d 885
TickTock 109:3e6f0e8fca0d 886 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 887 /* Read an object from the directory */
TickTock 109:3e6f0e8fca0d 888 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 889 #if _FS_MINIMIZE <= 1
TickTock 109:3e6f0e8fca0d 890 static
TickTock 109:3e6f0e8fca0d 891 FRESULT dir_read (
TickTock 109:3e6f0e8fca0d 892 eDIR *dj /* Pointer to the directory object that pointing the entry to be read */
TickTock 109:3e6f0e8fca0d 893 )
TickTock 109:3e6f0e8fca0d 894 {
TickTock 109:3e6f0e8fca0d 895 FRESULT res;
TickTock 109:3e6f0e8fca0d 896 BYTE c, *dir;
TickTock 109:3e6f0e8fca0d 897 #if _USE_LFN
TickTock 109:3e6f0e8fca0d 898 BYTE a, ord = 0xFF, sum = 0xFF;
TickTock 109:3e6f0e8fca0d 899 #endif
TickTock 109:3e6f0e8fca0d 900
TickTock 109:3e6f0e8fca0d 901 res = FR_NO_FILE;
TickTock 109:3e6f0e8fca0d 902 while (dj->sect) {
TickTock 109:3e6f0e8fca0d 903 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 904 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 905 dir = dj->dir; /* Ptr to the directory entry of current index */
TickTock 109:3e6f0e8fca0d 906 c = dir[DIR_Name];
TickTock 109:3e6f0e8fca0d 907 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */
TickTock 109:3e6f0e8fca0d 908 #if _USE_LFN /* LFN configuration */
TickTock 109:3e6f0e8fca0d 909 a = dir[DIR_Attr] & AM_MASK;
TickTock 109:3e6f0e8fca0d 910 if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
TickTock 109:3e6f0e8fca0d 911 ord = 0xFF;
TickTock 109:3e6f0e8fca0d 912 } else {
TickTock 109:3e6f0e8fca0d 913 if (a == AM_LFN) { /* An LFN entry is found */
TickTock 109:3e6f0e8fca0d 914 if (c & 0x40) { /* Is it start of LFN sequence? */
TickTock 109:3e6f0e8fca0d 915 sum = dir[LDIR_Chksum];
TickTock 109:3e6f0e8fca0d 916 c &= 0xBF; ord = c;
TickTock 109:3e6f0e8fca0d 917 dj->lfn_idx = dj->index;
TickTock 109:3e6f0e8fca0d 918 }
TickTock 109:3e6f0e8fca0d 919 /* Check LFN validity and capture it */
TickTock 109:3e6f0e8fca0d 920 ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
TickTock 109:3e6f0e8fca0d 921 } else { /* An SFN entry is found */
TickTock 109:3e6f0e8fca0d 922 if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
TickTock 109:3e6f0e8fca0d 923 dj->lfn_idx = 0xFFFF; /* It has no LFN. */
TickTock 109:3e6f0e8fca0d 924 break;
TickTock 109:3e6f0e8fca0d 925 }
TickTock 109:3e6f0e8fca0d 926 }
TickTock 109:3e6f0e8fca0d 927 #else /* Non LFN configuration */
TickTock 109:3e6f0e8fca0d 928 if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
TickTock 109:3e6f0e8fca0d 929 break;
TickTock 109:3e6f0e8fca0d 930 #endif
TickTock 109:3e6f0e8fca0d 931 res = dir_next(dj, FALSE); /* Next entry */
TickTock 109:3e6f0e8fca0d 932 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 933 }
TickTock 109:3e6f0e8fca0d 934
TickTock 109:3e6f0e8fca0d 935 if (res != FR_OK) dj->sect = 0;
TickTock 109:3e6f0e8fca0d 936
TickTock 109:3e6f0e8fca0d 937 return res;
TickTock 109:3e6f0e8fca0d 938 }
TickTock 109:3e6f0e8fca0d 939 #endif
TickTock 109:3e6f0e8fca0d 940
TickTock 109:3e6f0e8fca0d 941
TickTock 109:3e6f0e8fca0d 942
TickTock 109:3e6f0e8fca0d 943 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 944 /* Register an object to the directory */
TickTock 109:3e6f0e8fca0d 945 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 946 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 947 static
TickTock 109:3e6f0e8fca0d 948 FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
TickTock 109:3e6f0e8fca0d 949 eDIR *dj /* Target directory with object name to be created */
TickTock 109:3e6f0e8fca0d 950 )
TickTock 109:3e6f0e8fca0d 951 {
TickTock 109:3e6f0e8fca0d 952 FRESULT res;
TickTock 109:3e6f0e8fca0d 953 BYTE c, *dir;
TickTock 109:3e6f0e8fca0d 954 #if _USE_LFN /* LFN configuration */
TickTock 109:3e6f0e8fca0d 955 WORD n, ne, is;
TickTock 109:3e6f0e8fca0d 956 BYTE sn[12], *fn, sum;
TickTock 109:3e6f0e8fca0d 957 WCHAR *lfn;
TickTock 109:3e6f0e8fca0d 958
TickTock 109:3e6f0e8fca0d 959
TickTock 109:3e6f0e8fca0d 960 fn = dj->fn; lfn = dj->lfn;
TickTock 109:3e6f0e8fca0d 961 mem_cpy(sn, fn, 12);
TickTock 109:3e6f0e8fca0d 962
TickTock 109:3e6f0e8fca0d 963 if (_FS_RPATH && (sn[NS] & NS_DOT)) return FR_INVALID_NAME; /* Cannot create dot entry */
TickTock 109:3e6f0e8fca0d 964
TickTock 109:3e6f0e8fca0d 965 if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
TickTock 109:3e6f0e8fca0d 966 fn[NS] = 0; dj->lfn = NULL; /* Find only SFN */
TickTock 109:3e6f0e8fca0d 967 for (n = 1; n < 100; n++) {
TickTock 109:3e6f0e8fca0d 968 gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
TickTock 109:3e6f0e8fca0d 969 res = dir_find(dj); /* Check if the name collides with existing SFN */
TickTock 109:3e6f0e8fca0d 970 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 971 }
TickTock 109:3e6f0e8fca0d 972 if (n == 100) return FR_DENIED; /* Abort if too many collisions */
TickTock 109:3e6f0e8fca0d 973 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */
TickTock 109:3e6f0e8fca0d 974 fn[NS] = sn[NS]; dj->lfn = lfn;
TickTock 109:3e6f0e8fca0d 975 }
TickTock 109:3e6f0e8fca0d 976
TickTock 109:3e6f0e8fca0d 977 if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve reserve an SFN + LFN entries. */
TickTock 109:3e6f0e8fca0d 978 for (ne = 0; lfn[ne]; ne++) ;
TickTock 109:3e6f0e8fca0d 979 ne = (ne + 25) / 13;
TickTock 109:3e6f0e8fca0d 980 } else { /* Otherwise reserve only an SFN entry. */
TickTock 109:3e6f0e8fca0d 981 ne = 1;
TickTock 109:3e6f0e8fca0d 982 }
TickTock 109:3e6f0e8fca0d 983
TickTock 109:3e6f0e8fca0d 984 /* Reserve contiguous entries */
TickTock 109:3e6f0e8fca0d 985 res = dir_seek(dj, 0);
TickTock 109:3e6f0e8fca0d 986 if (res != FR_OK) return res;
TickTock 109:3e6f0e8fca0d 987 n = is = 0;
TickTock 109:3e6f0e8fca0d 988 do {
TickTock 109:3e6f0e8fca0d 989 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 990 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 991 c = *dj->dir; /* Check the entry status */
TickTock 109:3e6f0e8fca0d 992 if (c == 0xE5 || c == 0) { /* Is it a blank entry? */
TickTock 109:3e6f0e8fca0d 993 if (n == 0) is = dj->index; /* First index of the contigulus entry */
TickTock 109:3e6f0e8fca0d 994 if (++n == ne) break; /* A contiguous entry that requiered count is found */
TickTock 109:3e6f0e8fca0d 995 } else {
TickTock 109:3e6f0e8fca0d 996 n = 0; /* Not a blank entry. Restart to search */
TickTock 109:3e6f0e8fca0d 997 }
TickTock 109:3e6f0e8fca0d 998 res = dir_next(dj, TRUE); /* Next entry with table streach */
TickTock 109:3e6f0e8fca0d 999 } while (res == FR_OK);
TickTock 109:3e6f0e8fca0d 1000
TickTock 109:3e6f0e8fca0d 1001 if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */
TickTock 109:3e6f0e8fca0d 1002 res = dir_seek(dj, is);
TickTock 109:3e6f0e8fca0d 1003 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1004 sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
TickTock 109:3e6f0e8fca0d 1005 ne--;
TickTock 109:3e6f0e8fca0d 1006 do { /* Store LFN entries in bottom first */
TickTock 109:3e6f0e8fca0d 1007 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 1008 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 1009 fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
TickTock 109:3e6f0e8fca0d 1010 dj->fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 1011 res = dir_next(dj, FALSE); /* Next entry */
TickTock 109:3e6f0e8fca0d 1012 } while (res == FR_OK && --ne);
TickTock 109:3e6f0e8fca0d 1013 }
TickTock 109:3e6f0e8fca0d 1014 }
TickTock 109:3e6f0e8fca0d 1015
TickTock 109:3e6f0e8fca0d 1016 #else /* Non LFN configuration */
TickTock 109:3e6f0e8fca0d 1017 res = dir_seek(dj, 0);
TickTock 109:3e6f0e8fca0d 1018 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1019 do { /* Find a blank entry for the SFN */
TickTock 109:3e6f0e8fca0d 1020 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 1021 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 1022 c = *dj->dir;
TickTock 109:3e6f0e8fca0d 1023 if (c == 0xE5 || c == 0) break; /* Is it a blank entry? */
TickTock 109:3e6f0e8fca0d 1024 res = dir_next(dj, TRUE); /* Next entry with table streach */
TickTock 109:3e6f0e8fca0d 1025 } while (res == FR_OK);
TickTock 109:3e6f0e8fca0d 1026 }
TickTock 109:3e6f0e8fca0d 1027 #endif
TickTock 109:3e6f0e8fca0d 1028
TickTock 109:3e6f0e8fca0d 1029 if (res == FR_OK) { /* Initialize the SFN entry */
TickTock 109:3e6f0e8fca0d 1030 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 1031 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1032 dir = dj->dir;
TickTock 109:3e6f0e8fca0d 1033 mem_set(dir, 0, 32); /* Clean the entry */
TickTock 109:3e6f0e8fca0d 1034 mem_cpy(dir, dj->fn, 11); /* Put SFN */
TickTock 109:3e6f0e8fca0d 1035 dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
TickTock 109:3e6f0e8fca0d 1036 dj->fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 1037 }
TickTock 109:3e6f0e8fca0d 1038 }
TickTock 109:3e6f0e8fca0d 1039
TickTock 109:3e6f0e8fca0d 1040 return res;
TickTock 109:3e6f0e8fca0d 1041 }
TickTock 109:3e6f0e8fca0d 1042 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 1043
TickTock 109:3e6f0e8fca0d 1044
TickTock 109:3e6f0e8fca0d 1045
TickTock 109:3e6f0e8fca0d 1046
TickTock 109:3e6f0e8fca0d 1047 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1048 /* Remove an object from the directory */
TickTock 109:3e6f0e8fca0d 1049 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1050 #if !_FS_READONLY && !_FS_MINIMIZE
TickTock 109:3e6f0e8fca0d 1051 static
TickTock 109:3e6f0e8fca0d 1052 FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */
TickTock 109:3e6f0e8fca0d 1053 eDIR *dj /* Directory object pointing the entry to be removed */
TickTock 109:3e6f0e8fca0d 1054 )
TickTock 109:3e6f0e8fca0d 1055 {
TickTock 109:3e6f0e8fca0d 1056 FRESULT res;
TickTock 109:3e6f0e8fca0d 1057 #if _USE_LFN /* LFN configuration */
TickTock 109:3e6f0e8fca0d 1058 WORD i;
TickTock 109:3e6f0e8fca0d 1059
TickTock 109:3e6f0e8fca0d 1060 i = dj->index; /* SFN index */
TickTock 109:3e6f0e8fca0d 1061 res = dir_seek(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */
TickTock 109:3e6f0e8fca0d 1062 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1063 do {
TickTock 109:3e6f0e8fca0d 1064 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 1065 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 1066 *dj->dir = 0xE5; /* Mark the entry "deleted" */
TickTock 109:3e6f0e8fca0d 1067 dj->fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 1068 if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */
TickTock 109:3e6f0e8fca0d 1069 res = dir_next(dj, FALSE); /* Next entry */
TickTock 109:3e6f0e8fca0d 1070 } while (res == FR_OK);
TickTock 109:3e6f0e8fca0d 1071 if (res == FR_NO_FILE) res = FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 1072 }
TickTock 109:3e6f0e8fca0d 1073
TickTock 109:3e6f0e8fca0d 1074 #else /* Non LFN configuration */
TickTock 109:3e6f0e8fca0d 1075 res = dir_seek(dj, dj->index);
TickTock 109:3e6f0e8fca0d 1076 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1077 res = move_window(dj->fs, dj->sect);
TickTock 109:3e6f0e8fca0d 1078 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1079 *dj->dir = 0xE5; /* Mark the entry "deleted" */
TickTock 109:3e6f0e8fca0d 1080 dj->fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 1081 }
TickTock 109:3e6f0e8fca0d 1082 }
TickTock 109:3e6f0e8fca0d 1083 #endif
TickTock 109:3e6f0e8fca0d 1084
TickTock 109:3e6f0e8fca0d 1085 return res;
TickTock 109:3e6f0e8fca0d 1086 }
TickTock 109:3e6f0e8fca0d 1087 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 1088
TickTock 109:3e6f0e8fca0d 1089
TickTock 109:3e6f0e8fca0d 1090
TickTock 109:3e6f0e8fca0d 1091
TickTock 109:3e6f0e8fca0d 1092 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1093 /* Pick a segment and create the object name in directory form */
TickTock 109:3e6f0e8fca0d 1094 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1095
TickTock 109:3e6f0e8fca0d 1096 static
TickTock 109:3e6f0e8fca0d 1097 FRESULT create_name (
TickTock 109:3e6f0e8fca0d 1098 eDIR *dj, /* Pointer to the directory object */
TickTock 109:3e6f0e8fca0d 1099 const XCHAR **path /* Pointer to pointer to the segment in the path string */
TickTock 109:3e6f0e8fca0d 1100 )
TickTock 109:3e6f0e8fca0d 1101 {
TickTock 109:3e6f0e8fca0d 1102 #ifdef _EXCVT
TickTock 109:3e6f0e8fca0d 1103 static const BYTE cvt[] = _EXCVT;
TickTock 109:3e6f0e8fca0d 1104 #endif
TickTock 109:3e6f0e8fca0d 1105
TickTock 109:3e6f0e8fca0d 1106 #if _USE_LFN /* LFN configuration */
TickTock 109:3e6f0e8fca0d 1107 BYTE b, cf;
TickTock 109:3e6f0e8fca0d 1108 WCHAR w, *lfn;
TickTock 109:3e6f0e8fca0d 1109 int i, ni, si, di;
TickTock 109:3e6f0e8fca0d 1110 const XCHAR *p;
TickTock 109:3e6f0e8fca0d 1111
TickTock 109:3e6f0e8fca0d 1112 /* Create LFN in Unicode */
TickTock 109:3e6f0e8fca0d 1113 si = di = 0;
TickTock 109:3e6f0e8fca0d 1114 p = *path;
TickTock 109:3e6f0e8fca0d 1115 lfn = dj->lfn;
TickTock 109:3e6f0e8fca0d 1116 for (;;) {
TickTock 109:3e6f0e8fca0d 1117 w = p[si++]; /* Get a character */
TickTock 109:3e6f0e8fca0d 1118 if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */
TickTock 109:3e6f0e8fca0d 1119 if (di >= _MAX_LFN) /* Reject too long name */
TickTock 109:3e6f0e8fca0d 1120 return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1121 #if !_LFN_UNICODE
TickTock 109:3e6f0e8fca0d 1122 w &= 0xFF;
TickTock 109:3e6f0e8fca0d 1123 if (IsDBCS1(w)) { /* If it is a DBC 1st byte */
TickTock 109:3e6f0e8fca0d 1124 b = p[si++]; /* Get 2nd byte */
TickTock 109:3e6f0e8fca0d 1125 if (!IsDBCS2(b)) /* Reject invalid code for DBC */
TickTock 109:3e6f0e8fca0d 1126 return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1127 w = (w << 8) + b;
TickTock 109:3e6f0e8fca0d 1128 }
TickTock 109:3e6f0e8fca0d 1129 w = ff_convert(w, 1); /* Convert OEM to Unicode */
TickTock 109:3e6f0e8fca0d 1130 if (!w) return FR_INVALID_NAME; /* Reject invalid code */
TickTock 109:3e6f0e8fca0d 1131 #endif
TickTock 109:3e6f0e8fca0d 1132 if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
TickTock 109:3e6f0e8fca0d 1133 return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1134 lfn[di++] = w; /* Store the Unicode char */
TickTock 109:3e6f0e8fca0d 1135 }
TickTock 109:3e6f0e8fca0d 1136 *path = &p[si]; /* Rerurn pointer to the next segment */
TickTock 109:3e6f0e8fca0d 1137 cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
TickTock 109:3e6f0e8fca0d 1138 #if _FS_RPATH
TickTock 109:3e6f0e8fca0d 1139 if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
TickTock 109:3e6f0e8fca0d 1140 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
TickTock 109:3e6f0e8fca0d 1141 lfn[di] = 0;
TickTock 109:3e6f0e8fca0d 1142 for (i = 0; i < 11; i++)
TickTock 109:3e6f0e8fca0d 1143 dj->fn[i] = (i < di) ? '.' : ' ';
TickTock 109:3e6f0e8fca0d 1144 dj->fn[i] = cf | NS_DOT; /* This is a dot entry */
TickTock 109:3e6f0e8fca0d 1145 return FR_OK;
TickTock 109:3e6f0e8fca0d 1146 }
TickTock 109:3e6f0e8fca0d 1147 #endif
TickTock 109:3e6f0e8fca0d 1148 while (di) { /* Strip trailing spaces and dots */
TickTock 109:3e6f0e8fca0d 1149 w = lfn[di - 1];
TickTock 109:3e6f0e8fca0d 1150 if (w != ' ' && w != '.') break;
TickTock 109:3e6f0e8fca0d 1151 di--;
TickTock 109:3e6f0e8fca0d 1152 }
TickTock 109:3e6f0e8fca0d 1153 if (!di) return FR_INVALID_NAME; /* Reject null string */
TickTock 109:3e6f0e8fca0d 1154
TickTock 109:3e6f0e8fca0d 1155 lfn[di] = 0; /* LFN is created */
TickTock 109:3e6f0e8fca0d 1156
TickTock 109:3e6f0e8fca0d 1157 /* Create SFN in directory form */
TickTock 109:3e6f0e8fca0d 1158 mem_set(dj->fn, ' ', 11);
TickTock 109:3e6f0e8fca0d 1159 for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
TickTock 109:3e6f0e8fca0d 1160 if (si) cf |= NS_LOSS | NS_LFN;
TickTock 109:3e6f0e8fca0d 1161 while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
TickTock 109:3e6f0e8fca0d 1162
TickTock 109:3e6f0e8fca0d 1163 b = i = 0; ni = 8;
TickTock 109:3e6f0e8fca0d 1164 for (;;) {
TickTock 109:3e6f0e8fca0d 1165 w = lfn[si++]; /* Get an LFN char */
TickTock 109:3e6f0e8fca0d 1166 if (!w) break; /* Break on enf of the LFN */
TickTock 109:3e6f0e8fca0d 1167 if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
TickTock 109:3e6f0e8fca0d 1168 cf |= NS_LOSS | NS_LFN; continue;
TickTock 109:3e6f0e8fca0d 1169 }
TickTock 109:3e6f0e8fca0d 1170
TickTock 109:3e6f0e8fca0d 1171 if (i >= ni || si == di) { /* Extension or end of SFN */
TickTock 109:3e6f0e8fca0d 1172 if (ni == 11) { /* Long extension */
TickTock 109:3e6f0e8fca0d 1173 cf |= NS_LOSS | NS_LFN; break;
TickTock 109:3e6f0e8fca0d 1174 }
TickTock 109:3e6f0e8fca0d 1175 if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
TickTock 109:3e6f0e8fca0d 1176 if (si > di) break; /* No extension */
TickTock 109:3e6f0e8fca0d 1177 si = di; i = 8; ni = 11; /* Enter extension section */
TickTock 109:3e6f0e8fca0d 1178 b <<= 2; continue;
TickTock 109:3e6f0e8fca0d 1179 }
TickTock 109:3e6f0e8fca0d 1180
TickTock 109:3e6f0e8fca0d 1181 if (w >= 0x80) { /* Non ASCII char */
TickTock 109:3e6f0e8fca0d 1182 #ifdef _EXCVT
TickTock 109:3e6f0e8fca0d 1183 w = ff_convert(w, 0); /* Unicode -> OEM code */
TickTock 109:3e6f0e8fca0d 1184 if (w) w = cvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
TickTock 109:3e6f0e8fca0d 1185 #else
TickTock 109:3e6f0e8fca0d 1186 w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
TickTock 109:3e6f0e8fca0d 1187 #endif
TickTock 109:3e6f0e8fca0d 1188 cf |= NS_LFN; /* Force create LFN entry */
TickTock 109:3e6f0e8fca0d 1189 }
TickTock 109:3e6f0e8fca0d 1190
TickTock 109:3e6f0e8fca0d 1191 if (_DF1S && w >= 0x100) { /* Double byte char */
TickTock 109:3e6f0e8fca0d 1192 if (i >= ni - 1) {
TickTock 109:3e6f0e8fca0d 1193 cf |= NS_LOSS | NS_LFN; i = ni; continue;
TickTock 109:3e6f0e8fca0d 1194 }
TickTock 109:3e6f0e8fca0d 1195 dj->fn[i++] = (BYTE)(w >> 8);
TickTock 109:3e6f0e8fca0d 1196 } else { /* Single byte char */
TickTock 109:3e6f0e8fca0d 1197 if (!w || chk_chr("+,;[=]", w)) { /* Replace illegal chars for SFN */
TickTock 109:3e6f0e8fca0d 1198 w = '_'; cf |= NS_LOSS | NS_LFN; /* Lossy conversion */
TickTock 109:3e6f0e8fca0d 1199 } else {
TickTock 109:3e6f0e8fca0d 1200 if (IsUpper(w)) { /* ASCII large capital */
TickTock 109:3e6f0e8fca0d 1201 b |= 2;
TickTock 109:3e6f0e8fca0d 1202 } else {
TickTock 109:3e6f0e8fca0d 1203 if (IsLower(w)) { /* ASCII small capital */
TickTock 109:3e6f0e8fca0d 1204 b |= 1; w -= 0x20;
TickTock 109:3e6f0e8fca0d 1205 }
TickTock 109:3e6f0e8fca0d 1206 }
TickTock 109:3e6f0e8fca0d 1207 }
TickTock 109:3e6f0e8fca0d 1208 }
TickTock 109:3e6f0e8fca0d 1209 dj->fn[i++] = (BYTE)w;
TickTock 109:3e6f0e8fca0d 1210 }
TickTock 109:3e6f0e8fca0d 1211
TickTock 109:3e6f0e8fca0d 1212 if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05; /* If the first char collides with deleted mark, replace it with 0x05 */
TickTock 109:3e6f0e8fca0d 1213
TickTock 109:3e6f0e8fca0d 1214 if (ni == 8) b <<= 2;
TickTock 109:3e6f0e8fca0d 1215 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
TickTock 109:3e6f0e8fca0d 1216 cf |= NS_LFN;
TickTock 109:3e6f0e8fca0d 1217 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
TickTock 109:3e6f0e8fca0d 1218 if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */
TickTock 109:3e6f0e8fca0d 1219 if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */
TickTock 109:3e6f0e8fca0d 1220 }
TickTock 109:3e6f0e8fca0d 1221
TickTock 109:3e6f0e8fca0d 1222 dj->fn[NS] = cf; /* SFN is created */
TickTock 109:3e6f0e8fca0d 1223
TickTock 109:3e6f0e8fca0d 1224 return FR_OK;
TickTock 109:3e6f0e8fca0d 1225
TickTock 109:3e6f0e8fca0d 1226
TickTock 109:3e6f0e8fca0d 1227 #else /* Non-LFN configuration */
TickTock 109:3e6f0e8fca0d 1228 BYTE b, c, d, *sfn;
TickTock 109:3e6f0e8fca0d 1229 int ni, si, i;
TickTock 109:3e6f0e8fca0d 1230 const char *p;
TickTock 109:3e6f0e8fca0d 1231
TickTock 109:3e6f0e8fca0d 1232 /* Create file name in directory form */
TickTock 109:3e6f0e8fca0d 1233 sfn = dj->fn;
TickTock 109:3e6f0e8fca0d 1234 mem_set(sfn, ' ', 11);
TickTock 109:3e6f0e8fca0d 1235 si = i = b = 0; ni = 8;
TickTock 109:3e6f0e8fca0d 1236 p = *path;
TickTock 109:3e6f0e8fca0d 1237 #if _FS_RPATH
TickTock 109:3e6f0e8fca0d 1238 if (p[si] == '.') { /* Is this a dot entry? */
TickTock 109:3e6f0e8fca0d 1239 for (;;) {
TickTock 109:3e6f0e8fca0d 1240 c = p[si++];
TickTock 109:3e6f0e8fca0d 1241 if (c != '.' || si >= 3) break;
TickTock 109:3e6f0e8fca0d 1242 sfn[i++] = c;
TickTock 109:3e6f0e8fca0d 1243 }
TickTock 109:3e6f0e8fca0d 1244 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1245 *path = &p[si]; /* Rerurn pointer to the next segment */
TickTock 109:3e6f0e8fca0d 1246 sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
TickTock 109:3e6f0e8fca0d 1247 return FR_OK;
TickTock 109:3e6f0e8fca0d 1248 }
TickTock 109:3e6f0e8fca0d 1249 #endif
TickTock 109:3e6f0e8fca0d 1250 for (;;) {
TickTock 109:3e6f0e8fca0d 1251 c = p[si++];
TickTock 109:3e6f0e8fca0d 1252 if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
TickTock 109:3e6f0e8fca0d 1253 if (c == '.' || i >= ni) {
TickTock 109:3e6f0e8fca0d 1254 if (ni != 8 || c != '.') return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1255 i = 8; ni = 11;
TickTock 109:3e6f0e8fca0d 1256 b <<= 2; continue;
TickTock 109:3e6f0e8fca0d 1257 }
TickTock 109:3e6f0e8fca0d 1258 if (c >= 0x80) { /* Extended char */
TickTock 109:3e6f0e8fca0d 1259 #ifdef _EXCVT
TickTock 109:3e6f0e8fca0d 1260 c = cvt[c - 0x80]; /* Convert extend char (SBCS) */
TickTock 109:3e6f0e8fca0d 1261 #else
TickTock 109:3e6f0e8fca0d 1262 b |= 3; /* Eliminate NT flag if ext char is exist */
TickTock 109:3e6f0e8fca0d 1263 #if !_DF1S /* ASCII only cfg */
TickTock 109:3e6f0e8fca0d 1264 return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1265 #endif
TickTock 109:3e6f0e8fca0d 1266 #endif
TickTock 109:3e6f0e8fca0d 1267 }
TickTock 109:3e6f0e8fca0d 1268 if (IsDBCS1(c)) { /* DBC 1st byte? */
TickTock 109:3e6f0e8fca0d 1269 d = p[si++]; /* Get 2nd byte */
TickTock 109:3e6f0e8fca0d 1270 if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
TickTock 109:3e6f0e8fca0d 1271 return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1272 sfn[i++] = c;
TickTock 109:3e6f0e8fca0d 1273 sfn[i++] = d;
TickTock 109:3e6f0e8fca0d 1274 } else { /* Single byte code */
TickTock 109:3e6f0e8fca0d 1275 if (chk_chr(" \"*+,[=]|\x7F", c)) /* Reject illegal chrs for SFN */
TickTock 109:3e6f0e8fca0d 1276 return FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 1277 if (IsUpper(c)) { /* ASCII large capital? */
TickTock 109:3e6f0e8fca0d 1278 b |= 2;
TickTock 109:3e6f0e8fca0d 1279 } else {
TickTock 109:3e6f0e8fca0d 1280 if (IsLower(c)) { /* ASCII small capital? */
TickTock 109:3e6f0e8fca0d 1281 b |= 1; c -= 0x20;
TickTock 109:3e6f0e8fca0d 1282 }
TickTock 109:3e6f0e8fca0d 1283 }
TickTock 109:3e6f0e8fca0d 1284 sfn[i++] = c;
TickTock 109:3e6f0e8fca0d 1285 }
TickTock 109:3e6f0e8fca0d 1286 }
TickTock 109:3e6f0e8fca0d 1287 *path = &p[si]; /* Rerurn pointer to the next segment */
TickTock 109:3e6f0e8fca0d 1288 c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
TickTock 109:3e6f0e8fca0d 1289
TickTock 109:3e6f0e8fca0d 1290 if (!i) return FR_INVALID_NAME; /* Reject null string */
TickTock 109:3e6f0e8fca0d 1291 if (sfn[0] == 0xE5) sfn[0] = 0x05; /* When first char collides with 0xE5, replace it with 0x05 */
TickTock 109:3e6f0e8fca0d 1292
TickTock 109:3e6f0e8fca0d 1293 if (ni == 8) b <<= 2;
TickTock 109:3e6f0e8fca0d 1294 if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Extension has only small capital) */
TickTock 109:3e6f0e8fca0d 1295 if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Filename has only small capital) */
TickTock 109:3e6f0e8fca0d 1296
TickTock 109:3e6f0e8fca0d 1297 sfn[NS] = c; /* Store NT flag, File name is created */
TickTock 109:3e6f0e8fca0d 1298
TickTock 109:3e6f0e8fca0d 1299 return FR_OK;
TickTock 109:3e6f0e8fca0d 1300 #endif
TickTock 109:3e6f0e8fca0d 1301 }
TickTock 109:3e6f0e8fca0d 1302
TickTock 109:3e6f0e8fca0d 1303
TickTock 109:3e6f0e8fca0d 1304
TickTock 109:3e6f0e8fca0d 1305
TickTock 109:3e6f0e8fca0d 1306 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1307 /* Get file information from directory entry */
TickTock 109:3e6f0e8fca0d 1308 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1309 #if _FS_MINIMIZE <= 1
TickTock 109:3e6f0e8fca0d 1310 static
TickTock 109:3e6f0e8fca0d 1311 void get_fileinfo ( /* No return code */
TickTock 109:3e6f0e8fca0d 1312 eDIR *dj, /* Pointer to the directory object */
TickTock 109:3e6f0e8fca0d 1313 FILINFO *fno /* Pointer to the file information to be filled */
TickTock 109:3e6f0e8fca0d 1314 )
TickTock 109:3e6f0e8fca0d 1315 {
TickTock 109:3e6f0e8fca0d 1316 int i;
TickTock 109:3e6f0e8fca0d 1317 BYTE c, nt, *dir;
TickTock 109:3e6f0e8fca0d 1318 char *p;
TickTock 109:3e6f0e8fca0d 1319
TickTock 109:3e6f0e8fca0d 1320
TickTock 109:3e6f0e8fca0d 1321 p = fno->fname;
TickTock 109:3e6f0e8fca0d 1322 if (dj->sect) {
TickTock 109:3e6f0e8fca0d 1323 dir = dj->dir;
TickTock 109:3e6f0e8fca0d 1324 nt = dir[DIR_NTres]; /* NT flag */
TickTock 109:3e6f0e8fca0d 1325 for (i = 0; i < 8; i++) { /* Copy name body */
TickTock 109:3e6f0e8fca0d 1326 c = dir[i];
TickTock 109:3e6f0e8fca0d 1327 if (c == ' ') break;
TickTock 109:3e6f0e8fca0d 1328 if (c == 0x05) c = 0xE5;
TickTock 109:3e6f0e8fca0d 1329 if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20;
TickTock 109:3e6f0e8fca0d 1330 *p++ = c;
TickTock 109:3e6f0e8fca0d 1331 }
TickTock 109:3e6f0e8fca0d 1332 if (dir[8] != ' ') { /* Copy name extension */
TickTock 109:3e6f0e8fca0d 1333 *p++ = '.';
TickTock 109:3e6f0e8fca0d 1334 for (i = 8; i < 11; i++) {
TickTock 109:3e6f0e8fca0d 1335 c = dir[i];
TickTock 109:3e6f0e8fca0d 1336 if (c == ' ') break;
TickTock 109:3e6f0e8fca0d 1337 if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20;
TickTock 109:3e6f0e8fca0d 1338 *p++ = c;
TickTock 109:3e6f0e8fca0d 1339 }
TickTock 109:3e6f0e8fca0d 1340 }
TickTock 109:3e6f0e8fca0d 1341 fno->fattrib = dir[DIR_Attr]; /* Attribute */
TickTock 109:3e6f0e8fca0d 1342 fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
TickTock 109:3e6f0e8fca0d 1343 fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
TickTock 109:3e6f0e8fca0d 1344 fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
TickTock 109:3e6f0e8fca0d 1345 }
TickTock 109:3e6f0e8fca0d 1346 *p = 0;
TickTock 109:3e6f0e8fca0d 1347
TickTock 109:3e6f0e8fca0d 1348 #if _USE_LFN
TickTock 109:3e6f0e8fca0d 1349 if (fno->lfname) {
TickTock 109:3e6f0e8fca0d 1350 XCHAR *tp = fno->lfname;
TickTock 109:3e6f0e8fca0d 1351 WCHAR w, *lfn;
TickTock 109:3e6f0e8fca0d 1352
TickTock 109:3e6f0e8fca0d 1353 i = 0;
TickTock 109:3e6f0e8fca0d 1354 if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
TickTock 109:3e6f0e8fca0d 1355 lfn = dj->lfn;
TickTock 109:3e6f0e8fca0d 1356 while ((w = *lfn++) != 0) { /* Get an LFN char */
TickTock 109:3e6f0e8fca0d 1357 #if !_LFN_UNICODE
TickTock 109:3e6f0e8fca0d 1358 w = ff_convert(w, 0); /* Unicode -> OEM conversion */
TickTock 109:3e6f0e8fca0d 1359 if (!w) { i = 0; break; } /* Could not convert, no LFN */
TickTock 109:3e6f0e8fca0d 1360 if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC */
TickTock 109:3e6f0e8fca0d 1361 tp[i++] = (XCHAR)(w >> 8);
TickTock 109:3e6f0e8fca0d 1362 #endif
TickTock 109:3e6f0e8fca0d 1363 if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overrun, no LFN */
TickTock 109:3e6f0e8fca0d 1364 tp[i++] = (XCHAR)w;
TickTock 109:3e6f0e8fca0d 1365 }
TickTock 109:3e6f0e8fca0d 1366 }
TickTock 109:3e6f0e8fca0d 1367 tp[i] = 0; /* Terminator */
TickTock 109:3e6f0e8fca0d 1368 }
TickTock 109:3e6f0e8fca0d 1369 #endif
TickTock 109:3e6f0e8fca0d 1370 }
TickTock 109:3e6f0e8fca0d 1371 #endif /* _FS_MINIMIZE <= 1 */
TickTock 109:3e6f0e8fca0d 1372
TickTock 109:3e6f0e8fca0d 1373
TickTock 109:3e6f0e8fca0d 1374
TickTock 109:3e6f0e8fca0d 1375
TickTock 109:3e6f0e8fca0d 1376 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1377 /* Follow a file path */
TickTock 109:3e6f0e8fca0d 1378 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1379
TickTock 109:3e6f0e8fca0d 1380 static
TickTock 109:3e6f0e8fca0d 1381 FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
TickTock 109:3e6f0e8fca0d 1382 eDIR *dj, /* Directory object to return last directory and found object */
TickTock 109:3e6f0e8fca0d 1383 const XCHAR *path /* Full-path string to find a file or directory */
TickTock 109:3e6f0e8fca0d 1384 )
TickTock 109:3e6f0e8fca0d 1385 {
TickTock 109:3e6f0e8fca0d 1386 FRESULT res;
TickTock 109:3e6f0e8fca0d 1387 BYTE *dir, last;
TickTock 109:3e6f0e8fca0d 1388
TickTock 109:3e6f0e8fca0d 1389
TickTock 109:3e6f0e8fca0d 1390 while (!_USE_LFN && *path == ' ') path++; /* Skip leading spaces */
TickTock 109:3e6f0e8fca0d 1391 #if _FS_RPATH
TickTock 109:3e6f0e8fca0d 1392 if (*path == '/' || *path == '\\') { /* There is a heading separator */
TickTock 109:3e6f0e8fca0d 1393 path++; dj->sclust = 0; /* Strip it and start from the root dir */
TickTock 109:3e6f0e8fca0d 1394 } else { /* No heading saparator */
TickTock 109:3e6f0e8fca0d 1395 dj->sclust = dj->fs->cdir; /* Start from the current dir */
TickTock 109:3e6f0e8fca0d 1396 }
TickTock 109:3e6f0e8fca0d 1397 #else
TickTock 109:3e6f0e8fca0d 1398 if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
TickTock 109:3e6f0e8fca0d 1399 path++;
TickTock 109:3e6f0e8fca0d 1400 dj->sclust = 0; /* Start from the root dir */
TickTock 109:3e6f0e8fca0d 1401 #endif
TickTock 109:3e6f0e8fca0d 1402
TickTock 109:3e6f0e8fca0d 1403 if ((UINT)*path < ' ') { /* Null path means the start directory itself */
TickTock 109:3e6f0e8fca0d 1404 res = dir_seek(dj, 0);
TickTock 109:3e6f0e8fca0d 1405 dj->dir = NULL;
TickTock 109:3e6f0e8fca0d 1406
TickTock 109:3e6f0e8fca0d 1407 } else { /* Follow path */
TickTock 109:3e6f0e8fca0d 1408 for (;;) {
TickTock 109:3e6f0e8fca0d 1409 res = create_name(dj, &path); /* Get a segment */
TickTock 109:3e6f0e8fca0d 1410 if (res != FR_OK) break;
TickTock 109:3e6f0e8fca0d 1411 res = dir_find(dj); /* Find it */
TickTock 109:3e6f0e8fca0d 1412 last = *(dj->fn+NS) & NS_LAST;
TickTock 109:3e6f0e8fca0d 1413 if (res != FR_OK) { /* Could not find the object */
TickTock 109:3e6f0e8fca0d 1414 if (res == FR_NO_FILE && !last)
TickTock 109:3e6f0e8fca0d 1415 res = FR_NO_PATH;
TickTock 109:3e6f0e8fca0d 1416 break;
TickTock 109:3e6f0e8fca0d 1417 }
TickTock 109:3e6f0e8fca0d 1418 if (last) break; /* Last segment match. Function completed. */
TickTock 109:3e6f0e8fca0d 1419 dir = dj->dir; /* There is next segment. Follow the sub directory */
TickTock 109:3e6f0e8fca0d 1420 if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
TickTock 109:3e6f0e8fca0d 1421 res = FR_NO_PATH; break;
TickTock 109:3e6f0e8fca0d 1422 }
TickTock 109:3e6f0e8fca0d 1423 dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
TickTock 109:3e6f0e8fca0d 1424 }
TickTock 109:3e6f0e8fca0d 1425 }
TickTock 109:3e6f0e8fca0d 1426
TickTock 109:3e6f0e8fca0d 1427 return res;
TickTock 109:3e6f0e8fca0d 1428 }
TickTock 109:3e6f0e8fca0d 1429
TickTock 109:3e6f0e8fca0d 1430
TickTock 109:3e6f0e8fca0d 1431
TickTock 109:3e6f0e8fca0d 1432
TickTock 109:3e6f0e8fca0d 1433 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1434 /* Load boot record and check if it is an FAT boot record */
TickTock 109:3e6f0e8fca0d 1435 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1436
TickTock 109:3e6f0e8fca0d 1437 static
TickTock 109:3e6f0e8fca0d 1438 BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
TickTock 109:3e6f0e8fca0d 1439 FATFS *fs, /* File system object */
TickTock 109:3e6f0e8fca0d 1440 DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
TickTock 109:3e6f0e8fca0d 1441 )
TickTock 109:3e6f0e8fca0d 1442 {
TickTock 109:3e6f0e8fca0d 1443 if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK) /* Load boot record */
TickTock 109:3e6f0e8fca0d 1444 return 3;
TickTock 109:3e6f0e8fca0d 1445 if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */
TickTock 109:3e6f0e8fca0d 1446 return 2;
TickTock 109:3e6f0e8fca0d 1447
TickTock 109:3e6f0e8fca0d 1448 if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
TickTock 109:3e6f0e8fca0d 1449 return 0;
TickTock 109:3e6f0e8fca0d 1450 if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
TickTock 109:3e6f0e8fca0d 1451 return 0;
TickTock 109:3e6f0e8fca0d 1452
TickTock 109:3e6f0e8fca0d 1453 return 1;
TickTock 109:3e6f0e8fca0d 1454 }
TickTock 109:3e6f0e8fca0d 1455
TickTock 109:3e6f0e8fca0d 1456
TickTock 109:3e6f0e8fca0d 1457
TickTock 109:3e6f0e8fca0d 1458
TickTock 109:3e6f0e8fca0d 1459 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1460 /* Make sure that the file system is valid */
TickTock 109:3e6f0e8fca0d 1461 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1462
TickTock 109:3e6f0e8fca0d 1463
TickTock 109:3e6f0e8fca0d 1464 FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occured */
TickTock 109:3e6f0e8fca0d 1465 const XCHAR **path, /* Pointer to pointer to the path name (drive number) */
TickTock 109:3e6f0e8fca0d 1466 FATFS **rfs, /* Pointer to pointer to the found file system object */
TickTock 109:3e6f0e8fca0d 1467 BYTE chk_wp /* !=0: Check media write protection for write access */
TickTock 109:3e6f0e8fca0d 1468 )
TickTock 109:3e6f0e8fca0d 1469 {
TickTock 109:3e6f0e8fca0d 1470 BYTE fmt, *tbl;
TickTock 109:3e6f0e8fca0d 1471 UINT vol;
TickTock 109:3e6f0e8fca0d 1472 DSTATUS stat;
TickTock 109:3e6f0e8fca0d 1473 DWORD bsect, fsize, tsect, mclst;
TickTock 109:3e6f0e8fca0d 1474 const XCHAR *p = *path;
TickTock 109:3e6f0e8fca0d 1475 FATFS *fs;
TickTock 109:3e6f0e8fca0d 1476
TickTock 109:3e6f0e8fca0d 1477 /* Get logical drive number from the path name */
TickTock 109:3e6f0e8fca0d 1478 vol = p[0] - '0'; /* Is there a drive number? */
TickTock 109:3e6f0e8fca0d 1479 if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
TickTock 109:3e6f0e8fca0d 1480 p += 2; *path = p; /* Return pointer to the path name */
TickTock 109:3e6f0e8fca0d 1481 } else { /* No drive number is given */
TickTock 109:3e6f0e8fca0d 1482 #if _FS_RPATH
TickTock 109:3e6f0e8fca0d 1483 vol = Drive; /* Use current drive */
TickTock 109:3e6f0e8fca0d 1484 #else
TickTock 109:3e6f0e8fca0d 1485 vol = 0; /* Use drive 0 */
TickTock 109:3e6f0e8fca0d 1486 #endif
TickTock 109:3e6f0e8fca0d 1487 }
TickTock 109:3e6f0e8fca0d 1488
TickTock 109:3e6f0e8fca0d 1489 /* Check if the logical drive is valid or not */
TickTock 109:3e6f0e8fca0d 1490 if (vol >= _DRIVES) /* Is the drive number valid? */
TickTock 109:3e6f0e8fca0d 1491 return FR_INVALID_DRIVE;
TickTock 109:3e6f0e8fca0d 1492 *rfs = fs = FatFs[vol]; /* Returen pointer to the corresponding file system object */
TickTock 109:3e6f0e8fca0d 1493 if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
TickTock 109:3e6f0e8fca0d 1494
TickTock 109:3e6f0e8fca0d 1495 ENTER_FF(fs); /* Lock file system */
TickTock 109:3e6f0e8fca0d 1496
TickTock 109:3e6f0e8fca0d 1497 if (fs->fs_type) { /* If the logical drive has been mounted */
TickTock 109:3e6f0e8fca0d 1498 stat = disk_status(fs->drive);
TickTock 109:3e6f0e8fca0d 1499 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
TickTock 109:3e6f0e8fca0d 1500 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1501 if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
TickTock 109:3e6f0e8fca0d 1502 return FR_WRITE_PROTECTED;
TickTock 109:3e6f0e8fca0d 1503 #endif
TickTock 109:3e6f0e8fca0d 1504 return FR_OK; /* The file system object is valid */
TickTock 109:3e6f0e8fca0d 1505 }
TickTock 109:3e6f0e8fca0d 1506 }
TickTock 109:3e6f0e8fca0d 1507
TickTock 109:3e6f0e8fca0d 1508 /* The logical drive must be mounted. Following code attempts to mount the volume */
TickTock 109:3e6f0e8fca0d 1509
TickTock 109:3e6f0e8fca0d 1510 fs->fs_type = 0; /* Clear the file system object */
TickTock 109:3e6f0e8fca0d 1511 fs->drive = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
TickTock 109:3e6f0e8fca0d 1512 stat = disk_initialize(fs->drive); /* Initialize low level disk I/O layer */
TickTock 109:3e6f0e8fca0d 1513 if (stat & STA_NOINIT) /* Check if the drive is ready */
TickTock 109:3e6f0e8fca0d 1514 return FR_NOT_READY;
TickTock 109:3e6f0e8fca0d 1515 #if _MAX_SS != 512 /* Get disk sector size if needed */
TickTock 109:3e6f0e8fca0d 1516 if (disk_ioctl(fs->drive, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
TickTock 109:3e6f0e8fca0d 1517 return FR_NO_FILESYSTEM;
TickTock 109:3e6f0e8fca0d 1518 #endif
TickTock 109:3e6f0e8fca0d 1519 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1520 if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */
TickTock 109:3e6f0e8fca0d 1521 return FR_WRITE_PROTECTED;
TickTock 109:3e6f0e8fca0d 1522 #endif
TickTock 109:3e6f0e8fca0d 1523 /* Search FAT partition on the drive */
TickTock 109:3e6f0e8fca0d 1524 fmt = check_fs(fs, bsect = 0); /* Check sector 0 as an SFD format */
TickTock 109:3e6f0e8fca0d 1525 if (fmt == 1) { /* Not an FAT boot record, it may be patitioned */
TickTock 109:3e6f0e8fca0d 1526 /* Check a partition listed in top of the partition table */
TickTock 109:3e6f0e8fca0d 1527 tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */
TickTock 109:3e6f0e8fca0d 1528 if (tbl[4]) { /* Is the partition existing? */
TickTock 109:3e6f0e8fca0d 1529 bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
TickTock 109:3e6f0e8fca0d 1530 fmt = check_fs(fs, bsect); /* Check the partition */
TickTock 109:3e6f0e8fca0d 1531 }
TickTock 109:3e6f0e8fca0d 1532 }
TickTock 109:3e6f0e8fca0d 1533 if (fmt == 3) return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 1534 if (fmt || LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* No valid FAT patition is found */
TickTock 109:3e6f0e8fca0d 1535 return FR_NO_FILESYSTEM;
TickTock 109:3e6f0e8fca0d 1536
TickTock 109:3e6f0e8fca0d 1537 /* Initialize the file system object */
TickTock 109:3e6f0e8fca0d 1538 fsize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
TickTock 109:3e6f0e8fca0d 1539 if (!fsize) fsize = LD_DWORD(fs->win+BPB_FATSz32);
TickTock 109:3e6f0e8fca0d 1540 fs->sects_fat = fsize;
TickTock 109:3e6f0e8fca0d 1541 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */
TickTock 109:3e6f0e8fca0d 1542 fsize *= fs->n_fats; /* (Number of sectors in FAT area) */
TickTock 109:3e6f0e8fca0d 1543 fs->fatbase = bsect + LD_WORD(fs->win+BPB_RsvdSecCnt); /* FAT start sector (lba) */
TickTock 109:3e6f0e8fca0d 1544 fs->csize = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
TickTock 109:3e6f0e8fca0d 1545 fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Nmuber of root directory entries */
TickTock 109:3e6f0e8fca0d 1546 tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
TickTock 109:3e6f0e8fca0d 1547 if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
TickTock 109:3e6f0e8fca0d 1548 fs->max_clust = mclst = (tsect /* Last cluster# + 1 (Number of clusters + 2) */
TickTock 109:3e6f0e8fca0d 1549 - LD_WORD(fs->win+BPB_RsvdSecCnt) - fsize - fs->n_rootdir / (SS(fs)/32)
TickTock 109:3e6f0e8fca0d 1550 ) / fs->csize + 2;
TickTock 109:3e6f0e8fca0d 1551
TickTock 109:3e6f0e8fca0d 1552 fmt = FS_FAT12; /* Determine the FAT sub type */
TickTock 109:3e6f0e8fca0d 1553 if (mclst >= 0xFF7) fmt = FS_FAT16; /* Number of clusters >= 0xFF5 */
TickTock 109:3e6f0e8fca0d 1554 if (mclst >= 0xFFF7) fmt = FS_FAT32; /* Number of clusters >= 0xFFF5 */
TickTock 109:3e6f0e8fca0d 1555
TickTock 109:3e6f0e8fca0d 1556 if (fmt == FS_FAT32)
TickTock 109:3e6f0e8fca0d 1557 fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
TickTock 109:3e6f0e8fca0d 1558 else
TickTock 109:3e6f0e8fca0d 1559 fs->dirbase = fs->fatbase + fsize; /* Root directory start sector (lba) */
TickTock 109:3e6f0e8fca0d 1560 fs->database = fs->fatbase + fsize + fs->n_rootdir / (SS(fs)/32); /* Data start sector (lba) */
TickTock 109:3e6f0e8fca0d 1561
TickTock 109:3e6f0e8fca0d 1562 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1563 /* Initialize allocation information */
TickTock 109:3e6f0e8fca0d 1564 fs->free_clust = 0xFFFFFFFF;
TickTock 109:3e6f0e8fca0d 1565 fs->wflag = 0;
TickTock 109:3e6f0e8fca0d 1566 /* Get fsinfo if needed */
TickTock 109:3e6f0e8fca0d 1567 if (fmt == FS_FAT32) {
TickTock 109:3e6f0e8fca0d 1568 fs->fsi_flag = 0;
TickTock 109:3e6f0e8fca0d 1569 fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
TickTock 109:3e6f0e8fca0d 1570 if (disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK &&
TickTock 109:3e6f0e8fca0d 1571 LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
TickTock 109:3e6f0e8fca0d 1572 LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
TickTock 109:3e6f0e8fca0d 1573 LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
TickTock 109:3e6f0e8fca0d 1574 fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
TickTock 109:3e6f0e8fca0d 1575 fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
TickTock 109:3e6f0e8fca0d 1576 }
TickTock 109:3e6f0e8fca0d 1577 }
TickTock 109:3e6f0e8fca0d 1578 #endif
TickTock 109:3e6f0e8fca0d 1579 fs->fs_type = fmt; /* FAT sub-type */
TickTock 109:3e6f0e8fca0d 1580 fs->winsect = 0; /* Invalidate sector cache */
TickTock 109:3e6f0e8fca0d 1581 #if _FS_RPATH
TickTock 109:3e6f0e8fca0d 1582 fs->cdir = 0; /* Current directory (root dir) */
TickTock 109:3e6f0e8fca0d 1583 #endif
TickTock 109:3e6f0e8fca0d 1584 fs->id = ++Fsid; /* File system mount ID */
TickTock 109:3e6f0e8fca0d 1585
TickTock 109:3e6f0e8fca0d 1586 return FR_OK;
TickTock 109:3e6f0e8fca0d 1587 }
TickTock 109:3e6f0e8fca0d 1588
TickTock 109:3e6f0e8fca0d 1589
TickTock 109:3e6f0e8fca0d 1590
TickTock 109:3e6f0e8fca0d 1591
TickTock 109:3e6f0e8fca0d 1592 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1593 /* Check if the file/dir object is valid or not */
TickTock 109:3e6f0e8fca0d 1594 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1595
TickTock 109:3e6f0e8fca0d 1596 static
TickTock 109:3e6f0e8fca0d 1597 FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
TickTock 109:3e6f0e8fca0d 1598 FATFS *fs, /* Pointer to the file system object */
TickTock 109:3e6f0e8fca0d 1599 WORD id /* Member id of the target object to be checked */
TickTock 109:3e6f0e8fca0d 1600 )
TickTock 109:3e6f0e8fca0d 1601 {
TickTock 109:3e6f0e8fca0d 1602 if (!fs || !fs->fs_type || fs->id != id)
TickTock 109:3e6f0e8fca0d 1603 return FR_INVALID_OBJECT;
TickTock 109:3e6f0e8fca0d 1604
TickTock 109:3e6f0e8fca0d 1605 ENTER_FF(fs); /* Lock file system */
TickTock 109:3e6f0e8fca0d 1606
TickTock 109:3e6f0e8fca0d 1607 if (disk_status(fs->drive) & STA_NOINIT)
TickTock 109:3e6f0e8fca0d 1608 return FR_NOT_READY;
TickTock 109:3e6f0e8fca0d 1609
TickTock 109:3e6f0e8fca0d 1610 return FR_OK;
TickTock 109:3e6f0e8fca0d 1611 }
TickTock 109:3e6f0e8fca0d 1612
TickTock 109:3e6f0e8fca0d 1613
TickTock 109:3e6f0e8fca0d 1614
TickTock 109:3e6f0e8fca0d 1615
TickTock 109:3e6f0e8fca0d 1616 /*--------------------------------------------------------------------------
TickTock 109:3e6f0e8fca0d 1617
TickTock 109:3e6f0e8fca0d 1618 Public Functions
TickTock 109:3e6f0e8fca0d 1619
TickTock 109:3e6f0e8fca0d 1620 --------------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1621
TickTock 109:3e6f0e8fca0d 1622
TickTock 109:3e6f0e8fca0d 1623
TickTock 109:3e6f0e8fca0d 1624 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1625 /* Mount/Unmount a Locical Drive */
TickTock 109:3e6f0e8fca0d 1626 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1627
TickTock 109:3e6f0e8fca0d 1628 FRESULT f_mount (
TickTock 109:3e6f0e8fca0d 1629 BYTE vol, /* Logical drive number to be mounted/unmounted */
TickTock 109:3e6f0e8fca0d 1630 FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
TickTock 109:3e6f0e8fca0d 1631 )
TickTock 109:3e6f0e8fca0d 1632 {
TickTock 109:3e6f0e8fca0d 1633 FATFS *rfs;
TickTock 109:3e6f0e8fca0d 1634
TickTock 109:3e6f0e8fca0d 1635
TickTock 109:3e6f0e8fca0d 1636 if (vol >= _DRIVES) /* Check if the drive number is valid */
TickTock 109:3e6f0e8fca0d 1637 return FR_INVALID_DRIVE;
TickTock 109:3e6f0e8fca0d 1638 rfs = FatFs[vol]; /* Get current fs object */
TickTock 109:3e6f0e8fca0d 1639
TickTock 109:3e6f0e8fca0d 1640 if (rfs) {
TickTock 109:3e6f0e8fca0d 1641 #if _FS_REENTRANT /* Discard sync object of the current volume */
TickTock 109:3e6f0e8fca0d 1642 if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 1643 #endif
TickTock 109:3e6f0e8fca0d 1644 rfs->fs_type = 0; /* Clear old fs object */
TickTock 109:3e6f0e8fca0d 1645 }
TickTock 109:3e6f0e8fca0d 1646
TickTock 109:3e6f0e8fca0d 1647 if (fs) {
TickTock 109:3e6f0e8fca0d 1648 fs->fs_type = 0; /* Clear new fs object */
TickTock 109:3e6f0e8fca0d 1649 #if _FS_REENTRANT /* Create sync object for the new volume */
TickTock 109:3e6f0e8fca0d 1650 if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 1651 #endif
TickTock 109:3e6f0e8fca0d 1652 }
TickTock 109:3e6f0e8fca0d 1653 FatFs[vol] = fs; /* Register new fs object */
TickTock 109:3e6f0e8fca0d 1654
TickTock 109:3e6f0e8fca0d 1655 return FR_OK;
TickTock 109:3e6f0e8fca0d 1656 }
TickTock 109:3e6f0e8fca0d 1657
TickTock 109:3e6f0e8fca0d 1658
TickTock 109:3e6f0e8fca0d 1659
TickTock 109:3e6f0e8fca0d 1660
TickTock 109:3e6f0e8fca0d 1661 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1662 /* Open or Create a File */
TickTock 109:3e6f0e8fca0d 1663 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1664
TickTock 109:3e6f0e8fca0d 1665 FRESULT f_open (
TickTock 109:3e6f0e8fca0d 1666 FIL *fp, /* Pointer to the blank file object */
TickTock 109:3e6f0e8fca0d 1667 const XCHAR *path, /* Pointer to the file name */
TickTock 109:3e6f0e8fca0d 1668 BYTE mode /* Access mode and file open mode flags */
TickTock 109:3e6f0e8fca0d 1669 )
TickTock 109:3e6f0e8fca0d 1670 {
TickTock 109:3e6f0e8fca0d 1671 FRESULT res;
TickTock 109:3e6f0e8fca0d 1672 eDIR dj;
TickTock 109:3e6f0e8fca0d 1673 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 1674 BYTE *dir;
TickTock 109:3e6f0e8fca0d 1675
TickTock 109:3e6f0e8fca0d 1676
TickTock 109:3e6f0e8fca0d 1677 fp->fs = NULL; /* Clear file object */
TickTock 109:3e6f0e8fca0d 1678 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1679 mode &= (FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW);
TickTock 109:3e6f0e8fca0d 1680 res = chk_mounted(&path, &dj.fs, (BYTE)(mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)));
TickTock 109:3e6f0e8fca0d 1681 #else
TickTock 109:3e6f0e8fca0d 1682 mode &= FA_READ;
TickTock 109:3e6f0e8fca0d 1683 res = chk_mounted(&path, &dj.fs, 0);
TickTock 109:3e6f0e8fca0d 1684 #endif
TickTock 109:3e6f0e8fca0d 1685 if (res != FR_OK) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 1686 INITBUF(dj, sfn, lfn);
TickTock 109:3e6f0e8fca0d 1687 res = follow_path(&dj, path); /* Follow the file path */
TickTock 109:3e6f0e8fca0d 1688
TickTock 109:3e6f0e8fca0d 1689 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1690 /* Create or Open a file */
TickTock 109:3e6f0e8fca0d 1691 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
TickTock 109:3e6f0e8fca0d 1692 DWORD ps, cl;
TickTock 109:3e6f0e8fca0d 1693
TickTock 109:3e6f0e8fca0d 1694 if (res != FR_OK) { /* No file, create new */
TickTock 109:3e6f0e8fca0d 1695 if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
TickTock 109:3e6f0e8fca0d 1696 res = dir_register(&dj);
TickTock 109:3e6f0e8fca0d 1697 if (res != FR_OK) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 1698 mode |= FA_CREATE_ALWAYS;
TickTock 109:3e6f0e8fca0d 1699 dir = dj.dir; /* Created entry (SFN entry) */
TickTock 109:3e6f0e8fca0d 1700 }
TickTock 109:3e6f0e8fca0d 1701 else { /* Any object is already existing */
TickTock 109:3e6f0e8fca0d 1702 if (mode & FA_CREATE_NEW) /* Cannot create new */
TickTock 109:3e6f0e8fca0d 1703 LEAVE_FF(dj.fs, FR_EXIST);
TickTock 109:3e6f0e8fca0d 1704 dir = dj.dir;
TickTock 109:3e6f0e8fca0d 1705 if (!dir || (dir[DIR_Attr] & (AM_RDO | AM_DIR))) /* Cannot overwrite it (R/O or DIR) */
TickTock 109:3e6f0e8fca0d 1706 LEAVE_FF(dj.fs, FR_DENIED);
TickTock 109:3e6f0e8fca0d 1707 if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero on over write mode */
TickTock 109:3e6f0e8fca0d 1708 cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); /* Get start cluster */
TickTock 109:3e6f0e8fca0d 1709 ST_WORD(dir+DIR_FstClusHI, 0); /* cluster = 0 */
TickTock 109:3e6f0e8fca0d 1710 ST_WORD(dir+DIR_FstClusLO, 0);
TickTock 109:3e6f0e8fca0d 1711 ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
TickTock 109:3e6f0e8fca0d 1712 dj.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 1713 ps = dj.fs->winsect; /* Remove the cluster chain */
TickTock 109:3e6f0e8fca0d 1714 if (cl) {
TickTock 109:3e6f0e8fca0d 1715 res = remove_chain(dj.fs, cl);
TickTock 109:3e6f0e8fca0d 1716 if (res) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 1717 dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
TickTock 109:3e6f0e8fca0d 1718 }
TickTock 109:3e6f0e8fca0d 1719 res = move_window(dj.fs, ps);
TickTock 109:3e6f0e8fca0d 1720 if (res != FR_OK) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 1721 }
TickTock 109:3e6f0e8fca0d 1722 }
TickTock 109:3e6f0e8fca0d 1723 if (mode & FA_CREATE_ALWAYS) {
TickTock 109:3e6f0e8fca0d 1724 dir[DIR_Attr] = 0; /* Reset attribute */
TickTock 109:3e6f0e8fca0d 1725 ps = get_fattime();
TickTock 109:3e6f0e8fca0d 1726 ST_DWORD(dir+DIR_CrtTime, ps); /* Created time */
TickTock 109:3e6f0e8fca0d 1727 dj.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 1728 mode |= FA__WRITTEN; /* Set file changed flag */
TickTock 109:3e6f0e8fca0d 1729 }
TickTock 109:3e6f0e8fca0d 1730 }
TickTock 109:3e6f0e8fca0d 1731 /* Open an existing file */
TickTock 109:3e6f0e8fca0d 1732 else {
TickTock 109:3e6f0e8fca0d 1733 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 1734 if (res != FR_OK) LEAVE_FF(dj.fs, res); /* Follow failed */
TickTock 109:3e6f0e8fca0d 1735 dir = dj.dir;
TickTock 109:3e6f0e8fca0d 1736 if (!dir || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */
TickTock 109:3e6f0e8fca0d 1737 LEAVE_FF(dj.fs, FR_NO_FILE);
TickTock 109:3e6f0e8fca0d 1738 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1739 if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
TickTock 109:3e6f0e8fca0d 1740 LEAVE_FF(dj.fs, FR_DENIED);
TickTock 109:3e6f0e8fca0d 1741 }
TickTock 109:3e6f0e8fca0d 1742 fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
TickTock 109:3e6f0e8fca0d 1743 fp->dir_ptr = dj.dir;
TickTock 109:3e6f0e8fca0d 1744 #endif
TickTock 109:3e6f0e8fca0d 1745 fp->flag = mode; /* File access mode */
TickTock 109:3e6f0e8fca0d 1746 fp->org_clust = /* File start cluster */
TickTock 109:3e6f0e8fca0d 1747 ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
TickTock 109:3e6f0e8fca0d 1748 fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
TickTock 109:3e6f0e8fca0d 1749 fp->fptr = 0; fp->csect = 255; /* File pointer */
TickTock 109:3e6f0e8fca0d 1750 fp->dsect = 0;
TickTock 109:3e6f0e8fca0d 1751 fp->fs = dj.fs; fp->id = dj.fs->id; /* Owner file system object of the file */
TickTock 109:3e6f0e8fca0d 1752
TickTock 109:3e6f0e8fca0d 1753 LEAVE_FF(dj.fs, FR_OK);
TickTock 109:3e6f0e8fca0d 1754 }
TickTock 109:3e6f0e8fca0d 1755
TickTock 109:3e6f0e8fca0d 1756
TickTock 109:3e6f0e8fca0d 1757
TickTock 109:3e6f0e8fca0d 1758
TickTock 109:3e6f0e8fca0d 1759 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1760 /* Read File */
TickTock 109:3e6f0e8fca0d 1761 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1762
TickTock 109:3e6f0e8fca0d 1763 FRESULT f_read (
TickTock 109:3e6f0e8fca0d 1764 FIL *fp, /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 1765 void *buff, /* Pointer to data buffer */
TickTock 109:3e6f0e8fca0d 1766 UINT btr, /* Number of bytes to read */
TickTock 109:3e6f0e8fca0d 1767 UINT *br /* Pointer to number of bytes read */
TickTock 109:3e6f0e8fca0d 1768 )
TickTock 109:3e6f0e8fca0d 1769 {
TickTock 109:3e6f0e8fca0d 1770 FRESULT res;
TickTock 109:3e6f0e8fca0d 1771 DWORD clst, sect, remain;
TickTock 109:3e6f0e8fca0d 1772 UINT rcnt, cc;
TickTock 109:3e6f0e8fca0d 1773 BYTE *rbuff = (BYTE *)buff;
TickTock 109:3e6f0e8fca0d 1774
TickTock 109:3e6f0e8fca0d 1775
TickTock 109:3e6f0e8fca0d 1776 *br = 0; /* Initialize bytes read */
TickTock 109:3e6f0e8fca0d 1777
TickTock 109:3e6f0e8fca0d 1778 res = validate(fp->fs, fp->id); /* Check validity of the object */
TickTock 109:3e6f0e8fca0d 1779 if (res != FR_OK) LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 1780 if (fp->flag & FA__ERROR) /* Check abort flag */
TickTock 109:3e6f0e8fca0d 1781 LEAVE_FF(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 1782 if (!(fp->flag & FA_READ)) /* Check access mode */
TickTock 109:3e6f0e8fca0d 1783 LEAVE_FF(fp->fs, FR_DENIED);
TickTock 109:3e6f0e8fca0d 1784 remain = fp->fsize - fp->fptr;
TickTock 109:3e6f0e8fca0d 1785 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
TickTock 109:3e6f0e8fca0d 1786
TickTock 109:3e6f0e8fca0d 1787 for ( ; btr; /* Repeat until all data transferred */
TickTock 109:3e6f0e8fca0d 1788 rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
TickTock 109:3e6f0e8fca0d 1789 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
TickTock 109:3e6f0e8fca0d 1790 if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */
TickTock 109:3e6f0e8fca0d 1791 clst = (fp->fptr == 0) ? /* On the top of the file? */
TickTock 109:3e6f0e8fca0d 1792 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
TickTock 109:3e6f0e8fca0d 1793 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 1794 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1795 fp->curr_clust = clst; /* Update current cluster */
TickTock 109:3e6f0e8fca0d 1796 fp->csect = 0; /* Reset sector offset in the cluster */
TickTock 109:3e6f0e8fca0d 1797 }
TickTock 109:3e6f0e8fca0d 1798 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
TickTock 109:3e6f0e8fca0d 1799 if (!sect) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 1800 sect += fp->csect;
TickTock 109:3e6f0e8fca0d 1801 cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
TickTock 109:3e6f0e8fca0d 1802 if (cc) { /* Read maximum contiguous sectors directly */
TickTock 109:3e6f0e8fca0d 1803 if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */
TickTock 109:3e6f0e8fca0d 1804 cc = fp->fs->csize - fp->csect;
TickTock 109:3e6f0e8fca0d 1805 if (disk_read(fp->fs->drive, rbuff, sect, (BYTE)cc) != RES_OK)
TickTock 109:3e6f0e8fca0d 1806 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1807 #if !_FS_READONLY && _FS_MINIMIZE <= 2
TickTock 109:3e6f0e8fca0d 1808 #if _FS_TINY
TickTock 109:3e6f0e8fca0d 1809 if (fp->fs->wflag && fp->fs->winsect - sect < cc) /* Replace one of the read sectors with cached data if it contains a dirty sector */
TickTock 109:3e6f0e8fca0d 1810 mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
TickTock 109:3e6f0e8fca0d 1811 #else
TickTock 109:3e6f0e8fca0d 1812 if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) /* Replace one of the read sectors with cached data if it contains a dirty sector */
TickTock 109:3e6f0e8fca0d 1813 mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
TickTock 109:3e6f0e8fca0d 1814 #endif
TickTock 109:3e6f0e8fca0d 1815 #endif
TickTock 109:3e6f0e8fca0d 1816 fp->csect += (BYTE)cc; /* Next sector address in the cluster */
TickTock 109:3e6f0e8fca0d 1817 rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
TickTock 109:3e6f0e8fca0d 1818 continue;
TickTock 109:3e6f0e8fca0d 1819 }
TickTock 109:3e6f0e8fca0d 1820 #if !_FS_TINY
TickTock 109:3e6f0e8fca0d 1821 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1822 if (fp->flag & FA__DIRTY) { /* Write sector I/O buffer if needed */
TickTock 109:3e6f0e8fca0d 1823 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 1824 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1825 fp->flag &= ~FA__DIRTY;
TickTock 109:3e6f0e8fca0d 1826 }
TickTock 109:3e6f0e8fca0d 1827 #endif
TickTock 109:3e6f0e8fca0d 1828 if (fp->dsect != sect) { /* Fill sector buffer with file data */
TickTock 109:3e6f0e8fca0d 1829 if (disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 1830 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1831 }
TickTock 109:3e6f0e8fca0d 1832 #endif
TickTock 109:3e6f0e8fca0d 1833 fp->dsect = sect;
TickTock 109:3e6f0e8fca0d 1834 fp->csect++; /* Next sector address in the cluster */
TickTock 109:3e6f0e8fca0d 1835 }
TickTock 109:3e6f0e8fca0d 1836 rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
TickTock 109:3e6f0e8fca0d 1837 if (rcnt > btr) rcnt = btr;
TickTock 109:3e6f0e8fca0d 1838 #if _FS_TINY
TickTock 109:3e6f0e8fca0d 1839 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
TickTock 109:3e6f0e8fca0d 1840 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1841 mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
TickTock 109:3e6f0e8fca0d 1842 #else
TickTock 109:3e6f0e8fca0d 1843 mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
TickTock 109:3e6f0e8fca0d 1844 #endif
TickTock 109:3e6f0e8fca0d 1845 }
TickTock 109:3e6f0e8fca0d 1846
TickTock 109:3e6f0e8fca0d 1847 LEAVE_FF(fp->fs, FR_OK);
TickTock 109:3e6f0e8fca0d 1848 }
TickTock 109:3e6f0e8fca0d 1849
TickTock 109:3e6f0e8fca0d 1850
TickTock 109:3e6f0e8fca0d 1851
TickTock 109:3e6f0e8fca0d 1852
TickTock 109:3e6f0e8fca0d 1853 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 1854 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1855 /* Write File */
TickTock 109:3e6f0e8fca0d 1856 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1857
TickTock 109:3e6f0e8fca0d 1858 FRESULT f_write (
TickTock 109:3e6f0e8fca0d 1859 FIL *fp, /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 1860 const void *buff, /* Pointer to the data to be written */
TickTock 109:3e6f0e8fca0d 1861 UINT btw, /* Number of bytes to write */
TickTock 109:3e6f0e8fca0d 1862 UINT *bw /* Pointer to number of bytes written */
TickTock 109:3e6f0e8fca0d 1863 )
TickTock 109:3e6f0e8fca0d 1864 {
TickTock 109:3e6f0e8fca0d 1865 FRESULT res;
TickTock 109:3e6f0e8fca0d 1866 DWORD clst, sect;
TickTock 109:3e6f0e8fca0d 1867 UINT wcnt, cc;
TickTock 109:3e6f0e8fca0d 1868 const BYTE *wbuff = (const BYTE *)buff;
TickTock 109:3e6f0e8fca0d 1869
TickTock 109:3e6f0e8fca0d 1870
TickTock 109:3e6f0e8fca0d 1871 *bw = 0; /* Initialize bytes written */
TickTock 109:3e6f0e8fca0d 1872
TickTock 109:3e6f0e8fca0d 1873 res = validate(fp->fs, fp->id); /* Check validity of the object */
TickTock 109:3e6f0e8fca0d 1874 if (res != FR_OK) LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 1875 if (fp->flag & FA__ERROR) /* Check abort flag */
TickTock 109:3e6f0e8fca0d 1876 LEAVE_FF(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 1877 if (!(fp->flag & FA_WRITE)) /* Check access mode */
TickTock 109:3e6f0e8fca0d 1878 LEAVE_FF(fp->fs, FR_DENIED);
TickTock 109:3e6f0e8fca0d 1879 if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */
TickTock 109:3e6f0e8fca0d 1880
TickTock 109:3e6f0e8fca0d 1881 for ( ; btw; /* Repeat until all data transferred */
TickTock 109:3e6f0e8fca0d 1882 wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
TickTock 109:3e6f0e8fca0d 1883 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
TickTock 109:3e6f0e8fca0d 1884 if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */
TickTock 109:3e6f0e8fca0d 1885 if (fp->fptr == 0) { /* On the top of the file? */
TickTock 109:3e6f0e8fca0d 1886 clst = fp->org_clust; /* Follow from the origin */
TickTock 109:3e6f0e8fca0d 1887 if (clst == 0) /* When there is no cluster chain, */
TickTock 109:3e6f0e8fca0d 1888 fp->org_clust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */
TickTock 109:3e6f0e8fca0d 1889 } else { /* Middle or end of the file */
TickTock 109:3e6f0e8fca0d 1890 clst = create_chain(fp->fs, fp->curr_clust); /* Follow or streach cluster chain */
TickTock 109:3e6f0e8fca0d 1891 }
TickTock 109:3e6f0e8fca0d 1892 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */
TickTock 109:3e6f0e8fca0d 1893 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 1894 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1895 fp->curr_clust = clst; /* Update current cluster */
TickTock 109:3e6f0e8fca0d 1896 fp->csect = 0; /* Reset sector address in the cluster */
TickTock 109:3e6f0e8fca0d 1897 }
TickTock 109:3e6f0e8fca0d 1898 #if _FS_TINY
TickTock 109:3e6f0e8fca0d 1899 if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write back data buffer prior to following direct transfer */
TickTock 109:3e6f0e8fca0d 1900 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1901 #else
TickTock 109:3e6f0e8fca0d 1902 if (fp->flag & FA__DIRTY) { /* Write back data buffer prior to following direct transfer */
TickTock 109:3e6f0e8fca0d 1903 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 1904 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1905 fp->flag &= ~FA__DIRTY;
TickTock 109:3e6f0e8fca0d 1906 }
TickTock 109:3e6f0e8fca0d 1907 #endif
TickTock 109:3e6f0e8fca0d 1908 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
TickTock 109:3e6f0e8fca0d 1909 if (!sect) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 1910 sect += fp->csect;
TickTock 109:3e6f0e8fca0d 1911 cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
TickTock 109:3e6f0e8fca0d 1912 if (cc) { /* Write maximum contiguous sectors directly */
TickTock 109:3e6f0e8fca0d 1913 if (fp->csect + cc > fp->fs->csize) /* Clip at cluster boundary */
TickTock 109:3e6f0e8fca0d 1914 cc = fp->fs->csize - fp->csect;
TickTock 109:3e6f0e8fca0d 1915 if (disk_write(fp->fs->drive, wbuff, sect, (BYTE)cc) != RES_OK)
TickTock 109:3e6f0e8fca0d 1916 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1917 #if _FS_TINY
TickTock 109:3e6f0e8fca0d 1918 if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
TickTock 109:3e6f0e8fca0d 1919 mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
TickTock 109:3e6f0e8fca0d 1920 fp->fs->wflag = 0;
TickTock 109:3e6f0e8fca0d 1921 }
TickTock 109:3e6f0e8fca0d 1922 #else
TickTock 109:3e6f0e8fca0d 1923 if (fp->dsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */
TickTock 109:3e6f0e8fca0d 1924 mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
TickTock 109:3e6f0e8fca0d 1925 fp->flag &= ~FA__DIRTY;
TickTock 109:3e6f0e8fca0d 1926 }
TickTock 109:3e6f0e8fca0d 1927 #endif
TickTock 109:3e6f0e8fca0d 1928 fp->csect += (BYTE)cc; /* Next sector address in the cluster */
TickTock 109:3e6f0e8fca0d 1929 wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
TickTock 109:3e6f0e8fca0d 1930 continue;
TickTock 109:3e6f0e8fca0d 1931 }
TickTock 109:3e6f0e8fca0d 1932 #if _FS_TINY
TickTock 109:3e6f0e8fca0d 1933 if (fp->fptr >= fp->fsize) { /* Avoid silly buffer filling at growing edge */
TickTock 109:3e6f0e8fca0d 1934 if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1935 fp->fs->winsect = sect;
TickTock 109:3e6f0e8fca0d 1936 }
TickTock 109:3e6f0e8fca0d 1937 #else
TickTock 109:3e6f0e8fca0d 1938 if (fp->dsect != sect) { /* Fill sector buffer with file data */
TickTock 109:3e6f0e8fca0d 1939 if (fp->fptr < fp->fsize &&
TickTock 109:3e6f0e8fca0d 1940 disk_read(fp->fs->drive, fp->buf, sect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 1941 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1942 }
TickTock 109:3e6f0e8fca0d 1943 #endif
TickTock 109:3e6f0e8fca0d 1944 fp->dsect = sect;
TickTock 109:3e6f0e8fca0d 1945 fp->csect++; /* Next sector address in the cluster */
TickTock 109:3e6f0e8fca0d 1946 }
TickTock 109:3e6f0e8fca0d 1947 wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Put partial sector into file I/O buffer */
TickTock 109:3e6f0e8fca0d 1948 if (wcnt > btw) wcnt = btw;
TickTock 109:3e6f0e8fca0d 1949 #if _FS_TINY
TickTock 109:3e6f0e8fca0d 1950 if (move_window(fp->fs, fp->dsect)) /* Move sector window */
TickTock 109:3e6f0e8fca0d 1951 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1952 mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
TickTock 109:3e6f0e8fca0d 1953 fp->fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 1954 #else
TickTock 109:3e6f0e8fca0d 1955 mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
TickTock 109:3e6f0e8fca0d 1956 fp->flag |= FA__DIRTY;
TickTock 109:3e6f0e8fca0d 1957 #endif
TickTock 109:3e6f0e8fca0d 1958 }
TickTock 109:3e6f0e8fca0d 1959
TickTock 109:3e6f0e8fca0d 1960 if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
TickTock 109:3e6f0e8fca0d 1961 fp->flag |= FA__WRITTEN; /* Set file changed flag */
TickTock 109:3e6f0e8fca0d 1962
TickTock 109:3e6f0e8fca0d 1963 LEAVE_FF(fp->fs, FR_OK);
TickTock 109:3e6f0e8fca0d 1964 }
TickTock 109:3e6f0e8fca0d 1965
TickTock 109:3e6f0e8fca0d 1966
TickTock 109:3e6f0e8fca0d 1967
TickTock 109:3e6f0e8fca0d 1968
TickTock 109:3e6f0e8fca0d 1969 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1970 /* Synchronize the File Object */
TickTock 109:3e6f0e8fca0d 1971 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 1972
TickTock 109:3e6f0e8fca0d 1973 FRESULT f_sync (
TickTock 109:3e6f0e8fca0d 1974 FIL *fp /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 1975 )
TickTock 109:3e6f0e8fca0d 1976 {
TickTock 109:3e6f0e8fca0d 1977 FRESULT res;
TickTock 109:3e6f0e8fca0d 1978 DWORD tim;
TickTock 109:3e6f0e8fca0d 1979 BYTE *dir;
TickTock 109:3e6f0e8fca0d 1980
TickTock 109:3e6f0e8fca0d 1981
TickTock 109:3e6f0e8fca0d 1982 res = validate(fp->fs, fp->id); /* Check validity of the object */
TickTock 109:3e6f0e8fca0d 1983 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1984 if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
TickTock 109:3e6f0e8fca0d 1985 #if !_FS_TINY /* Write-back dirty buffer */
TickTock 109:3e6f0e8fca0d 1986 if (fp->flag & FA__DIRTY) {
TickTock 109:3e6f0e8fca0d 1987 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 1988 LEAVE_FF(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 1989 fp->flag &= ~FA__DIRTY;
TickTock 109:3e6f0e8fca0d 1990 }
TickTock 109:3e6f0e8fca0d 1991 #endif
TickTock 109:3e6f0e8fca0d 1992 /* Update the directory entry */
TickTock 109:3e6f0e8fca0d 1993 res = move_window(fp->fs, fp->dir_sect);
TickTock 109:3e6f0e8fca0d 1994 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 1995 dir = fp->dir_ptr;
TickTock 109:3e6f0e8fca0d 1996 dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
TickTock 109:3e6f0e8fca0d 1997 ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
TickTock 109:3e6f0e8fca0d 1998 ST_WORD(dir+DIR_FstClusLO, fp->org_clust); /* Update start cluster */
TickTock 109:3e6f0e8fca0d 1999 ST_WORD(dir+DIR_FstClusHI, fp->org_clust >> 16);
TickTock 109:3e6f0e8fca0d 2000 tim = get_fattime(); /* Updated time */
TickTock 109:3e6f0e8fca0d 2001 ST_DWORD(dir+DIR_WrtTime, tim);
TickTock 109:3e6f0e8fca0d 2002 fp->flag &= ~FA__WRITTEN;
TickTock 109:3e6f0e8fca0d 2003 fp->fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 2004 res = sync(fp->fs);
TickTock 109:3e6f0e8fca0d 2005 }
TickTock 109:3e6f0e8fca0d 2006 }
TickTock 109:3e6f0e8fca0d 2007 }
TickTock 109:3e6f0e8fca0d 2008
TickTock 109:3e6f0e8fca0d 2009 LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 2010 }
TickTock 109:3e6f0e8fca0d 2011
TickTock 109:3e6f0e8fca0d 2012 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 2013
TickTock 109:3e6f0e8fca0d 2014
TickTock 109:3e6f0e8fca0d 2015
TickTock 109:3e6f0e8fca0d 2016
TickTock 109:3e6f0e8fca0d 2017 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2018 /* Close File */
TickTock 109:3e6f0e8fca0d 2019 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2020
TickTock 109:3e6f0e8fca0d 2021 FRESULT f_close (
TickTock 109:3e6f0e8fca0d 2022 FIL *fp /* Pointer to the file object to be closed */
TickTock 109:3e6f0e8fca0d 2023 )
TickTock 109:3e6f0e8fca0d 2024 {
TickTock 109:3e6f0e8fca0d 2025 FRESULT res;
TickTock 109:3e6f0e8fca0d 2026
TickTock 109:3e6f0e8fca0d 2027
TickTock 109:3e6f0e8fca0d 2028 #if _FS_READONLY
TickTock 109:3e6f0e8fca0d 2029 res = validate(fp->fs, fp->id);
TickTock 109:3e6f0e8fca0d 2030 if (res == FR_OK) fp->fs = NULL;
TickTock 109:3e6f0e8fca0d 2031 LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 2032 #else
TickTock 109:3e6f0e8fca0d 2033 res = f_sync(fp);
TickTock 109:3e6f0e8fca0d 2034 if (res == FR_OK) fp->fs = NULL;
TickTock 109:3e6f0e8fca0d 2035 return res;
TickTock 109:3e6f0e8fca0d 2036 #endif
TickTock 109:3e6f0e8fca0d 2037 }
TickTock 109:3e6f0e8fca0d 2038
TickTock 109:3e6f0e8fca0d 2039
TickTock 109:3e6f0e8fca0d 2040
TickTock 109:3e6f0e8fca0d 2041
TickTock 109:3e6f0e8fca0d 2042 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2043 /* Change Current Drive/Directory */
TickTock 109:3e6f0e8fca0d 2044 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2045
TickTock 109:3e6f0e8fca0d 2046 #if _FS_RPATH
TickTock 109:3e6f0e8fca0d 2047
TickTock 109:3e6f0e8fca0d 2048 FRESULT f_chdrive (
TickTock 109:3e6f0e8fca0d 2049 BYTE drv /* Drive number */
TickTock 109:3e6f0e8fca0d 2050 )
TickTock 109:3e6f0e8fca0d 2051 {
TickTock 109:3e6f0e8fca0d 2052 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
TickTock 109:3e6f0e8fca0d 2053
TickTock 109:3e6f0e8fca0d 2054 Drive = drv;
TickTock 109:3e6f0e8fca0d 2055
TickTock 109:3e6f0e8fca0d 2056 return FR_OK;
TickTock 109:3e6f0e8fca0d 2057 }
TickTock 109:3e6f0e8fca0d 2058
TickTock 109:3e6f0e8fca0d 2059
TickTock 109:3e6f0e8fca0d 2060
TickTock 109:3e6f0e8fca0d 2061
TickTock 109:3e6f0e8fca0d 2062 FRESULT f_chdir (
TickTock 109:3e6f0e8fca0d 2063 const XCHAR *path /* Pointer to the directory path */
TickTock 109:3e6f0e8fca0d 2064 )
TickTock 109:3e6f0e8fca0d 2065 {
TickTock 109:3e6f0e8fca0d 2066 FRESULT res;
TickTock 109:3e6f0e8fca0d 2067 DIR dj;
TickTock 109:3e6f0e8fca0d 2068 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2069 BYTE *dir;
TickTock 109:3e6f0e8fca0d 2070
TickTock 109:3e6f0e8fca0d 2071
TickTock 109:3e6f0e8fca0d 2072 res = chk_mounted(&path, &dj.fs, 0);
TickTock 109:3e6f0e8fca0d 2073 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2074 INITBUF(dj, sfn, lfn);
TickTock 109:3e6f0e8fca0d 2075 res = follow_path(&dj, path); /* Follow the file path */
TickTock 109:3e6f0e8fca0d 2076 if (res == FR_OK) { /* Follow completed */
TickTock 109:3e6f0e8fca0d 2077 dir = dj.dir; /* Pointer to the entry */
TickTock 109:3e6f0e8fca0d 2078 if (!dir) {
TickTock 109:3e6f0e8fca0d 2079 dj.fs->cdir = 0; /* No entry (root dir) */
TickTock 109:3e6f0e8fca0d 2080 } else {
TickTock 109:3e6f0e8fca0d 2081 if (dir[DIR_Attr] & AM_DIR) /* Reached to the dir */
TickTock 109:3e6f0e8fca0d 2082 dj.fs->cdir = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
TickTock 109:3e6f0e8fca0d 2083 else
TickTock 109:3e6f0e8fca0d 2084 res = FR_NO_PATH; /* Could not reach the dir (it is a file) */
TickTock 109:3e6f0e8fca0d 2085 }
TickTock 109:3e6f0e8fca0d 2086 }
TickTock 109:3e6f0e8fca0d 2087 if (res == FR_NO_FILE) res = FR_NO_PATH;
TickTock 109:3e6f0e8fca0d 2088 }
TickTock 109:3e6f0e8fca0d 2089
TickTock 109:3e6f0e8fca0d 2090 LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2091 }
TickTock 109:3e6f0e8fca0d 2092
TickTock 109:3e6f0e8fca0d 2093 #endif
TickTock 109:3e6f0e8fca0d 2094
TickTock 109:3e6f0e8fca0d 2095
TickTock 109:3e6f0e8fca0d 2096
TickTock 109:3e6f0e8fca0d 2097 #if _FS_MINIMIZE <= 2
TickTock 109:3e6f0e8fca0d 2098 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2099 /* Seek File R/W Pointer */
TickTock 109:3e6f0e8fca0d 2100 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2101
TickTock 109:3e6f0e8fca0d 2102 FRESULT f_lseek (
TickTock 109:3e6f0e8fca0d 2103 FIL *fp, /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 2104 DWORD ofs /* File pointer from top of file */
TickTock 109:3e6f0e8fca0d 2105 )
TickTock 109:3e6f0e8fca0d 2106 {
TickTock 109:3e6f0e8fca0d 2107 FRESULT res;
TickTock 109:3e6f0e8fca0d 2108 DWORD clst, bcs, nsect, ifptr;
TickTock 109:3e6f0e8fca0d 2109
TickTock 109:3e6f0e8fca0d 2110
TickTock 109:3e6f0e8fca0d 2111 res = validate(fp->fs, fp->id); /* Check validity of the object */
TickTock 109:3e6f0e8fca0d 2112 if (res != FR_OK) LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 2113 if (fp->flag & FA__ERROR) /* Check abort flag */
TickTock 109:3e6f0e8fca0d 2114 LEAVE_FF(fp->fs, FR_INT_ERR);
TickTock 110:ffddff3ad2f2 2115 // if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
TickTock 110:ffddff3ad2f2 2116 //#if !_FS_READONLY /* LAJ: Always clip offset with file size */
TickTock 110:ffddff3ad2f2 2117 // && !(fp->flag & FA_WRITE)
TickTock 110:ffddff3ad2f2 2118 //#endif
TickTock 110:ffddff3ad2f2 2119 if (ofs > fp->fsize)
TickTock 110:ffddff3ad2f2 2120 ofs = fp->fsize; /* LAJ: Always clip offset with file size */
TickTock 109:3e6f0e8fca0d 2121
TickTock 109:3e6f0e8fca0d 2122 ifptr = fp->fptr;
TickTock 109:3e6f0e8fca0d 2123 fp->fptr = nsect = 0; fp->csect = 255;
TickTock 109:3e6f0e8fca0d 2124 if (ofs > 0) {
TickTock 109:3e6f0e8fca0d 2125 bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
TickTock 109:3e6f0e8fca0d 2126 if (ifptr > 0 &&
TickTock 109:3e6f0e8fca0d 2127 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
TickTock 109:3e6f0e8fca0d 2128 fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
TickTock 109:3e6f0e8fca0d 2129 ofs -= fp->fptr;
TickTock 109:3e6f0e8fca0d 2130 clst = fp->curr_clust;
TickTock 109:3e6f0e8fca0d 2131 } else { /* When seek to back cluster, */
TickTock 109:3e6f0e8fca0d 2132 clst = fp->org_clust; /* start from the first cluster */
TickTock 109:3e6f0e8fca0d 2133 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 2134 if (clst == 0) { /* If no cluster chain, create a new chain */
TickTock 109:3e6f0e8fca0d 2135 clst = create_chain(fp->fs, 0);
TickTock 109:3e6f0e8fca0d 2136 if (clst == 1) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2137 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 2138 fp->org_clust = clst;
TickTock 109:3e6f0e8fca0d 2139 }
TickTock 109:3e6f0e8fca0d 2140 #endif
TickTock 109:3e6f0e8fca0d 2141 fp->curr_clust = clst;
TickTock 109:3e6f0e8fca0d 2142 }
TickTock 109:3e6f0e8fca0d 2143 if (clst != 0) {
TickTock 109:3e6f0e8fca0d 2144 while (ofs > bcs) { /* Cluster following loop */
TickTock 109:3e6f0e8fca0d 2145 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 2146 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
TickTock 109:3e6f0e8fca0d 2147 clst = create_chain(fp->fs, clst); /* Force streached if in write mode */
TickTock 109:3e6f0e8fca0d 2148 if (clst == 0) { /* When disk gets full, clip file size */
TickTock 109:3e6f0e8fca0d 2149 ofs = bcs; break;
TickTock 109:3e6f0e8fca0d 2150 }
TickTock 109:3e6f0e8fca0d 2151 } else
TickTock 109:3e6f0e8fca0d 2152 #endif
TickTock 109:3e6f0e8fca0d 2153 clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
TickTock 109:3e6f0e8fca0d 2154 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 2155 if (clst <= 1 || clst >= fp->fs->max_clust) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2156 fp->curr_clust = clst;
TickTock 109:3e6f0e8fca0d 2157 fp->fptr += bcs;
TickTock 109:3e6f0e8fca0d 2158 ofs -= bcs;
TickTock 109:3e6f0e8fca0d 2159 }
TickTock 109:3e6f0e8fca0d 2160 fp->fptr += ofs;
TickTock 109:3e6f0e8fca0d 2161 fp->csect = (BYTE)(ofs / SS(fp->fs)); /* Sector offset in the cluster */
TickTock 109:3e6f0e8fca0d 2162 if (ofs % SS(fp->fs)) {
TickTock 109:3e6f0e8fca0d 2163 nsect = clust2sect(fp->fs, clst); /* Current sector */
TickTock 109:3e6f0e8fca0d 2164 if (!nsect) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2165 nsect += fp->csect;
TickTock 109:3e6f0e8fca0d 2166 fp->csect++;
TickTock 109:3e6f0e8fca0d 2167 }
TickTock 109:3e6f0e8fca0d 2168 }
TickTock 109:3e6f0e8fca0d 2169 }
TickTock 109:3e6f0e8fca0d 2170 if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) {
TickTock 109:3e6f0e8fca0d 2171 #if !_FS_TINY
TickTock 109:3e6f0e8fca0d 2172 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 2173 if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */
TickTock 109:3e6f0e8fca0d 2174 if (disk_write(fp->fs->drive, fp->buf, fp->dsect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 2175 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 2176 fp->flag &= ~FA__DIRTY;
TickTock 109:3e6f0e8fca0d 2177 }
TickTock 109:3e6f0e8fca0d 2178 #endif
TickTock 109:3e6f0e8fca0d 2179 if (disk_read(fp->fs->drive, fp->buf, nsect, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 2180 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 2181 #endif
TickTock 109:3e6f0e8fca0d 2182 fp->dsect = nsect;
TickTock 109:3e6f0e8fca0d 2183 }
TickTock 109:3e6f0e8fca0d 2184 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 2185 if (fp->fptr > fp->fsize) { /* Set changed flag if the file size is extended */
TickTock 109:3e6f0e8fca0d 2186 fp->fsize = fp->fptr;
TickTock 109:3e6f0e8fca0d 2187 fp->flag |= FA__WRITTEN;
TickTock 109:3e6f0e8fca0d 2188 }
TickTock 109:3e6f0e8fca0d 2189 #endif
TickTock 109:3e6f0e8fca0d 2190
TickTock 109:3e6f0e8fca0d 2191 LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 2192 }
TickTock 109:3e6f0e8fca0d 2193
TickTock 109:3e6f0e8fca0d 2194
TickTock 109:3e6f0e8fca0d 2195
TickTock 109:3e6f0e8fca0d 2196
TickTock 109:3e6f0e8fca0d 2197 #if _FS_MINIMIZE <= 1
TickTock 109:3e6f0e8fca0d 2198 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2199 /* Create a Directroy Object */
TickTock 109:3e6f0e8fca0d 2200 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2201
TickTock 109:3e6f0e8fca0d 2202 FRESULT f_opendir (
TickTock 109:3e6f0e8fca0d 2203 eDIR *dj, /* Pointer to directory object to create */
TickTock 109:3e6f0e8fca0d 2204 const XCHAR *path /* Pointer to the directory path */
TickTock 109:3e6f0e8fca0d 2205 )
TickTock 109:3e6f0e8fca0d 2206 {
TickTock 109:3e6f0e8fca0d 2207 FRESULT res;
TickTock 109:3e6f0e8fca0d 2208 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2209 BYTE *dir;
TickTock 109:3e6f0e8fca0d 2210
TickTock 109:3e6f0e8fca0d 2211
TickTock 109:3e6f0e8fca0d 2212 res = chk_mounted(&path, &dj->fs, 0);
TickTock 109:3e6f0e8fca0d 2213 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2214 INITBUF((*dj), sfn, lfn);
TickTock 109:3e6f0e8fca0d 2215 res = follow_path(dj, path); /* Follow the path to the directory */
TickTock 109:3e6f0e8fca0d 2216 if (res == FR_OK) { /* Follow completed */
TickTock 109:3e6f0e8fca0d 2217 dir = dj->dir;
TickTock 109:3e6f0e8fca0d 2218 if (dir) { /* It is not the root dir */
TickTock 109:3e6f0e8fca0d 2219 if (dir[DIR_Attr] & AM_DIR) { /* The object is a directory */
TickTock 109:3e6f0e8fca0d 2220 dj->sclust = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
TickTock 109:3e6f0e8fca0d 2221 } else { /* The object is not a directory */
TickTock 109:3e6f0e8fca0d 2222 res = FR_NO_PATH;
TickTock 109:3e6f0e8fca0d 2223 }
TickTock 109:3e6f0e8fca0d 2224 }
TickTock 109:3e6f0e8fca0d 2225 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2226 dj->id = dj->fs->id;
TickTock 109:3e6f0e8fca0d 2227 res = dir_seek(dj, 0); /* Rewind dir */
TickTock 109:3e6f0e8fca0d 2228 }
TickTock 109:3e6f0e8fca0d 2229 }
TickTock 109:3e6f0e8fca0d 2230 if (res == FR_NO_FILE) res = FR_NO_PATH;
TickTock 109:3e6f0e8fca0d 2231 }
TickTock 109:3e6f0e8fca0d 2232
TickTock 109:3e6f0e8fca0d 2233 LEAVE_FF(dj->fs, res);
TickTock 109:3e6f0e8fca0d 2234 }
TickTock 109:3e6f0e8fca0d 2235
TickTock 109:3e6f0e8fca0d 2236
TickTock 109:3e6f0e8fca0d 2237
TickTock 109:3e6f0e8fca0d 2238
TickTock 109:3e6f0e8fca0d 2239 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2240 /* Read Directory Entry in Sequense */
TickTock 109:3e6f0e8fca0d 2241 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2242
TickTock 109:3e6f0e8fca0d 2243 FRESULT f_readdir (
TickTock 109:3e6f0e8fca0d 2244 eDIR *dj, /* Pointer to the open directory object */
TickTock 109:3e6f0e8fca0d 2245 FILINFO *fno /* Pointer to file information to return */
TickTock 109:3e6f0e8fca0d 2246 )
TickTock 109:3e6f0e8fca0d 2247 {
TickTock 109:3e6f0e8fca0d 2248 FRESULT res;
TickTock 109:3e6f0e8fca0d 2249 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2250
TickTock 109:3e6f0e8fca0d 2251
TickTock 109:3e6f0e8fca0d 2252 res = validate(dj->fs, dj->id); /* Check validity of the object */
TickTock 109:3e6f0e8fca0d 2253 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2254 INITBUF((*dj), sfn, lfn);
TickTock 109:3e6f0e8fca0d 2255 if (!fno) {
TickTock 109:3e6f0e8fca0d 2256 res = dir_seek(dj, 0);
TickTock 109:3e6f0e8fca0d 2257 } else {
TickTock 109:3e6f0e8fca0d 2258 res = dir_read(dj);
TickTock 109:3e6f0e8fca0d 2259 if (res == FR_NO_FILE) {
TickTock 109:3e6f0e8fca0d 2260 dj->sect = 0;
TickTock 109:3e6f0e8fca0d 2261 res = FR_OK;
TickTock 109:3e6f0e8fca0d 2262 }
TickTock 109:3e6f0e8fca0d 2263 if (res == FR_OK) { /* A valid entry is found */
TickTock 109:3e6f0e8fca0d 2264 get_fileinfo(dj, fno); /* Get the object information */
TickTock 109:3e6f0e8fca0d 2265 res = dir_next(dj, FALSE); /* Increment index for next */
TickTock 109:3e6f0e8fca0d 2266 if (res == FR_NO_FILE) {
TickTock 109:3e6f0e8fca0d 2267 dj->sect = 0;
TickTock 109:3e6f0e8fca0d 2268 res = FR_OK;
TickTock 109:3e6f0e8fca0d 2269 }
TickTock 109:3e6f0e8fca0d 2270 }
TickTock 109:3e6f0e8fca0d 2271 }
TickTock 109:3e6f0e8fca0d 2272 }
TickTock 109:3e6f0e8fca0d 2273
TickTock 109:3e6f0e8fca0d 2274 LEAVE_FF(dj->fs, res);
TickTock 109:3e6f0e8fca0d 2275 }
TickTock 109:3e6f0e8fca0d 2276
TickTock 109:3e6f0e8fca0d 2277
TickTock 109:3e6f0e8fca0d 2278
TickTock 109:3e6f0e8fca0d 2279 #if _FS_MINIMIZE == 0
TickTock 109:3e6f0e8fca0d 2280 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2281 /* Get File Status */
TickTock 109:3e6f0e8fca0d 2282 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2283
TickTock 109:3e6f0e8fca0d 2284 FRESULT f_stat (
TickTock 109:3e6f0e8fca0d 2285 const XCHAR *path, /* Pointer to the file path */
TickTock 109:3e6f0e8fca0d 2286 FILINFO *fno /* Pointer to file information to return */
TickTock 109:3e6f0e8fca0d 2287 )
TickTock 109:3e6f0e8fca0d 2288 {
TickTock 109:3e6f0e8fca0d 2289 FRESULT res;
TickTock 109:3e6f0e8fca0d 2290 eDIR dj;
TickTock 109:3e6f0e8fca0d 2291 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2292
TickTock 109:3e6f0e8fca0d 2293
TickTock 109:3e6f0e8fca0d 2294 res = chk_mounted(&path, &dj.fs, 0);
TickTock 109:3e6f0e8fca0d 2295 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2296 INITBUF(dj, sfn, lfn);
TickTock 109:3e6f0e8fca0d 2297 res = follow_path(&dj, path); /* Follow the file path */
TickTock 109:3e6f0e8fca0d 2298 if (res == FR_OK) { /* Follwo completed */
TickTock 109:3e6f0e8fca0d 2299 if (dj.dir) /* Found an object */
TickTock 109:3e6f0e8fca0d 2300 get_fileinfo(&dj, fno);
TickTock 109:3e6f0e8fca0d 2301 else /* It is root dir */
TickTock 109:3e6f0e8fca0d 2302 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2303 }
TickTock 109:3e6f0e8fca0d 2304 }
TickTock 109:3e6f0e8fca0d 2305
TickTock 109:3e6f0e8fca0d 2306 LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2307 }
TickTock 109:3e6f0e8fca0d 2308
TickTock 109:3e6f0e8fca0d 2309
TickTock 109:3e6f0e8fca0d 2310
TickTock 109:3e6f0e8fca0d 2311 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 2312 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2313 /* Get Number of Free Clusters */
TickTock 109:3e6f0e8fca0d 2314 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2315
TickTock 109:3e6f0e8fca0d 2316 FRESULT f_getfree (
TickTock 109:3e6f0e8fca0d 2317 const XCHAR *path, /* Pointer to the logical drive number (root dir) */
TickTock 109:3e6f0e8fca0d 2318 DWORD *nclst, /* Pointer to the variable to return number of free clusters */
TickTock 109:3e6f0e8fca0d 2319 FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */
TickTock 109:3e6f0e8fca0d 2320 )
TickTock 109:3e6f0e8fca0d 2321 {
TickTock 109:3e6f0e8fca0d 2322 FRESULT res;
TickTock 109:3e6f0e8fca0d 2323 DWORD n, clst, sect, stat;
TickTock 109:3e6f0e8fca0d 2324 UINT i;
TickTock 109:3e6f0e8fca0d 2325 BYTE fat, *p;
TickTock 109:3e6f0e8fca0d 2326
TickTock 109:3e6f0e8fca0d 2327
TickTock 109:3e6f0e8fca0d 2328 /* Get drive number */
TickTock 109:3e6f0e8fca0d 2329 res = chk_mounted(&path, fatfs, 0);
TickTock 109:3e6f0e8fca0d 2330 if (res != FR_OK) LEAVE_FF(*fatfs, res);
TickTock 109:3e6f0e8fca0d 2331
TickTock 109:3e6f0e8fca0d 2332 /* If number of free cluster is valid, return it without cluster scan. */
TickTock 109:3e6f0e8fca0d 2333 if ((*fatfs)->free_clust <= (*fatfs)->max_clust - 2) {
TickTock 109:3e6f0e8fca0d 2334 *nclst = (*fatfs)->free_clust;
TickTock 109:3e6f0e8fca0d 2335 LEAVE_FF(*fatfs, FR_OK);
TickTock 109:3e6f0e8fca0d 2336 }
TickTock 109:3e6f0e8fca0d 2337
TickTock 109:3e6f0e8fca0d 2338 /* Get number of free clusters */
TickTock 109:3e6f0e8fca0d 2339 fat = (*fatfs)->fs_type;
TickTock 109:3e6f0e8fca0d 2340 n = 0;
TickTock 109:3e6f0e8fca0d 2341 if (fat == FS_FAT12) {
TickTock 109:3e6f0e8fca0d 2342 clst = 2;
TickTock 109:3e6f0e8fca0d 2343 do {
TickTock 109:3e6f0e8fca0d 2344 stat = get_fat(*fatfs, clst);
TickTock 109:3e6f0e8fca0d 2345 if (stat == 0xFFFFFFFF) LEAVE_FF(*fatfs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 2346 if (stat == 1) LEAVE_FF(*fatfs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2347 if (stat == 0) n++;
TickTock 109:3e6f0e8fca0d 2348 } while (++clst < (*fatfs)->max_clust);
TickTock 109:3e6f0e8fca0d 2349 } else {
TickTock 109:3e6f0e8fca0d 2350 clst = (*fatfs)->max_clust;
TickTock 109:3e6f0e8fca0d 2351 sect = (*fatfs)->fatbase;
TickTock 109:3e6f0e8fca0d 2352 i = 0; p = 0;
TickTock 109:3e6f0e8fca0d 2353 do {
TickTock 109:3e6f0e8fca0d 2354 if (!i) {
TickTock 109:3e6f0e8fca0d 2355 res = move_window(*fatfs, sect++);
TickTock 109:3e6f0e8fca0d 2356 if (res != FR_OK)
TickTock 109:3e6f0e8fca0d 2357 LEAVE_FF(*fatfs, res);
TickTock 109:3e6f0e8fca0d 2358 p = (*fatfs)->win;
TickTock 109:3e6f0e8fca0d 2359 i = SS(*fatfs);
TickTock 109:3e6f0e8fca0d 2360 }
TickTock 109:3e6f0e8fca0d 2361 if (fat == FS_FAT16) {
TickTock 109:3e6f0e8fca0d 2362 if (LD_WORD(p) == 0) n++;
TickTock 109:3e6f0e8fca0d 2363 p += 2; i -= 2;
TickTock 109:3e6f0e8fca0d 2364 } else {
TickTock 109:3e6f0e8fca0d 2365 if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
TickTock 109:3e6f0e8fca0d 2366 p += 4; i -= 4;
TickTock 109:3e6f0e8fca0d 2367 }
TickTock 109:3e6f0e8fca0d 2368 } while (--clst);
TickTock 109:3e6f0e8fca0d 2369 }
TickTock 109:3e6f0e8fca0d 2370 (*fatfs)->free_clust = n;
TickTock 109:3e6f0e8fca0d 2371 if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1;
TickTock 109:3e6f0e8fca0d 2372 *nclst = n;
TickTock 109:3e6f0e8fca0d 2373
TickTock 109:3e6f0e8fca0d 2374 LEAVE_FF(*fatfs, FR_OK);
TickTock 109:3e6f0e8fca0d 2375 }
TickTock 109:3e6f0e8fca0d 2376
TickTock 109:3e6f0e8fca0d 2377
TickTock 109:3e6f0e8fca0d 2378
TickTock 109:3e6f0e8fca0d 2379
TickTock 109:3e6f0e8fca0d 2380 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2381 /* Truncate File */
TickTock 109:3e6f0e8fca0d 2382 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2383
TickTock 109:3e6f0e8fca0d 2384 FRESULT f_truncate (
TickTock 109:3e6f0e8fca0d 2385 FIL *fp /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 2386 )
TickTock 109:3e6f0e8fca0d 2387 {
TickTock 109:3e6f0e8fca0d 2388 FRESULT res;
TickTock 109:3e6f0e8fca0d 2389 DWORD ncl;
TickTock 109:3e6f0e8fca0d 2390
TickTock 109:3e6f0e8fca0d 2391
TickTock 109:3e6f0e8fca0d 2392 res = validate(fp->fs, fp->id); /* Check validity of the object */
TickTock 109:3e6f0e8fca0d 2393 if (res != FR_OK) LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 2394 if (fp->flag & FA__ERROR) /* Check abort flag */
TickTock 109:3e6f0e8fca0d 2395 LEAVE_FF(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2396 if (!(fp->flag & FA_WRITE)) /* Check access mode */
TickTock 109:3e6f0e8fca0d 2397 LEAVE_FF(fp->fs, FR_DENIED);
TickTock 109:3e6f0e8fca0d 2398
TickTock 109:3e6f0e8fca0d 2399 if (fp->fsize > fp->fptr) {
TickTock 109:3e6f0e8fca0d 2400 fp->fsize = fp->fptr; /* Set file size to current R/W point */
TickTock 109:3e6f0e8fca0d 2401 fp->flag |= FA__WRITTEN;
TickTock 109:3e6f0e8fca0d 2402 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
TickTock 109:3e6f0e8fca0d 2403 res = remove_chain(fp->fs, fp->org_clust);
TickTock 109:3e6f0e8fca0d 2404 fp->org_clust = 0;
TickTock 109:3e6f0e8fca0d 2405 } else { /* When truncate a part of the file, remove remaining clusters */
TickTock 109:3e6f0e8fca0d 2406 ncl = get_fat(fp->fs, fp->curr_clust);
TickTock 109:3e6f0e8fca0d 2407 res = FR_OK;
TickTock 109:3e6f0e8fca0d 2408 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2409 if (ncl == 1) res = FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 2410 if (res == FR_OK && ncl < fp->fs->max_clust) {
TickTock 109:3e6f0e8fca0d 2411 res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF);
TickTock 109:3e6f0e8fca0d 2412 if (res == FR_OK) res = remove_chain(fp->fs, ncl);
TickTock 109:3e6f0e8fca0d 2413 }
TickTock 109:3e6f0e8fca0d 2414 }
TickTock 109:3e6f0e8fca0d 2415 }
TickTock 109:3e6f0e8fca0d 2416 if (res != FR_OK) fp->flag |= FA__ERROR;
TickTock 109:3e6f0e8fca0d 2417
TickTock 109:3e6f0e8fca0d 2418 LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 2419 }
TickTock 109:3e6f0e8fca0d 2420
TickTock 109:3e6f0e8fca0d 2421
TickTock 109:3e6f0e8fca0d 2422
TickTock 109:3e6f0e8fca0d 2423
TickTock 109:3e6f0e8fca0d 2424 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2425 /* Delete a File or Directory */
TickTock 109:3e6f0e8fca0d 2426 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2427
TickTock 109:3e6f0e8fca0d 2428 FRESULT f_unlink (
TickTock 109:3e6f0e8fca0d 2429 const XCHAR *path /* Pointer to the file or directory path */
TickTock 109:3e6f0e8fca0d 2430 )
TickTock 109:3e6f0e8fca0d 2431 {
TickTock 109:3e6f0e8fca0d 2432 FRESULT res;
TickTock 109:3e6f0e8fca0d 2433 eDIR dj, sdj;
TickTock 109:3e6f0e8fca0d 2434 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2435 BYTE *dir;
TickTock 109:3e6f0e8fca0d 2436 DWORD dclst;
TickTock 109:3e6f0e8fca0d 2437
TickTock 109:3e6f0e8fca0d 2438
TickTock 109:3e6f0e8fca0d 2439 res = chk_mounted(&path, &dj.fs, 1);
TickTock 109:3e6f0e8fca0d 2440 if (res != FR_OK) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2441
TickTock 109:3e6f0e8fca0d 2442 INITBUF(dj, sfn, lfn);
TickTock 109:3e6f0e8fca0d 2443 res = follow_path(&dj, path); /* Follow the file path */
TickTock 109:3e6f0e8fca0d 2444 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
TickTock 109:3e6f0e8fca0d 2445 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2446 if (res != FR_OK) LEAVE_FF(dj.fs, res); /* Follow failed */
TickTock 109:3e6f0e8fca0d 2447
TickTock 109:3e6f0e8fca0d 2448 dir = dj.dir;
TickTock 109:3e6f0e8fca0d 2449 if (!dir) /* Is it the root directory? */
TickTock 109:3e6f0e8fca0d 2450 LEAVE_FF(dj.fs, FR_INVALID_NAME);
TickTock 109:3e6f0e8fca0d 2451 if (dir[DIR_Attr] & AM_RDO) /* Is it a R/O object? */
TickTock 109:3e6f0e8fca0d 2452 LEAVE_FF(dj.fs, FR_DENIED);
TickTock 109:3e6f0e8fca0d 2453 dclst = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
TickTock 109:3e6f0e8fca0d 2454
TickTock 109:3e6f0e8fca0d 2455 if (dir[DIR_Attr] & AM_DIR) { /* It is a sub-directory */
TickTock 109:3e6f0e8fca0d 2456 if (dclst < 2) LEAVE_FF(dj.fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2457 mem_cpy(&sdj, &dj, sizeof(eDIR)); /* Check if the sub-dir is empty or not */
TickTock 109:3e6f0e8fca0d 2458 sdj.sclust = dclst;
TickTock 109:3e6f0e8fca0d 2459 res = dir_seek(&sdj, 2);
TickTock 109:3e6f0e8fca0d 2460 if (res != FR_OK) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2461 res = dir_read(&sdj);
TickTock 109:3e6f0e8fca0d 2462 if (res == FR_OK) res = FR_DENIED; /* Not empty sub-dir */
TickTock 109:3e6f0e8fca0d 2463 if (res != FR_NO_FILE) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2464 }
TickTock 109:3e6f0e8fca0d 2465
TickTock 109:3e6f0e8fca0d 2466 res = dir_remove(&dj); /* Remove directory entry */
TickTock 109:3e6f0e8fca0d 2467 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2468 if (dclst)
TickTock 109:3e6f0e8fca0d 2469 res = remove_chain(dj.fs, dclst); /* Remove the cluster chain */
TickTock 109:3e6f0e8fca0d 2470 if (res == FR_OK) res = sync(dj.fs);
TickTock 109:3e6f0e8fca0d 2471 }
TickTock 109:3e6f0e8fca0d 2472
TickTock 109:3e6f0e8fca0d 2473 LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2474 }
TickTock 109:3e6f0e8fca0d 2475
TickTock 109:3e6f0e8fca0d 2476
TickTock 109:3e6f0e8fca0d 2477
TickTock 109:3e6f0e8fca0d 2478
TickTock 109:3e6f0e8fca0d 2479 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2480 /* Create a Directory */
TickTock 109:3e6f0e8fca0d 2481 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2482
TickTock 109:3e6f0e8fca0d 2483 FRESULT f_mkdir (
TickTock 109:3e6f0e8fca0d 2484 const XCHAR *path /* Pointer to the directory path */
TickTock 109:3e6f0e8fca0d 2485 )
TickTock 109:3e6f0e8fca0d 2486 {
TickTock 109:3e6f0e8fca0d 2487 FRESULT res;
TickTock 109:3e6f0e8fca0d 2488 eDIR dj;
TickTock 109:3e6f0e8fca0d 2489 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2490 BYTE *dir, n;
TickTock 109:3e6f0e8fca0d 2491 DWORD dsect, dclst, pclst, tim;
TickTock 109:3e6f0e8fca0d 2492
TickTock 109:3e6f0e8fca0d 2493
TickTock 109:3e6f0e8fca0d 2494 res = chk_mounted(&path, &dj.fs, 1);
TickTock 109:3e6f0e8fca0d 2495 if (res != FR_OK) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2496
TickTock 109:3e6f0e8fca0d 2497 INITBUF(dj, sfn, lfn);
TickTock 109:3e6f0e8fca0d 2498 res = follow_path(&dj, path); /* Follow the file path */
TickTock 109:3e6f0e8fca0d 2499 if (res == FR_OK) res = FR_EXIST; /* Any file or directory is already existing */
TickTock 109:3e6f0e8fca0d 2500 if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT))
TickTock 109:3e6f0e8fca0d 2501 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2502 if (res != FR_NO_FILE) /* Any error occured */
TickTock 109:3e6f0e8fca0d 2503 LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2504
TickTock 109:3e6f0e8fca0d 2505 dclst = create_chain(dj.fs, 0); /* Allocate a new cluster for new directory table */
TickTock 109:3e6f0e8fca0d 2506 res = FR_OK;
TickTock 109:3e6f0e8fca0d 2507 if (dclst == 0) res = FR_DENIED;
TickTock 109:3e6f0e8fca0d 2508 if (dclst == 1) res = FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 2509 if (dclst == 0xFFFFFFFF) res = FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2510 if (res == FR_OK)
TickTock 109:3e6f0e8fca0d 2511 res = move_window(dj.fs, 0);
TickTock 109:3e6f0e8fca0d 2512 if (res != FR_OK) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2513 dsect = clust2sect(dj.fs, dclst);
TickTock 109:3e6f0e8fca0d 2514
TickTock 109:3e6f0e8fca0d 2515 dir = dj.fs->win; /* Initialize the new directory table */
TickTock 109:3e6f0e8fca0d 2516 mem_set(dir, 0, SS(dj.fs));
TickTock 109:3e6f0e8fca0d 2517 mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
TickTock 109:3e6f0e8fca0d 2518 dir[DIR_Name] = '.';
TickTock 109:3e6f0e8fca0d 2519 dir[DIR_Attr] = AM_DIR;
TickTock 109:3e6f0e8fca0d 2520 tim = get_fattime();
TickTock 109:3e6f0e8fca0d 2521 ST_DWORD(dir+DIR_WrtTime, tim);
TickTock 109:3e6f0e8fca0d 2522 ST_WORD(dir+DIR_FstClusLO, dclst);
TickTock 109:3e6f0e8fca0d 2523 ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
TickTock 109:3e6f0e8fca0d 2524 mem_cpy(dir+32, dir, 32); /* Create ".." entry */
TickTock 109:3e6f0e8fca0d 2525 dir[33] = '.';
TickTock 109:3e6f0e8fca0d 2526 pclst = dj.sclust;
TickTock 109:3e6f0e8fca0d 2527 if (dj.fs->fs_type == FS_FAT32 && pclst == dj.fs->dirbase)
TickTock 109:3e6f0e8fca0d 2528 pclst = 0;
TickTock 109:3e6f0e8fca0d 2529 ST_WORD(dir+32+DIR_FstClusLO, pclst);
TickTock 109:3e6f0e8fca0d 2530 ST_WORD(dir+32+DIR_FstClusHI, pclst >> 16);
TickTock 109:3e6f0e8fca0d 2531 for (n = 0; n < dj.fs->csize; n++) { /* Write dot entries and clear left sectors */
TickTock 109:3e6f0e8fca0d 2532 dj.fs->winsect = dsect++;
TickTock 109:3e6f0e8fca0d 2533 dj.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 2534 res = move_window(dj.fs, 0);
TickTock 109:3e6f0e8fca0d 2535 if (res) LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2536 mem_set(dir, 0, SS(dj.fs));
TickTock 109:3e6f0e8fca0d 2537 }
TickTock 109:3e6f0e8fca0d 2538
TickTock 109:3e6f0e8fca0d 2539 res = dir_register(&dj);
TickTock 109:3e6f0e8fca0d 2540 if (res != FR_OK) {
TickTock 109:3e6f0e8fca0d 2541 remove_chain(dj.fs, dclst);
TickTock 109:3e6f0e8fca0d 2542 } else {
TickTock 109:3e6f0e8fca0d 2543 dir = dj.dir;
TickTock 109:3e6f0e8fca0d 2544 dir[DIR_Attr] = AM_DIR; /* Attribute */
TickTock 109:3e6f0e8fca0d 2545 ST_DWORD(dir+DIR_WrtTime, tim); /* Crated time */
TickTock 109:3e6f0e8fca0d 2546 ST_WORD(dir+DIR_FstClusLO, dclst); /* Table start cluster */
TickTock 109:3e6f0e8fca0d 2547 ST_WORD(dir+DIR_FstClusHI, dclst >> 16);
TickTock 109:3e6f0e8fca0d 2548 dj.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 2549 res = sync(dj.fs);
TickTock 109:3e6f0e8fca0d 2550 }
TickTock 109:3e6f0e8fca0d 2551
TickTock 109:3e6f0e8fca0d 2552 LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2553 }
TickTock 109:3e6f0e8fca0d 2554
TickTock 109:3e6f0e8fca0d 2555
TickTock 109:3e6f0e8fca0d 2556
TickTock 109:3e6f0e8fca0d 2557
TickTock 109:3e6f0e8fca0d 2558 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2559 /* Change File Attribute */
TickTock 109:3e6f0e8fca0d 2560 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2561
TickTock 109:3e6f0e8fca0d 2562 FRESULT f_chmod (
TickTock 109:3e6f0e8fca0d 2563 const XCHAR *path, /* Pointer to the file path */
TickTock 109:3e6f0e8fca0d 2564 BYTE value, /* Attribute bits */
TickTock 109:3e6f0e8fca0d 2565 BYTE mask /* Attribute mask to change */
TickTock 109:3e6f0e8fca0d 2566 )
TickTock 109:3e6f0e8fca0d 2567 {
TickTock 109:3e6f0e8fca0d 2568 FRESULT res;
TickTock 109:3e6f0e8fca0d 2569 eDIR dj;
TickTock 109:3e6f0e8fca0d 2570 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2571 BYTE *dir;
TickTock 109:3e6f0e8fca0d 2572
TickTock 109:3e6f0e8fca0d 2573
TickTock 109:3e6f0e8fca0d 2574 res = chk_mounted(&path, &dj.fs, 1);
TickTock 109:3e6f0e8fca0d 2575 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2576 INITBUF(dj, sfn, lfn);
TickTock 109:3e6f0e8fca0d 2577 res = follow_path(&dj, path); /* Follow the file path */
TickTock 109:3e6f0e8fca0d 2578 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
TickTock 109:3e6f0e8fca0d 2579 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2580 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2581 dir = dj.dir;
TickTock 109:3e6f0e8fca0d 2582 if (!dir) { /* Is it a root directory? */
TickTock 109:3e6f0e8fca0d 2583 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2584 } else { /* File or sub directory */
TickTock 109:3e6f0e8fca0d 2585 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
TickTock 109:3e6f0e8fca0d 2586 dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
TickTock 109:3e6f0e8fca0d 2587 dj.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 2588 res = sync(dj.fs);
TickTock 109:3e6f0e8fca0d 2589 }
TickTock 109:3e6f0e8fca0d 2590 }
TickTock 109:3e6f0e8fca0d 2591 }
TickTock 109:3e6f0e8fca0d 2592
TickTock 109:3e6f0e8fca0d 2593 LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2594 }
TickTock 109:3e6f0e8fca0d 2595
TickTock 109:3e6f0e8fca0d 2596
TickTock 109:3e6f0e8fca0d 2597
TickTock 109:3e6f0e8fca0d 2598
TickTock 109:3e6f0e8fca0d 2599 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2600 /* Change Timestamp */
TickTock 109:3e6f0e8fca0d 2601 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2602
TickTock 109:3e6f0e8fca0d 2603 FRESULT f_utime (
TickTock 109:3e6f0e8fca0d 2604 const XCHAR *path, /* Pointer to the file/directory name */
TickTock 109:3e6f0e8fca0d 2605 const FILINFO *fno /* Pointer to the timestamp to be set */
TickTock 109:3e6f0e8fca0d 2606 )
TickTock 109:3e6f0e8fca0d 2607 {
TickTock 109:3e6f0e8fca0d 2608 FRESULT res;
TickTock 109:3e6f0e8fca0d 2609 eDIR dj;
TickTock 109:3e6f0e8fca0d 2610 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2611 BYTE *dir;
TickTock 109:3e6f0e8fca0d 2612
TickTock 109:3e6f0e8fca0d 2613
TickTock 109:3e6f0e8fca0d 2614 res = chk_mounted(&path, &dj.fs, 1);
TickTock 109:3e6f0e8fca0d 2615 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2616 INITBUF(dj, sfn, lfn);
TickTock 109:3e6f0e8fca0d 2617 res = follow_path(&dj, path); /* Follow the file path */
TickTock 109:3e6f0e8fca0d 2618 if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT))
TickTock 109:3e6f0e8fca0d 2619 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2620 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2621 dir = dj.dir;
TickTock 109:3e6f0e8fca0d 2622 if (!dir) { /* Root directory */
TickTock 109:3e6f0e8fca0d 2623 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2624 } else { /* File or sub-directory */
TickTock 109:3e6f0e8fca0d 2625 ST_WORD(dir+DIR_WrtTime, fno->ftime);
TickTock 109:3e6f0e8fca0d 2626 ST_WORD(dir+DIR_WrtDate, fno->fdate);
TickTock 109:3e6f0e8fca0d 2627 dj.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 2628 res = sync(dj.fs);
TickTock 109:3e6f0e8fca0d 2629 }
TickTock 109:3e6f0e8fca0d 2630 }
TickTock 109:3e6f0e8fca0d 2631 }
TickTock 109:3e6f0e8fca0d 2632
TickTock 109:3e6f0e8fca0d 2633 LEAVE_FF(dj.fs, res);
TickTock 109:3e6f0e8fca0d 2634 }
TickTock 109:3e6f0e8fca0d 2635
TickTock 109:3e6f0e8fca0d 2636
TickTock 109:3e6f0e8fca0d 2637
TickTock 109:3e6f0e8fca0d 2638
TickTock 109:3e6f0e8fca0d 2639 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2640 /* Rename File/Directory */
TickTock 109:3e6f0e8fca0d 2641 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2642
TickTock 109:3e6f0e8fca0d 2643 FRESULT f_rename (
TickTock 109:3e6f0e8fca0d 2644 const XCHAR *path_old, /* Pointer to the old name */
TickTock 109:3e6f0e8fca0d 2645 const XCHAR *path_new /* Pointer to the new name */
TickTock 109:3e6f0e8fca0d 2646 )
TickTock 109:3e6f0e8fca0d 2647 {
TickTock 109:3e6f0e8fca0d 2648 FRESULT res;
TickTock 109:3e6f0e8fca0d 2649 eDIR dj_old, dj_new;
TickTock 109:3e6f0e8fca0d 2650 NAMEBUF(sfn, lfn);
TickTock 109:3e6f0e8fca0d 2651 BYTE buf[21], *dir;
TickTock 109:3e6f0e8fca0d 2652 DWORD dw;
TickTock 109:3e6f0e8fca0d 2653
TickTock 109:3e6f0e8fca0d 2654
TickTock 109:3e6f0e8fca0d 2655 INITBUF(dj_old, sfn, lfn);
TickTock 109:3e6f0e8fca0d 2656 res = chk_mounted(&path_old, &dj_old.fs, 1);
TickTock 109:3e6f0e8fca0d 2657 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2658 dj_new.fs = dj_old.fs;
TickTock 109:3e6f0e8fca0d 2659 res = follow_path(&dj_old, path_old); /* Check old object */
TickTock 109:3e6f0e8fca0d 2660 if (_FS_RPATH && res == FR_OK && (dj_old.fn[NS] & NS_DOT))
TickTock 109:3e6f0e8fca0d 2661 res = FR_INVALID_NAME;
TickTock 109:3e6f0e8fca0d 2662 }
TickTock 109:3e6f0e8fca0d 2663 if (res != FR_OK) LEAVE_FF(dj_old.fs, res); /* The old object is not found */
TickTock 109:3e6f0e8fca0d 2664
TickTock 109:3e6f0e8fca0d 2665 if (!dj_old.dir) LEAVE_FF(dj_old.fs, FR_NO_FILE); /* Is root dir? */
TickTock 109:3e6f0e8fca0d 2666 mem_cpy(buf, dj_old.dir+DIR_Attr, 21); /* Save the object information */
TickTock 109:3e6f0e8fca0d 2667
TickTock 109:3e6f0e8fca0d 2668 mem_cpy(&dj_new, &dj_old, sizeof(eDIR));
TickTock 109:3e6f0e8fca0d 2669 res = follow_path(&dj_new, path_new); /* Check new object */
TickTock 109:3e6f0e8fca0d 2670 if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */
TickTock 109:3e6f0e8fca0d 2671 if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */
TickTock 109:3e6f0e8fca0d 2672 res = dir_register(&dj_new); /* Register the new object */
TickTock 109:3e6f0e8fca0d 2673 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2674 dir = dj_new.dir; /* Copy object information into new entry */
TickTock 109:3e6f0e8fca0d 2675 mem_cpy(dir+13, buf+2, 19);
TickTock 109:3e6f0e8fca0d 2676 dir[DIR_Attr] = buf[0] | AM_ARC;
TickTock 109:3e6f0e8fca0d 2677 dj_old.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 2678 if (dir[DIR_Attr] & AM_DIR) { /* Update .. entry in the directory if needed */
TickTock 109:3e6f0e8fca0d 2679 dw = clust2sect(dj_new.fs, (DWORD)LD_WORD(dir+DIR_FstClusHI) | LD_WORD(dir+DIR_FstClusLO));
TickTock 109:3e6f0e8fca0d 2680 if (!dw) {
TickTock 109:3e6f0e8fca0d 2681 res = FR_INT_ERR;
TickTock 109:3e6f0e8fca0d 2682 } else {
TickTock 109:3e6f0e8fca0d 2683 res = move_window(dj_new.fs, dw);
TickTock 109:3e6f0e8fca0d 2684 dir = dj_new.fs->win+32;
TickTock 109:3e6f0e8fca0d 2685 if (res == FR_OK && dir[1] == '.') {
TickTock 109:3e6f0e8fca0d 2686 dw = (dj_new.fs->fs_type == FS_FAT32 && dj_new.sclust == dj_new.fs->dirbase) ? 0 : dj_new.sclust;
TickTock 109:3e6f0e8fca0d 2687 ST_WORD(dir+DIR_FstClusLO, dw);
TickTock 109:3e6f0e8fca0d 2688 ST_WORD(dir+DIR_FstClusHI, dw >> 16);
TickTock 109:3e6f0e8fca0d 2689 dj_new.fs->wflag = 1;
TickTock 109:3e6f0e8fca0d 2690 }
TickTock 109:3e6f0e8fca0d 2691 }
TickTock 109:3e6f0e8fca0d 2692 }
TickTock 109:3e6f0e8fca0d 2693 if (res == FR_OK) {
TickTock 109:3e6f0e8fca0d 2694 res = dir_remove(&dj_old); /* Remove old entry */
TickTock 109:3e6f0e8fca0d 2695 if (res == FR_OK)
TickTock 109:3e6f0e8fca0d 2696 res = sync(dj_old.fs);
TickTock 109:3e6f0e8fca0d 2697 }
TickTock 109:3e6f0e8fca0d 2698 }
TickTock 109:3e6f0e8fca0d 2699 }
TickTock 109:3e6f0e8fca0d 2700
TickTock 109:3e6f0e8fca0d 2701 LEAVE_FF(dj_old.fs, res);
TickTock 109:3e6f0e8fca0d 2702 }
TickTock 109:3e6f0e8fca0d 2703
TickTock 109:3e6f0e8fca0d 2704 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 2705 #endif /* _FS_MINIMIZE == 0 */
TickTock 109:3e6f0e8fca0d 2706 #endif /* _FS_MINIMIZE <= 1 */
TickTock 109:3e6f0e8fca0d 2707 #endif /* _FS_MINIMIZE <= 2 */
TickTock 109:3e6f0e8fca0d 2708
TickTock 109:3e6f0e8fca0d 2709
TickTock 109:3e6f0e8fca0d 2710
TickTock 109:3e6f0e8fca0d 2711 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2712 /* Forward data to the stream directly (Available on only _FS_TINY cfg) */
TickTock 109:3e6f0e8fca0d 2713 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2714 #if _USE_FORWARD && _FS_TINY
TickTock 109:3e6f0e8fca0d 2715
TickTock 109:3e6f0e8fca0d 2716 FRESULT f_forward (
TickTock 109:3e6f0e8fca0d 2717 FIL *fp, /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 2718 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */
TickTock 109:3e6f0e8fca0d 2719 UINT btr, /* Number of bytes to forward */
TickTock 109:3e6f0e8fca0d 2720 UINT *bf /* Pointer to number of bytes forwarded */
TickTock 109:3e6f0e8fca0d 2721 )
TickTock 109:3e6f0e8fca0d 2722 {
TickTock 109:3e6f0e8fca0d 2723 FRESULT res;
TickTock 109:3e6f0e8fca0d 2724 DWORD remain, clst, sect;
TickTock 109:3e6f0e8fca0d 2725 UINT rcnt;
TickTock 109:3e6f0e8fca0d 2726
TickTock 109:3e6f0e8fca0d 2727
TickTock 109:3e6f0e8fca0d 2728 *bf = 0;
TickTock 109:3e6f0e8fca0d 2729
TickTock 109:3e6f0e8fca0d 2730 res = validate(fp->fs, fp->id); /* Check validity of the object */
TickTock 109:3e6f0e8fca0d 2731 if (res != FR_OK) LEAVE_FF(fp->fs, res);
TickTock 109:3e6f0e8fca0d 2732 if (fp->flag & FA__ERROR) /* Check error flag */
TickTock 109:3e6f0e8fca0d 2733 LEAVE_FF(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2734 if (!(fp->flag & FA_READ)) /* Check access mode */
TickTock 109:3e6f0e8fca0d 2735 LEAVE_FF(fp->fs, FR_DENIED);
TickTock 109:3e6f0e8fca0d 2736
TickTock 109:3e6f0e8fca0d 2737 remain = fp->fsize - fp->fptr;
TickTock 109:3e6f0e8fca0d 2738 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
TickTock 109:3e6f0e8fca0d 2739
TickTock 109:3e6f0e8fca0d 2740 for ( ; btr && (*func)(NULL, 0); /* Repeat until all data transferred or stream becomes busy */
TickTock 109:3e6f0e8fca0d 2741 fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) {
TickTock 109:3e6f0e8fca0d 2742 if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
TickTock 109:3e6f0e8fca0d 2743 if (fp->csect >= fp->fs->csize) { /* On the cluster boundary? */
TickTock 109:3e6f0e8fca0d 2744 clst = (fp->fptr == 0) ? /* On the top of the file? */
TickTock 109:3e6f0e8fca0d 2745 fp->org_clust : get_fat(fp->fs, fp->curr_clust);
TickTock 109:3e6f0e8fca0d 2746 if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2747 if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 2748 fp->curr_clust = clst; /* Update current cluster */
TickTock 109:3e6f0e8fca0d 2749 fp->csect = 0; /* Reset sector address in the cluster */
TickTock 109:3e6f0e8fca0d 2750 }
TickTock 109:3e6f0e8fca0d 2751 fp->csect++; /* Next sector address in the cluster */
TickTock 109:3e6f0e8fca0d 2752 }
TickTock 109:3e6f0e8fca0d 2753 sect = clust2sect(fp->fs, fp->curr_clust); /* Get current data sector */
TickTock 109:3e6f0e8fca0d 2754 if (!sect) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2755 sect += fp->csect - 1;
TickTock 109:3e6f0e8fca0d 2756 if (move_window(fp->fs, sect)) /* Move sector window */
TickTock 109:3e6f0e8fca0d 2757 ABORT(fp->fs, FR_DISK_ERR);
TickTock 109:3e6f0e8fca0d 2758 fp->dsect = sect;
TickTock 109:3e6f0e8fca0d 2759 rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
TickTock 109:3e6f0e8fca0d 2760 if (rcnt > btr) rcnt = btr;
TickTock 109:3e6f0e8fca0d 2761 rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
TickTock 109:3e6f0e8fca0d 2762 if (!rcnt) ABORT(fp->fs, FR_INT_ERR);
TickTock 109:3e6f0e8fca0d 2763 }
TickTock 109:3e6f0e8fca0d 2764
TickTock 109:3e6f0e8fca0d 2765 LEAVE_FF(fp->fs, FR_OK);
TickTock 109:3e6f0e8fca0d 2766 }
TickTock 109:3e6f0e8fca0d 2767 #endif /* _USE_FORWARD */
TickTock 109:3e6f0e8fca0d 2768
TickTock 109:3e6f0e8fca0d 2769
TickTock 109:3e6f0e8fca0d 2770
TickTock 109:3e6f0e8fca0d 2771 #if _USE_MKFS && !_FS_READONLY
TickTock 109:3e6f0e8fca0d 2772 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2773 /* Create File System on the Drive */
TickTock 109:3e6f0e8fca0d 2774 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2775 #define N_ROOTDIR 512 /* Multiple of 32 and <= 2048 */
TickTock 109:3e6f0e8fca0d 2776 #define N_FATS 1 /* 1 or 2 */
TickTock 109:3e6f0e8fca0d 2777 #define MAX_SECTOR 131072000UL /* Maximum partition size */
TickTock 109:3e6f0e8fca0d 2778 #define MIN_SECTOR 2000UL /* Minimum partition size */
TickTock 109:3e6f0e8fca0d 2779
TickTock 109:3e6f0e8fca0d 2780
TickTock 109:3e6f0e8fca0d 2781 FRESULT f_mkfs (
TickTock 109:3e6f0e8fca0d 2782 BYTE drv, /* Logical drive number */
TickTock 109:3e6f0e8fca0d 2783 BYTE partition, /* Partitioning rule 0:FDISK, 1:SFD */
TickTock 109:3e6f0e8fca0d 2784 WORD allocsize /* Allocation unit size [bytes] */
TickTock 109:3e6f0e8fca0d 2785 )
TickTock 109:3e6f0e8fca0d 2786 {
TickTock 109:3e6f0e8fca0d 2787 static const DWORD sstbl[] = { 2048000, 1024000, 512000, 256000, 128000, 64000, 32000, 16000, 8000, 4000, 0 };
TickTock 109:3e6f0e8fca0d 2788 static const WORD cstbl[] = { 32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512 };
TickTock 109:3e6f0e8fca0d 2789 BYTE fmt, m, *tbl;
TickTock 109:3e6f0e8fca0d 2790 DWORD b_part, b_fat, b_dir, b_data; /* Area offset (LBA) */
TickTock 109:3e6f0e8fca0d 2791 DWORD n_part, n_rsv, n_fat, n_dir; /* Area size */
TickTock 109:3e6f0e8fca0d 2792 DWORD n_clst, d, n;
TickTock 109:3e6f0e8fca0d 2793 WORD as;
TickTock 109:3e6f0e8fca0d 2794 FATFS *fs;
TickTock 109:3e6f0e8fca0d 2795 DSTATUS stat;
TickTock 109:3e6f0e8fca0d 2796
TickTock 109:3e6f0e8fca0d 2797
TickTock 109:3e6f0e8fca0d 2798 /* Check validity of the parameters */
TickTock 109:3e6f0e8fca0d 2799 if (drv >= _DRIVES) return FR_INVALID_DRIVE;
TickTock 109:3e6f0e8fca0d 2800 if (partition >= 2) return FR_MKFS_ABORTED;
TickTock 109:3e6f0e8fca0d 2801
TickTock 109:3e6f0e8fca0d 2802 /* Check mounted drive and clear work area */
TickTock 109:3e6f0e8fca0d 2803 fs = FatFs[drv];
TickTock 109:3e6f0e8fca0d 2804 if (!fs) return FR_NOT_ENABLED;
TickTock 109:3e6f0e8fca0d 2805 fs->fs_type = 0;
TickTock 109:3e6f0e8fca0d 2806 drv = LD2PD(drv);
TickTock 109:3e6f0e8fca0d 2807
TickTock 109:3e6f0e8fca0d 2808 /* Get disk statics */
TickTock 109:3e6f0e8fca0d 2809 stat = disk_initialize(drv);
TickTock 109:3e6f0e8fca0d 2810 if (stat & STA_NOINIT) return FR_NOT_READY;
TickTock 109:3e6f0e8fca0d 2811 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
TickTock 109:3e6f0e8fca0d 2812 #if _MAX_SS != 512 /* Get disk sector size */
TickTock 109:3e6f0e8fca0d 2813 if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK
TickTock 109:3e6f0e8fca0d 2814 || SS(fs) > _MAX_SS)
TickTock 109:3e6f0e8fca0d 2815 return FR_MKFS_ABORTED;
TickTock 109:3e6f0e8fca0d 2816 #endif
TickTock 109:3e6f0e8fca0d 2817 if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR)
TickTock 109:3e6f0e8fca0d 2818 return FR_MKFS_ABORTED;
TickTock 109:3e6f0e8fca0d 2819 if (n_part > MAX_SECTOR) n_part = MAX_SECTOR;
TickTock 109:3e6f0e8fca0d 2820 b_part = (!partition) ? 63 : 0; /* Boot sector */
TickTock 109:3e6f0e8fca0d 2821 n_part -= b_part;
TickTock 109:3e6f0e8fca0d 2822 for (d = 512; d <= 32768U && d != allocsize; d <<= 1) ; /* Check validity of the allocation unit size */
TickTock 109:3e6f0e8fca0d 2823 if (d != allocsize) allocsize = 0;
TickTock 109:3e6f0e8fca0d 2824 if (!allocsize) { /* Auto selection of cluster size */
TickTock 109:3e6f0e8fca0d 2825 d = n_part;
TickTock 109:3e6f0e8fca0d 2826 for (as = SS(fs); as > 512U; as >>= 1) d >>= 1;
TickTock 109:3e6f0e8fca0d 2827 for (n = 0; d < sstbl[n]; n++) ;
TickTock 109:3e6f0e8fca0d 2828 allocsize = cstbl[n];
TickTock 109:3e6f0e8fca0d 2829 }
TickTock 109:3e6f0e8fca0d 2830 if (allocsize < SS(fs)) allocsize = SS(fs);
TickTock 109:3e6f0e8fca0d 2831
TickTock 109:3e6f0e8fca0d 2832 allocsize /= SS(fs); /* Number of sectors per cluster */
TickTock 109:3e6f0e8fca0d 2833
TickTock 109:3e6f0e8fca0d 2834 /* Pre-compute number of clusters and FAT type */
TickTock 109:3e6f0e8fca0d 2835 n_clst = n_part / allocsize;
TickTock 109:3e6f0e8fca0d 2836 fmt = FS_FAT12;
TickTock 109:3e6f0e8fca0d 2837 if (n_clst >= 0xFF5) fmt = FS_FAT16;
TickTock 109:3e6f0e8fca0d 2838 if (n_clst >= 0xFFF5) fmt = FS_FAT32;
TickTock 109:3e6f0e8fca0d 2839
TickTock 109:3e6f0e8fca0d 2840 /* Determine offset and size of FAT structure */
TickTock 109:3e6f0e8fca0d 2841 switch (fmt) {
TickTock 109:3e6f0e8fca0d 2842 case FS_FAT12:
TickTock 109:3e6f0e8fca0d 2843 n_fat = ((n_clst * 3 + 1) / 2 + 3 + SS(fs) - 1) / SS(fs);
TickTock 109:3e6f0e8fca0d 2844 n_rsv = 1 + partition;
TickTock 109:3e6f0e8fca0d 2845 n_dir = N_ROOTDIR * 32 / SS(fs);
TickTock 109:3e6f0e8fca0d 2846 break;
TickTock 109:3e6f0e8fca0d 2847 case FS_FAT16:
TickTock 109:3e6f0e8fca0d 2848 n_fat = ((n_clst * 2) + 4 + SS(fs) - 1) / SS(fs);
TickTock 109:3e6f0e8fca0d 2849 n_rsv = 1 + partition;
TickTock 109:3e6f0e8fca0d 2850 n_dir = N_ROOTDIR * 32 / SS(fs);
TickTock 109:3e6f0e8fca0d 2851 break;
TickTock 109:3e6f0e8fca0d 2852 default:
TickTock 109:3e6f0e8fca0d 2853 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
TickTock 109:3e6f0e8fca0d 2854 n_rsv = 33 - partition;
TickTock 109:3e6f0e8fca0d 2855 n_dir = 0;
TickTock 109:3e6f0e8fca0d 2856 }
TickTock 109:3e6f0e8fca0d 2857 b_fat = b_part + n_rsv; /* FATs start sector */
TickTock 109:3e6f0e8fca0d 2858 b_dir = b_fat + n_fat * N_FATS; /* Directory start sector */
TickTock 109:3e6f0e8fca0d 2859 b_data = b_dir + n_dir; /* Data start sector */
TickTock 109:3e6f0e8fca0d 2860
TickTock 109:3e6f0e8fca0d 2861 /* Align data start sector to erase block boundary (for flash memory media) */
TickTock 109:3e6f0e8fca0d 2862 if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK) return FR_MKFS_ABORTED;
TickTock 109:3e6f0e8fca0d 2863 n = (b_data + n - 1) & ~(n - 1);
TickTock 109:3e6f0e8fca0d 2864 n_fat += (n - b_data) / N_FATS;
TickTock 109:3e6f0e8fca0d 2865 /* b_dir and b_data are no longer used below */
TickTock 109:3e6f0e8fca0d 2866
TickTock 109:3e6f0e8fca0d 2867 /* Determine number of cluster and final check of validity of the FAT type */
TickTock 109:3e6f0e8fca0d 2868 n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize;
TickTock 109:3e6f0e8fca0d 2869 if ( (fmt == FS_FAT16 && n_clst < 0xFF5)
TickTock 109:3e6f0e8fca0d 2870 || (fmt == FS_FAT32 && n_clst < 0xFFF5))
TickTock 109:3e6f0e8fca0d 2871 return FR_MKFS_ABORTED;
TickTock 109:3e6f0e8fca0d 2872
TickTock 109:3e6f0e8fca0d 2873 /* Create partition table if needed */
TickTock 109:3e6f0e8fca0d 2874 if (!partition) {
TickTock 109:3e6f0e8fca0d 2875 DWORD n_disk = b_part + n_part;
TickTock 109:3e6f0e8fca0d 2876
TickTock 109:3e6f0e8fca0d 2877 mem_set(fs->win, 0, SS(fs));
TickTock 109:3e6f0e8fca0d 2878 tbl = fs->win+MBR_Table;
TickTock 109:3e6f0e8fca0d 2879 ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */
TickTock 109:3e6f0e8fca0d 2880 if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */
TickTock 109:3e6f0e8fca0d 2881 n_disk = n_disk / 63 / 255;
TickTock 109:3e6f0e8fca0d 2882 tbl[7] = (BYTE)n_disk;
TickTock 109:3e6f0e8fca0d 2883 tbl[6] = (BYTE)((n_disk >> 2) | 63);
TickTock 109:3e6f0e8fca0d 2884 } else {
TickTock 109:3e6f0e8fca0d 2885 ST_WORD(&tbl[6], 0xFFFF);
TickTock 109:3e6f0e8fca0d 2886 }
TickTock 109:3e6f0e8fca0d 2887 tbl[5] = 254;
TickTock 109:3e6f0e8fca0d 2888 if (fmt != FS_FAT32) /* System ID */
TickTock 109:3e6f0e8fca0d 2889 tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
TickTock 109:3e6f0e8fca0d 2890 else
TickTock 109:3e6f0e8fca0d 2891 tbl[4] = 0x0c;
TickTock 109:3e6f0e8fca0d 2892 ST_DWORD(tbl+8, 63); /* Partition start in LBA */
TickTock 109:3e6f0e8fca0d 2893 ST_DWORD(tbl+12, n_part); /* Partition size in LBA */
TickTock 109:3e6f0e8fca0d 2894 ST_WORD(tbl+64, 0xAA55); /* Signature */
TickTock 109:3e6f0e8fca0d 2895 if (disk_write(drv, fs->win, 0, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 2896 return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2897 partition = 0xF8;
TickTock 109:3e6f0e8fca0d 2898 } else {
TickTock 109:3e6f0e8fca0d 2899 partition = 0xF0;
TickTock 109:3e6f0e8fca0d 2900 }
TickTock 109:3e6f0e8fca0d 2901
TickTock 109:3e6f0e8fca0d 2902 /* Create boot record */
TickTock 109:3e6f0e8fca0d 2903 tbl = fs->win; /* Clear buffer */
TickTock 109:3e6f0e8fca0d 2904 mem_set(tbl, 0, SS(fs));
TickTock 109:3e6f0e8fca0d 2905 ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */
TickTock 109:3e6f0e8fca0d 2906 ST_WORD(tbl+BPB_BytsPerSec, SS(fs)); /* Sector size */
TickTock 109:3e6f0e8fca0d 2907 tbl[BPB_SecPerClus] = (BYTE)allocsize; /* Sectors per cluster */
TickTock 109:3e6f0e8fca0d 2908 ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */
TickTock 109:3e6f0e8fca0d 2909 tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
TickTock 109:3e6f0e8fca0d 2910 ST_WORD(tbl+BPB_RootEntCnt, SS(fs) / 32 * n_dir); /* Number of rootdir entries */
TickTock 109:3e6f0e8fca0d 2911 if (n_part < 0x10000) { /* Number of total sectors */
TickTock 109:3e6f0e8fca0d 2912 ST_WORD(tbl+BPB_TotSec16, n_part);
TickTock 109:3e6f0e8fca0d 2913 } else {
TickTock 109:3e6f0e8fca0d 2914 ST_DWORD(tbl+BPB_TotSec32, n_part);
TickTock 109:3e6f0e8fca0d 2915 }
TickTock 109:3e6f0e8fca0d 2916 tbl[BPB_Media] = partition; /* Media descripter */
TickTock 109:3e6f0e8fca0d 2917 ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */
TickTock 109:3e6f0e8fca0d 2918 ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */
TickTock 109:3e6f0e8fca0d 2919 ST_DWORD(tbl+BPB_HiddSec, b_part); /* Hidden sectors */
TickTock 109:3e6f0e8fca0d 2920 n = get_fattime(); /* Use current time as a VSN */
TickTock 109:3e6f0e8fca0d 2921 if (fmt != FS_FAT32) {
TickTock 109:3e6f0e8fca0d 2922 ST_DWORD(tbl+BS_VolID, n); /* Volume serial number */
TickTock 109:3e6f0e8fca0d 2923 ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of secters per FAT */
TickTock 109:3e6f0e8fca0d 2924 tbl[BS_DrvNum] = 0x80; /* Drive number */
TickTock 109:3e6f0e8fca0d 2925 tbl[BS_BootSig] = 0x29; /* Extended boot signature */
TickTock 109:3e6f0e8fca0d 2926 mem_cpy(tbl+BS_VolLab, "NO NAME FAT ", 19); /* Volume lavel, FAT signature */
TickTock 109:3e6f0e8fca0d 2927 } else {
TickTock 109:3e6f0e8fca0d 2928 ST_DWORD(tbl+BS_VolID32, n); /* Volume serial number */
TickTock 109:3e6f0e8fca0d 2929 ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of secters per FAT */
TickTock 109:3e6f0e8fca0d 2930 ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory cluster (2) */
TickTock 109:3e6f0e8fca0d 2931 ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (bs+1) */
TickTock 109:3e6f0e8fca0d 2932 ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (bs+6) */
TickTock 109:3e6f0e8fca0d 2933 tbl[BS_DrvNum32] = 0x80; /* Drive number */
TickTock 109:3e6f0e8fca0d 2934 tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
TickTock 109:3e6f0e8fca0d 2935 mem_cpy(tbl+BS_VolLab32, "NO NAME FAT32 ", 19); /* Volume lavel, FAT signature */
TickTock 109:3e6f0e8fca0d 2936 }
TickTock 109:3e6f0e8fca0d 2937 ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature */
TickTock 109:3e6f0e8fca0d 2938 if (SS(fs) > 512U) {
TickTock 109:3e6f0e8fca0d 2939 ST_WORD(tbl+SS(fs)-2, 0xAA55);
TickTock 109:3e6f0e8fca0d 2940 }
TickTock 109:3e6f0e8fca0d 2941 if (disk_write(drv, tbl, b_part+0, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 2942 return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2943 if (fmt == FS_FAT32)
TickTock 109:3e6f0e8fca0d 2944 disk_write(drv, tbl, b_part+6, 1);
TickTock 109:3e6f0e8fca0d 2945
TickTock 109:3e6f0e8fca0d 2946 /* Initialize FAT area */
TickTock 109:3e6f0e8fca0d 2947 for (m = 0; m < N_FATS; m++) {
TickTock 109:3e6f0e8fca0d 2948 mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */
TickTock 109:3e6f0e8fca0d 2949 if (fmt != FS_FAT32) {
TickTock 109:3e6f0e8fca0d 2950 n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
TickTock 109:3e6f0e8fca0d 2951 n |= partition;
TickTock 109:3e6f0e8fca0d 2952 ST_DWORD(tbl, n); /* Reserve cluster #0-1 (FAT12/16) */
TickTock 109:3e6f0e8fca0d 2953 } else {
TickTock 109:3e6f0e8fca0d 2954 ST_DWORD(tbl+0, 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */
TickTock 109:3e6f0e8fca0d 2955 ST_DWORD(tbl+4, 0xFFFFFFFF);
TickTock 109:3e6f0e8fca0d 2956 ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
TickTock 109:3e6f0e8fca0d 2957 }
TickTock 109:3e6f0e8fca0d 2958 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 2959 return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2960 mem_set(tbl, 0, SS(fs)); /* Following FAT entries are filled by zero */
TickTock 109:3e6f0e8fca0d 2961 for (n = 1; n < n_fat; n++) {
TickTock 109:3e6f0e8fca0d 2962 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 2963 return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2964 }
TickTock 109:3e6f0e8fca0d 2965 }
TickTock 109:3e6f0e8fca0d 2966
TickTock 109:3e6f0e8fca0d 2967 /* Initialize Root directory */
TickTock 109:3e6f0e8fca0d 2968 m = (BYTE)((fmt == FS_FAT32) ? allocsize : n_dir);
TickTock 109:3e6f0e8fca0d 2969 do {
TickTock 109:3e6f0e8fca0d 2970 if (disk_write(drv, tbl, b_fat++, 1) != RES_OK)
TickTock 109:3e6f0e8fca0d 2971 return FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2972 } while (--m);
TickTock 109:3e6f0e8fca0d 2973
TickTock 109:3e6f0e8fca0d 2974 /* Create FSInfo record if needed */
TickTock 109:3e6f0e8fca0d 2975 if (fmt == FS_FAT32) {
TickTock 109:3e6f0e8fca0d 2976 ST_WORD(tbl+BS_55AA, 0xAA55);
TickTock 109:3e6f0e8fca0d 2977 ST_DWORD(tbl+FSI_LeadSig, 0x41615252);
TickTock 109:3e6f0e8fca0d 2978 ST_DWORD(tbl+FSI_StrucSig, 0x61417272);
TickTock 109:3e6f0e8fca0d 2979 ST_DWORD(tbl+FSI_Free_Count, n_clst - 1);
TickTock 109:3e6f0e8fca0d 2980 ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF);
TickTock 109:3e6f0e8fca0d 2981 disk_write(drv, tbl, b_part+1, 1);
TickTock 109:3e6f0e8fca0d 2982 disk_write(drv, tbl, b_part+7, 1);
TickTock 109:3e6f0e8fca0d 2983 }
TickTock 109:3e6f0e8fca0d 2984
TickTock 109:3e6f0e8fca0d 2985 return (disk_ioctl(drv, CTRL_SYNC, (void*)NULL) == RES_OK) ? FR_OK : FR_DISK_ERR;
TickTock 109:3e6f0e8fca0d 2986 }
TickTock 109:3e6f0e8fca0d 2987
TickTock 109:3e6f0e8fca0d 2988 #endif /* _USE_MKFS && !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 2989
TickTock 109:3e6f0e8fca0d 2990
TickTock 109:3e6f0e8fca0d 2991
TickTock 109:3e6f0e8fca0d 2992
TickTock 109:3e6f0e8fca0d 2993 #if _USE_STRFUNC
TickTock 109:3e6f0e8fca0d 2994 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2995 /* Get a string from the file */
TickTock 109:3e6f0e8fca0d 2996 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 2997 char* f_gets (
TickTock 109:3e6f0e8fca0d 2998 char* buff, /* Pointer to the string buffer to read */
TickTock 109:3e6f0e8fca0d 2999 int len, /* Size of string buffer */
TickTock 109:3e6f0e8fca0d 3000 FIL* fil /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 3001 )
TickTock 109:3e6f0e8fca0d 3002 {
TickTock 109:3e6f0e8fca0d 3003 int i = 0;
TickTock 109:3e6f0e8fca0d 3004 char *p = buff;
TickTock 109:3e6f0e8fca0d 3005 UINT rc;
TickTock 109:3e6f0e8fca0d 3006
TickTock 109:3e6f0e8fca0d 3007
TickTock 109:3e6f0e8fca0d 3008 while (i < len - 1) { /* Read bytes until buffer gets filled */
TickTock 109:3e6f0e8fca0d 3009 f_read(fil, p, 1, &rc);
TickTock 109:3e6f0e8fca0d 3010 if (rc != 1) break; /* Break when no data to read */
TickTock 109:3e6f0e8fca0d 3011 #if _USE_STRFUNC >= 2
TickTock 109:3e6f0e8fca0d 3012 if (*p == '\r') continue; /* Strip '\r' */
TickTock 109:3e6f0e8fca0d 3013 #endif
TickTock 109:3e6f0e8fca0d 3014 i++;
TickTock 109:3e6f0e8fca0d 3015 if (*p++ == '\n') break; /* Break when reached end of line */
TickTock 109:3e6f0e8fca0d 3016 }
TickTock 109:3e6f0e8fca0d 3017 *p = 0;
TickTock 109:3e6f0e8fca0d 3018 return i ? buff : NULL; /* When no data read (eof or error), return with error. */
TickTock 109:3e6f0e8fca0d 3019 }
TickTock 109:3e6f0e8fca0d 3020
TickTock 109:3e6f0e8fca0d 3021
TickTock 109:3e6f0e8fca0d 3022
TickTock 109:3e6f0e8fca0d 3023 #if !_FS_READONLY
TickTock 109:3e6f0e8fca0d 3024 #include <stdarg.h>
TickTock 109:3e6f0e8fca0d 3025 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 3026 /* Put a character to the file */
TickTock 109:3e6f0e8fca0d 3027 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 3028 int f_putc (
TickTock 109:3e6f0e8fca0d 3029 int chr, /* A character to be output */
TickTock 109:3e6f0e8fca0d 3030 FIL* fil /* Ponter to the file object */
TickTock 109:3e6f0e8fca0d 3031 )
TickTock 109:3e6f0e8fca0d 3032 {
TickTock 109:3e6f0e8fca0d 3033 UINT bw;
TickTock 109:3e6f0e8fca0d 3034 char c;
TickTock 109:3e6f0e8fca0d 3035
TickTock 109:3e6f0e8fca0d 3036
TickTock 109:3e6f0e8fca0d 3037 #if _USE_STRFUNC >= 2
TickTock 109:3e6f0e8fca0d 3038 if (chr == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */
TickTock 109:3e6f0e8fca0d 3039 #endif
TickTock 109:3e6f0e8fca0d 3040 if (!fil) { /* Special value may be used to switch the destination to any other device */
TickTock 109:3e6f0e8fca0d 3041 /* put_console(chr); */
TickTock 109:3e6f0e8fca0d 3042 return chr;
TickTock 109:3e6f0e8fca0d 3043 }
TickTock 109:3e6f0e8fca0d 3044 c = (char)chr;
TickTock 109:3e6f0e8fca0d 3045 f_write(fil, &c, 1, &bw); /* Write a byte to the file */
TickTock 109:3e6f0e8fca0d 3046 return bw ? chr : EOF; /* Return the result */
TickTock 109:3e6f0e8fca0d 3047 }
TickTock 109:3e6f0e8fca0d 3048
TickTock 109:3e6f0e8fca0d 3049
TickTock 109:3e6f0e8fca0d 3050
TickTock 109:3e6f0e8fca0d 3051
TickTock 109:3e6f0e8fca0d 3052 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 3053 /* Put a string to the file */
TickTock 109:3e6f0e8fca0d 3054 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 3055 int f_puts (
TickTock 109:3e6f0e8fca0d 3056 const char* str, /* Pointer to the string to be output */
TickTock 109:3e6f0e8fca0d 3057 FIL* fil /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 3058 )
TickTock 109:3e6f0e8fca0d 3059 {
TickTock 109:3e6f0e8fca0d 3060 int n;
TickTock 109:3e6f0e8fca0d 3061
TickTock 109:3e6f0e8fca0d 3062
TickTock 109:3e6f0e8fca0d 3063 for (n = 0; *str; str++, n++) {
TickTock 109:3e6f0e8fca0d 3064 if (f_putc(*str, fil) == EOF) return EOF;
TickTock 109:3e6f0e8fca0d 3065 }
TickTock 109:3e6f0e8fca0d 3066 return n;
TickTock 109:3e6f0e8fca0d 3067 }
TickTock 109:3e6f0e8fca0d 3068
TickTock 109:3e6f0e8fca0d 3069
TickTock 109:3e6f0e8fca0d 3070
TickTock 109:3e6f0e8fca0d 3071
TickTock 109:3e6f0e8fca0d 3072 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 3073 /* Put a formatted string to the file */
TickTock 109:3e6f0e8fca0d 3074 /*-----------------------------------------------------------------------*/
TickTock 109:3e6f0e8fca0d 3075 int f_printf (
TickTock 109:3e6f0e8fca0d 3076 FIL* fil, /* Pointer to the file object */
TickTock 109:3e6f0e8fca0d 3077 const char* str, /* Pointer to the format string */
TickTock 109:3e6f0e8fca0d 3078 ... /* Optional arguments... */
TickTock 109:3e6f0e8fca0d 3079 )
TickTock 109:3e6f0e8fca0d 3080 {
TickTock 109:3e6f0e8fca0d 3081 va_list arp;
TickTock 109:3e6f0e8fca0d 3082 UCHAR c, f, r;
TickTock 109:3e6f0e8fca0d 3083 ULONG val;
TickTock 109:3e6f0e8fca0d 3084 char s[16];
TickTock 109:3e6f0e8fca0d 3085 int i, w, res, cc;
TickTock 109:3e6f0e8fca0d 3086
TickTock 109:3e6f0e8fca0d 3087
TickTock 109:3e6f0e8fca0d 3088 va_start(arp, str);
TickTock 109:3e6f0e8fca0d 3089
TickTock 109:3e6f0e8fca0d 3090 for (cc = res = 0; cc != EOF; res += cc) {
TickTock 109:3e6f0e8fca0d 3091 c = *str++;
TickTock 109:3e6f0e8fca0d 3092 if (c == 0) break; /* End of string */
TickTock 109:3e6f0e8fca0d 3093 if (c != '%') { /* Non escape cahracter */
TickTock 109:3e6f0e8fca0d 3094 cc = f_putc(c, fil);
TickTock 109:3e6f0e8fca0d 3095 if (cc != EOF) cc = 1;
TickTock 109:3e6f0e8fca0d 3096 continue;
TickTock 109:3e6f0e8fca0d 3097 }
TickTock 109:3e6f0e8fca0d 3098 w = f = 0;
TickTock 109:3e6f0e8fca0d 3099 c = *str++;
TickTock 109:3e6f0e8fca0d 3100 if (c == '0') { /* Flag: '0' padding */
TickTock 109:3e6f0e8fca0d 3101 f = 1; c = *str++;
TickTock 109:3e6f0e8fca0d 3102 }
TickTock 109:3e6f0e8fca0d 3103 while (c >= '0' && c <= '9') { /* Precision */
TickTock 109:3e6f0e8fca0d 3104 w = w * 10 + (c - '0');
TickTock 109:3e6f0e8fca0d 3105 c = *str++;
TickTock 109:3e6f0e8fca0d 3106 }
TickTock 109:3e6f0e8fca0d 3107 if (c == 'l') { /* Prefix: Size is long int */
TickTock 109:3e6f0e8fca0d 3108 f |= 2; c = *str++;
TickTock 109:3e6f0e8fca0d 3109 }
TickTock 109:3e6f0e8fca0d 3110 if (c == 's') { /* Type is string */
TickTock 109:3e6f0e8fca0d 3111 cc = f_puts(va_arg(arp, char*), fil);
TickTock 109:3e6f0e8fca0d 3112 continue;
TickTock 109:3e6f0e8fca0d 3113 }
TickTock 109:3e6f0e8fca0d 3114 if (c == 'c') { /* Type is character */
TickTock 109:3e6f0e8fca0d 3115 cc = f_putc(va_arg(arp, int), fil);
TickTock 109:3e6f0e8fca0d 3116 if (cc != EOF) cc = 1;
TickTock 109:3e6f0e8fca0d 3117 continue;
TickTock 109:3e6f0e8fca0d 3118 }
TickTock 109:3e6f0e8fca0d 3119 r = 0;
TickTock 109:3e6f0e8fca0d 3120 if (c == 'd') r = 10; /* Type is signed decimal */
TickTock 109:3e6f0e8fca0d 3121 if (c == 'u') r = 10; /* Type is unsigned decimal */
TickTock 109:3e6f0e8fca0d 3122 if (c == 'X') r = 16; /* Type is unsigned hexdecimal */
TickTock 109:3e6f0e8fca0d 3123 if (r == 0) break; /* Unknown type */
TickTock 109:3e6f0e8fca0d 3124 if (f & 2) { /* Get the value */
TickTock 109:3e6f0e8fca0d 3125 val = (ULONG)va_arg(arp, long);
TickTock 109:3e6f0e8fca0d 3126 } else {
TickTock 109:3e6f0e8fca0d 3127 val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);
TickTock 109:3e6f0e8fca0d 3128 }
TickTock 109:3e6f0e8fca0d 3129 /* Put numeral string */
TickTock 109:3e6f0e8fca0d 3130 if (c == 'd') {
TickTock 109:3e6f0e8fca0d 3131 if (val & 0x80000000) {
TickTock 109:3e6f0e8fca0d 3132 val = 0 - val;
TickTock 109:3e6f0e8fca0d 3133 f |= 4;
TickTock 109:3e6f0e8fca0d 3134 }
TickTock 109:3e6f0e8fca0d 3135 }
TickTock 109:3e6f0e8fca0d 3136 i = sizeof(s) - 1; s[i] = 0;
TickTock 109:3e6f0e8fca0d 3137 do {
TickTock 109:3e6f0e8fca0d 3138 c = (UCHAR)(val % r + '0');
TickTock 109:3e6f0e8fca0d 3139 if (c > '9') c += 7;
TickTock 109:3e6f0e8fca0d 3140 s[--i] = c;
TickTock 109:3e6f0e8fca0d 3141 val /= r;
TickTock 109:3e6f0e8fca0d 3142 } while (i && val);
TickTock 109:3e6f0e8fca0d 3143 if (i && (f & 4)) s[--i] = '-';
TickTock 109:3e6f0e8fca0d 3144 w = sizeof(s) - 1 - w;
TickTock 109:3e6f0e8fca0d 3145 while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';
TickTock 109:3e6f0e8fca0d 3146 cc = f_puts(&s[i], fil);
TickTock 109:3e6f0e8fca0d 3147 }
TickTock 109:3e6f0e8fca0d 3148
TickTock 109:3e6f0e8fca0d 3149 va_end(arp);
TickTock 109:3e6f0e8fca0d 3150 return (cc == EOF) ? cc : res;
TickTock 109:3e6f0e8fca0d 3151 }
TickTock 109:3e6f0e8fca0d 3152
TickTock 109:3e6f0e8fca0d 3153 #endif /* !_FS_READONLY */
TickTock 109:3e6f0e8fca0d 3154 #endif /* _USE_STRFUNC */