183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2c30a15e5SDonggeun Kim /*
3c30a15e5SDonggeun Kim * fat_write.c
4c30a15e5SDonggeun Kim *
5c30a15e5SDonggeun Kim * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
6c30a15e5SDonggeun Kim */
7c30a15e5SDonggeun Kim
8c30a15e5SDonggeun Kim #include <common.h>
9c30a15e5SDonggeun Kim #include <command.h>
10c30a15e5SDonggeun Kim #include <config.h>
11c30a15e5SDonggeun Kim #include <fat.h>
12c30a15e5SDonggeun Kim #include <asm/byteorder.h>
13c30a15e5SDonggeun Kim #include <part.h>
14fb7e16ccSRichard Genoud #include <linux/ctype.h>
159e374e7bSTom Rini #include <div64.h>
169e374e7bSTom Rini #include <linux/math64.h>
17c30a15e5SDonggeun Kim #include "fat.c"
18c30a15e5SDonggeun Kim
uppercase(char * str,int len)19c30a15e5SDonggeun Kim static void uppercase(char *str, int len)
20c30a15e5SDonggeun Kim {
21c30a15e5SDonggeun Kim int i;
22c30a15e5SDonggeun Kim
23c30a15e5SDonggeun Kim for (i = 0; i < len; i++) {
24fb7e16ccSRichard Genoud *str = toupper(*str);
25c30a15e5SDonggeun Kim str++;
26c30a15e5SDonggeun Kim }
27c30a15e5SDonggeun Kim }
28c30a15e5SDonggeun Kim
29c30a15e5SDonggeun Kim static int total_sector;
disk_write(__u32 block,__u32 nr_blocks,void * buf)30079df722SDonggeun Kim static int disk_write(__u32 block, __u32 nr_blocks, void *buf)
31c30a15e5SDonggeun Kim {
320a04ed86SŁukasz Majewski ulong ret;
330a04ed86SŁukasz Majewski
342a981dc2SSimon Glass if (!cur_dev)
35c30a15e5SDonggeun Kim return -1;
36c30a15e5SDonggeun Kim
37079df722SDonggeun Kim if (cur_part_info.start + block + nr_blocks >
38079df722SDonggeun Kim cur_part_info.start + total_sector) {
39c30a15e5SDonggeun Kim printf("error: overflow occurs\n");
40c30a15e5SDonggeun Kim return -1;
41c30a15e5SDonggeun Kim }
42c30a15e5SDonggeun Kim
432a981dc2SSimon Glass ret = blk_dwrite(cur_dev, cur_part_info.start + block, nr_blocks, buf);
440a04ed86SŁukasz Majewski if (nr_blocks && ret == 0)
450a04ed86SŁukasz Majewski return -1;
460a04ed86SŁukasz Majewski
470a04ed86SŁukasz Majewski return ret;
48c30a15e5SDonggeun Kim }
49c30a15e5SDonggeun Kim
50c30a15e5SDonggeun Kim /*
51c30a15e5SDonggeun Kim * Set short name in directory entry
52c30a15e5SDonggeun Kim */
set_name(dir_entry * dirent,const char * filename)53c30a15e5SDonggeun Kim static void set_name(dir_entry *dirent, const char *filename)
54c30a15e5SDonggeun Kim {
55c30a15e5SDonggeun Kim char s_name[VFAT_MAXLEN_BYTES];
56c30a15e5SDonggeun Kim char *period;
57c30a15e5SDonggeun Kim int period_location, len, i, ext_num;
58c30a15e5SDonggeun Kim
59c30a15e5SDonggeun Kim if (filename == NULL)
60c30a15e5SDonggeun Kim return;
61c30a15e5SDonggeun Kim
62c30a15e5SDonggeun Kim len = strlen(filename);
63c30a15e5SDonggeun Kim if (len == 0)
64c30a15e5SDonggeun Kim return;
65c30a15e5SDonggeun Kim
6673dc8328SPiotr Wilczek strcpy(s_name, filename);
67c30a15e5SDonggeun Kim uppercase(s_name, len);
68c30a15e5SDonggeun Kim
69c30a15e5SDonggeun Kim period = strchr(s_name, '.');
70c30a15e5SDonggeun Kim if (period == NULL) {
71c30a15e5SDonggeun Kim period_location = len;
72c30a15e5SDonggeun Kim ext_num = 0;
73c30a15e5SDonggeun Kim } else {
74c30a15e5SDonggeun Kim period_location = period - s_name;
75c30a15e5SDonggeun Kim ext_num = len - period_location - 1;
76c30a15e5SDonggeun Kim }
77c30a15e5SDonggeun Kim
78c30a15e5SDonggeun Kim /* Pad spaces when the length of file name is shorter than eight */
79c30a15e5SDonggeun Kim if (period_location < 8) {
80c30a15e5SDonggeun Kim memcpy(dirent->name, s_name, period_location);
81c30a15e5SDonggeun Kim for (i = period_location; i < 8; i++)
82c30a15e5SDonggeun Kim dirent->name[i] = ' ';
83c30a15e5SDonggeun Kim } else if (period_location == 8) {
84c30a15e5SDonggeun Kim memcpy(dirent->name, s_name, period_location);
85c30a15e5SDonggeun Kim } else {
86c30a15e5SDonggeun Kim memcpy(dirent->name, s_name, 6);
87c30a15e5SDonggeun Kim dirent->name[6] = '~';
88c30a15e5SDonggeun Kim dirent->name[7] = '1';
89c30a15e5SDonggeun Kim }
90c30a15e5SDonggeun Kim
91c30a15e5SDonggeun Kim if (ext_num < 3) {
92c30a15e5SDonggeun Kim memcpy(dirent->ext, s_name + period_location + 1, ext_num);
93c30a15e5SDonggeun Kim for (i = ext_num; i < 3; i++)
94c30a15e5SDonggeun Kim dirent->ext[i] = ' ';
95c30a15e5SDonggeun Kim } else
96c30a15e5SDonggeun Kim memcpy(dirent->ext, s_name + period_location + 1, 3);
97c30a15e5SDonggeun Kim
98c30a15e5SDonggeun Kim debug("name : %s\n", dirent->name);
99c30a15e5SDonggeun Kim debug("ext : %s\n", dirent->ext);
100c30a15e5SDonggeun Kim }
101c30a15e5SDonggeun Kim
102c30a15e5SDonggeun Kim /*
103c30a15e5SDonggeun Kim * Write fat buffer into block device
104c30a15e5SDonggeun Kim */
flush_dirty_fat_buffer(fsdata * mydata)1053c0ed9c3SStefan Brüns static int flush_dirty_fat_buffer(fsdata *mydata)
106c30a15e5SDonggeun Kim {
107c30a15e5SDonggeun Kim int getsize = FATBUFBLOCKS;
108c30a15e5SDonggeun Kim __u32 fatlength = mydata->fatlength;
109c30a15e5SDonggeun Kim __u8 *bufptr = mydata->fatbuf;
110c30a15e5SDonggeun Kim __u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
111c30a15e5SDonggeun Kim
1123c0ed9c3SStefan Brüns debug("debug: evicting %d, dirty: %d\n", mydata->fatbufnum,
1133c0ed9c3SStefan Brüns (int)mydata->fat_dirty);
1143c0ed9c3SStefan Brüns
1153c0ed9c3SStefan Brüns if ((!mydata->fat_dirty) || (mydata->fatbufnum == -1))
1163c0ed9c3SStefan Brüns return 0;
1173c0ed9c3SStefan Brüns
1186c1a8080SStefan Brüns /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
1196c1a8080SStefan Brüns if (startblock + getsize > fatlength)
1206c1a8080SStefan Brüns getsize = fatlength - startblock;
121c30a15e5SDonggeun Kim
1226c1a8080SStefan Brüns startblock += mydata->fat_sect;
123c30a15e5SDonggeun Kim
124c30a15e5SDonggeun Kim /* Write FAT buf */
125c30a15e5SDonggeun Kim if (disk_write(startblock, getsize, bufptr) < 0) {
126c30a15e5SDonggeun Kim debug("error: writing FAT blocks\n");
127c30a15e5SDonggeun Kim return -1;
128c30a15e5SDonggeun Kim }
129c30a15e5SDonggeun Kim
1304ced2039SAKASHI Takahiro if (mydata->fats == 2) {
131627182eaSDonggeun Kim /* Update corresponding second FAT blocks */
132627182eaSDonggeun Kim startblock += mydata->fatlength;
133627182eaSDonggeun Kim if (disk_write(startblock, getsize, bufptr) < 0) {
134627182eaSDonggeun Kim debug("error: writing second FAT blocks\n");
135627182eaSDonggeun Kim return -1;
136627182eaSDonggeun Kim }
137627182eaSDonggeun Kim }
1383c0ed9c3SStefan Brüns mydata->fat_dirty = 0;
139627182eaSDonggeun Kim
140c30a15e5SDonggeun Kim return 0;
141c30a15e5SDonggeun Kim }
142c30a15e5SDonggeun Kim
143c30a15e5SDonggeun Kim /*
144c30a15e5SDonggeun Kim * Set the file name information from 'name' into 'slotptr',
145c30a15e5SDonggeun Kim */
str2slot(dir_slot * slotptr,const char * name,int * idx)146c30a15e5SDonggeun Kim static int str2slot(dir_slot *slotptr, const char *name, int *idx)
147c30a15e5SDonggeun Kim {
148c30a15e5SDonggeun Kim int j, end_idx = 0;
149c30a15e5SDonggeun Kim
150c30a15e5SDonggeun Kim for (j = 0; j <= 8; j += 2) {
151c30a15e5SDonggeun Kim if (name[*idx] == 0x00) {
152c30a15e5SDonggeun Kim slotptr->name0_4[j] = 0;
153c30a15e5SDonggeun Kim slotptr->name0_4[j + 1] = 0;
154c30a15e5SDonggeun Kim end_idx++;
155c30a15e5SDonggeun Kim goto name0_4;
156c30a15e5SDonggeun Kim }
157c30a15e5SDonggeun Kim slotptr->name0_4[j] = name[*idx];
158c30a15e5SDonggeun Kim (*idx)++;
159c30a15e5SDonggeun Kim end_idx++;
160c30a15e5SDonggeun Kim }
161c30a15e5SDonggeun Kim for (j = 0; j <= 10; j += 2) {
162c30a15e5SDonggeun Kim if (name[*idx] == 0x00) {
163c30a15e5SDonggeun Kim slotptr->name5_10[j] = 0;
164c30a15e5SDonggeun Kim slotptr->name5_10[j + 1] = 0;
165c30a15e5SDonggeun Kim end_idx++;
166c30a15e5SDonggeun Kim goto name5_10;
167c30a15e5SDonggeun Kim }
168c30a15e5SDonggeun Kim slotptr->name5_10[j] = name[*idx];
169c30a15e5SDonggeun Kim (*idx)++;
170c30a15e5SDonggeun Kim end_idx++;
171c30a15e5SDonggeun Kim }
172c30a15e5SDonggeun Kim for (j = 0; j <= 2; j += 2) {
173c30a15e5SDonggeun Kim if (name[*idx] == 0x00) {
174c30a15e5SDonggeun Kim slotptr->name11_12[j] = 0;
175c30a15e5SDonggeun Kim slotptr->name11_12[j + 1] = 0;
176c30a15e5SDonggeun Kim end_idx++;
177c30a15e5SDonggeun Kim goto name11_12;
178c30a15e5SDonggeun Kim }
179c30a15e5SDonggeun Kim slotptr->name11_12[j] = name[*idx];
180c30a15e5SDonggeun Kim (*idx)++;
181c30a15e5SDonggeun Kim end_idx++;
182c30a15e5SDonggeun Kim }
183c30a15e5SDonggeun Kim
184c30a15e5SDonggeun Kim if (name[*idx] == 0x00)
185c30a15e5SDonggeun Kim return 1;
186c30a15e5SDonggeun Kim
187c30a15e5SDonggeun Kim return 0;
188c30a15e5SDonggeun Kim /* Not used characters are filled with 0xff 0xff */
189c30a15e5SDonggeun Kim name0_4:
190c30a15e5SDonggeun Kim for (; end_idx < 5; end_idx++) {
191c30a15e5SDonggeun Kim slotptr->name0_4[end_idx * 2] = 0xff;
192c30a15e5SDonggeun Kim slotptr->name0_4[end_idx * 2 + 1] = 0xff;
193c30a15e5SDonggeun Kim }
194c30a15e5SDonggeun Kim end_idx = 5;
195c30a15e5SDonggeun Kim name5_10:
196c30a15e5SDonggeun Kim end_idx -= 5;
197c30a15e5SDonggeun Kim for (; end_idx < 6; end_idx++) {
198c30a15e5SDonggeun Kim slotptr->name5_10[end_idx * 2] = 0xff;
199c30a15e5SDonggeun Kim slotptr->name5_10[end_idx * 2 + 1] = 0xff;
200c30a15e5SDonggeun Kim }
201c30a15e5SDonggeun Kim end_idx = 11;
202c30a15e5SDonggeun Kim name11_12:
203c30a15e5SDonggeun Kim end_idx -= 11;
204c30a15e5SDonggeun Kim for (; end_idx < 2; end_idx++) {
205c30a15e5SDonggeun Kim slotptr->name11_12[end_idx * 2] = 0xff;
206c30a15e5SDonggeun Kim slotptr->name11_12[end_idx * 2 + 1] = 0xff;
207c30a15e5SDonggeun Kim }
208c30a15e5SDonggeun Kim
209c30a15e5SDonggeun Kim return 1;
210c30a15e5SDonggeun Kim }
211c30a15e5SDonggeun Kim
2124ced2039SAKASHI Takahiro static int flush_dir_table(fat_itr *itr);
213c30a15e5SDonggeun Kim
214c30a15e5SDonggeun Kim /*
215c30a15e5SDonggeun Kim * Fill dir_slot entries with appropriate name, id, and attr
2164ced2039SAKASHI Takahiro * 'itr' will point to a next entry
217c30a15e5SDonggeun Kim */
2184ced2039SAKASHI Takahiro static int
fill_dir_slot(fat_itr * itr,const char * l_name)2194ced2039SAKASHI Takahiro fill_dir_slot(fat_itr *itr, const char *l_name)
220c30a15e5SDonggeun Kim {
2217aa1a6b7STien Fong Chee __u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
2227aa1a6b7STien Fong Chee dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
2238506eb8dSAnatolij Gustschin __u8 counter = 0, checksum;
224c30a15e5SDonggeun Kim int idx = 0, ret;
225c30a15e5SDonggeun Kim
226ed76f912SStefan Brüns /* Get short file name checksum value */
2274ced2039SAKASHI Takahiro checksum = mkcksum(itr->dent->name, itr->dent->ext);
228c30a15e5SDonggeun Kim
229c30a15e5SDonggeun Kim do {
230c30a15e5SDonggeun Kim memset(slotptr, 0x00, sizeof(dir_slot));
231c30a15e5SDonggeun Kim ret = str2slot(slotptr, l_name, &idx);
232c30a15e5SDonggeun Kim slotptr->id = ++counter;
233c30a15e5SDonggeun Kim slotptr->attr = ATTR_VFAT;
234c30a15e5SDonggeun Kim slotptr->alias_checksum = checksum;
235c30a15e5SDonggeun Kim slotptr++;
236c30a15e5SDonggeun Kim } while (ret == 0);
237c30a15e5SDonggeun Kim
238c30a15e5SDonggeun Kim slotptr--;
239c30a15e5SDonggeun Kim slotptr->id |= LAST_LONG_ENTRY_MASK;
240c30a15e5SDonggeun Kim
241c30a15e5SDonggeun Kim while (counter >= 1) {
2424ced2039SAKASHI Takahiro memcpy(itr->dent, slotptr, sizeof(dir_slot));
243c30a15e5SDonggeun Kim slotptr--;
244c30a15e5SDonggeun Kim counter--;
2454ced2039SAKASHI Takahiro if (!fat_itr_next(itr))
2464ced2039SAKASHI Takahiro if (!itr->dent && !itr->is_root && flush_dir_table(itr))
2474ced2039SAKASHI Takahiro return -1;
248c30a15e5SDonggeun Kim }
249c30a15e5SDonggeun Kim
2504ced2039SAKASHI Takahiro if (!itr->dent && !itr->is_root)
251c30a15e5SDonggeun Kim /*
2524ced2039SAKASHI Takahiro * don't care return value here because we have already
2534ced2039SAKASHI Takahiro * finished completing an entry with name, only ending up
2544ced2039SAKASHI Takahiro * no more entry left
255c30a15e5SDonggeun Kim */
2564ced2039SAKASHI Takahiro flush_dir_table(itr);
257c30a15e5SDonggeun Kim
258c30a15e5SDonggeun Kim return 0;
259c30a15e5SDonggeun Kim }
260c30a15e5SDonggeun Kim
261c30a15e5SDonggeun Kim /*
26249abbd9cSPhilipp Skadorov * Set the entry at index 'entry' in a FAT (12/16/32) table.
263c30a15e5SDonggeun Kim */
set_fatent_value(fsdata * mydata,__u32 entry,__u32 entry_value)264c30a15e5SDonggeun Kim static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
265c30a15e5SDonggeun Kim {
26649abbd9cSPhilipp Skadorov __u32 bufnum, offset, off16;
26749abbd9cSPhilipp Skadorov __u16 val1, val2;
268c30a15e5SDonggeun Kim
269c30a15e5SDonggeun Kim switch (mydata->fatsize) {
270c30a15e5SDonggeun Kim case 32:
271c30a15e5SDonggeun Kim bufnum = entry / FAT32BUFSIZE;
272c30a15e5SDonggeun Kim offset = entry - bufnum * FAT32BUFSIZE;
273c30a15e5SDonggeun Kim break;
274c30a15e5SDonggeun Kim case 16:
275c30a15e5SDonggeun Kim bufnum = entry / FAT16BUFSIZE;
276c30a15e5SDonggeun Kim offset = entry - bufnum * FAT16BUFSIZE;
277c30a15e5SDonggeun Kim break;
27849abbd9cSPhilipp Skadorov case 12:
27949abbd9cSPhilipp Skadorov bufnum = entry / FAT12BUFSIZE;
28049abbd9cSPhilipp Skadorov offset = entry - bufnum * FAT12BUFSIZE;
28149abbd9cSPhilipp Skadorov break;
282c30a15e5SDonggeun Kim default:
283c30a15e5SDonggeun Kim /* Unsupported FAT size */
284c30a15e5SDonggeun Kim return -1;
285c30a15e5SDonggeun Kim }
286c30a15e5SDonggeun Kim
287c30a15e5SDonggeun Kim /* Read a new block of FAT entries into the cache. */
288c30a15e5SDonggeun Kim if (bufnum != mydata->fatbufnum) {
289c30a15e5SDonggeun Kim int getsize = FATBUFBLOCKS;
290c30a15e5SDonggeun Kim __u8 *bufptr = mydata->fatbuf;
291c30a15e5SDonggeun Kim __u32 fatlength = mydata->fatlength;
292c30a15e5SDonggeun Kim __u32 startblock = bufnum * FATBUFBLOCKS;
293c30a15e5SDonggeun Kim
2946c1a8080SStefan Brüns /* Cap length if fatlength is not a multiple of FATBUFBLOCKS */
2956c1a8080SStefan Brüns if (startblock + getsize > fatlength)
2966c1a8080SStefan Brüns getsize = fatlength - startblock;
297c30a15e5SDonggeun Kim
2983c0ed9c3SStefan Brüns if (flush_dirty_fat_buffer(mydata) < 0)
299c30a15e5SDonggeun Kim return -1;
300c30a15e5SDonggeun Kim
3016c1a8080SStefan Brüns startblock += mydata->fat_sect;
3026c1a8080SStefan Brüns
303c30a15e5SDonggeun Kim if (disk_read(startblock, getsize, bufptr) < 0) {
304c30a15e5SDonggeun Kim debug("Error reading FAT blocks\n");
305c30a15e5SDonggeun Kim return -1;
306c30a15e5SDonggeun Kim }
307c30a15e5SDonggeun Kim mydata->fatbufnum = bufnum;
308c30a15e5SDonggeun Kim }
309c30a15e5SDonggeun Kim
3103c0ed9c3SStefan Brüns /* Mark as dirty */
3113c0ed9c3SStefan Brüns mydata->fat_dirty = 1;
3123c0ed9c3SStefan Brüns
313c30a15e5SDonggeun Kim /* Set the actual entry */
314c30a15e5SDonggeun Kim switch (mydata->fatsize) {
315c30a15e5SDonggeun Kim case 32:
316c30a15e5SDonggeun Kim ((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
317c30a15e5SDonggeun Kim break;
318c30a15e5SDonggeun Kim case 16:
319c30a15e5SDonggeun Kim ((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
320c30a15e5SDonggeun Kim break;
32149abbd9cSPhilipp Skadorov case 12:
32249abbd9cSPhilipp Skadorov off16 = (offset * 3) / 4;
32349abbd9cSPhilipp Skadorov
32449abbd9cSPhilipp Skadorov switch (offset & 0x3) {
32549abbd9cSPhilipp Skadorov case 0:
32649abbd9cSPhilipp Skadorov val1 = cpu_to_le16(entry_value) & 0xfff;
32749abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff;
32849abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] |= val1;
32949abbd9cSPhilipp Skadorov break;
33049abbd9cSPhilipp Skadorov case 1:
33149abbd9cSPhilipp Skadorov val1 = cpu_to_le16(entry_value) & 0xf;
33249abbd9cSPhilipp Skadorov val2 = (cpu_to_le16(entry_value) >> 4) & 0xff;
33349abbd9cSPhilipp Skadorov
33449abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] &= ~0xf000;
33549abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 12);
33649abbd9cSPhilipp Skadorov
33749abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xff;
33849abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
33949abbd9cSPhilipp Skadorov break;
34049abbd9cSPhilipp Skadorov case 2:
34149abbd9cSPhilipp Skadorov val1 = cpu_to_le16(entry_value) & 0xff;
34249abbd9cSPhilipp Skadorov val2 = (cpu_to_le16(entry_value) >> 8) & 0xf;
34349abbd9cSPhilipp Skadorov
34449abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] &= ~0xff00;
34549abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 8);
34649abbd9cSPhilipp Skadorov
34749abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16 + 1] &= ~0xf;
34849abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16 + 1] |= val2;
34949abbd9cSPhilipp Skadorov break;
35049abbd9cSPhilipp Skadorov case 3:
35149abbd9cSPhilipp Skadorov val1 = cpu_to_le16(entry_value) & 0xfff;
35249abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] &= ~0xfff0;
35349abbd9cSPhilipp Skadorov ((__u16 *)mydata->fatbuf)[off16] |= (val1 << 4);
35449abbd9cSPhilipp Skadorov break;
35549abbd9cSPhilipp Skadorov default:
35649abbd9cSPhilipp Skadorov break;
35749abbd9cSPhilipp Skadorov }
35849abbd9cSPhilipp Skadorov
35949abbd9cSPhilipp Skadorov break;
360c30a15e5SDonggeun Kim default:
361c30a15e5SDonggeun Kim return -1;
362c30a15e5SDonggeun Kim }
363c30a15e5SDonggeun Kim
364c30a15e5SDonggeun Kim return 0;
365c30a15e5SDonggeun Kim }
366c30a15e5SDonggeun Kim
367c30a15e5SDonggeun Kim /*
36849abbd9cSPhilipp Skadorov * Determine the next free cluster after 'entry' in a FAT (12/16/32) table
369ae1755beSStefan Brüns * and link it to 'entry'. EOC marker is not set on returned entry.
370c30a15e5SDonggeun Kim */
determine_fatent(fsdata * mydata,__u32 entry)371c30a15e5SDonggeun Kim static __u32 determine_fatent(fsdata *mydata, __u32 entry)
372c30a15e5SDonggeun Kim {
373c30a15e5SDonggeun Kim __u32 next_fat, next_entry = entry + 1;
374c30a15e5SDonggeun Kim
375c30a15e5SDonggeun Kim while (1) {
376b8948d2aSStefan Brüns next_fat = get_fatent(mydata, next_entry);
377c30a15e5SDonggeun Kim if (next_fat == 0) {
378ae1755beSStefan Brüns /* found free entry, link to entry */
379c30a15e5SDonggeun Kim set_fatent_value(mydata, entry, next_entry);
380c30a15e5SDonggeun Kim break;
381c30a15e5SDonggeun Kim }
382c30a15e5SDonggeun Kim next_entry++;
383c30a15e5SDonggeun Kim }
384c30a15e5SDonggeun Kim debug("FAT%d: entry: %08x, entry_value: %04x\n",
385c30a15e5SDonggeun Kim mydata->fatsize, entry, next_entry);
386c30a15e5SDonggeun Kim
387c30a15e5SDonggeun Kim return next_entry;
388c30a15e5SDonggeun Kim }
389c30a15e5SDonggeun Kim
390f105fe7bSHeinrich Schuchardt /**
391f105fe7bSHeinrich Schuchardt * set_cluster() - write data to cluster
392f105fe7bSHeinrich Schuchardt *
393f105fe7bSHeinrich Schuchardt * Write 'size' bytes from 'buffer' into the specified cluster.
394f105fe7bSHeinrich Schuchardt *
395f105fe7bSHeinrich Schuchardt * @mydata: data to be written
396f105fe7bSHeinrich Schuchardt * @clustnum: cluster to be written to
397f105fe7bSHeinrich Schuchardt * @buffer: data to be written
398f105fe7bSHeinrich Schuchardt * @size: bytes to be written (but not more than the size of a cluster)
399f105fe7bSHeinrich Schuchardt * Return: 0 on success, -1 otherwise
400c30a15e5SDonggeun Kim */
401c30a15e5SDonggeun Kim static int
set_cluster(fsdata * mydata,u32 clustnum,u8 * buffer,u32 size)402f105fe7bSHeinrich Schuchardt set_cluster(fsdata *mydata, u32 clustnum, u8 *buffer, u32 size)
403c30a15e5SDonggeun Kim {
404f105fe7bSHeinrich Schuchardt u32 idx = 0;
405f105fe7bSHeinrich Schuchardt u32 startsect;
4068133f43dSBenoît Thébaudeau int ret;
407c30a15e5SDonggeun Kim
408c30a15e5SDonggeun Kim if (clustnum > 0)
409265edc03SRob Clark startsect = clust_to_sect(mydata, clustnum);
410c30a15e5SDonggeun Kim else
411c30a15e5SDonggeun Kim startsect = mydata->rootdir_sect;
412c30a15e5SDonggeun Kim
413c30a15e5SDonggeun Kim debug("clustnum: %d, startsect: %d\n", clustnum, startsect);
414c30a15e5SDonggeun Kim
4158133f43dSBenoît Thébaudeau if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
4168133f43dSBenoît Thébaudeau ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
4178133f43dSBenoît Thébaudeau
4181c381cebSHeinrich Schuchardt debug("FAT: Misaligned buffer address (%p)\n", buffer);
4198133f43dSBenoît Thébaudeau
4208133f43dSBenoît Thébaudeau while (size >= mydata->sect_size) {
4218133f43dSBenoît Thébaudeau memcpy(tmpbuf, buffer, mydata->sect_size);
4228133f43dSBenoît Thébaudeau ret = disk_write(startsect++, 1, tmpbuf);
4238133f43dSBenoît Thébaudeau if (ret != 1) {
4248133f43dSBenoît Thébaudeau debug("Error writing data (got %d)\n", ret);
425c30a15e5SDonggeun Kim return -1;
426c30a15e5SDonggeun Kim }
4278133f43dSBenoît Thébaudeau
4288133f43dSBenoît Thébaudeau buffer += mydata->sect_size;
4298133f43dSBenoît Thébaudeau size -= mydata->sect_size;
4306b8f185fSWu, Josh }
4318133f43dSBenoît Thébaudeau } else if (size >= mydata->sect_size) {
432c30a15e5SDonggeun Kim idx = size / mydata->sect_size;
4338133f43dSBenoît Thébaudeau ret = disk_write(startsect, idx, buffer);
4348133f43dSBenoît Thébaudeau if (ret != idx) {
4358133f43dSBenoît Thébaudeau debug("Error writing data (got %d)\n", ret);
436c30a15e5SDonggeun Kim return -1;
437c30a15e5SDonggeun Kim }
438c30a15e5SDonggeun Kim
4398133f43dSBenoît Thébaudeau startsect += idx;
4408133f43dSBenoît Thébaudeau idx *= mydata->sect_size;
4418133f43dSBenoît Thébaudeau buffer += idx;
4428133f43dSBenoît Thébaudeau size -= idx;
4438133f43dSBenoît Thébaudeau }
4448133f43dSBenoît Thébaudeau
4458133f43dSBenoît Thébaudeau if (size) {
4468133f43dSBenoît Thébaudeau ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
447f105fe7bSHeinrich Schuchardt /* Do not leak content of stack */
448f105fe7bSHeinrich Schuchardt memset(tmpbuf, 0, mydata->sect_size);
4498133f43dSBenoît Thébaudeau memcpy(tmpbuf, buffer, size);
4508133f43dSBenoît Thébaudeau ret = disk_write(startsect, 1, tmpbuf);
4518133f43dSBenoît Thébaudeau if (ret != 1) {
4528133f43dSBenoît Thébaudeau debug("Error writing data (got %d)\n", ret);
4538133f43dSBenoît Thébaudeau return -1;
4548133f43dSBenoît Thébaudeau }
455c30a15e5SDonggeun Kim }
456c30a15e5SDonggeun Kim
457c30a15e5SDonggeun Kim return 0;
458c30a15e5SDonggeun Kim }
459c30a15e5SDonggeun Kim
460cb8af8afSAKASHI Takahiro static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
461cb8af8afSAKASHI Takahiro
462cb8af8afSAKASHI Takahiro /*
463cb8af8afSAKASHI Takahiro * Read and modify data on existing and consecutive cluster blocks
464cb8af8afSAKASHI Takahiro */
465cb8af8afSAKASHI Takahiro static int
get_set_cluster(fsdata * mydata,__u32 clustnum,loff_t pos,__u8 * buffer,loff_t size,loff_t * gotsize)466cb8af8afSAKASHI Takahiro get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
467cb8af8afSAKASHI Takahiro loff_t size, loff_t *gotsize)
468cb8af8afSAKASHI Takahiro {
469cb8af8afSAKASHI Takahiro unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
470cb8af8afSAKASHI Takahiro __u32 startsect;
471cb8af8afSAKASHI Takahiro loff_t wsize;
472cb8af8afSAKASHI Takahiro int clustcount, i, ret;
473cb8af8afSAKASHI Takahiro
474cb8af8afSAKASHI Takahiro *gotsize = 0;
475cb8af8afSAKASHI Takahiro if (!size)
476cb8af8afSAKASHI Takahiro return 0;
477cb8af8afSAKASHI Takahiro
478cb8af8afSAKASHI Takahiro assert(pos < bytesperclust);
479cb8af8afSAKASHI Takahiro startsect = clust_to_sect(mydata, clustnum);
480cb8af8afSAKASHI Takahiro
481cb8af8afSAKASHI Takahiro debug("clustnum: %d, startsect: %d, pos: %lld\n",
482cb8af8afSAKASHI Takahiro clustnum, startsect, pos);
483cb8af8afSAKASHI Takahiro
484cb8af8afSAKASHI Takahiro /* partial write at beginning */
485cb8af8afSAKASHI Takahiro if (pos) {
486cb8af8afSAKASHI Takahiro wsize = min(bytesperclust - pos, size);
487cb8af8afSAKASHI Takahiro ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
488cb8af8afSAKASHI Takahiro if (ret != mydata->clust_size) {
489cb8af8afSAKASHI Takahiro debug("Error reading data (got %d)\n", ret);
490cb8af8afSAKASHI Takahiro return -1;
491cb8af8afSAKASHI Takahiro }
492cb8af8afSAKASHI Takahiro
493cb8af8afSAKASHI Takahiro memcpy(tmpbuf_cluster + pos, buffer, wsize);
494cb8af8afSAKASHI Takahiro ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
495cb8af8afSAKASHI Takahiro if (ret != mydata->clust_size) {
496cb8af8afSAKASHI Takahiro debug("Error writing data (got %d)\n", ret);
497cb8af8afSAKASHI Takahiro return -1;
498cb8af8afSAKASHI Takahiro }
499cb8af8afSAKASHI Takahiro
500cb8af8afSAKASHI Takahiro size -= wsize;
501cb8af8afSAKASHI Takahiro buffer += wsize;
502cb8af8afSAKASHI Takahiro *gotsize += wsize;
503cb8af8afSAKASHI Takahiro
504cb8af8afSAKASHI Takahiro startsect += mydata->clust_size;
505cb8af8afSAKASHI Takahiro
506cb8af8afSAKASHI Takahiro if (!size)
507cb8af8afSAKASHI Takahiro return 0;
508cb8af8afSAKASHI Takahiro }
509cb8af8afSAKASHI Takahiro
510cb8af8afSAKASHI Takahiro /* full-cluster write */
511cb8af8afSAKASHI Takahiro if (size >= bytesperclust) {
512cb8af8afSAKASHI Takahiro clustcount = lldiv(size, bytesperclust);
513cb8af8afSAKASHI Takahiro
514cb8af8afSAKASHI Takahiro if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
515cb8af8afSAKASHI Takahiro wsize = clustcount * bytesperclust;
516cb8af8afSAKASHI Takahiro ret = disk_write(startsect,
517cb8af8afSAKASHI Takahiro clustcount * mydata->clust_size,
518cb8af8afSAKASHI Takahiro buffer);
519cb8af8afSAKASHI Takahiro if (ret != clustcount * mydata->clust_size) {
520cb8af8afSAKASHI Takahiro debug("Error writing data (got %d)\n", ret);
521cb8af8afSAKASHI Takahiro return -1;
522cb8af8afSAKASHI Takahiro }
523cb8af8afSAKASHI Takahiro
524cb8af8afSAKASHI Takahiro size -= wsize;
525cb8af8afSAKASHI Takahiro buffer += wsize;
526cb8af8afSAKASHI Takahiro *gotsize += wsize;
527cb8af8afSAKASHI Takahiro
528cb8af8afSAKASHI Takahiro startsect += clustcount * mydata->clust_size;
529cb8af8afSAKASHI Takahiro } else {
530cb8af8afSAKASHI Takahiro for (i = 0; i < clustcount; i++) {
531cb8af8afSAKASHI Takahiro memcpy(tmpbuf_cluster, buffer, bytesperclust);
532cb8af8afSAKASHI Takahiro ret = disk_write(startsect,
533cb8af8afSAKASHI Takahiro mydata->clust_size,
534cb8af8afSAKASHI Takahiro tmpbuf_cluster);
535cb8af8afSAKASHI Takahiro if (ret != mydata->clust_size) {
536cb8af8afSAKASHI Takahiro debug("Error writing data (got %d)\n",
537cb8af8afSAKASHI Takahiro ret);
538cb8af8afSAKASHI Takahiro return -1;
539cb8af8afSAKASHI Takahiro }
540cb8af8afSAKASHI Takahiro
541cb8af8afSAKASHI Takahiro size -= bytesperclust;
542cb8af8afSAKASHI Takahiro buffer += bytesperclust;
543cb8af8afSAKASHI Takahiro *gotsize += bytesperclust;
544cb8af8afSAKASHI Takahiro
545cb8af8afSAKASHI Takahiro startsect += mydata->clust_size;
546cb8af8afSAKASHI Takahiro }
547cb8af8afSAKASHI Takahiro }
548cb8af8afSAKASHI Takahiro }
549cb8af8afSAKASHI Takahiro
550cb8af8afSAKASHI Takahiro /* partial write at end */
551cb8af8afSAKASHI Takahiro if (size) {
552cb8af8afSAKASHI Takahiro wsize = size;
553cb8af8afSAKASHI Takahiro ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
554cb8af8afSAKASHI Takahiro if (ret != mydata->clust_size) {
555cb8af8afSAKASHI Takahiro debug("Error reading data (got %d)\n", ret);
556cb8af8afSAKASHI Takahiro return -1;
557cb8af8afSAKASHI Takahiro }
558cb8af8afSAKASHI Takahiro memcpy(tmpbuf_cluster, buffer, wsize);
559cb8af8afSAKASHI Takahiro ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
560cb8af8afSAKASHI Takahiro if (ret != mydata->clust_size) {
561cb8af8afSAKASHI Takahiro debug("Error writing data (got %d)\n", ret);
562cb8af8afSAKASHI Takahiro return -1;
563cb8af8afSAKASHI Takahiro }
564cb8af8afSAKASHI Takahiro
565cb8af8afSAKASHI Takahiro size -= wsize;
566cb8af8afSAKASHI Takahiro buffer += wsize;
567cb8af8afSAKASHI Takahiro *gotsize += wsize;
568cb8af8afSAKASHI Takahiro }
569cb8af8afSAKASHI Takahiro
570cb8af8afSAKASHI Takahiro assert(!size);
571cb8af8afSAKASHI Takahiro
572cb8af8afSAKASHI Takahiro return 0;
573cb8af8afSAKASHI Takahiro }
574cb8af8afSAKASHI Takahiro
575c30a15e5SDonggeun Kim /*
576c30a15e5SDonggeun Kim * Find the first empty cluster
577c30a15e5SDonggeun Kim */
find_empty_cluster(fsdata * mydata)578c30a15e5SDonggeun Kim static int find_empty_cluster(fsdata *mydata)
579c30a15e5SDonggeun Kim {
580c30a15e5SDonggeun Kim __u32 fat_val, entry = 3;
581c30a15e5SDonggeun Kim
582c30a15e5SDonggeun Kim while (1) {
583b8948d2aSStefan Brüns fat_val = get_fatent(mydata, entry);
584c30a15e5SDonggeun Kim if (fat_val == 0)
585c30a15e5SDonggeun Kim break;
586c30a15e5SDonggeun Kim entry++;
587c30a15e5SDonggeun Kim }
588c30a15e5SDonggeun Kim
589c30a15e5SDonggeun Kim return entry;
590c30a15e5SDonggeun Kim }
591c30a15e5SDonggeun Kim
592c30a15e5SDonggeun Kim /*
5934ced2039SAKASHI Takahiro * Write directory entries in itr's buffer to block device
594c30a15e5SDonggeun Kim */
flush_dir_table(fat_itr * itr)5954ced2039SAKASHI Takahiro static int flush_dir_table(fat_itr *itr)
596c30a15e5SDonggeun Kim {
5974ced2039SAKASHI Takahiro fsdata *mydata = itr->fsdata;
598c30a15e5SDonggeun Kim int dir_newclust = 0;
5994ced2039SAKASHI Takahiro unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
600c30a15e5SDonggeun Kim
6014ced2039SAKASHI Takahiro if (set_cluster(mydata, itr->clust, itr->block, bytesperclust) != 0) {
6024ced2039SAKASHI Takahiro printf("error: writing directory entry\n");
6034ced2039SAKASHI Takahiro return -1;
604c30a15e5SDonggeun Kim }
605c30a15e5SDonggeun Kim dir_newclust = find_empty_cluster(mydata);
6064ced2039SAKASHI Takahiro set_fatent_value(mydata, itr->clust, dir_newclust);
607c30a15e5SDonggeun Kim if (mydata->fatsize == 32)
608c30a15e5SDonggeun Kim set_fatent_value(mydata, dir_newclust, 0xffffff8);
609c30a15e5SDonggeun Kim else if (mydata->fatsize == 16)
610c30a15e5SDonggeun Kim set_fatent_value(mydata, dir_newclust, 0xfff8);
61149abbd9cSPhilipp Skadorov else if (mydata->fatsize == 12)
61249abbd9cSPhilipp Skadorov set_fatent_value(mydata, dir_newclust, 0xff8);
613c30a15e5SDonggeun Kim
6144ced2039SAKASHI Takahiro itr->clust = dir_newclust;
6154ced2039SAKASHI Takahiro itr->next_clust = dir_newclust;
616c30a15e5SDonggeun Kim
6173c0ed9c3SStefan Brüns if (flush_dirty_fat_buffer(mydata) < 0)
6184ced2039SAKASHI Takahiro return -1;
619c30a15e5SDonggeun Kim
6204ced2039SAKASHI Takahiro memset(itr->block, 0x00, bytesperclust);
621c30a15e5SDonggeun Kim
6224ced2039SAKASHI Takahiro itr->dent = (dir_entry *)itr->block;
6234ced2039SAKASHI Takahiro itr->last_cluster = 1;
6244ced2039SAKASHI Takahiro itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
6254ced2039SAKASHI Takahiro
6264ced2039SAKASHI Takahiro return 0;
627c30a15e5SDonggeun Kim }
628c30a15e5SDonggeun Kim
629c30a15e5SDonggeun Kim /*
630c30a15e5SDonggeun Kim * Set empty cluster from 'entry' to the end of a file
631c30a15e5SDonggeun Kim */
clear_fatent(fsdata * mydata,__u32 entry)632c30a15e5SDonggeun Kim static int clear_fatent(fsdata *mydata, __u32 entry)
633c30a15e5SDonggeun Kim {
634c30a15e5SDonggeun Kim __u32 fat_val;
635c30a15e5SDonggeun Kim
63649abbd9cSPhilipp Skadorov while (!CHECK_CLUST(entry, mydata->fatsize)) {
637b8948d2aSStefan Brüns fat_val = get_fatent(mydata, entry);
638c30a15e5SDonggeun Kim if (fat_val != 0)
639c30a15e5SDonggeun Kim set_fatent_value(mydata, entry, 0);
640c30a15e5SDonggeun Kim else
641c30a15e5SDonggeun Kim break;
642c30a15e5SDonggeun Kim
643c30a15e5SDonggeun Kim entry = fat_val;
644c30a15e5SDonggeun Kim }
645c30a15e5SDonggeun Kim
646c30a15e5SDonggeun Kim /* Flush fat buffer */
6473c0ed9c3SStefan Brüns if (flush_dirty_fat_buffer(mydata) < 0)
648c30a15e5SDonggeun Kim return -1;
649c30a15e5SDonggeun Kim
650c30a15e5SDonggeun Kim return 0;
651c30a15e5SDonggeun Kim }
652c30a15e5SDonggeun Kim
653c30a15e5SDonggeun Kim /*
654704df6aaSAKASHI Takahiro * Set start cluster in directory entry
655704df6aaSAKASHI Takahiro */
set_start_cluster(const fsdata * mydata,dir_entry * dentptr,__u32 start_cluster)656704df6aaSAKASHI Takahiro static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
657704df6aaSAKASHI Takahiro __u32 start_cluster)
658704df6aaSAKASHI Takahiro {
659704df6aaSAKASHI Takahiro if (mydata->fatsize == 32)
660704df6aaSAKASHI Takahiro dentptr->starthi =
661704df6aaSAKASHI Takahiro cpu_to_le16((start_cluster & 0xffff0000) >> 16);
662704df6aaSAKASHI Takahiro dentptr->start = cpu_to_le16(start_cluster & 0xffff);
663704df6aaSAKASHI Takahiro }
664704df6aaSAKASHI Takahiro
665704df6aaSAKASHI Takahiro /*
666704df6aaSAKASHI Takahiro * Check whether adding a file makes the file system to
667704df6aaSAKASHI Takahiro * exceed the size of the block device
668704df6aaSAKASHI Takahiro * Return -1 when overflow occurs, otherwise return 0
669704df6aaSAKASHI Takahiro */
check_overflow(fsdata * mydata,__u32 clustnum,loff_t size)670704df6aaSAKASHI Takahiro static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
671704df6aaSAKASHI Takahiro {
672704df6aaSAKASHI Takahiro __u32 startsect, sect_num, offset;
673704df6aaSAKASHI Takahiro
674704df6aaSAKASHI Takahiro if (clustnum > 0)
675704df6aaSAKASHI Takahiro startsect = clust_to_sect(mydata, clustnum);
676704df6aaSAKASHI Takahiro else
677704df6aaSAKASHI Takahiro startsect = mydata->rootdir_sect;
678704df6aaSAKASHI Takahiro
679704df6aaSAKASHI Takahiro sect_num = div_u64_rem(size, mydata->sect_size, &offset);
680704df6aaSAKASHI Takahiro
681704df6aaSAKASHI Takahiro if (offset != 0)
682704df6aaSAKASHI Takahiro sect_num++;
683704df6aaSAKASHI Takahiro
684704df6aaSAKASHI Takahiro if (startsect + sect_num > total_sector)
685704df6aaSAKASHI Takahiro return -1;
686704df6aaSAKASHI Takahiro return 0;
687704df6aaSAKASHI Takahiro }
688704df6aaSAKASHI Takahiro
689704df6aaSAKASHI Takahiro /*
690c30a15e5SDonggeun Kim * Write at most 'maxsize' bytes from 'buffer' into
691c30a15e5SDonggeun Kim * the file associated with 'dentptr'
6921ad0b98aSSuriyan Ramasami * Update the number of bytes written in *gotsize and return 0
6931ad0b98aSSuriyan Ramasami * or return -1 on fatal errors.
694c30a15e5SDonggeun Kim */
695c30a15e5SDonggeun Kim static int
set_contents(fsdata * mydata,dir_entry * dentptr,loff_t pos,__u8 * buffer,loff_t maxsize,loff_t * gotsize)696704df6aaSAKASHI Takahiro set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
6971ad0b98aSSuriyan Ramasami loff_t maxsize, loff_t *gotsize)
698c30a15e5SDonggeun Kim {
699c30a15e5SDonggeun Kim unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
700c30a15e5SDonggeun Kim __u32 curclust = START(dentptr);
701c30a15e5SDonggeun Kim __u32 endclust = 0, newclust = 0;
702*7274b763SHeinrich Schuchardt u64 cur_pos, filesize;
703*7274b763SHeinrich Schuchardt loff_t offset, actsize, wsize;
704c30a15e5SDonggeun Kim
7051ad0b98aSSuriyan Ramasami *gotsize = 0;
706cb8af8afSAKASHI Takahiro filesize = pos + maxsize;
707c30a15e5SDonggeun Kim
7081ad0b98aSSuriyan Ramasami debug("%llu bytes\n", filesize);
709c30a15e5SDonggeun Kim
710cb8af8afSAKASHI Takahiro if (!filesize) {
711cb8af8afSAKASHI Takahiro if (!curclust)
712cb8af8afSAKASHI Takahiro return 0;
713cb8af8afSAKASHI Takahiro if (!CHECK_CLUST(curclust, mydata->fatsize) ||
714cb8af8afSAKASHI Takahiro IS_LAST_CLUST(curclust, mydata->fatsize)) {
715cb8af8afSAKASHI Takahiro clear_fatent(mydata, curclust);
716cb8af8afSAKASHI Takahiro set_start_cluster(mydata, dentptr, 0);
717cb8af8afSAKASHI Takahiro return 0;
718cb8af8afSAKASHI Takahiro }
719cb8af8afSAKASHI Takahiro debug("curclust: 0x%x\n", curclust);
720cb8af8afSAKASHI Takahiro debug("Invalid FAT entry\n");
721cb8af8afSAKASHI Takahiro return -1;
722cb8af8afSAKASHI Takahiro }
723cb8af8afSAKASHI Takahiro
724cb8af8afSAKASHI Takahiro if (!curclust) {
725cb8af8afSAKASHI Takahiro assert(pos == 0);
726cb8af8afSAKASHI Takahiro goto set_clusters;
727cb8af8afSAKASHI Takahiro }
728cb8af8afSAKASHI Takahiro
729cb8af8afSAKASHI Takahiro /* go to cluster at pos */
730cb8af8afSAKASHI Takahiro cur_pos = bytesperclust;
731cb8af8afSAKASHI Takahiro while (1) {
732cb8af8afSAKASHI Takahiro if (pos <= cur_pos)
733cb8af8afSAKASHI Takahiro break;
734cb8af8afSAKASHI Takahiro if (IS_LAST_CLUST(curclust, mydata->fatsize))
735cb8af8afSAKASHI Takahiro break;
736cb8af8afSAKASHI Takahiro
737cb8af8afSAKASHI Takahiro newclust = get_fatent(mydata, curclust);
738cb8af8afSAKASHI Takahiro if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
739cb8af8afSAKASHI Takahiro CHECK_CLUST(newclust, mydata->fatsize)) {
740cb8af8afSAKASHI Takahiro debug("curclust: 0x%x\n", curclust);
741cb8af8afSAKASHI Takahiro debug("Invalid FAT entry\n");
742cb8af8afSAKASHI Takahiro return -1;
743cb8af8afSAKASHI Takahiro }
744cb8af8afSAKASHI Takahiro
745cb8af8afSAKASHI Takahiro cur_pos += bytesperclust;
746cb8af8afSAKASHI Takahiro curclust = newclust;
747cb8af8afSAKASHI Takahiro }
748cb8af8afSAKASHI Takahiro if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
749cb8af8afSAKASHI Takahiro assert(pos == cur_pos);
750cb8af8afSAKASHI Takahiro goto set_clusters;
751cb8af8afSAKASHI Takahiro }
752cb8af8afSAKASHI Takahiro
753cb8af8afSAKASHI Takahiro assert(pos < cur_pos);
754cb8af8afSAKASHI Takahiro cur_pos -= bytesperclust;
755cb8af8afSAKASHI Takahiro
756cb8af8afSAKASHI Takahiro /* overwrite */
757cb8af8afSAKASHI Takahiro assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
758cb8af8afSAKASHI Takahiro !CHECK_CLUST(curclust, mydata->fatsize));
759cb8af8afSAKASHI Takahiro
760cb8af8afSAKASHI Takahiro while (1) {
761cb8af8afSAKASHI Takahiro /* search for allocated consecutive clusters */
762cb8af8afSAKASHI Takahiro actsize = bytesperclust;
763cb8af8afSAKASHI Takahiro endclust = curclust;
764cb8af8afSAKASHI Takahiro while (1) {
765cb8af8afSAKASHI Takahiro if (filesize <= (cur_pos + actsize))
766cb8af8afSAKASHI Takahiro break;
767cb8af8afSAKASHI Takahiro
768cb8af8afSAKASHI Takahiro newclust = get_fatent(mydata, endclust);
769cb8af8afSAKASHI Takahiro
770cb8af8afSAKASHI Takahiro if (IS_LAST_CLUST(newclust, mydata->fatsize))
771cb8af8afSAKASHI Takahiro break;
772cb8af8afSAKASHI Takahiro if (CHECK_CLUST(newclust, mydata->fatsize)) {
773cb8af8afSAKASHI Takahiro debug("curclust: 0x%x\n", curclust);
774cb8af8afSAKASHI Takahiro debug("Invalid FAT entry\n");
775cb8af8afSAKASHI Takahiro return -1;
776cb8af8afSAKASHI Takahiro }
777cb8af8afSAKASHI Takahiro
778cb8af8afSAKASHI Takahiro actsize += bytesperclust;
779cb8af8afSAKASHI Takahiro endclust = newclust;
780cb8af8afSAKASHI Takahiro }
781cb8af8afSAKASHI Takahiro
782cb8af8afSAKASHI Takahiro /* overwrite to <curclust..endclust> */
783cb8af8afSAKASHI Takahiro if (pos < cur_pos)
784cb8af8afSAKASHI Takahiro offset = 0;
785cb8af8afSAKASHI Takahiro else
786cb8af8afSAKASHI Takahiro offset = pos - cur_pos;
787cb8af8afSAKASHI Takahiro wsize = min(cur_pos + actsize, filesize) - pos;
788cb8af8afSAKASHI Takahiro if (get_set_cluster(mydata, curclust, offset,
789cb8af8afSAKASHI Takahiro buffer, wsize, &actsize)) {
790cb8af8afSAKASHI Takahiro printf("Error get-and-setting cluster\n");
791cb8af8afSAKASHI Takahiro return -1;
792cb8af8afSAKASHI Takahiro }
793cb8af8afSAKASHI Takahiro buffer += wsize;
794cb8af8afSAKASHI Takahiro *gotsize += wsize;
795cb8af8afSAKASHI Takahiro cur_pos += offset + wsize;
796cb8af8afSAKASHI Takahiro
797cb8af8afSAKASHI Takahiro if (filesize <= cur_pos)
798cb8af8afSAKASHI Takahiro break;
799cb8af8afSAKASHI Takahiro
800cb8af8afSAKASHI Takahiro /* CHECK: newclust = get_fatent(mydata, endclust); */
801cb8af8afSAKASHI Takahiro
802cb8af8afSAKASHI Takahiro if (IS_LAST_CLUST(newclust, mydata->fatsize))
803cb8af8afSAKASHI Takahiro /* no more clusters */
804cb8af8afSAKASHI Takahiro break;
805cb8af8afSAKASHI Takahiro
806cb8af8afSAKASHI Takahiro curclust = newclust;
807cb8af8afSAKASHI Takahiro }
808cb8af8afSAKASHI Takahiro
809cb8af8afSAKASHI Takahiro if (filesize <= cur_pos) {
810cb8af8afSAKASHI Takahiro /* no more write */
811cb8af8afSAKASHI Takahiro newclust = get_fatent(mydata, endclust);
812cb8af8afSAKASHI Takahiro if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
813cb8af8afSAKASHI Takahiro /* truncate the rest */
814cb8af8afSAKASHI Takahiro clear_fatent(mydata, newclust);
815cb8af8afSAKASHI Takahiro
816cb8af8afSAKASHI Takahiro /* Mark end of file in FAT */
817cb8af8afSAKASHI Takahiro if (mydata->fatsize == 12)
818cb8af8afSAKASHI Takahiro newclust = 0xfff;
819cb8af8afSAKASHI Takahiro else if (mydata->fatsize == 16)
820cb8af8afSAKASHI Takahiro newclust = 0xffff;
821cb8af8afSAKASHI Takahiro else if (mydata->fatsize == 32)
822cb8af8afSAKASHI Takahiro newclust = 0xfffffff;
823cb8af8afSAKASHI Takahiro set_fatent_value(mydata, endclust, newclust);
824cb8af8afSAKASHI Takahiro }
825cb8af8afSAKASHI Takahiro
826cb8af8afSAKASHI Takahiro return 0;
827cb8af8afSAKASHI Takahiro }
828cb8af8afSAKASHI Takahiro
829cb8af8afSAKASHI Takahiro curclust = endclust;
830cb8af8afSAKASHI Takahiro filesize -= cur_pos;
831*7274b763SHeinrich Schuchardt assert(!do_div(cur_pos, bytesperclust));
832cb8af8afSAKASHI Takahiro
833cb8af8afSAKASHI Takahiro set_clusters:
834cb8af8afSAKASHI Takahiro /* allocate and write */
835cb8af8afSAKASHI Takahiro assert(!pos);
836cb8af8afSAKASHI Takahiro
837cb8af8afSAKASHI Takahiro /* Assure that curclust is valid */
838cb8af8afSAKASHI Takahiro if (!curclust) {
839cb8af8afSAKASHI Takahiro curclust = find_empty_cluster(mydata);
840cb8af8afSAKASHI Takahiro set_start_cluster(mydata, dentptr, curclust);
841cb8af8afSAKASHI Takahiro } else {
842cb8af8afSAKASHI Takahiro newclust = get_fatent(mydata, curclust);
843cb8af8afSAKASHI Takahiro
844cb8af8afSAKASHI Takahiro if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
845cb8af8afSAKASHI Takahiro newclust = determine_fatent(mydata, curclust);
846cb8af8afSAKASHI Takahiro set_fatent_value(mydata, curclust, newclust);
847cb8af8afSAKASHI Takahiro curclust = newclust;
848cb8af8afSAKASHI Takahiro } else {
849cb8af8afSAKASHI Takahiro debug("error: something wrong\n");
8501254b44aSBenoît Thébaudeau return -1;
8511254b44aSBenoît Thébaudeau }
852704df6aaSAKASHI Takahiro }
853704df6aaSAKASHI Takahiro
854cb8af8afSAKASHI Takahiro /* TODO: already partially written */
855704df6aaSAKASHI Takahiro if (check_overflow(mydata, curclust, filesize)) {
856704df6aaSAKASHI Takahiro printf("Error: no space left: %llu\n", filesize);
857704df6aaSAKASHI Takahiro return -1;
8581254b44aSBenoît Thébaudeau }
8591254b44aSBenoît Thébaudeau
860c30a15e5SDonggeun Kim actsize = bytesperclust;
861c30a15e5SDonggeun Kim endclust = curclust;
862c30a15e5SDonggeun Kim do {
863c30a15e5SDonggeun Kim /* search for consecutive clusters */
864c30a15e5SDonggeun Kim while (actsize < filesize) {
865c30a15e5SDonggeun Kim newclust = determine_fatent(mydata, endclust);
866c30a15e5SDonggeun Kim
867c30a15e5SDonggeun Kim if ((newclust - 1) != endclust)
868704df6aaSAKASHI Takahiro /* write to <curclust..endclust> */
869c30a15e5SDonggeun Kim goto getit;
870c30a15e5SDonggeun Kim
871c30a15e5SDonggeun Kim if (CHECK_CLUST(newclust, mydata->fatsize)) {
8725e1a860eSBenoît Thébaudeau debug("newclust: 0x%x\n", newclust);
873c30a15e5SDonggeun Kim debug("Invalid FAT entry\n");
8741ad0b98aSSuriyan Ramasami return 0;
875c30a15e5SDonggeun Kim }
876c30a15e5SDonggeun Kim endclust = newclust;
877c30a15e5SDonggeun Kim actsize += bytesperclust;
878c30a15e5SDonggeun Kim }
879c30a15e5SDonggeun Kim
880c30a15e5SDonggeun Kim /* set remaining bytes */
881c30a15e5SDonggeun Kim actsize = filesize;
882f105fe7bSHeinrich Schuchardt if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
883c30a15e5SDonggeun Kim debug("error: writing cluster\n");
884c30a15e5SDonggeun Kim return -1;
885c30a15e5SDonggeun Kim }
8861ad0b98aSSuriyan Ramasami *gotsize += actsize;
887c30a15e5SDonggeun Kim
888c30a15e5SDonggeun Kim /* Mark end of file in FAT */
88949abbd9cSPhilipp Skadorov if (mydata->fatsize == 12)
89049abbd9cSPhilipp Skadorov newclust = 0xfff;
89149abbd9cSPhilipp Skadorov else if (mydata->fatsize == 16)
892c30a15e5SDonggeun Kim newclust = 0xffff;
893c30a15e5SDonggeun Kim else if (mydata->fatsize == 32)
894c30a15e5SDonggeun Kim newclust = 0xfffffff;
895c30a15e5SDonggeun Kim set_fatent_value(mydata, endclust, newclust);
896c30a15e5SDonggeun Kim
8971ad0b98aSSuriyan Ramasami return 0;
898c30a15e5SDonggeun Kim getit:
899f105fe7bSHeinrich Schuchardt if (set_cluster(mydata, curclust, buffer, (u32)actsize) != 0) {
900c30a15e5SDonggeun Kim debug("error: writing cluster\n");
901c30a15e5SDonggeun Kim return -1;
902c30a15e5SDonggeun Kim }
9031ad0b98aSSuriyan Ramasami *gotsize += actsize;
904c30a15e5SDonggeun Kim filesize -= actsize;
905c30a15e5SDonggeun Kim buffer += actsize;
906c30a15e5SDonggeun Kim
9075e1a860eSBenoît Thébaudeau if (CHECK_CLUST(newclust, mydata->fatsize)) {
9085e1a860eSBenoît Thébaudeau debug("newclust: 0x%x\n", newclust);
909c30a15e5SDonggeun Kim debug("Invalid FAT entry\n");
9101ad0b98aSSuriyan Ramasami return 0;
911c30a15e5SDonggeun Kim }
912c30a15e5SDonggeun Kim actsize = bytesperclust;
913c30a15e5SDonggeun Kim curclust = endclust = newclust;
914c30a15e5SDonggeun Kim } while (1);
915c30a15e5SDonggeun Kim
916704df6aaSAKASHI Takahiro return 0;
9171254b44aSBenoît Thébaudeau }
9181254b44aSBenoît Thébaudeau
9191254b44aSBenoît Thébaudeau /*
9201254b44aSBenoît Thébaudeau * Fill dir_entry
9211254b44aSBenoît Thébaudeau */
fill_dentry(fsdata * mydata,dir_entry * dentptr,const char * filename,__u32 start_cluster,__u32 size,__u8 attr)9221254b44aSBenoît Thébaudeau static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
9231254b44aSBenoît Thébaudeau const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
9241254b44aSBenoît Thébaudeau {
9251254b44aSBenoît Thébaudeau set_start_cluster(mydata, dentptr, start_cluster);
926c30a15e5SDonggeun Kim dentptr->size = cpu_to_le32(size);
927c30a15e5SDonggeun Kim
928c30a15e5SDonggeun Kim dentptr->attr = attr;
929c30a15e5SDonggeun Kim
930c30a15e5SDonggeun Kim set_name(dentptr, filename);
931c30a15e5SDonggeun Kim }
932c30a15e5SDonggeun Kim
933c30a15e5SDonggeun Kim /*
934c30a15e5SDonggeun Kim * Find a directory entry based on filename or start cluster number
935c30a15e5SDonggeun Kim * If the directory entry is not found,
936c30a15e5SDonggeun Kim * the new position for writing a directory entry will be returned
937c30a15e5SDonggeun Kim */
find_directory_entry(fat_itr * itr,char * filename)9384ced2039SAKASHI Takahiro static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
939c30a15e5SDonggeun Kim {
9404ced2039SAKASHI Takahiro int match = 0;
941c30a15e5SDonggeun Kim
9424ced2039SAKASHI Takahiro while (fat_itr_next(itr)) {
9434ced2039SAKASHI Takahiro /* check both long and short name: */
9444ced2039SAKASHI Takahiro if (!strcasecmp(filename, itr->name))
9454ced2039SAKASHI Takahiro match = 1;
9464ced2039SAKASHI Takahiro else if (itr->name != itr->s_name &&
9474ced2039SAKASHI Takahiro !strcasecmp(filename, itr->s_name))
9484ced2039SAKASHI Takahiro match = 1;
949c30a15e5SDonggeun Kim
9504ced2039SAKASHI Takahiro if (!match)
9514ced2039SAKASHI Takahiro continue;
952c30a15e5SDonggeun Kim
9534ced2039SAKASHI Takahiro if (itr->dent->name[0] == '\0')
9544ced2039SAKASHI Takahiro return NULL;
9554ced2039SAKASHI Takahiro else
9564ced2039SAKASHI Takahiro return itr->dent;
9574ced2039SAKASHI Takahiro }
958c30a15e5SDonggeun Kim
9594ced2039SAKASHI Takahiro if (!itr->dent && !itr->is_root && flush_dir_table(itr))
9604ced2039SAKASHI Takahiro /* indicate that allocating dent failed */
9614ced2039SAKASHI Takahiro itr->dent = NULL;
9624ced2039SAKASHI Takahiro
963c30a15e5SDonggeun Kim return NULL;
964c30a15e5SDonggeun Kim }
965c30a15e5SDonggeun Kim
split_filename(char * filename,char ** dirname,char ** basename)9664ced2039SAKASHI Takahiro static int split_filename(char *filename, char **dirname, char **basename)
9674ced2039SAKASHI Takahiro {
9684ced2039SAKASHI Takahiro char *p, *last_slash, *last_slash_cont;
969c30a15e5SDonggeun Kim
9704ced2039SAKASHI Takahiro again:
9714ced2039SAKASHI Takahiro p = filename;
9724ced2039SAKASHI Takahiro last_slash = NULL;
9734ced2039SAKASHI Takahiro last_slash_cont = NULL;
9744ced2039SAKASHI Takahiro while (*p) {
9754ced2039SAKASHI Takahiro if (ISDIRDELIM(*p)) {
9764ced2039SAKASHI Takahiro last_slash = p;
9774ced2039SAKASHI Takahiro last_slash_cont = p;
9784ced2039SAKASHI Takahiro /* continuous slashes */
9794ced2039SAKASHI Takahiro while (ISDIRDELIM(*p))
9804ced2039SAKASHI Takahiro last_slash_cont = p++;
9814ced2039SAKASHI Takahiro if (!*p)
982c30a15e5SDonggeun Kim break;
983c30a15e5SDonggeun Kim }
9844ced2039SAKASHI Takahiro p++;
9854ced2039SAKASHI Takahiro }
9864ced2039SAKASHI Takahiro
9874ced2039SAKASHI Takahiro if (last_slash) {
9884ced2039SAKASHI Takahiro if (last_slash_cont == (filename + strlen(filename) - 1)) {
9894ced2039SAKASHI Takahiro /* remove trailing slashes */
9904ced2039SAKASHI Takahiro *last_slash = '\0';
9914ced2039SAKASHI Takahiro goto again;
9924ced2039SAKASHI Takahiro }
9934ced2039SAKASHI Takahiro
9944ced2039SAKASHI Takahiro if (last_slash == filename) {
9954ced2039SAKASHI Takahiro /* avoid ""(null) directory */
9964ced2039SAKASHI Takahiro *dirname = "/";
997cb940c7eSRichard Genoud } else {
9984ced2039SAKASHI Takahiro *last_slash = '\0';
9994ced2039SAKASHI Takahiro *dirname = filename;
1000c30a15e5SDonggeun Kim }
1001c30a15e5SDonggeun Kim
10024ced2039SAKASHI Takahiro *last_slash_cont = '\0';
10034ced2039SAKASHI Takahiro *basename = last_slash_cont + 1;
10044ced2039SAKASHI Takahiro } else {
10054ced2039SAKASHI Takahiro *dirname = "/"; /* root by default */
10064ced2039SAKASHI Takahiro *basename = filename;
1007c30a15e5SDonggeun Kim }
1008c30a15e5SDonggeun Kim
10094ced2039SAKASHI Takahiro return 0;
1010c30a15e5SDonggeun Kim }
1011c30a15e5SDonggeun Kim
normalize_longname(char * l_filename,const char * filename)101225bb9dabSAKASHI Takahiro static int normalize_longname(char *l_filename, const char *filename)
101325bb9dabSAKASHI Takahiro {
101425bb9dabSAKASHI Takahiro const char *p, legal[] = "!#$%&\'()-.@^`_{}~";
1015819c80f5STom Rini unsigned char c;
101625bb9dabSAKASHI Takahiro int name_len;
101725bb9dabSAKASHI Takahiro
101825bb9dabSAKASHI Takahiro /* Check that the filename is valid */
101925bb9dabSAKASHI Takahiro for (p = filename; p < filename + strlen(filename); p++) {
102025bb9dabSAKASHI Takahiro c = *p;
102125bb9dabSAKASHI Takahiro
102225bb9dabSAKASHI Takahiro if (('0' <= c) && (c <= '9'))
102325bb9dabSAKASHI Takahiro continue;
102425bb9dabSAKASHI Takahiro if (('A' <= c) && (c <= 'Z'))
102525bb9dabSAKASHI Takahiro continue;
102625bb9dabSAKASHI Takahiro if (('a' <= c) && (c <= 'z'))
102725bb9dabSAKASHI Takahiro continue;
102825bb9dabSAKASHI Takahiro if (strchr(legal, c))
102925bb9dabSAKASHI Takahiro continue;
103025bb9dabSAKASHI Takahiro /* extended code */
103125bb9dabSAKASHI Takahiro if ((0x80 <= c) && (c <= 0xff))
103225bb9dabSAKASHI Takahiro continue;
103325bb9dabSAKASHI Takahiro
103425bb9dabSAKASHI Takahiro return -1;
103525bb9dabSAKASHI Takahiro }
103625bb9dabSAKASHI Takahiro
103725bb9dabSAKASHI Takahiro /* Normalize it */
103825bb9dabSAKASHI Takahiro name_len = strlen(filename);
103925bb9dabSAKASHI Takahiro if (name_len >= VFAT_MAXLEN_BYTES)
104025bb9dabSAKASHI Takahiro /* should return an error? */
104125bb9dabSAKASHI Takahiro name_len = VFAT_MAXLEN_BYTES - 1;
104225bb9dabSAKASHI Takahiro
104325bb9dabSAKASHI Takahiro memcpy(l_filename, filename, name_len);
104425bb9dabSAKASHI Takahiro l_filename[name_len] = 0; /* terminate the string */
104525bb9dabSAKASHI Takahiro downcase(l_filename, INT_MAX);
104625bb9dabSAKASHI Takahiro
104725bb9dabSAKASHI Takahiro return 0;
104825bb9dabSAKASHI Takahiro }
104925bb9dabSAKASHI Takahiro
file_fat_write_at(const char * filename,loff_t pos,void * buffer,loff_t size,loff_t * actwrite)1050704df6aaSAKASHI Takahiro int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
1051704df6aaSAKASHI Takahiro loff_t size, loff_t *actwrite)
1052c30a15e5SDonggeun Kim {
10534ced2039SAKASHI Takahiro dir_entry *retdent;
10544ced2039SAKASHI Takahiro fsdata datablock = { .fatbuf = NULL, };
1055c30a15e5SDonggeun Kim fsdata *mydata = &datablock;
10564ced2039SAKASHI Takahiro fat_itr *itr = NULL;
105725bb9dabSAKASHI Takahiro int ret = -1;
10584ced2039SAKASHI Takahiro char *filename_copy, *parent, *basename;
1059c30a15e5SDonggeun Kim char l_filename[VFAT_MAXLEN_BYTES];
1060c30a15e5SDonggeun Kim
1061704df6aaSAKASHI Takahiro debug("writing %s\n", filename);
1062704df6aaSAKASHI Takahiro
10634ced2039SAKASHI Takahiro filename_copy = strdup(filename);
10644ced2039SAKASHI Takahiro if (!filename_copy)
1065f1149ceaSAKASHI Takahiro return -ENOMEM;
1066c30a15e5SDonggeun Kim
10674ced2039SAKASHI Takahiro split_filename(filename_copy, &parent, &basename);
10684ced2039SAKASHI Takahiro if (!strlen(basename)) {
10694ced2039SAKASHI Takahiro ret = -EINVAL;
1070c30a15e5SDonggeun Kim goto exit;
1071c30a15e5SDonggeun Kim }
1072c30a15e5SDonggeun Kim
10734ced2039SAKASHI Takahiro filename = basename;
107425bb9dabSAKASHI Takahiro if (normalize_longname(l_filename, filename)) {
107525bb9dabSAKASHI Takahiro printf("FAT: illegal filename (%s)\n", filename);
107625bb9dabSAKASHI Takahiro ret = -EINVAL;
107725bb9dabSAKASHI Takahiro goto exit;
107825bb9dabSAKASHI Takahiro }
1079c30a15e5SDonggeun Kim
10804ced2039SAKASHI Takahiro itr = malloc_cache_aligned(sizeof(fat_itr));
10814ced2039SAKASHI Takahiro if (!itr) {
10824ced2039SAKASHI Takahiro ret = -ENOMEM;
10834ced2039SAKASHI Takahiro goto exit;
10844ced2039SAKASHI Takahiro }
10854ced2039SAKASHI Takahiro
10864ced2039SAKASHI Takahiro ret = fat_itr_root(itr, &datablock);
10874ced2039SAKASHI Takahiro if (ret)
10884ced2039SAKASHI Takahiro goto exit;
10894ced2039SAKASHI Takahiro
10904ced2039SAKASHI Takahiro total_sector = datablock.total_sect;
10914ced2039SAKASHI Takahiro
10924ced2039SAKASHI Takahiro ret = fat_itr_resolve(itr, parent, TYPE_DIR);
10934ced2039SAKASHI Takahiro if (ret) {
10944ced2039SAKASHI Takahiro printf("%s: doesn't exist (%d)\n", parent, ret);
10954ced2039SAKASHI Takahiro goto exit;
10964ced2039SAKASHI Takahiro }
10974ced2039SAKASHI Takahiro
10984ced2039SAKASHI Takahiro retdent = find_directory_entry(itr, l_filename);
10994ced2039SAKASHI Takahiro
1100c30a15e5SDonggeun Kim if (retdent) {
11014ced2039SAKASHI Takahiro if (fat_itr_isdir(itr)) {
11024ced2039SAKASHI Takahiro ret = -EISDIR;
11034ced2039SAKASHI Takahiro goto exit;
11044ced2039SAKASHI Takahiro }
11054ced2039SAKASHI Takahiro
1106cb8af8afSAKASHI Takahiro /* A file exists */
1107cb8af8afSAKASHI Takahiro if (pos == -1)
1108cb8af8afSAKASHI Takahiro /* Append to the end */
1109cb8af8afSAKASHI Takahiro pos = FAT2CPU32(retdent->size);
1110cb8af8afSAKASHI Takahiro if (pos > retdent->size) {
1111cb8af8afSAKASHI Takahiro /* No hole allowed */
1112cb8af8afSAKASHI Takahiro ret = -EINVAL;
1113cb8af8afSAKASHI Takahiro goto exit;
1114cb8af8afSAKASHI Takahiro }
1115cb8af8afSAKASHI Takahiro
1116704df6aaSAKASHI Takahiro /* Update file size in a directory entry */
1117704df6aaSAKASHI Takahiro retdent->size = cpu_to_le32(pos + size);
11181254b44aSBenoît Thébaudeau } else {
11194ced2039SAKASHI Takahiro /* Create a new file */
11204ced2039SAKASHI Takahiro
11214ced2039SAKASHI Takahiro if (itr->is_root) {
11224ced2039SAKASHI Takahiro /* root dir cannot have "." or ".." */
11234ced2039SAKASHI Takahiro if (!strcmp(l_filename, ".") ||
11244ced2039SAKASHI Takahiro !strcmp(l_filename, "..")) {
11254ced2039SAKASHI Takahiro ret = -EINVAL;
11264ced2039SAKASHI Takahiro goto exit;
11274ced2039SAKASHI Takahiro }
11284ced2039SAKASHI Takahiro }
11294ced2039SAKASHI Takahiro
11304ced2039SAKASHI Takahiro if (!itr->dent) {
11314ced2039SAKASHI Takahiro printf("Error: allocating new dir entry\n");
11324ced2039SAKASHI Takahiro ret = -EIO;
11334ced2039SAKASHI Takahiro goto exit;
11344ced2039SAKASHI Takahiro }
11354ced2039SAKASHI Takahiro
1136cb8af8afSAKASHI Takahiro if (pos) {
1137cb8af8afSAKASHI Takahiro /* No hole allowed */
1138cb8af8afSAKASHI Takahiro ret = -EINVAL;
1139cb8af8afSAKASHI Takahiro goto exit;
1140cb8af8afSAKASHI Takahiro }
1141cb8af8afSAKASHI Takahiro
11424ced2039SAKASHI Takahiro memset(itr->dent, 0, sizeof(*itr->dent));
11434ced2039SAKASHI Takahiro
11441254b44aSBenoît Thébaudeau /* Set short name to set alias checksum field in dir_slot */
11454ced2039SAKASHI Takahiro set_name(itr->dent, filename);
11464ced2039SAKASHI Takahiro if (fill_dir_slot(itr, filename)) {
11474ced2039SAKASHI Takahiro ret = -EIO;
11484ced2039SAKASHI Takahiro goto exit;
11494ced2039SAKASHI Takahiro }
11501254b44aSBenoît Thébaudeau
11514ced2039SAKASHI Takahiro /* Set attribute as archive for regular file */
1152704df6aaSAKASHI Takahiro fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20);
1153c30a15e5SDonggeun Kim
11544ced2039SAKASHI Takahiro retdent = itr->dent;
1155e876be4bSBenoît Thébaudeau }
1156e876be4bSBenoît Thébaudeau
1157704df6aaSAKASHI Takahiro ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
11588506eb8dSAnatolij Gustschin if (ret < 0) {
1159c30a15e5SDonggeun Kim printf("Error: writing contents\n");
1160f1149ceaSAKASHI Takahiro ret = -EIO;
1161c30a15e5SDonggeun Kim goto exit;
1162c30a15e5SDonggeun Kim }
11631ad0b98aSSuriyan Ramasami debug("attempt to write 0x%llx bytes\n", *actwrite);
1164c30a15e5SDonggeun Kim
1165c30a15e5SDonggeun Kim /* Flush fat buffer */
11663c0ed9c3SStefan Brüns ret = flush_dirty_fat_buffer(mydata);
1167c30a15e5SDonggeun Kim if (ret) {
1168c30a15e5SDonggeun Kim printf("Error: flush fat buffer\n");
1169f1149ceaSAKASHI Takahiro ret = -EIO;
1170c30a15e5SDonggeun Kim goto exit;
1171c30a15e5SDonggeun Kim }
1172c30a15e5SDonggeun Kim
1173c30a15e5SDonggeun Kim /* Write directory table to device */
11744ced2039SAKASHI Takahiro ret = set_cluster(mydata, itr->clust, itr->block,
1175c30a15e5SDonggeun Kim mydata->clust_size * mydata->sect_size);
1176f1149ceaSAKASHI Takahiro if (ret) {
1177c30a15e5SDonggeun Kim printf("Error: writing directory entry\n");
1178f1149ceaSAKASHI Takahiro ret = -EIO;
1179f1149ceaSAKASHI Takahiro }
1180c30a15e5SDonggeun Kim
1181c30a15e5SDonggeun Kim exit:
11824ced2039SAKASHI Takahiro free(filename_copy);
1183c30a15e5SDonggeun Kim free(mydata->fatbuf);
11844ced2039SAKASHI Takahiro free(itr);
11851ad0b98aSSuriyan Ramasami return ret;
1186c30a15e5SDonggeun Kim }
1187c30a15e5SDonggeun Kim
file_fat_write(const char * filename,void * buffer,loff_t offset,loff_t maxsize,loff_t * actwrite)11881ad0b98aSSuriyan Ramasami int file_fat_write(const char *filename, void *buffer, loff_t offset,
11891ad0b98aSSuriyan Ramasami loff_t maxsize, loff_t *actwrite)
1190c30a15e5SDonggeun Kim {
1191704df6aaSAKASHI Takahiro return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
1192c30a15e5SDonggeun Kim }
119331a18d57SAKASHI Takahiro
fat_dir_entries(fat_itr * itr)1194f8240ce9SAKASHI Takahiro static int fat_dir_entries(fat_itr *itr)
1195f8240ce9SAKASHI Takahiro {
1196f8240ce9SAKASHI Takahiro fat_itr *dirs;
1197f8240ce9SAKASHI Takahiro fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
1198f8240ce9SAKASHI Takahiro /* for FATBUFSIZE */
1199f8240ce9SAKASHI Takahiro int count;
1200f8240ce9SAKASHI Takahiro
1201f8240ce9SAKASHI Takahiro dirs = malloc_cache_aligned(sizeof(fat_itr));
1202f8240ce9SAKASHI Takahiro if (!dirs) {
1203f8240ce9SAKASHI Takahiro debug("Error: allocating memory\n");
1204f8240ce9SAKASHI Takahiro count = -ENOMEM;
1205f8240ce9SAKASHI Takahiro goto exit;
1206f8240ce9SAKASHI Takahiro }
1207f8240ce9SAKASHI Takahiro
1208f8240ce9SAKASHI Takahiro /* duplicate fsdata */
1209f8240ce9SAKASHI Takahiro fat_itr_child(dirs, itr);
1210f8240ce9SAKASHI Takahiro fsdata = *dirs->fsdata;
1211f8240ce9SAKASHI Takahiro
1212f8240ce9SAKASHI Takahiro /* allocate local fat buffer */
1213f8240ce9SAKASHI Takahiro fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
1214f8240ce9SAKASHI Takahiro if (!fsdata.fatbuf) {
1215f8240ce9SAKASHI Takahiro debug("Error: allocating memory\n");
1216f8240ce9SAKASHI Takahiro count = -ENOMEM;
1217f8240ce9SAKASHI Takahiro goto exit;
1218f8240ce9SAKASHI Takahiro }
1219f8240ce9SAKASHI Takahiro fsdata.fatbufnum = -1;
1220f8240ce9SAKASHI Takahiro dirs->fsdata = &fsdata;
1221f8240ce9SAKASHI Takahiro
1222f8240ce9SAKASHI Takahiro for (count = 0; fat_itr_next(dirs); count++)
1223f8240ce9SAKASHI Takahiro ;
1224f8240ce9SAKASHI Takahiro
1225f8240ce9SAKASHI Takahiro exit:
1226f8240ce9SAKASHI Takahiro free(fsdata.fatbuf);
1227f8240ce9SAKASHI Takahiro free(dirs);
1228f8240ce9SAKASHI Takahiro return count;
1229f8240ce9SAKASHI Takahiro }
1230f8240ce9SAKASHI Takahiro
delete_dentry(fat_itr * itr)1231f8240ce9SAKASHI Takahiro static int delete_dentry(fat_itr *itr)
1232f8240ce9SAKASHI Takahiro {
1233f8240ce9SAKASHI Takahiro fsdata *mydata = itr->fsdata;
1234f8240ce9SAKASHI Takahiro dir_entry *dentptr = itr->dent;
1235f8240ce9SAKASHI Takahiro
1236f8240ce9SAKASHI Takahiro /* free cluster blocks */
1237f8240ce9SAKASHI Takahiro clear_fatent(mydata, START(dentptr));
1238f8240ce9SAKASHI Takahiro if (flush_dirty_fat_buffer(mydata) < 0) {
1239f8240ce9SAKASHI Takahiro printf("Error: flush fat buffer\n");
1240f8240ce9SAKASHI Takahiro return -EIO;
1241f8240ce9SAKASHI Takahiro }
1242f8240ce9SAKASHI Takahiro
1243f8240ce9SAKASHI Takahiro /*
1244f8240ce9SAKASHI Takahiro * update a directory entry
1245f8240ce9SAKASHI Takahiro * TODO:
1246f8240ce9SAKASHI Takahiro * - long file name support
1247f8240ce9SAKASHI Takahiro * - find and mark the "new" first invalid entry as name[0]=0x00
1248f8240ce9SAKASHI Takahiro */
1249f8240ce9SAKASHI Takahiro memset(dentptr, 0, sizeof(*dentptr));
1250f8240ce9SAKASHI Takahiro dentptr->name[0] = 0xe5;
1251f8240ce9SAKASHI Takahiro
1252f8240ce9SAKASHI Takahiro if (set_cluster(mydata, itr->clust, itr->block,
1253f8240ce9SAKASHI Takahiro mydata->clust_size * mydata->sect_size) != 0) {
1254f8240ce9SAKASHI Takahiro printf("error: writing directory entry\n");
1255f8240ce9SAKASHI Takahiro return -EIO;
1256f8240ce9SAKASHI Takahiro }
1257f8240ce9SAKASHI Takahiro
1258f8240ce9SAKASHI Takahiro return 0;
1259f8240ce9SAKASHI Takahiro }
1260f8240ce9SAKASHI Takahiro
fat_unlink(const char * filename)1261f8240ce9SAKASHI Takahiro int fat_unlink(const char *filename)
1262f8240ce9SAKASHI Takahiro {
1263f8240ce9SAKASHI Takahiro fsdata fsdata = { .fatbuf = NULL, };
1264f8240ce9SAKASHI Takahiro fat_itr *itr = NULL;
1265f8240ce9SAKASHI Takahiro int n_entries, ret;
1266f8240ce9SAKASHI Takahiro char *filename_copy, *dirname, *basename;
1267f8240ce9SAKASHI Takahiro
1268f8240ce9SAKASHI Takahiro filename_copy = strdup(filename);
12690d532e91SHeinrich Schuchardt if (!filename_copy) {
12700d532e91SHeinrich Schuchardt printf("Error: allocating memory\n");
12710d532e91SHeinrich Schuchardt ret = -ENOMEM;
12720d532e91SHeinrich Schuchardt goto exit;
12730d532e91SHeinrich Schuchardt }
1274f8240ce9SAKASHI Takahiro split_filename(filename_copy, &dirname, &basename);
1275f8240ce9SAKASHI Takahiro
1276f8240ce9SAKASHI Takahiro if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
1277f8240ce9SAKASHI Takahiro printf("Error: cannot remove root\n");
1278f8240ce9SAKASHI Takahiro ret = -EINVAL;
1279f8240ce9SAKASHI Takahiro goto exit;
1280f8240ce9SAKASHI Takahiro }
1281f8240ce9SAKASHI Takahiro
1282f8240ce9SAKASHI Takahiro itr = malloc_cache_aligned(sizeof(fat_itr));
1283f8240ce9SAKASHI Takahiro if (!itr) {
1284f8240ce9SAKASHI Takahiro printf("Error: allocating memory\n");
12850d532e91SHeinrich Schuchardt ret = -ENOMEM;
12860d532e91SHeinrich Schuchardt goto exit;
1287f8240ce9SAKASHI Takahiro }
1288f8240ce9SAKASHI Takahiro
1289f8240ce9SAKASHI Takahiro ret = fat_itr_root(itr, &fsdata);
1290f8240ce9SAKASHI Takahiro if (ret)
1291f8240ce9SAKASHI Takahiro goto exit;
1292f8240ce9SAKASHI Takahiro
1293f8240ce9SAKASHI Takahiro total_sector = fsdata.total_sect;
1294f8240ce9SAKASHI Takahiro
1295f8240ce9SAKASHI Takahiro ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
1296f8240ce9SAKASHI Takahiro if (ret) {
1297f8240ce9SAKASHI Takahiro printf("%s: doesn't exist (%d)\n", dirname, ret);
1298f8240ce9SAKASHI Takahiro ret = -ENOENT;
1299f8240ce9SAKASHI Takahiro goto exit;
1300f8240ce9SAKASHI Takahiro }
1301f8240ce9SAKASHI Takahiro
1302f8240ce9SAKASHI Takahiro if (!find_directory_entry(itr, basename)) {
1303f8240ce9SAKASHI Takahiro printf("%s: doesn't exist\n", basename);
1304f8240ce9SAKASHI Takahiro ret = -ENOENT;
1305f8240ce9SAKASHI Takahiro goto exit;
1306f8240ce9SAKASHI Takahiro }
1307f8240ce9SAKASHI Takahiro
1308f8240ce9SAKASHI Takahiro if (fat_itr_isdir(itr)) {
1309f8240ce9SAKASHI Takahiro n_entries = fat_dir_entries(itr);
1310f8240ce9SAKASHI Takahiro if (n_entries < 0) {
1311f8240ce9SAKASHI Takahiro ret = n_entries;
1312f8240ce9SAKASHI Takahiro goto exit;
1313f8240ce9SAKASHI Takahiro }
1314f8240ce9SAKASHI Takahiro if (n_entries > 2) {
1315f8240ce9SAKASHI Takahiro printf("Error: directory is not empty: %d\n",
1316f8240ce9SAKASHI Takahiro n_entries);
1317f8240ce9SAKASHI Takahiro ret = -EINVAL;
1318f8240ce9SAKASHI Takahiro goto exit;
1319f8240ce9SAKASHI Takahiro }
1320f8240ce9SAKASHI Takahiro }
1321f8240ce9SAKASHI Takahiro
1322f8240ce9SAKASHI Takahiro ret = delete_dentry(itr);
1323f8240ce9SAKASHI Takahiro
1324f8240ce9SAKASHI Takahiro exit:
1325f8240ce9SAKASHI Takahiro free(fsdata.fatbuf);
1326f8240ce9SAKASHI Takahiro free(itr);
1327f8240ce9SAKASHI Takahiro free(filename_copy);
1328f8240ce9SAKASHI Takahiro
1329f8240ce9SAKASHI Takahiro return ret;
1330f8240ce9SAKASHI Takahiro }
1331f8240ce9SAKASHI Takahiro
fat_mkdir(const char * new_dirname)133231a18d57SAKASHI Takahiro int fat_mkdir(const char *new_dirname)
133331a18d57SAKASHI Takahiro {
133431a18d57SAKASHI Takahiro dir_entry *retdent;
133531a18d57SAKASHI Takahiro fsdata datablock = { .fatbuf = NULL, };
133631a18d57SAKASHI Takahiro fsdata *mydata = &datablock;
133731a18d57SAKASHI Takahiro fat_itr *itr = NULL;
133831a18d57SAKASHI Takahiro char *dirname_copy, *parent, *dirname;
133931a18d57SAKASHI Takahiro char l_dirname[VFAT_MAXLEN_BYTES];
134031a18d57SAKASHI Takahiro int ret = -1;
134131a18d57SAKASHI Takahiro loff_t actwrite;
134231a18d57SAKASHI Takahiro unsigned int bytesperclust;
134331a18d57SAKASHI Takahiro dir_entry *dotdent = NULL;
134431a18d57SAKASHI Takahiro
134531a18d57SAKASHI Takahiro dirname_copy = strdup(new_dirname);
134631a18d57SAKASHI Takahiro if (!dirname_copy)
134731a18d57SAKASHI Takahiro goto exit;
134831a18d57SAKASHI Takahiro
134931a18d57SAKASHI Takahiro split_filename(dirname_copy, &parent, &dirname);
135031a18d57SAKASHI Takahiro if (!strlen(dirname)) {
135131a18d57SAKASHI Takahiro ret = -EINVAL;
135231a18d57SAKASHI Takahiro goto exit;
135331a18d57SAKASHI Takahiro }
135431a18d57SAKASHI Takahiro
135531a18d57SAKASHI Takahiro if (normalize_longname(l_dirname, dirname)) {
135631a18d57SAKASHI Takahiro printf("FAT: illegal filename (%s)\n", dirname);
135731a18d57SAKASHI Takahiro ret = -EINVAL;
135831a18d57SAKASHI Takahiro goto exit;
135931a18d57SAKASHI Takahiro }
136031a18d57SAKASHI Takahiro
136131a18d57SAKASHI Takahiro itr = malloc_cache_aligned(sizeof(fat_itr));
136231a18d57SAKASHI Takahiro if (!itr) {
136331a18d57SAKASHI Takahiro ret = -ENOMEM;
136431a18d57SAKASHI Takahiro goto exit;
136531a18d57SAKASHI Takahiro }
136631a18d57SAKASHI Takahiro
136731a18d57SAKASHI Takahiro ret = fat_itr_root(itr, &datablock);
136831a18d57SAKASHI Takahiro if (ret)
136931a18d57SAKASHI Takahiro goto exit;
137031a18d57SAKASHI Takahiro
137131a18d57SAKASHI Takahiro total_sector = datablock.total_sect;
137231a18d57SAKASHI Takahiro
137331a18d57SAKASHI Takahiro ret = fat_itr_resolve(itr, parent, TYPE_DIR);
137431a18d57SAKASHI Takahiro if (ret) {
137531a18d57SAKASHI Takahiro printf("%s: doesn't exist (%d)\n", parent, ret);
137631a18d57SAKASHI Takahiro goto exit;
137731a18d57SAKASHI Takahiro }
137831a18d57SAKASHI Takahiro
137931a18d57SAKASHI Takahiro retdent = find_directory_entry(itr, l_dirname);
138031a18d57SAKASHI Takahiro
138131a18d57SAKASHI Takahiro if (retdent) {
138231a18d57SAKASHI Takahiro printf("%s: already exists\n", l_dirname);
138331a18d57SAKASHI Takahiro ret = -EEXIST;
138431a18d57SAKASHI Takahiro goto exit;
138531a18d57SAKASHI Takahiro } else {
138631a18d57SAKASHI Takahiro if (itr->is_root) {
138731a18d57SAKASHI Takahiro /* root dir cannot have "." or ".." */
138831a18d57SAKASHI Takahiro if (!strcmp(l_dirname, ".") ||
138931a18d57SAKASHI Takahiro !strcmp(l_dirname, "..")) {
139031a18d57SAKASHI Takahiro ret = -EINVAL;
139131a18d57SAKASHI Takahiro goto exit;
139231a18d57SAKASHI Takahiro }
139331a18d57SAKASHI Takahiro }
139431a18d57SAKASHI Takahiro
139531a18d57SAKASHI Takahiro if (!itr->dent) {
139631a18d57SAKASHI Takahiro printf("Error: allocating new dir entry\n");
139731a18d57SAKASHI Takahiro ret = -EIO;
139831a18d57SAKASHI Takahiro goto exit;
139931a18d57SAKASHI Takahiro }
140031a18d57SAKASHI Takahiro
140131a18d57SAKASHI Takahiro memset(itr->dent, 0, sizeof(*itr->dent));
140231a18d57SAKASHI Takahiro
140331a18d57SAKASHI Takahiro /* Set short name to set alias checksum field in dir_slot */
140431a18d57SAKASHI Takahiro set_name(itr->dent, dirname);
140531a18d57SAKASHI Takahiro fill_dir_slot(itr, dirname);
140631a18d57SAKASHI Takahiro
140731a18d57SAKASHI Takahiro /* Set attribute as archive for regular file */
140831a18d57SAKASHI Takahiro fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0,
140931a18d57SAKASHI Takahiro ATTR_DIR | ATTR_ARCH);
141031a18d57SAKASHI Takahiro
141131a18d57SAKASHI Takahiro retdent = itr->dent;
141231a18d57SAKASHI Takahiro }
141331a18d57SAKASHI Takahiro
141431a18d57SAKASHI Takahiro /* Default entries */
141531a18d57SAKASHI Takahiro bytesperclust = mydata->clust_size * mydata->sect_size;
141631a18d57SAKASHI Takahiro dotdent = malloc_cache_aligned(bytesperclust);
141731a18d57SAKASHI Takahiro if (!dotdent) {
141831a18d57SAKASHI Takahiro ret = -ENOMEM;
141931a18d57SAKASHI Takahiro goto exit;
142031a18d57SAKASHI Takahiro }
142131a18d57SAKASHI Takahiro memset(dotdent, 0, bytesperclust);
142231a18d57SAKASHI Takahiro
142331a18d57SAKASHI Takahiro memcpy(dotdent[0].name, ". ", 8);
142431a18d57SAKASHI Takahiro memcpy(dotdent[0].ext, " ", 3);
142531a18d57SAKASHI Takahiro dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
142631a18d57SAKASHI Takahiro
142731a18d57SAKASHI Takahiro memcpy(dotdent[1].name, ".. ", 8);
142831a18d57SAKASHI Takahiro memcpy(dotdent[1].ext, " ", 3);
142931a18d57SAKASHI Takahiro dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
143031a18d57SAKASHI Takahiro set_start_cluster(mydata, &dotdent[1], itr->start_clust);
143131a18d57SAKASHI Takahiro
143231a18d57SAKASHI Takahiro ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
143331a18d57SAKASHI Takahiro bytesperclust, &actwrite);
143431a18d57SAKASHI Takahiro if (ret < 0) {
143531a18d57SAKASHI Takahiro printf("Error: writing contents\n");
143631a18d57SAKASHI Takahiro goto exit;
143731a18d57SAKASHI Takahiro }
143831a18d57SAKASHI Takahiro /* Write twice for "." */
143931a18d57SAKASHI Takahiro set_start_cluster(mydata, &dotdent[0], START(retdent));
144031a18d57SAKASHI Takahiro ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
144131a18d57SAKASHI Takahiro bytesperclust, &actwrite);
144231a18d57SAKASHI Takahiro if (ret < 0) {
144331a18d57SAKASHI Takahiro printf("Error: writing contents\n");
144431a18d57SAKASHI Takahiro goto exit;
144531a18d57SAKASHI Takahiro }
144631a18d57SAKASHI Takahiro
144731a18d57SAKASHI Takahiro /* Flush fat buffer */
144831a18d57SAKASHI Takahiro ret = flush_dirty_fat_buffer(mydata);
144931a18d57SAKASHI Takahiro if (ret) {
145031a18d57SAKASHI Takahiro printf("Error: flush fat buffer\n");
145131a18d57SAKASHI Takahiro goto exit;
145231a18d57SAKASHI Takahiro }
145331a18d57SAKASHI Takahiro
145431a18d57SAKASHI Takahiro /* Write directory table to device */
145531a18d57SAKASHI Takahiro ret = set_cluster(mydata, itr->clust, itr->block,
145631a18d57SAKASHI Takahiro mydata->clust_size * mydata->sect_size);
145731a18d57SAKASHI Takahiro if (ret)
145831a18d57SAKASHI Takahiro printf("Error: writing directory entry\n");
145931a18d57SAKASHI Takahiro
146031a18d57SAKASHI Takahiro exit:
146131a18d57SAKASHI Takahiro free(dirname_copy);
146231a18d57SAKASHI Takahiro free(mydata->fatbuf);
146331a18d57SAKASHI Takahiro free(itr);
146431a18d57SAKASHI Takahiro free(dotdent);
146531a18d57SAKASHI Takahiro return ret;
146631a18d57SAKASHI Takahiro }
1467