xref: /rk3399_rockchip-uboot/fs/fat/fat_write.c (revision 627182ea9d0f157f7280aa650dd4c06461b20c3e)
1c30a15e5SDonggeun Kim /*
2c30a15e5SDonggeun Kim  * fat_write.c
3c30a15e5SDonggeun Kim  *
4c30a15e5SDonggeun Kim  * R/W (V)FAT 12/16/32 filesystem implementation by Donggeun Kim
5c30a15e5SDonggeun Kim  *
6c30a15e5SDonggeun Kim  * See file CREDITS for list of people who contributed to this
7c30a15e5SDonggeun Kim  * project.
8c30a15e5SDonggeun Kim  *
9c30a15e5SDonggeun Kim  * This program is free software; you can redistribute it and/or
10c30a15e5SDonggeun Kim  * modify it under the terms of the GNU General Public License as
11c30a15e5SDonggeun Kim  * published by the Free Software Foundation; either version 2 of
12c30a15e5SDonggeun Kim  * the License, or (at your option) any later version.
13c30a15e5SDonggeun Kim  *
14c30a15e5SDonggeun Kim  * This program is distributed in the hope that it will be useful,
15c30a15e5SDonggeun Kim  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16c30a15e5SDonggeun Kim  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17c30a15e5SDonggeun Kim  * GNU General Public License for more details.
18c30a15e5SDonggeun Kim  *
19c30a15e5SDonggeun Kim  * You should have received a copy of the GNU General Public License
20c30a15e5SDonggeun Kim  * along with this program; if not, write to the Free Software
21c30a15e5SDonggeun Kim  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22c30a15e5SDonggeun Kim  * MA 02111-1307 USA
23c30a15e5SDonggeun Kim  */
24c30a15e5SDonggeun Kim 
25c30a15e5SDonggeun Kim #include <common.h>
26c30a15e5SDonggeun Kim #include <command.h>
27c30a15e5SDonggeun Kim #include <config.h>
28c30a15e5SDonggeun Kim #include <fat.h>
29c30a15e5SDonggeun Kim #include <asm/byteorder.h>
30c30a15e5SDonggeun Kim #include <part.h>
31c30a15e5SDonggeun Kim #include "fat.c"
32c30a15e5SDonggeun Kim 
33c30a15e5SDonggeun Kim static void uppercase(char *str, int len)
34c30a15e5SDonggeun Kim {
35c30a15e5SDonggeun Kim 	int i;
36c30a15e5SDonggeun Kim 
37c30a15e5SDonggeun Kim 	for (i = 0; i < len; i++) {
38c30a15e5SDonggeun Kim 		TOUPPER(*str);
39c30a15e5SDonggeun Kim 		str++;
40c30a15e5SDonggeun Kim 	}
41c30a15e5SDonggeun Kim }
42c30a15e5SDonggeun Kim 
43c30a15e5SDonggeun Kim static int total_sector;
44c30a15e5SDonggeun Kim static int disk_write(__u32 startblock, __u32 getsize, __u8 *bufptr)
45c30a15e5SDonggeun Kim {
46c30a15e5SDonggeun Kim 	if (cur_dev == NULL)
47c30a15e5SDonggeun Kim 		return -1;
48c30a15e5SDonggeun Kim 
49c30a15e5SDonggeun Kim 	if (startblock + getsize > total_sector) {
50c30a15e5SDonggeun Kim 		printf("error: overflow occurs\n");
51c30a15e5SDonggeun Kim 		return -1;
52c30a15e5SDonggeun Kim 	}
53c30a15e5SDonggeun Kim 
54c30a15e5SDonggeun Kim 	startblock += part_offset;
55c30a15e5SDonggeun Kim 
56c30a15e5SDonggeun Kim 	if (cur_dev->block_read) {
57c30a15e5SDonggeun Kim 		return cur_dev->block_write(cur_dev->dev, startblock, getsize,
58c30a15e5SDonggeun Kim 					   (unsigned long *) bufptr);
59c30a15e5SDonggeun Kim 	}
60c30a15e5SDonggeun Kim 	return -1;
61c30a15e5SDonggeun Kim }
62c30a15e5SDonggeun Kim 
63c30a15e5SDonggeun Kim /*
64c30a15e5SDonggeun Kim  * Set short name in directory entry
65c30a15e5SDonggeun Kim  */
66c30a15e5SDonggeun Kim static void set_name(dir_entry *dirent, const char *filename)
67c30a15e5SDonggeun Kim {
68c30a15e5SDonggeun Kim 	char s_name[VFAT_MAXLEN_BYTES];
69c30a15e5SDonggeun Kim 	char *period;
70c30a15e5SDonggeun Kim 	int period_location, len, i, ext_num;
71c30a15e5SDonggeun Kim 
72c30a15e5SDonggeun Kim 	if (filename == NULL)
73c30a15e5SDonggeun Kim 		return;
74c30a15e5SDonggeun Kim 
75c30a15e5SDonggeun Kim 	len = strlen(filename);
76c30a15e5SDonggeun Kim 	if (len == 0)
77c30a15e5SDonggeun Kim 		return;
78c30a15e5SDonggeun Kim 
79c30a15e5SDonggeun Kim 	memcpy(s_name, filename, len);
80c30a15e5SDonggeun Kim 	uppercase(s_name, len);
81c30a15e5SDonggeun Kim 
82c30a15e5SDonggeun Kim 	period = strchr(s_name, '.');
83c30a15e5SDonggeun Kim 	if (period == NULL) {
84c30a15e5SDonggeun Kim 		period_location = len;
85c30a15e5SDonggeun Kim 		ext_num = 0;
86c30a15e5SDonggeun Kim 	} else {
87c30a15e5SDonggeun Kim 		period_location = period - s_name;
88c30a15e5SDonggeun Kim 		ext_num = len - period_location - 1;
89c30a15e5SDonggeun Kim 	}
90c30a15e5SDonggeun Kim 
91c30a15e5SDonggeun Kim 	/* Pad spaces when the length of file name is shorter than eight */
92c30a15e5SDonggeun Kim 	if (period_location < 8) {
93c30a15e5SDonggeun Kim 		memcpy(dirent->name, s_name, period_location);
94c30a15e5SDonggeun Kim 		for (i = period_location; i < 8; i++)
95c30a15e5SDonggeun Kim 			dirent->name[i] = ' ';
96c30a15e5SDonggeun Kim 	} else if (period_location == 8) {
97c30a15e5SDonggeun Kim 		memcpy(dirent->name, s_name, period_location);
98c30a15e5SDonggeun Kim 	} else {
99c30a15e5SDonggeun Kim 		memcpy(dirent->name, s_name, 6);
100c30a15e5SDonggeun Kim 		dirent->name[6] = '~';
101c30a15e5SDonggeun Kim 		dirent->name[7] = '1';
102c30a15e5SDonggeun Kim 	}
103c30a15e5SDonggeun Kim 
104c30a15e5SDonggeun Kim 	if (ext_num < 3) {
105c30a15e5SDonggeun Kim 		memcpy(dirent->ext, s_name + period_location + 1, ext_num);
106c30a15e5SDonggeun Kim 		for (i = ext_num; i < 3; i++)
107c30a15e5SDonggeun Kim 			dirent->ext[i] = ' ';
108c30a15e5SDonggeun Kim 	} else
109c30a15e5SDonggeun Kim 		memcpy(dirent->ext, s_name + period_location + 1, 3);
110c30a15e5SDonggeun Kim 
111c30a15e5SDonggeun Kim 	debug("name : %s\n", dirent->name);
112c30a15e5SDonggeun Kim 	debug("ext : %s\n", dirent->ext);
113c30a15e5SDonggeun Kim }
114c30a15e5SDonggeun Kim 
115*627182eaSDonggeun Kim static __u8 num_of_fats;
116c30a15e5SDonggeun Kim /*
117c30a15e5SDonggeun Kim  * Write fat buffer into block device
118c30a15e5SDonggeun Kim  */
119c30a15e5SDonggeun Kim static int flush_fat_buffer(fsdata *mydata)
120c30a15e5SDonggeun Kim {
121c30a15e5SDonggeun Kim 	int getsize = FATBUFBLOCKS;
122c30a15e5SDonggeun Kim 	__u32 fatlength = mydata->fatlength;
123c30a15e5SDonggeun Kim 	__u8 *bufptr = mydata->fatbuf;
124c30a15e5SDonggeun Kim 	__u32 startblock = mydata->fatbufnum * FATBUFBLOCKS;
125c30a15e5SDonggeun Kim 
126c30a15e5SDonggeun Kim 	fatlength *= mydata->sect_size;
127c30a15e5SDonggeun Kim 	startblock += mydata->fat_sect;
128c30a15e5SDonggeun Kim 
129c30a15e5SDonggeun Kim 	if (getsize > fatlength)
130c30a15e5SDonggeun Kim 		getsize = fatlength;
131c30a15e5SDonggeun Kim 
132c30a15e5SDonggeun Kim 	/* Write FAT buf */
133c30a15e5SDonggeun Kim 	if (disk_write(startblock, getsize, bufptr) < 0) {
134c30a15e5SDonggeun Kim 		debug("error: writing FAT blocks\n");
135c30a15e5SDonggeun Kim 		return -1;
136c30a15e5SDonggeun Kim 	}
137c30a15e5SDonggeun Kim 
138*627182eaSDonggeun Kim 	if (num_of_fats == 2) {
139*627182eaSDonggeun Kim 		/* Update corresponding second FAT blocks */
140*627182eaSDonggeun Kim 		startblock += mydata->fatlength;
141*627182eaSDonggeun Kim 		if (disk_write(startblock, getsize, bufptr) < 0) {
142*627182eaSDonggeun Kim 			debug("error: writing second FAT blocks\n");
143*627182eaSDonggeun Kim 			return -1;
144*627182eaSDonggeun Kim 		}
145*627182eaSDonggeun Kim 	}
146*627182eaSDonggeun Kim 
147c30a15e5SDonggeun Kim 	return 0;
148c30a15e5SDonggeun Kim }
149c30a15e5SDonggeun Kim 
150c30a15e5SDonggeun Kim /*
151c30a15e5SDonggeun Kim  * Get the entry at index 'entry' in a FAT (12/16/32) table.
152c30a15e5SDonggeun Kim  * On failure 0x00 is returned.
153c30a15e5SDonggeun Kim  * When bufnum is changed, write back the previous fatbuf to the disk.
154c30a15e5SDonggeun Kim  */
155c30a15e5SDonggeun Kim static __u32 get_fatent_value(fsdata *mydata, __u32 entry)
156c30a15e5SDonggeun Kim {
157c30a15e5SDonggeun Kim 	__u32 bufnum;
158c30a15e5SDonggeun Kim 	__u32 off16, offset;
159c30a15e5SDonggeun Kim 	__u32 ret = 0x00;
160c30a15e5SDonggeun Kim 	__u16 val1, val2;
161c30a15e5SDonggeun Kim 
162c30a15e5SDonggeun Kim 	switch (mydata->fatsize) {
163c30a15e5SDonggeun Kim 	case 32:
164c30a15e5SDonggeun Kim 		bufnum = entry / FAT32BUFSIZE;
165c30a15e5SDonggeun Kim 		offset = entry - bufnum * FAT32BUFSIZE;
166c30a15e5SDonggeun Kim 		break;
167c30a15e5SDonggeun Kim 	case 16:
168c30a15e5SDonggeun Kim 		bufnum = entry / FAT16BUFSIZE;
169c30a15e5SDonggeun Kim 		offset = entry - bufnum * FAT16BUFSIZE;
170c30a15e5SDonggeun Kim 		break;
171c30a15e5SDonggeun Kim 	case 12:
172c30a15e5SDonggeun Kim 		bufnum = entry / FAT12BUFSIZE;
173c30a15e5SDonggeun Kim 		offset = entry - bufnum * FAT12BUFSIZE;
174c30a15e5SDonggeun Kim 		break;
175c30a15e5SDonggeun Kim 
176c30a15e5SDonggeun Kim 	default:
177c30a15e5SDonggeun Kim 		/* Unsupported FAT size */
178c30a15e5SDonggeun Kim 		return ret;
179c30a15e5SDonggeun Kim 	}
180c30a15e5SDonggeun Kim 
181c30a15e5SDonggeun Kim 	debug("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
182c30a15e5SDonggeun Kim 	       mydata->fatsize, entry, entry, offset, offset);
183c30a15e5SDonggeun Kim 
184c30a15e5SDonggeun Kim 	/* Read a new block of FAT entries into the cache. */
185c30a15e5SDonggeun Kim 	if (bufnum != mydata->fatbufnum) {
186c30a15e5SDonggeun Kim 		int getsize = FATBUFBLOCKS;
187c30a15e5SDonggeun Kim 		__u8 *bufptr = mydata->fatbuf;
188c30a15e5SDonggeun Kim 		__u32 fatlength = mydata->fatlength;
189c30a15e5SDonggeun Kim 		__u32 startblock = bufnum * FATBUFBLOCKS;
190c30a15e5SDonggeun Kim 
191c30a15e5SDonggeun Kim 		if (getsize > fatlength)
192c30a15e5SDonggeun Kim 			getsize = fatlength;
193c30a15e5SDonggeun Kim 
194c30a15e5SDonggeun Kim 		fatlength *= mydata->sect_size;	/* We want it in bytes now */
195c30a15e5SDonggeun Kim 		startblock += mydata->fat_sect;	/* Offset from start of disk */
196c30a15e5SDonggeun Kim 
197c30a15e5SDonggeun Kim 		/* Write back the fatbuf to the disk */
198c30a15e5SDonggeun Kim 		if (mydata->fatbufnum != -1) {
199c30a15e5SDonggeun Kim 			if (flush_fat_buffer(mydata) < 0)
200c30a15e5SDonggeun Kim 				return -1;
201c30a15e5SDonggeun Kim 		}
202c30a15e5SDonggeun Kim 
203c30a15e5SDonggeun Kim 		if (disk_read(startblock, getsize, bufptr) < 0) {
204c30a15e5SDonggeun Kim 			debug("Error reading FAT blocks\n");
205c30a15e5SDonggeun Kim 			return ret;
206c30a15e5SDonggeun Kim 		}
207c30a15e5SDonggeun Kim 		mydata->fatbufnum = bufnum;
208c30a15e5SDonggeun Kim 	}
209c30a15e5SDonggeun Kim 
210c30a15e5SDonggeun Kim 	/* Get the actual entry from the table */
211c30a15e5SDonggeun Kim 	switch (mydata->fatsize) {
212c30a15e5SDonggeun Kim 	case 32:
213c30a15e5SDonggeun Kim 		ret = FAT2CPU32(((__u32 *) mydata->fatbuf)[offset]);
214c30a15e5SDonggeun Kim 		break;
215c30a15e5SDonggeun Kim 	case 16:
216c30a15e5SDonggeun Kim 		ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[offset]);
217c30a15e5SDonggeun Kim 		break;
218c30a15e5SDonggeun Kim 	case 12:
219c30a15e5SDonggeun Kim 		off16 = (offset * 3) / 4;
220c30a15e5SDonggeun Kim 
221c30a15e5SDonggeun Kim 		switch (offset & 0x3) {
222c30a15e5SDonggeun Kim 		case 0:
223c30a15e5SDonggeun Kim 			ret = FAT2CPU16(((__u16 *) mydata->fatbuf)[off16]);
224c30a15e5SDonggeun Kim 			ret &= 0xfff;
225c30a15e5SDonggeun Kim 			break;
226c30a15e5SDonggeun Kim 		case 1:
227c30a15e5SDonggeun Kim 			val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
228c30a15e5SDonggeun Kim 			val1 &= 0xf000;
229c30a15e5SDonggeun Kim 			val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
230c30a15e5SDonggeun Kim 			val2 &= 0x00ff;
231c30a15e5SDonggeun Kim 			ret = (val2 << 4) | (val1 >> 12);
232c30a15e5SDonggeun Kim 			break;
233c30a15e5SDonggeun Kim 		case 2:
234c30a15e5SDonggeun Kim 			val1 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
235c30a15e5SDonggeun Kim 			val1 &= 0xff00;
236c30a15e5SDonggeun Kim 			val2 = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16 + 1]);
237c30a15e5SDonggeun Kim 			val2 &= 0x000f;
238c30a15e5SDonggeun Kim 			ret = (val2 << 8) | (val1 >> 8);
239c30a15e5SDonggeun Kim 			break;
240c30a15e5SDonggeun Kim 		case 3:
241c30a15e5SDonggeun Kim 			ret = FAT2CPU16(((__u16 *)mydata->fatbuf)[off16]);
242c30a15e5SDonggeun Kim 			ret = (ret & 0xfff0) >> 4;
243c30a15e5SDonggeun Kim 			break;
244c30a15e5SDonggeun Kim 		default:
245c30a15e5SDonggeun Kim 			break;
246c30a15e5SDonggeun Kim 		}
247c30a15e5SDonggeun Kim 		break;
248c30a15e5SDonggeun Kim 	}
249c30a15e5SDonggeun Kim 	debug("FAT%d: ret: %08x, entry: %08x, offset: %04x\n",
250c30a15e5SDonggeun Kim 	       mydata->fatsize, ret, entry, offset);
251c30a15e5SDonggeun Kim 
252c30a15e5SDonggeun Kim 	return ret;
253c30a15e5SDonggeun Kim }
254c30a15e5SDonggeun Kim 
255c30a15e5SDonggeun Kim #ifdef CONFIG_SUPPORT_VFAT
256c30a15e5SDonggeun Kim /*
257c30a15e5SDonggeun Kim  * Set the file name information from 'name' into 'slotptr',
258c30a15e5SDonggeun Kim  */
259c30a15e5SDonggeun Kim static int str2slot(dir_slot *slotptr, const char *name, int *idx)
260c30a15e5SDonggeun Kim {
261c30a15e5SDonggeun Kim 	int j, end_idx = 0;
262c30a15e5SDonggeun Kim 
263c30a15e5SDonggeun Kim 	for (j = 0; j <= 8; j += 2) {
264c30a15e5SDonggeun Kim 		if (name[*idx] == 0x00) {
265c30a15e5SDonggeun Kim 			slotptr->name0_4[j] = 0;
266c30a15e5SDonggeun Kim 			slotptr->name0_4[j + 1] = 0;
267c30a15e5SDonggeun Kim 			end_idx++;
268c30a15e5SDonggeun Kim 			goto name0_4;
269c30a15e5SDonggeun Kim 		}
270c30a15e5SDonggeun Kim 		slotptr->name0_4[j] = name[*idx];
271c30a15e5SDonggeun Kim 		(*idx)++;
272c30a15e5SDonggeun Kim 		end_idx++;
273c30a15e5SDonggeun Kim 	}
274c30a15e5SDonggeun Kim 	for (j = 0; j <= 10; j += 2) {
275c30a15e5SDonggeun Kim 		if (name[*idx] == 0x00) {
276c30a15e5SDonggeun Kim 			slotptr->name5_10[j] = 0;
277c30a15e5SDonggeun Kim 			slotptr->name5_10[j + 1] = 0;
278c30a15e5SDonggeun Kim 			end_idx++;
279c30a15e5SDonggeun Kim 			goto name5_10;
280c30a15e5SDonggeun Kim 		}
281c30a15e5SDonggeun Kim 		slotptr->name5_10[j] = name[*idx];
282c30a15e5SDonggeun Kim 		(*idx)++;
283c30a15e5SDonggeun Kim 		end_idx++;
284c30a15e5SDonggeun Kim 	}
285c30a15e5SDonggeun Kim 	for (j = 0; j <= 2; j += 2) {
286c30a15e5SDonggeun Kim 		if (name[*idx] == 0x00) {
287c30a15e5SDonggeun Kim 			slotptr->name11_12[j] = 0;
288c30a15e5SDonggeun Kim 			slotptr->name11_12[j + 1] = 0;
289c30a15e5SDonggeun Kim 			end_idx++;
290c30a15e5SDonggeun Kim 			goto name11_12;
291c30a15e5SDonggeun Kim 		}
292c30a15e5SDonggeun Kim 		slotptr->name11_12[j] = name[*idx];
293c30a15e5SDonggeun Kim 		(*idx)++;
294c30a15e5SDonggeun Kim 		end_idx++;
295c30a15e5SDonggeun Kim 	}
296c30a15e5SDonggeun Kim 
297c30a15e5SDonggeun Kim 	if (name[*idx] == 0x00)
298c30a15e5SDonggeun Kim 		return 1;
299c30a15e5SDonggeun Kim 
300c30a15e5SDonggeun Kim 	return 0;
301c30a15e5SDonggeun Kim /* Not used characters are filled with 0xff 0xff */
302c30a15e5SDonggeun Kim name0_4:
303c30a15e5SDonggeun Kim 	for (; end_idx < 5; end_idx++) {
304c30a15e5SDonggeun Kim 		slotptr->name0_4[end_idx * 2] = 0xff;
305c30a15e5SDonggeun Kim 		slotptr->name0_4[end_idx * 2 + 1] = 0xff;
306c30a15e5SDonggeun Kim 	}
307c30a15e5SDonggeun Kim 	end_idx = 5;
308c30a15e5SDonggeun Kim name5_10:
309c30a15e5SDonggeun Kim 	end_idx -= 5;
310c30a15e5SDonggeun Kim 	for (; end_idx < 6; end_idx++) {
311c30a15e5SDonggeun Kim 		slotptr->name5_10[end_idx * 2] = 0xff;
312c30a15e5SDonggeun Kim 		slotptr->name5_10[end_idx * 2 + 1] = 0xff;
313c30a15e5SDonggeun Kim 	}
314c30a15e5SDonggeun Kim 	end_idx = 11;
315c30a15e5SDonggeun Kim name11_12:
316c30a15e5SDonggeun Kim 	end_idx -= 11;
317c30a15e5SDonggeun Kim 	for (; end_idx < 2; end_idx++) {
318c30a15e5SDonggeun Kim 		slotptr->name11_12[end_idx * 2] = 0xff;
319c30a15e5SDonggeun Kim 		slotptr->name11_12[end_idx * 2 + 1] = 0xff;
320c30a15e5SDonggeun Kim 	}
321c30a15e5SDonggeun Kim 
322c30a15e5SDonggeun Kim 	return 1;
323c30a15e5SDonggeun Kim }
324c30a15e5SDonggeun Kim 
325c30a15e5SDonggeun Kim static int is_next_clust(fsdata *mydata, dir_entry *dentptr);
326c30a15e5SDonggeun Kim static void flush_dir_table(fsdata *mydata, dir_entry **dentptr);
327c30a15e5SDonggeun Kim 
328c30a15e5SDonggeun Kim /*
329c30a15e5SDonggeun Kim  * Fill dir_slot entries with appropriate name, id, and attr
330c30a15e5SDonggeun Kim  * The real directory entry is returned by 'dentptr'
331c30a15e5SDonggeun Kim  */
332c30a15e5SDonggeun Kim static void
333c30a15e5SDonggeun Kim fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name)
334c30a15e5SDonggeun Kim {
335c30a15e5SDonggeun Kim 	dir_slot *slotptr = (dir_slot *)get_vfatname_block;
3368506eb8dSAnatolij Gustschin 	__u8 counter = 0, checksum;
337c30a15e5SDonggeun Kim 	int idx = 0, ret;
338c30a15e5SDonggeun Kim 	char s_name[16];
339c30a15e5SDonggeun Kim 
340c30a15e5SDonggeun Kim 	/* Get short file name and checksum value */
341c30a15e5SDonggeun Kim 	strncpy(s_name, (*dentptr)->name, 16);
342c30a15e5SDonggeun Kim 	checksum = mkcksum(s_name);
343c30a15e5SDonggeun Kim 
344c30a15e5SDonggeun Kim 	do {
345c30a15e5SDonggeun Kim 		memset(slotptr, 0x00, sizeof(dir_slot));
346c30a15e5SDonggeun Kim 		ret = str2slot(slotptr, l_name, &idx);
347c30a15e5SDonggeun Kim 		slotptr->id = ++counter;
348c30a15e5SDonggeun Kim 		slotptr->attr = ATTR_VFAT;
349c30a15e5SDonggeun Kim 		slotptr->alias_checksum = checksum;
350c30a15e5SDonggeun Kim 		slotptr++;
351c30a15e5SDonggeun Kim 	} while (ret == 0);
352c30a15e5SDonggeun Kim 
353c30a15e5SDonggeun Kim 	slotptr--;
354c30a15e5SDonggeun Kim 	slotptr->id |= LAST_LONG_ENTRY_MASK;
355c30a15e5SDonggeun Kim 
356c30a15e5SDonggeun Kim 	while (counter >= 1) {
357c30a15e5SDonggeun Kim 		if (is_next_clust(mydata, *dentptr)) {
358c30a15e5SDonggeun Kim 			/* A new cluster is allocated for directory table */
359c30a15e5SDonggeun Kim 			flush_dir_table(mydata, dentptr);
360c30a15e5SDonggeun Kim 		}
361c30a15e5SDonggeun Kim 		memcpy(*dentptr, slotptr, sizeof(dir_slot));
362c30a15e5SDonggeun Kim 		(*dentptr)++;
363c30a15e5SDonggeun Kim 		slotptr--;
364c30a15e5SDonggeun Kim 		counter--;
365c30a15e5SDonggeun Kim 	}
366c30a15e5SDonggeun Kim 
367c30a15e5SDonggeun Kim 	if (is_next_clust(mydata, *dentptr)) {
368c30a15e5SDonggeun Kim 		/* A new cluster is allocated for directory table */
369c30a15e5SDonggeun Kim 		flush_dir_table(mydata, dentptr);
370c30a15e5SDonggeun Kim 	}
371c30a15e5SDonggeun Kim }
372c30a15e5SDonggeun Kim 
373c30a15e5SDonggeun Kim static __u32 dir_curclust;
374c30a15e5SDonggeun Kim 
375c30a15e5SDonggeun Kim /*
376c30a15e5SDonggeun Kim  * Extract the full long filename starting at 'retdent' (which is really
377c30a15e5SDonggeun Kim  * a slot) into 'l_name'. If successful also copy the real directory entry
378c30a15e5SDonggeun Kim  * into 'retdent'
379c30a15e5SDonggeun Kim  * If additional adjacent cluster for directory entries is read into memory,
380c30a15e5SDonggeun Kim  * then 'get_vfatname_block' is copied into 'get_dentfromdir_block' and
381c30a15e5SDonggeun Kim  * the location of the real directory entry is returned by 'retdent'
382c30a15e5SDonggeun Kim  * Return 0 on success, -1 otherwise.
383c30a15e5SDonggeun Kim  */
384c30a15e5SDonggeun Kim static int
385c30a15e5SDonggeun Kim get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
386c30a15e5SDonggeun Kim 	      dir_entry **retdent, char *l_name)
387c30a15e5SDonggeun Kim {
388c30a15e5SDonggeun Kim 	dir_entry *realdent;
389c30a15e5SDonggeun Kim 	dir_slot *slotptr = (dir_slot *)(*retdent);
390c30a15e5SDonggeun Kim 	dir_slot *slotptr2 = NULL;
391c30a15e5SDonggeun Kim 	__u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
392c30a15e5SDonggeun Kim 							PREFETCH_BLOCKS :
393c30a15e5SDonggeun Kim 							mydata->clust_size);
394c30a15e5SDonggeun Kim 	__u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
395c30a15e5SDonggeun Kim 	int idx = 0, cur_position = 0;
396c30a15e5SDonggeun Kim 
397c30a15e5SDonggeun Kim 	if (counter > VFAT_MAXSEQ) {
398c30a15e5SDonggeun Kim 		debug("Error: VFAT name is too long\n");
399c30a15e5SDonggeun Kim 		return -1;
400c30a15e5SDonggeun Kim 	}
401c30a15e5SDonggeun Kim 
402c30a15e5SDonggeun Kim 	while ((__u8 *)slotptr < buflimit) {
403c30a15e5SDonggeun Kim 		if (counter == 0)
404c30a15e5SDonggeun Kim 			break;
405c30a15e5SDonggeun Kim 		if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
406c30a15e5SDonggeun Kim 			return -1;
407c30a15e5SDonggeun Kim 		slotptr++;
408c30a15e5SDonggeun Kim 		counter--;
409c30a15e5SDonggeun Kim 	}
410c30a15e5SDonggeun Kim 
411c30a15e5SDonggeun Kim 	if ((__u8 *)slotptr >= buflimit) {
412c30a15e5SDonggeun Kim 		if (curclust == 0)
413c30a15e5SDonggeun Kim 			return -1;
414c30a15e5SDonggeun Kim 		curclust = get_fatent_value(mydata, dir_curclust);
415c30a15e5SDonggeun Kim 		if (CHECK_CLUST(curclust, mydata->fatsize)) {
416c30a15e5SDonggeun Kim 			debug("curclust: 0x%x\n", curclust);
417c30a15e5SDonggeun Kim 			printf("Invalid FAT entry\n");
418c30a15e5SDonggeun Kim 			return -1;
419c30a15e5SDonggeun Kim 		}
420c30a15e5SDonggeun Kim 
421c30a15e5SDonggeun Kim 		dir_curclust = curclust;
422c30a15e5SDonggeun Kim 
423c30a15e5SDonggeun Kim 		if (get_cluster(mydata, curclust, get_vfatname_block,
424c30a15e5SDonggeun Kim 				mydata->clust_size * mydata->sect_size) != 0) {
425c30a15e5SDonggeun Kim 			debug("Error: reading directory block\n");
426c30a15e5SDonggeun Kim 			return -1;
427c30a15e5SDonggeun Kim 		}
428c30a15e5SDonggeun Kim 
429c30a15e5SDonggeun Kim 		slotptr2 = (dir_slot *)get_vfatname_block;
430c30a15e5SDonggeun Kim 		while (counter > 0) {
431c30a15e5SDonggeun Kim 			if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
432c30a15e5SDonggeun Kim 			    & 0xff) != counter)
433c30a15e5SDonggeun Kim 				return -1;
434c30a15e5SDonggeun Kim 			slotptr2++;
435c30a15e5SDonggeun Kim 			counter--;
436c30a15e5SDonggeun Kim 		}
437c30a15e5SDonggeun Kim 
438c30a15e5SDonggeun Kim 		/* Save the real directory entry */
439c30a15e5SDonggeun Kim 		realdent = (dir_entry *)slotptr2;
440c30a15e5SDonggeun Kim 		while ((__u8 *)slotptr2 > get_vfatname_block) {
441c30a15e5SDonggeun Kim 			slotptr2--;
442c30a15e5SDonggeun Kim 			slot2str(slotptr2, l_name, &idx);
443c30a15e5SDonggeun Kim 		}
444c30a15e5SDonggeun Kim 	} else {
445c30a15e5SDonggeun Kim 		/* Save the real directory entry */
446c30a15e5SDonggeun Kim 		realdent = (dir_entry *)slotptr;
447c30a15e5SDonggeun Kim 	}
448c30a15e5SDonggeun Kim 
449c30a15e5SDonggeun Kim 	do {
450c30a15e5SDonggeun Kim 		slotptr--;
451c30a15e5SDonggeun Kim 		if (slot2str(slotptr, l_name, &idx))
452c30a15e5SDonggeun Kim 			break;
453c30a15e5SDonggeun Kim 	} while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
454c30a15e5SDonggeun Kim 
455c30a15e5SDonggeun Kim 	l_name[idx] = '\0';
456c30a15e5SDonggeun Kim 	if (*l_name == DELETED_FLAG)
457c30a15e5SDonggeun Kim 		*l_name = '\0';
458c30a15e5SDonggeun Kim 	else if (*l_name == aRING)
459c30a15e5SDonggeun Kim 		*l_name = DELETED_FLAG;
460c30a15e5SDonggeun Kim 	downcase(l_name);
461c30a15e5SDonggeun Kim 
462c30a15e5SDonggeun Kim 	/* Return the real directory entry */
463c30a15e5SDonggeun Kim 	*retdent = realdent;
464c30a15e5SDonggeun Kim 
465c30a15e5SDonggeun Kim 	if (slotptr2) {
466c30a15e5SDonggeun Kim 		memcpy(get_dentfromdir_block, get_vfatname_block,
467c30a15e5SDonggeun Kim 			mydata->clust_size * mydata->sect_size);
468c30a15e5SDonggeun Kim 		cur_position = (__u8 *)realdent - get_vfatname_block;
469c30a15e5SDonggeun Kim 		*retdent = (dir_entry *) &get_dentfromdir_block[cur_position];
470c30a15e5SDonggeun Kim 	}
471c30a15e5SDonggeun Kim 
472c30a15e5SDonggeun Kim 	return 0;
473c30a15e5SDonggeun Kim }
474c30a15e5SDonggeun Kim 
475c30a15e5SDonggeun Kim #endif
476c30a15e5SDonggeun Kim 
477c30a15e5SDonggeun Kim /*
478c30a15e5SDonggeun Kim  * Set the entry at index 'entry' in a FAT (16/32) table.
479c30a15e5SDonggeun Kim  */
480c30a15e5SDonggeun Kim static int set_fatent_value(fsdata *mydata, __u32 entry, __u32 entry_value)
481c30a15e5SDonggeun Kim {
482c30a15e5SDonggeun Kim 	__u32 bufnum, offset;
483c30a15e5SDonggeun Kim 
484c30a15e5SDonggeun Kim 	switch (mydata->fatsize) {
485c30a15e5SDonggeun Kim 	case 32:
486c30a15e5SDonggeun Kim 		bufnum = entry / FAT32BUFSIZE;
487c30a15e5SDonggeun Kim 		offset = entry - bufnum * FAT32BUFSIZE;
488c30a15e5SDonggeun Kim 		break;
489c30a15e5SDonggeun Kim 	case 16:
490c30a15e5SDonggeun Kim 		bufnum = entry / FAT16BUFSIZE;
491c30a15e5SDonggeun Kim 		offset = entry - bufnum * FAT16BUFSIZE;
492c30a15e5SDonggeun Kim 		break;
493c30a15e5SDonggeun Kim 	default:
494c30a15e5SDonggeun Kim 		/* Unsupported FAT size */
495c30a15e5SDonggeun Kim 		return -1;
496c30a15e5SDonggeun Kim 	}
497c30a15e5SDonggeun Kim 
498c30a15e5SDonggeun Kim 	/* Read a new block of FAT entries into the cache. */
499c30a15e5SDonggeun Kim 	if (bufnum != mydata->fatbufnum) {
500c30a15e5SDonggeun Kim 		int getsize = FATBUFBLOCKS;
501c30a15e5SDonggeun Kim 		__u8 *bufptr = mydata->fatbuf;
502c30a15e5SDonggeun Kim 		__u32 fatlength = mydata->fatlength;
503c30a15e5SDonggeun Kim 		__u32 startblock = bufnum * FATBUFBLOCKS;
504c30a15e5SDonggeun Kim 
505c30a15e5SDonggeun Kim 		fatlength *= mydata->sect_size;
506c30a15e5SDonggeun Kim 		startblock += mydata->fat_sect;
507c30a15e5SDonggeun Kim 
508c30a15e5SDonggeun Kim 		if (getsize > fatlength)
509c30a15e5SDonggeun Kim 			getsize = fatlength;
510c30a15e5SDonggeun Kim 
511c30a15e5SDonggeun Kim 		if (mydata->fatbufnum != -1) {
512c30a15e5SDonggeun Kim 			if (flush_fat_buffer(mydata) < 0)
513c30a15e5SDonggeun Kim 				return -1;
514c30a15e5SDonggeun Kim 		}
515c30a15e5SDonggeun Kim 
516c30a15e5SDonggeun Kim 		if (disk_read(startblock, getsize, bufptr) < 0) {
517c30a15e5SDonggeun Kim 			debug("Error reading FAT blocks\n");
518c30a15e5SDonggeun Kim 			return -1;
519c30a15e5SDonggeun Kim 		}
520c30a15e5SDonggeun Kim 		mydata->fatbufnum = bufnum;
521c30a15e5SDonggeun Kim 	}
522c30a15e5SDonggeun Kim 
523c30a15e5SDonggeun Kim 	/* Set the actual entry */
524c30a15e5SDonggeun Kim 	switch (mydata->fatsize) {
525c30a15e5SDonggeun Kim 	case 32:
526c30a15e5SDonggeun Kim 		((__u32 *) mydata->fatbuf)[offset] = cpu_to_le32(entry_value);
527c30a15e5SDonggeun Kim 		break;
528c30a15e5SDonggeun Kim 	case 16:
529c30a15e5SDonggeun Kim 		((__u16 *) mydata->fatbuf)[offset] = cpu_to_le16(entry_value);
530c30a15e5SDonggeun Kim 		break;
531c30a15e5SDonggeun Kim 	default:
532c30a15e5SDonggeun Kim 		return -1;
533c30a15e5SDonggeun Kim 	}
534c30a15e5SDonggeun Kim 
535c30a15e5SDonggeun Kim 	return 0;
536c30a15e5SDonggeun Kim }
537c30a15e5SDonggeun Kim 
538c30a15e5SDonggeun Kim /*
539c30a15e5SDonggeun Kim  * Determine the entry value at index 'entry' in a FAT (16/32) table
540c30a15e5SDonggeun Kim  */
541c30a15e5SDonggeun Kim static __u32 determine_fatent(fsdata *mydata, __u32 entry)
542c30a15e5SDonggeun Kim {
543c30a15e5SDonggeun Kim 	__u32 next_fat, next_entry = entry + 1;
544c30a15e5SDonggeun Kim 
545c30a15e5SDonggeun Kim 	while (1) {
546c30a15e5SDonggeun Kim 		next_fat = get_fatent_value(mydata, next_entry);
547c30a15e5SDonggeun Kim 		if (next_fat == 0) {
548c30a15e5SDonggeun Kim 			set_fatent_value(mydata, entry, next_entry);
549c30a15e5SDonggeun Kim 			break;
550c30a15e5SDonggeun Kim 		}
551c30a15e5SDonggeun Kim 		next_entry++;
552c30a15e5SDonggeun Kim 	}
553c30a15e5SDonggeun Kim 	debug("FAT%d: entry: %08x, entry_value: %04x\n",
554c30a15e5SDonggeun Kim 	       mydata->fatsize, entry, next_entry);
555c30a15e5SDonggeun Kim 
556c30a15e5SDonggeun Kim 	return next_entry;
557c30a15e5SDonggeun Kim }
558c30a15e5SDonggeun Kim 
559c30a15e5SDonggeun Kim /*
560c30a15e5SDonggeun Kim  * Write at most 'size' bytes from 'buffer' into the specified cluster.
561c30a15e5SDonggeun Kim  * Return 0 on success, -1 otherwise.
562c30a15e5SDonggeun Kim  */
563c30a15e5SDonggeun Kim static int
564c30a15e5SDonggeun Kim set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
565c30a15e5SDonggeun Kim 	     unsigned long size)
566c30a15e5SDonggeun Kim {
567c30a15e5SDonggeun Kim 	int idx = 0;
568c30a15e5SDonggeun Kim 	__u32 startsect;
569c30a15e5SDonggeun Kim 
570c30a15e5SDonggeun Kim 	if (clustnum > 0)
571c30a15e5SDonggeun Kim 		startsect = mydata->data_begin +
572c30a15e5SDonggeun Kim 				clustnum * mydata->clust_size;
573c30a15e5SDonggeun Kim 	else
574c30a15e5SDonggeun Kim 		startsect = mydata->rootdir_sect;
575c30a15e5SDonggeun Kim 
576c30a15e5SDonggeun Kim 	debug("clustnum: %d, startsect: %d\n", clustnum, startsect);
577c30a15e5SDonggeun Kim 
578c30a15e5SDonggeun Kim 	if (disk_write(startsect, size / mydata->sect_size, buffer) < 0) {
579c30a15e5SDonggeun Kim 		debug("Error writing data\n");
580c30a15e5SDonggeun Kim 		return -1;
581c30a15e5SDonggeun Kim 	}
582c30a15e5SDonggeun Kim 
583c30a15e5SDonggeun Kim 	if (size % mydata->sect_size) {
584c30a15e5SDonggeun Kim 		__u8 tmpbuf[mydata->sect_size];
585c30a15e5SDonggeun Kim 
586c30a15e5SDonggeun Kim 		idx = size / mydata->sect_size;
587c30a15e5SDonggeun Kim 		buffer += idx * mydata->sect_size;
588c30a15e5SDonggeun Kim 		memcpy(tmpbuf, buffer, size % mydata->sect_size);
589c30a15e5SDonggeun Kim 
590c30a15e5SDonggeun Kim 		if (disk_write(startsect + idx, 1, tmpbuf) < 0) {
591c30a15e5SDonggeun Kim 			debug("Error writing data\n");
592c30a15e5SDonggeun Kim 			return -1;
593c30a15e5SDonggeun Kim 		}
594c30a15e5SDonggeun Kim 
595c30a15e5SDonggeun Kim 		return 0;
596c30a15e5SDonggeun Kim 	}
597c30a15e5SDonggeun Kim 
598c30a15e5SDonggeun Kim 	return 0;
599c30a15e5SDonggeun Kim }
600c30a15e5SDonggeun Kim 
601c30a15e5SDonggeun Kim /*
602c30a15e5SDonggeun Kim  * Find the first empty cluster
603c30a15e5SDonggeun Kim  */
604c30a15e5SDonggeun Kim static int find_empty_cluster(fsdata *mydata)
605c30a15e5SDonggeun Kim {
606c30a15e5SDonggeun Kim 	__u32 fat_val, entry = 3;
607c30a15e5SDonggeun Kim 
608c30a15e5SDonggeun Kim 	while (1) {
609c30a15e5SDonggeun Kim 		fat_val = get_fatent_value(mydata, entry);
610c30a15e5SDonggeun Kim 		if (fat_val == 0)
611c30a15e5SDonggeun Kim 			break;
612c30a15e5SDonggeun Kim 		entry++;
613c30a15e5SDonggeun Kim 	}
614c30a15e5SDonggeun Kim 
615c30a15e5SDonggeun Kim 	return entry;
616c30a15e5SDonggeun Kim }
617c30a15e5SDonggeun Kim 
618c30a15e5SDonggeun Kim /*
619c30a15e5SDonggeun Kim  * Write directory entries in 'get_dentfromdir_block' to block device
620c30a15e5SDonggeun Kim  */
621c30a15e5SDonggeun Kim static void flush_dir_table(fsdata *mydata, dir_entry **dentptr)
622c30a15e5SDonggeun Kim {
623c30a15e5SDonggeun Kim 	int dir_newclust = 0;
624c30a15e5SDonggeun Kim 
625c30a15e5SDonggeun Kim 	if (set_cluster(mydata, dir_curclust,
626c30a15e5SDonggeun Kim 		    get_dentfromdir_block,
627c30a15e5SDonggeun Kim 		    mydata->clust_size * mydata->sect_size) != 0) {
628c30a15e5SDonggeun Kim 		printf("error: wrinting directory entry\n");
629c30a15e5SDonggeun Kim 		return;
630c30a15e5SDonggeun Kim 	}
631c30a15e5SDonggeun Kim 	dir_newclust = find_empty_cluster(mydata);
632c30a15e5SDonggeun Kim 	set_fatent_value(mydata, dir_curclust, dir_newclust);
633c30a15e5SDonggeun Kim 	if (mydata->fatsize == 32)
634c30a15e5SDonggeun Kim 		set_fatent_value(mydata, dir_newclust, 0xffffff8);
635c30a15e5SDonggeun Kim 	else if (mydata->fatsize == 16)
636c30a15e5SDonggeun Kim 		set_fatent_value(mydata, dir_newclust, 0xfff8);
637c30a15e5SDonggeun Kim 
638c30a15e5SDonggeun Kim 	dir_curclust = dir_newclust;
639c30a15e5SDonggeun Kim 
640c30a15e5SDonggeun Kim 	if (flush_fat_buffer(mydata) < 0)
641c30a15e5SDonggeun Kim 		return;
642c30a15e5SDonggeun Kim 
643c30a15e5SDonggeun Kim 	memset(get_dentfromdir_block, 0x00,
644c30a15e5SDonggeun Kim 		mydata->clust_size * mydata->sect_size);
645c30a15e5SDonggeun Kim 
646c30a15e5SDonggeun Kim 	*dentptr = (dir_entry *) get_dentfromdir_block;
647c30a15e5SDonggeun Kim }
648c30a15e5SDonggeun Kim 
649c30a15e5SDonggeun Kim /*
650c30a15e5SDonggeun Kim  * Set empty cluster from 'entry' to the end of a file
651c30a15e5SDonggeun Kim  */
652c30a15e5SDonggeun Kim static int clear_fatent(fsdata *mydata, __u32 entry)
653c30a15e5SDonggeun Kim {
654c30a15e5SDonggeun Kim 	__u32 fat_val;
655c30a15e5SDonggeun Kim 
656c30a15e5SDonggeun Kim 	while (1) {
657c30a15e5SDonggeun Kim 		fat_val = get_fatent_value(mydata, entry);
658c30a15e5SDonggeun Kim 		if (fat_val != 0)
659c30a15e5SDonggeun Kim 			set_fatent_value(mydata, entry, 0);
660c30a15e5SDonggeun Kim 		else
661c30a15e5SDonggeun Kim 			break;
662c30a15e5SDonggeun Kim 
663c30a15e5SDonggeun Kim 		if (fat_val == 0xfffffff || fat_val == 0xffff)
664c30a15e5SDonggeun Kim 			break;
665c30a15e5SDonggeun Kim 
666c30a15e5SDonggeun Kim 		entry = fat_val;
667c30a15e5SDonggeun Kim 	}
668c30a15e5SDonggeun Kim 
669c30a15e5SDonggeun Kim 	/* Flush fat buffer */
670c30a15e5SDonggeun Kim 	if (flush_fat_buffer(mydata) < 0)
671c30a15e5SDonggeun Kim 		return -1;
672c30a15e5SDonggeun Kim 
673c30a15e5SDonggeun Kim 	return 0;
674c30a15e5SDonggeun Kim }
675c30a15e5SDonggeun Kim 
676c30a15e5SDonggeun Kim /*
677c30a15e5SDonggeun Kim  * Write at most 'maxsize' bytes from 'buffer' into
678c30a15e5SDonggeun Kim  * the file associated with 'dentptr'
679c30a15e5SDonggeun Kim  * Return the number of bytes read or -1 on fatal errors.
680c30a15e5SDonggeun Kim  */
681c30a15e5SDonggeun Kim static int
682c30a15e5SDonggeun Kim set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
683c30a15e5SDonggeun Kim 	      unsigned long maxsize)
684c30a15e5SDonggeun Kim {
685c30a15e5SDonggeun Kim 	unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
686c30a15e5SDonggeun Kim 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
687c30a15e5SDonggeun Kim 	__u32 curclust = START(dentptr);
688c30a15e5SDonggeun Kim 	__u32 endclust = 0, newclust = 0;
689c30a15e5SDonggeun Kim 	unsigned long actsize;
690c30a15e5SDonggeun Kim 
691c30a15e5SDonggeun Kim 	debug("Filesize: %ld bytes\n", filesize);
692c30a15e5SDonggeun Kim 
693c30a15e5SDonggeun Kim 	if (maxsize > 0 && filesize > maxsize)
694c30a15e5SDonggeun Kim 		filesize = maxsize;
695c30a15e5SDonggeun Kim 
696c30a15e5SDonggeun Kim 	debug("%ld bytes\n", filesize);
697c30a15e5SDonggeun Kim 
698c30a15e5SDonggeun Kim 	actsize = bytesperclust;
699c30a15e5SDonggeun Kim 	endclust = curclust;
700c30a15e5SDonggeun Kim 	do {
701c30a15e5SDonggeun Kim 		/* search for consecutive clusters */
702c30a15e5SDonggeun Kim 		while (actsize < filesize) {
703c30a15e5SDonggeun Kim 			newclust = determine_fatent(mydata, endclust);
704c30a15e5SDonggeun Kim 
705c30a15e5SDonggeun Kim 			if ((newclust - 1) != endclust)
706c30a15e5SDonggeun Kim 				goto getit;
707c30a15e5SDonggeun Kim 
708c30a15e5SDonggeun Kim 			if (CHECK_CLUST(newclust, mydata->fatsize)) {
709c30a15e5SDonggeun Kim 				debug("curclust: 0x%x\n", newclust);
710c30a15e5SDonggeun Kim 				debug("Invalid FAT entry\n");
711c30a15e5SDonggeun Kim 				return gotsize;
712c30a15e5SDonggeun Kim 			}
713c30a15e5SDonggeun Kim 			endclust = newclust;
714c30a15e5SDonggeun Kim 			actsize += bytesperclust;
715c30a15e5SDonggeun Kim 		}
716c30a15e5SDonggeun Kim 		/* actsize >= file size */
717c30a15e5SDonggeun Kim 		actsize -= bytesperclust;
718c30a15e5SDonggeun Kim 		/* set remaining clusters */
719c30a15e5SDonggeun Kim 		if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
720c30a15e5SDonggeun Kim 			debug("error: writing cluster\n");
721c30a15e5SDonggeun Kim 			return -1;
722c30a15e5SDonggeun Kim 		}
723c30a15e5SDonggeun Kim 
724c30a15e5SDonggeun Kim 		/* set remaining bytes */
725c30a15e5SDonggeun Kim 		gotsize += (int)actsize;
726c30a15e5SDonggeun Kim 		filesize -= actsize;
727c30a15e5SDonggeun Kim 		buffer += actsize;
728c30a15e5SDonggeun Kim 		actsize = filesize;
729c30a15e5SDonggeun Kim 
730c30a15e5SDonggeun Kim 		if (set_cluster(mydata, endclust, buffer, (int)actsize) != 0) {
731c30a15e5SDonggeun Kim 			debug("error: writing cluster\n");
732c30a15e5SDonggeun Kim 			return -1;
733c30a15e5SDonggeun Kim 		}
734c30a15e5SDonggeun Kim 		gotsize += actsize;
735c30a15e5SDonggeun Kim 
736c30a15e5SDonggeun Kim 		/* Mark end of file in FAT */
737c30a15e5SDonggeun Kim 		if (mydata->fatsize == 16)
738c30a15e5SDonggeun Kim 			newclust = 0xffff;
739c30a15e5SDonggeun Kim 		else if (mydata->fatsize == 32)
740c30a15e5SDonggeun Kim 			newclust = 0xfffffff;
741c30a15e5SDonggeun Kim 		set_fatent_value(mydata, endclust, newclust);
742c30a15e5SDonggeun Kim 
743c30a15e5SDonggeun Kim 		return gotsize;
744c30a15e5SDonggeun Kim getit:
745c30a15e5SDonggeun Kim 		if (set_cluster(mydata, curclust, buffer, (int)actsize) != 0) {
746c30a15e5SDonggeun Kim 			debug("error: writing cluster\n");
747c30a15e5SDonggeun Kim 			return -1;
748c30a15e5SDonggeun Kim 		}
749c30a15e5SDonggeun Kim 		gotsize += (int)actsize;
750c30a15e5SDonggeun Kim 		filesize -= actsize;
751c30a15e5SDonggeun Kim 		buffer += actsize;
752c30a15e5SDonggeun Kim 
753c30a15e5SDonggeun Kim 		if (CHECK_CLUST(curclust, mydata->fatsize)) {
754c30a15e5SDonggeun Kim 			debug("curclust: 0x%x\n", curclust);
755c30a15e5SDonggeun Kim 			debug("Invalid FAT entry\n");
756c30a15e5SDonggeun Kim 			return gotsize;
757c30a15e5SDonggeun Kim 		}
758c30a15e5SDonggeun Kim 		actsize = bytesperclust;
759c30a15e5SDonggeun Kim 		curclust = endclust = newclust;
760c30a15e5SDonggeun Kim 	} while (1);
761c30a15e5SDonggeun Kim }
762c30a15e5SDonggeun Kim 
763c30a15e5SDonggeun Kim /*
764c30a15e5SDonggeun Kim  * Fill dir_entry
765c30a15e5SDonggeun Kim  */
766c30a15e5SDonggeun Kim static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
767c30a15e5SDonggeun Kim 	const char *filename, __u32 start_cluster, __u32 size, __u8 attr)
768c30a15e5SDonggeun Kim {
769c30a15e5SDonggeun Kim 	if (mydata->fatsize == 32)
770c30a15e5SDonggeun Kim 		dentptr->starthi =
771c30a15e5SDonggeun Kim 			cpu_to_le16((start_cluster & 0xffff0000) >> 16);
772c30a15e5SDonggeun Kim 	dentptr->start = cpu_to_le16(start_cluster & 0xffff);
773c30a15e5SDonggeun Kim 	dentptr->size = cpu_to_le32(size);
774c30a15e5SDonggeun Kim 
775c30a15e5SDonggeun Kim 	dentptr->attr = attr;
776c30a15e5SDonggeun Kim 
777c30a15e5SDonggeun Kim 	set_name(dentptr, filename);
778c30a15e5SDonggeun Kim }
779c30a15e5SDonggeun Kim 
780c30a15e5SDonggeun Kim /*
781c30a15e5SDonggeun Kim  * Check whether adding a file makes the file system to
782c30a15e5SDonggeun Kim  * exceed the size of the block device
783c30a15e5SDonggeun Kim  * Return -1 when overflow occurs, otherwise return 0
784c30a15e5SDonggeun Kim  */
785c30a15e5SDonggeun Kim static int check_overflow(fsdata *mydata, __u32 clustnum, unsigned long size)
786c30a15e5SDonggeun Kim {
787c30a15e5SDonggeun Kim 	__u32 startsect, sect_num;
788c30a15e5SDonggeun Kim 
789c30a15e5SDonggeun Kim 	if (clustnum > 0) {
790c30a15e5SDonggeun Kim 		startsect = mydata->data_begin +
791c30a15e5SDonggeun Kim 				clustnum * mydata->clust_size;
792c30a15e5SDonggeun Kim 	} else {
793c30a15e5SDonggeun Kim 		startsect = mydata->rootdir_sect;
794c30a15e5SDonggeun Kim 	}
795c30a15e5SDonggeun Kim 
796c30a15e5SDonggeun Kim 	sect_num = size / mydata->sect_size;
797c30a15e5SDonggeun Kim 	if (size % mydata->sect_size)
798c30a15e5SDonggeun Kim 		sect_num++;
799c30a15e5SDonggeun Kim 
800c30a15e5SDonggeun Kim 	if (startsect + sect_num > total_sector)
801c30a15e5SDonggeun Kim 		return -1;
802c30a15e5SDonggeun Kim 
803c30a15e5SDonggeun Kim 	return 0;
804c30a15e5SDonggeun Kim }
805c30a15e5SDonggeun Kim 
806c30a15e5SDonggeun Kim /*
807c30a15e5SDonggeun Kim  * Check if adding several entries exceed one cluster boundary
808c30a15e5SDonggeun Kim  */
809c30a15e5SDonggeun Kim static int is_next_clust(fsdata *mydata, dir_entry *dentptr)
810c30a15e5SDonggeun Kim {
811c30a15e5SDonggeun Kim 	int cur_position;
812c30a15e5SDonggeun Kim 
813c30a15e5SDonggeun Kim 	cur_position = (__u8 *)dentptr - get_dentfromdir_block;
814c30a15e5SDonggeun Kim 
815c30a15e5SDonggeun Kim 	if (cur_position >= mydata->clust_size * mydata->sect_size)
816c30a15e5SDonggeun Kim 		return 1;
817c30a15e5SDonggeun Kim 	else
818c30a15e5SDonggeun Kim 		return 0;
819c30a15e5SDonggeun Kim }
820c30a15e5SDonggeun Kim 
821c30a15e5SDonggeun Kim static dir_entry *empty_dentptr;
822c30a15e5SDonggeun Kim /*
823c30a15e5SDonggeun Kim  * Find a directory entry based on filename or start cluster number
824c30a15e5SDonggeun Kim  * If the directory entry is not found,
825c30a15e5SDonggeun Kim  * the new position for writing a directory entry will be returned
826c30a15e5SDonggeun Kim  */
827c30a15e5SDonggeun Kim static dir_entry *find_directory_entry(fsdata *mydata, int startsect,
828c30a15e5SDonggeun Kim 	char *filename, dir_entry *retdent, __u32 start)
829c30a15e5SDonggeun Kim {
830c30a15e5SDonggeun Kim 	__u16 prevcksum = 0xffff;
831c30a15e5SDonggeun Kim 	__u32 curclust = (startsect - mydata->data_begin) / mydata->clust_size;
832c30a15e5SDonggeun Kim 
833c30a15e5SDonggeun Kim 	debug("get_dentfromdir: %s\n", filename);
834c30a15e5SDonggeun Kim 
835c30a15e5SDonggeun Kim 	while (1) {
836c30a15e5SDonggeun Kim 		dir_entry *dentptr;
837c30a15e5SDonggeun Kim 
838c30a15e5SDonggeun Kim 		int i;
839c30a15e5SDonggeun Kim 
840c30a15e5SDonggeun Kim 		if (get_cluster(mydata, curclust, get_dentfromdir_block,
841c30a15e5SDonggeun Kim 			    mydata->clust_size * mydata->sect_size) != 0) {
842c30a15e5SDonggeun Kim 			printf("Error: reading directory block\n");
843c30a15e5SDonggeun Kim 			return NULL;
844c30a15e5SDonggeun Kim 		}
845c30a15e5SDonggeun Kim 
846c30a15e5SDonggeun Kim 		dentptr = (dir_entry *)get_dentfromdir_block;
847c30a15e5SDonggeun Kim 
848c30a15e5SDonggeun Kim 		dir_curclust = curclust;
849c30a15e5SDonggeun Kim 
850c30a15e5SDonggeun Kim 		for (i = 0; i < DIRENTSPERCLUST; i++) {
851c30a15e5SDonggeun Kim 			char s_name[14], l_name[VFAT_MAXLEN_BYTES];
852c30a15e5SDonggeun Kim 
853c30a15e5SDonggeun Kim 			l_name[0] = '\0';
854c30a15e5SDonggeun Kim 			if (dentptr->name[0] == DELETED_FLAG) {
855c30a15e5SDonggeun Kim 				dentptr++;
856c30a15e5SDonggeun Kim 				if (is_next_clust(mydata, dentptr))
857c30a15e5SDonggeun Kim 					break;
858c30a15e5SDonggeun Kim 				continue;
859c30a15e5SDonggeun Kim 			}
860c30a15e5SDonggeun Kim 			if ((dentptr->attr & ATTR_VOLUME)) {
861c30a15e5SDonggeun Kim #ifdef CONFIG_SUPPORT_VFAT
862c30a15e5SDonggeun Kim 				if ((dentptr->attr & ATTR_VFAT) &&
863c30a15e5SDonggeun Kim 				    (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
864c30a15e5SDonggeun Kim 					prevcksum =
865c30a15e5SDonggeun Kim 					((dir_slot *)dentptr)->alias_checksum;
866c30a15e5SDonggeun Kim 					get_long_file_name(mydata, curclust,
867c30a15e5SDonggeun Kim 						     get_dentfromdir_block,
868c30a15e5SDonggeun Kim 						     &dentptr, l_name);
869c30a15e5SDonggeun Kim 					debug("vfatname: |%s|\n", l_name);
870c30a15e5SDonggeun Kim 				} else
871c30a15e5SDonggeun Kim #endif
872c30a15e5SDonggeun Kim 				{
873c30a15e5SDonggeun Kim 					/* Volume label or VFAT entry */
874c30a15e5SDonggeun Kim 					dentptr++;
875c30a15e5SDonggeun Kim 					if (is_next_clust(mydata, dentptr))
876c30a15e5SDonggeun Kim 						break;
877c30a15e5SDonggeun Kim 					continue;
878c30a15e5SDonggeun Kim 				}
879c30a15e5SDonggeun Kim 			}
880c30a15e5SDonggeun Kim 			if (dentptr->name[0] == 0) {
881c30a15e5SDonggeun Kim 				debug("Dentname == NULL - %d\n", i);
882c30a15e5SDonggeun Kim 				empty_dentptr = dentptr;
883c30a15e5SDonggeun Kim 				return NULL;
884c30a15e5SDonggeun Kim 			}
885c30a15e5SDonggeun Kim 
886c30a15e5SDonggeun Kim 			get_name(dentptr, s_name);
887c30a15e5SDonggeun Kim 
888c30a15e5SDonggeun Kim 			if (strcmp(filename, s_name)
889c30a15e5SDonggeun Kim 			    && strcmp(filename, l_name)) {
890c30a15e5SDonggeun Kim 				debug("Mismatch: |%s|%s|\n",
891c30a15e5SDonggeun Kim 					s_name, l_name);
892c30a15e5SDonggeun Kim 				dentptr++;
893c30a15e5SDonggeun Kim 				if (is_next_clust(mydata, dentptr))
894c30a15e5SDonggeun Kim 					break;
895c30a15e5SDonggeun Kim 				continue;
896c30a15e5SDonggeun Kim 			}
897c30a15e5SDonggeun Kim 
898c30a15e5SDonggeun Kim 			memcpy(retdent, dentptr, sizeof(dir_entry));
899c30a15e5SDonggeun Kim 
900c30a15e5SDonggeun Kim 			debug("DentName: %s", s_name);
901c30a15e5SDonggeun Kim 			debug(", start: 0x%x", START(dentptr));
902c30a15e5SDonggeun Kim 			debug(", size:  0x%x %s\n",
903c30a15e5SDonggeun Kim 			      FAT2CPU32(dentptr->size),
904c30a15e5SDonggeun Kim 			      (dentptr->attr & ATTR_DIR) ?
905c30a15e5SDonggeun Kim 			      "(DIR)" : "");
906c30a15e5SDonggeun Kim 
907c30a15e5SDonggeun Kim 			return dentptr;
908c30a15e5SDonggeun Kim 		}
909c30a15e5SDonggeun Kim 
910c30a15e5SDonggeun Kim 		curclust = get_fatent_value(mydata, dir_curclust);
911c30a15e5SDonggeun Kim 		if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) {
912c30a15e5SDonggeun Kim 			empty_dentptr = dentptr;
913c30a15e5SDonggeun Kim 			return NULL;
914c30a15e5SDonggeun Kim 		}
915c30a15e5SDonggeun Kim 		if (CHECK_CLUST(curclust, mydata->fatsize)) {
916c30a15e5SDonggeun Kim 			debug("curclust: 0x%x\n", curclust);
917c30a15e5SDonggeun Kim 			debug("Invalid FAT entry\n");
918c30a15e5SDonggeun Kim 			return NULL;
919c30a15e5SDonggeun Kim 		}
920c30a15e5SDonggeun Kim 	}
921c30a15e5SDonggeun Kim 
922c30a15e5SDonggeun Kim 	return NULL;
923c30a15e5SDonggeun Kim }
924c30a15e5SDonggeun Kim 
925c30a15e5SDonggeun Kim static int do_fat_write(const char *filename, void *buffer,
926c30a15e5SDonggeun Kim 	unsigned long size)
927c30a15e5SDonggeun Kim {
928c30a15e5SDonggeun Kim 	dir_entry *dentptr, *retdent;
929c30a15e5SDonggeun Kim 	dir_slot *slotptr;
930c30a15e5SDonggeun Kim 	__u32 startsect;
931c30a15e5SDonggeun Kim 	__u32 start_cluster;
932c30a15e5SDonggeun Kim 	boot_sector bs;
933c30a15e5SDonggeun Kim 	volume_info volinfo;
934c30a15e5SDonggeun Kim 	fsdata datablock;
935c30a15e5SDonggeun Kim 	fsdata *mydata = &datablock;
936c30a15e5SDonggeun Kim 	int cursect;
937c30a15e5SDonggeun Kim 	int root_cluster, ret = -1, name_len;
938c30a15e5SDonggeun Kim 	char l_filename[VFAT_MAXLEN_BYTES];
9398506eb8dSAnatolij Gustschin 	int write_size = size;
940c30a15e5SDonggeun Kim 
941c30a15e5SDonggeun Kim 	dir_curclust = 0;
942c30a15e5SDonggeun Kim 
943c30a15e5SDonggeun Kim 	if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
944c30a15e5SDonggeun Kim 		debug("error: reading boot sector\n");
945c30a15e5SDonggeun Kim 		return -1;
946c30a15e5SDonggeun Kim 	}
947c30a15e5SDonggeun Kim 
948c30a15e5SDonggeun Kim 	total_sector = bs.total_sect;
949c30a15e5SDonggeun Kim 	if (total_sector == 0)
950c30a15e5SDonggeun Kim 		total_sector = part_size;
951c30a15e5SDonggeun Kim 
952c30a15e5SDonggeun Kim 	root_cluster = bs.root_cluster;
953c30a15e5SDonggeun Kim 
954c30a15e5SDonggeun Kim 	if (mydata->fatsize == 32)
955c30a15e5SDonggeun Kim 		mydata->fatlength = bs.fat32_length;
956c30a15e5SDonggeun Kim 	else
957c30a15e5SDonggeun Kim 		mydata->fatlength = bs.fat_length;
958c30a15e5SDonggeun Kim 
959c30a15e5SDonggeun Kim 	mydata->fat_sect = bs.reserved;
960c30a15e5SDonggeun Kim 
961c30a15e5SDonggeun Kim 	cursect = mydata->rootdir_sect
962c30a15e5SDonggeun Kim 		= mydata->fat_sect + mydata->fatlength * bs.fats;
963*627182eaSDonggeun Kim 	num_of_fats = bs.fats;
964c30a15e5SDonggeun Kim 
965c30a15e5SDonggeun Kim 	mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
966c30a15e5SDonggeun Kim 	mydata->clust_size = bs.cluster_size;
967c30a15e5SDonggeun Kim 
968c30a15e5SDonggeun Kim 	if (mydata->fatsize == 32) {
969c30a15e5SDonggeun Kim 		mydata->data_begin = mydata->rootdir_sect -
970c30a15e5SDonggeun Kim 					(mydata->clust_size * 2);
971c30a15e5SDonggeun Kim 	} else {
972c30a15e5SDonggeun Kim 		int rootdir_size;
973c30a15e5SDonggeun Kim 
974c30a15e5SDonggeun Kim 		rootdir_size = ((bs.dir_entries[1]  * (int)256 +
975c30a15e5SDonggeun Kim 				 bs.dir_entries[0]) *
976c30a15e5SDonggeun Kim 				 sizeof(dir_entry)) /
977c30a15e5SDonggeun Kim 				 mydata->sect_size;
978c30a15e5SDonggeun Kim 		mydata->data_begin = mydata->rootdir_sect +
979c30a15e5SDonggeun Kim 					rootdir_size -
980c30a15e5SDonggeun Kim 					(mydata->clust_size * 2);
981c30a15e5SDonggeun Kim 	}
982c30a15e5SDonggeun Kim 
983c30a15e5SDonggeun Kim 	mydata->fatbufnum = -1;
984c30a15e5SDonggeun Kim 	mydata->fatbuf = malloc(FATBUFSIZE);
985c30a15e5SDonggeun Kim 	if (mydata->fatbuf == NULL) {
986c30a15e5SDonggeun Kim 		debug("Error: allocating memory\n");
987c30a15e5SDonggeun Kim 		return -1;
988c30a15e5SDonggeun Kim 	}
989c30a15e5SDonggeun Kim 
990c30a15e5SDonggeun Kim 	if (disk_read(cursect,
991c30a15e5SDonggeun Kim 		(mydata->fatsize == 32) ?
992c30a15e5SDonggeun Kim 		(mydata->clust_size) :
993c30a15e5SDonggeun Kim 		PREFETCH_BLOCKS, do_fat_read_block) < 0) {
994c30a15e5SDonggeun Kim 		debug("Error: reading rootdir block\n");
995c30a15e5SDonggeun Kim 		goto exit;
996c30a15e5SDonggeun Kim 	}
997c30a15e5SDonggeun Kim 	dentptr = (dir_entry *) do_fat_read_block;
998c30a15e5SDonggeun Kim 
999c30a15e5SDonggeun Kim 	name_len = strlen(filename);
10008506eb8dSAnatolij Gustschin 	if (name_len >= VFAT_MAXLEN_BYTES)
10018506eb8dSAnatolij Gustschin 		name_len = VFAT_MAXLEN_BYTES - 1;
10028506eb8dSAnatolij Gustschin 
1003c30a15e5SDonggeun Kim 	memcpy(l_filename, filename, name_len);
10048506eb8dSAnatolij Gustschin 	l_filename[name_len] = 0; /* terminate the string */
1005c30a15e5SDonggeun Kim 	downcase(l_filename);
1006c30a15e5SDonggeun Kim 
1007c30a15e5SDonggeun Kim 	startsect = mydata->rootdir_sect;
1008c30a15e5SDonggeun Kim 	retdent = find_directory_entry(mydata, startsect,
1009c30a15e5SDonggeun Kim 				l_filename, dentptr, 0);
1010c30a15e5SDonggeun Kim 	if (retdent) {
1011c30a15e5SDonggeun Kim 		/* Update file size and start_cluster in a directory entry */
1012c30a15e5SDonggeun Kim 		retdent->size = cpu_to_le32(size);
1013c30a15e5SDonggeun Kim 		start_cluster = FAT2CPU16(retdent->start);
1014c30a15e5SDonggeun Kim 		if (mydata->fatsize == 32)
1015c30a15e5SDonggeun Kim 			start_cluster |=
1016c30a15e5SDonggeun Kim 				(FAT2CPU16(retdent->starthi) << 16);
1017c30a15e5SDonggeun Kim 
1018c30a15e5SDonggeun Kim 		ret = check_overflow(mydata, start_cluster, size);
1019c30a15e5SDonggeun Kim 		if (ret) {
1020c30a15e5SDonggeun Kim 			printf("Error: %ld overflow\n", size);
1021c30a15e5SDonggeun Kim 			goto exit;
1022c30a15e5SDonggeun Kim 		}
1023c30a15e5SDonggeun Kim 
1024c30a15e5SDonggeun Kim 		ret = clear_fatent(mydata, start_cluster);
1025c30a15e5SDonggeun Kim 		if (ret) {
1026c30a15e5SDonggeun Kim 			printf("Error: clearing FAT entries\n");
1027c30a15e5SDonggeun Kim 			goto exit;
1028c30a15e5SDonggeun Kim 		}
1029c30a15e5SDonggeun Kim 
1030c30a15e5SDonggeun Kim 		ret = set_contents(mydata, retdent, buffer, size);
10318506eb8dSAnatolij Gustschin 		if (ret < 0) {
1032c30a15e5SDonggeun Kim 			printf("Error: writing contents\n");
1033c30a15e5SDonggeun Kim 			goto exit;
1034c30a15e5SDonggeun Kim 		}
10358506eb8dSAnatolij Gustschin 		write_size = ret;
10368506eb8dSAnatolij Gustschin 		debug("attempt to write 0x%x bytes\n", write_size);
1037c30a15e5SDonggeun Kim 
1038c30a15e5SDonggeun Kim 		/* Flush fat buffer */
1039c30a15e5SDonggeun Kim 		ret = flush_fat_buffer(mydata);
1040c30a15e5SDonggeun Kim 		if (ret) {
1041c30a15e5SDonggeun Kim 			printf("Error: flush fat buffer\n");
1042c30a15e5SDonggeun Kim 			goto exit;
1043c30a15e5SDonggeun Kim 		}
1044c30a15e5SDonggeun Kim 
1045c30a15e5SDonggeun Kim 		/* Write directory table to device */
1046c30a15e5SDonggeun Kim 		ret = set_cluster(mydata, dir_curclust,
1047c30a15e5SDonggeun Kim 			    get_dentfromdir_block,
1048c30a15e5SDonggeun Kim 			    mydata->clust_size * mydata->sect_size);
1049c30a15e5SDonggeun Kim 		if (ret) {
10508506eb8dSAnatolij Gustschin 			printf("Error: writing directory entry\n");
1051c30a15e5SDonggeun Kim 			goto exit;
1052c30a15e5SDonggeun Kim 		}
1053c30a15e5SDonggeun Kim 	} else {
1054c30a15e5SDonggeun Kim 		slotptr = (dir_slot *)empty_dentptr;
1055c30a15e5SDonggeun Kim 
1056c30a15e5SDonggeun Kim 		/* Set short name to set alias checksum field in dir_slot */
1057c30a15e5SDonggeun Kim 		set_name(empty_dentptr, filename);
1058c30a15e5SDonggeun Kim 		fill_dir_slot(mydata, &empty_dentptr, filename);
1059c30a15e5SDonggeun Kim 
1060c30a15e5SDonggeun Kim 		ret = start_cluster = find_empty_cluster(mydata);
1061c30a15e5SDonggeun Kim 		if (ret < 0) {
1062c30a15e5SDonggeun Kim 			printf("Error: finding empty cluster\n");
1063c30a15e5SDonggeun Kim 			goto exit;
1064c30a15e5SDonggeun Kim 		}
1065c30a15e5SDonggeun Kim 
1066c30a15e5SDonggeun Kim 		ret = check_overflow(mydata, start_cluster, size);
1067c30a15e5SDonggeun Kim 		if (ret) {
1068c30a15e5SDonggeun Kim 			printf("Error: %ld overflow\n", size);
1069c30a15e5SDonggeun Kim 			goto exit;
1070c30a15e5SDonggeun Kim 		}
1071c30a15e5SDonggeun Kim 
1072c30a15e5SDonggeun Kim 		/* Set attribute as archieve for regular file */
1073c30a15e5SDonggeun Kim 		fill_dentry(mydata, empty_dentptr, filename,
1074c30a15e5SDonggeun Kim 			start_cluster, size, 0x20);
1075c30a15e5SDonggeun Kim 
1076c30a15e5SDonggeun Kim 		ret = set_contents(mydata, empty_dentptr, buffer, size);
10778506eb8dSAnatolij Gustschin 		if (ret < 0) {
1078c30a15e5SDonggeun Kim 			printf("Error: writing contents\n");
1079c30a15e5SDonggeun Kim 			goto exit;
1080c30a15e5SDonggeun Kim 		}
10818506eb8dSAnatolij Gustschin 		write_size = ret;
10828506eb8dSAnatolij Gustschin 		debug("attempt to write 0x%x bytes\n", write_size);
1083c30a15e5SDonggeun Kim 
1084c30a15e5SDonggeun Kim 		/* Flush fat buffer */
1085c30a15e5SDonggeun Kim 		ret = flush_fat_buffer(mydata);
1086c30a15e5SDonggeun Kim 		if (ret) {
1087c30a15e5SDonggeun Kim 			printf("Error: flush fat buffer\n");
1088c30a15e5SDonggeun Kim 			goto exit;
1089c30a15e5SDonggeun Kim 		}
1090c30a15e5SDonggeun Kim 
1091c30a15e5SDonggeun Kim 		/* Write directory table to device */
1092c30a15e5SDonggeun Kim 		ret = set_cluster(mydata, dir_curclust,
1093c30a15e5SDonggeun Kim 			    get_dentfromdir_block,
1094c30a15e5SDonggeun Kim 			    mydata->clust_size * mydata->sect_size);
1095c30a15e5SDonggeun Kim 		if (ret) {
1096c30a15e5SDonggeun Kim 			printf("Error: writing directory entry\n");
1097c30a15e5SDonggeun Kim 			goto exit;
1098c30a15e5SDonggeun Kim 		}
1099c30a15e5SDonggeun Kim 	}
1100c30a15e5SDonggeun Kim 
1101c30a15e5SDonggeun Kim exit:
1102c30a15e5SDonggeun Kim 	free(mydata->fatbuf);
11038506eb8dSAnatolij Gustschin 	return ret < 0 ? ret : write_size;
1104c30a15e5SDonggeun Kim }
1105c30a15e5SDonggeun Kim 
1106c30a15e5SDonggeun Kim int file_fat_write(const char *filename, void *buffer, unsigned long maxsize)
1107c30a15e5SDonggeun Kim {
1108c30a15e5SDonggeun Kim 	printf("writing %s\n", filename);
1109c30a15e5SDonggeun Kim 	return do_fat_write(filename, buffer, maxsize);
1110c30a15e5SDonggeun Kim }
1111