xref: /openbmc/u-boot/fs/fat/fat_write.c (revision 7869e647a60ae706457bb601a3c2ea51e9fdd413)
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