File: /usr/src/linux/fs/fat/dir.c

1     /*
2      *  linux/fs/fat/dir.c
3      *
4      *  directory handling functions for fat-based filesystems
5      *
6      *  Written 1992,1993 by Werner Almesberger
7      *
8      *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
9      *
10      *  VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
11      *  Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
12      *  Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
13      *  Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
14      */
15     
16     #define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
17     
18     #include <linux/version.h>
19     #include <linux/fs.h>
20     #include <linux/msdos_fs.h>
21     #include <linux/nls.h>
22     #include <linux/kernel.h>
23     #include <linux/errno.h>
24     #include <linux/stat.h>
25     #include <linux/string.h>
26     #include <linux/ioctl.h>
27     #include <linux/dirent.h>
28     #include <linux/mm.h>
29     #include <linux/ctype.h>
30     
31     #include <asm/uaccess.h>
32     
33     #include "msbuffer.h"
34     
35     #define PRINTK(X)
36     
37     struct file_operations fat_dir_operations = {
38     	read:		generic_read_dir,
39     	readdir:	fat_readdir,
40     	ioctl:		fat_dir_ioctl,
41     	fsync:		file_fsync,
42     };
43     
44     /*
45      * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
46      * If uni_xlate is enabled and we can't get a 1:1 conversion, use a
47      * colon as an escape character since it is normally invalid on the vfat
48      * filesystem. The following four characters are the hexadecimal digits
49      * of Unicode value. This lets us do a full dump and restore of Unicode
50      * filenames. We could get into some trouble with long Unicode names,
51      * but ignore that right now.
52      * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
53      */
54     static int
55     uni16_to_x8(unsigned char *ascii, wchar_t *uni, int uni_xlate,
56     	    struct nls_table *nls)
57     {
58     	wchar_t *ip, ec;
59     	unsigned char *op, nc;
60     	int charlen;
61     	int k;
62     
63     	ip = uni;
64     	op = ascii;
65     
66     	while (*ip) {
67     		ec = *ip++;
68     		if ( (charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) {
69     			op += charlen;
70     		} else {
71     			if (uni_xlate == 1) {
72     				*op = ':';
73     				for (k = 4; k > 0; k--) {
74     					nc = ec & 0xF;
75     					op[k] = nc > 9	? nc + ('a' - 10)
76     							: nc + '0';
77     					ec >>= 4;
78     				}
79     				op += 5;
80     			} else {
81     				*op++ = '?';
82     			}
83     		}
84     		/* We have some slack there, so it's OK */
85     		if (op>ascii+256) {
86     			op = ascii + 256;
87     			break;
88     		}
89     	}
90     	*op = 0;
91     	return (op - ascii);
92     }
93     
94     #if 0
95     static void dump_de(struct msdos_dir_entry *de)
96     {
97     	int i;
98     	unsigned char *p = (unsigned char *) de;
99     	printk("[");
100     
101     	for (i = 0; i < 32; i++, p++) {
102     		printk("%02x ", *p);
103     	}
104     	printk("]\n");
105     }
106     #endif
107     
108     static inline unsigned char
109     fat_tolower(struct nls_table *t, unsigned char c)
110     {
111     	unsigned char nc = t->charset2lower[c];
112     
113     	return nc ? nc : c;
114     }
115     
116     static inline int
117     fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
118     {
119     	int charlen;
120     
121     	charlen = t->char2uni(c, clen, uni);
122     	if (charlen < 0) {
123     		*uni = 0x003f;	/* a question mark */
124     		charlen = 1;
125     	}
126     	return charlen;
127     }
128     
129     static inline int
130     fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni)
131     {
132     	int charlen;
133     	wchar_t wc;
134     
135     	charlen = t->char2uni(c, clen, &wc);
136     	if (charlen < 0) {
137     		*uni = 0x003f;	/* a question mark */
138     		charlen = 1;
139     	} else if (charlen <= 1) {
140     		unsigned char nc = t->charset2lower[*c];
141     		
142     		if (!nc)
143     			nc = *c;
144     		
145     		if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) {
146     			*uni = 0x003f;	/* a question mark */
147     			charlen = 1;
148     		}
149     	} else
150     		*uni = wc;
151     	
152     	return charlen;
153     }
154     
155     static int
156     fat_strnicmp(struct nls_table *t, const unsigned char *s1,
157     					const unsigned char *s2, int len)
158     {
159     	while(len--)
160     		if (fat_tolower(t, *s1++) != fat_tolower(t, *s2++))
161     			return 1;
162     
163     	return 0;
164     }
165     
166     /*
167      * Return values: negative -> error, 0 -> not found, positive -> found,
168      * value is the total amount of slots, including the shortname entry.
169      */
170     int fat_search_long(struct inode *inode, const char *name, int name_len,
171     			int anycase, loff_t *spos, loff_t *lpos)
172     {
173     	struct super_block *sb = inode->i_sb;
174     	struct buffer_head *bh = NULL;
175     	struct msdos_dir_entry *de;
176     	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
177     	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
178     	wchar_t bufuname[14];
179     	unsigned char xlate_len, long_slots, *unicode = NULL;
180     	char work[8], bufname[260];	/* 256 + 4 */
181     	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
182     	int utf8 = MSDOS_SB(sb)->options.utf8;
183     	int nocase = MSDOS_SB(sb)->options.nocase;
184     	int ino, chl, i, j, last_u, res = 0;
185     	loff_t cpos = 0;
186     
187     	while(1) {
188     		if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
189     			goto EODir;
190     parse_record:
191     		long_slots = 0;
192     		if (de->name[0] == (__s8) DELETED_FLAG)
193     			continue;
194     		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
195     			continue;
196     		if (de->attr != ATTR_EXT && IS_FREE(de->name))
197     			continue;
198     		if (de->attr == ATTR_EXT) {
199     			struct msdos_dir_slot *ds;
200     			int offset;
201     			unsigned char id;
202     			unsigned char slot;
203     			unsigned char slots;
204     			unsigned char sum;
205     			unsigned char alias_checksum;
206     
207     			if (!unicode) {
208     				unicode = (unsigned char *)
209     					__get_free_page(GFP_KERNEL);
210     				if (!unicode) {
211     					fat_brelse(sb, bh);
212     					return -ENOMEM;
213     				}
214     			}
215     parse_long:
216     			slots = 0;
217     			offset = 0;
218     			ds = (struct msdos_dir_slot *) de;
219     			id = ds->id;
220     			if (!(id & 0x40))
221     				continue;
222     			slots = id & ~0x40;
223     			if (slots > 20 || !slots)	/* ceil(256 * 2 / 26) */
224     				continue;
225     			long_slots = slots;
226     			alias_checksum = ds->alias_checksum;
227     
228     			slot = slots;
229     			while (1) {
230     				slot--;
231     				offset = slot * 26;
232     				memcpy(&unicode[offset], ds->name0_4, 10);
233     				memcpy(&unicode[offset+10], ds->name5_10, 12);
234     				memcpy(&unicode[offset+22], ds->name11_12, 4);
235     				offset += 26;
236     
237     				if (ds->id & 0x40) {
238     					unicode[offset] = 0;
239     					unicode[offset+1] = 0;
240     				}
241     				if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
242     					goto EODir;
243     				if (slot == 0)
244     					break;
245     				ds = (struct msdos_dir_slot *) de;
246     				if (ds->attr !=  ATTR_EXT)
247     					goto parse_record;
248     				if ((ds->id & ~0x40) != slot)
249     					goto parse_long;
250     				if (ds->alias_checksum != alias_checksum)
251     					goto parse_long;
252     			}
253     			if (de->name[0] == (__s8) DELETED_FLAG)
254     				continue;
255     			if (de->attr ==  ATTR_EXT)
256     				goto parse_long;
257     			if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
258     				continue;
259     			for (sum = 0, i = 0; i < 11; i++)
260     				sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
261     			if (sum != alias_checksum)
262     				long_slots = 0;
263     		}
264     
265     		for (i = 0; i < 8; i++) {
266     			/* see namei.c, msdos_format_name */
267     			if (de->name[i] == 0x05)
268     				work[i] = 0xE5;
269     			else
270     				work[i] = de->name[i];
271     		}
272     		for (i = 0, j = 0, last_u = 0; i < 8;) {
273     			if (!work[i]) break;
274     			if (nocase)
275     				chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
276     			else
277     				chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
278     			if (chl <= 1) {
279     				if (work[i] != ' ')
280     					last_u = j;
281     			} else {
282     				last_u = j;
283     			}
284     			i += chl;
285     		}
286     		j = last_u;
287     		fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
288     		for (i = 0; i < 3;) {
289     			if (!de->ext[i]) break;
290     			if (nocase)
291     				chl = fat_short2uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
292     			else
293     				chl = fat_short2lower_uni(nls_disk, &de->ext[i], 3 - i, &bufuname[j++]);
294     			if (chl <= 1) {
295     				if (de->ext[i] != ' ')
296     					last_u = j;
297     			} else {
298     				last_u = j;
299     			}
300     			i += chl;
301     		}
302     		if (!last_u)
303     			continue;
304     
305     		bufuname[last_u] = 0x0000;
306     		xlate_len = utf8
307     			?utf8_wcstombs(bufname, bufuname, sizeof(bufname))
308     			:uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
309     		if (xlate_len == name_len)
310     			if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
311     			    (anycase && !fat_strnicmp(nls_io, name, bufname,
312     								xlate_len)))
313     				goto Found;
314     
315     		if (long_slots) {
316     			xlate_len = utf8
317     				?utf8_wcstombs(bufname, (wchar_t *) unicode, sizeof(bufname))
318     				:uni16_to_x8(bufname, (wchar_t *) unicode, uni_xlate, nls_io);
319     			if (xlate_len != name_len)
320     				continue;
321     			if ((!anycase && !memcmp(name, bufname, xlate_len)) ||
322     			    (anycase && !fat_strnicmp(nls_io, name, bufname,
323     								xlate_len)))
324     				goto Found;
325     		}
326     	}
327     
328     Found:
329     	res = long_slots + 1;
330     	*spos = cpos - sizeof(struct msdos_dir_entry);
331     	*lpos = cpos - res*sizeof(struct msdos_dir_entry);
332     EODir:
333     	fat_brelse(sb, bh);
334     	if (unicode) {
335     		free_page((unsigned long) unicode);
336     	}
337     	return res;
338     }
339     
340     static int fat_readdirx(struct inode *inode, struct file *filp, void *dirent,
341     			filldir_t filldir, int shortnames, int both)
342     {
343     	struct super_block *sb = inode->i_sb;
344     	struct buffer_head *bh;
345     	struct msdos_dir_entry *de;
346     	struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
347     	struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
348     	wchar_t bufuname[14];
349     	unsigned char long_slots, *unicode = NULL;
350     	char c, work[8], bufname[56], *ptname = bufname;
351     	unsigned long lpos, dummy, *furrfu = &lpos;
352     	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
353     	int isvfat = MSDOS_SB(sb)->options.isvfat;
354     	int utf8 = MSDOS_SB(sb)->options.utf8;
355     	int nocase = MSDOS_SB(sb)->options.nocase;
356     	int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0;
357     	loff_t cpos;
358     
359     	cpos = filp->f_pos;
360     /* Fake . and .. for the root directory. */
361     	if (inode->i_ino == MSDOS_ROOT_INO) {
362     		while (cpos < 2) {
363     			if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0)
364     				return 0;
365     			cpos++;
366     			filp->f_pos++;
367     		}
368     		if (cpos == 2) {
369     			dummy = 2;
370     			furrfu = &dummy;
371     			cpos = 0;
372     		}
373     	}
374     	if (cpos & (sizeof(struct msdos_dir_entry)-1))
375     		return -ENOENT;
376     
377      	bh = NULL;
378     GetNew:
379     	long_slots = 0;
380     	if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
381     		goto EODir;
382     	/* Check for long filename entry */
383     	if (isvfat) {
384     		if (de->name[0] == (__s8) DELETED_FLAG)
385     			goto RecEnd;
386     		if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
387     			goto RecEnd;
388     		if (de->attr != ATTR_EXT && IS_FREE(de->name))
389     			goto RecEnd;
390     	} else {
391     		if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
392     			goto RecEnd;
393     	}
394     
395     	if (isvfat && de->attr == ATTR_EXT) {
396     		struct msdos_dir_slot *ds;
397     		int offset;
398     		unsigned char id;
399     		unsigned char slot;
400     		unsigned char slots;
401     		unsigned char sum;
402     		unsigned char alias_checksum;
403     
404     		if (!unicode) {
405     			unicode = (unsigned char *)
406     				__get_free_page(GFP_KERNEL);
407     			if (!unicode) {
408     				filp->f_pos = cpos;
409     				fat_brelse(sb, bh);
410     				return -ENOMEM;
411     			}
412     		}
413     ParseLong:
414     		slots = 0;
415     		offset = 0;
416     		ds = (struct msdos_dir_slot *) de;
417     		id = ds->id;
418     		if (!(id & 0x40))
419     			goto RecEnd;
420     		slots = id & ~0x40;
421     		if (slots > 20 || !slots)	/* ceil(256 * 2 / 26) */
422     			goto RecEnd;
423     		long_slots = slots;
424     		alias_checksum = ds->alias_checksum;
425     
426     		slot = slots;
427     		while (1) {
428     			slot--;
429     			offset = slot * 26;
430     			memcpy(&unicode[offset], ds->name0_4, 10);
431     			memcpy(&unicode[offset+10], ds->name5_10, 12);
432     			memcpy(&unicode[offset+22], ds->name11_12, 4);
433     			offset += 26;
434     
435     			if (ds->id & 0x40) {
436     				unicode[offset] = 0;
437     				unicode[offset+1] = 0;
438     			}
439     			if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
440     				goto EODir;
441     			if (slot == 0)
442     				break;
443     			ds = (struct msdos_dir_slot *) de;
444     			if (ds->attr !=  ATTR_EXT)
445     				goto RecEnd;	/* XXX */
446     			if ((ds->id & ~0x40) != slot)
447     				goto ParseLong;
448     			if (ds->alias_checksum != alias_checksum)
449     				goto ParseLong;
450     		}
451     		if (de->name[0] == (__s8) DELETED_FLAG)
452     			goto RecEnd;
453     		if (de->attr ==  ATTR_EXT)
454     			goto ParseLong;
455     		if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
456     			goto RecEnd;
457     		for (sum = 0, i = 0; i < 11; i++)
458     			sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
459     		if (sum != alias_checksum)
460     			long_slots = 0;
461     	}
462     
463     	if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
464     		*ptname++ = '.';
465     		dotoffset = 1;
466     	}
467     
468     	for (i = 0; i < 8; i++) {
469     		/* see namei.c, msdos_format_name */
470     		if (de->name[i] == 0x05)
471     			work[i] = 0xE5;
472     		else
473     			work[i] = de->name[i];
474     	}
475     	for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
476     		if (!(c = work[i])) break;
477     		if (nocase)
478     			chl = fat_short2uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
479     		else
480     			chl = fat_short2lower_uni(nls_disk, &work[i], 8 - i, &bufuname[j++]);
481     		if (chl <= 1) {
482     			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
483     			if (c != ' ') {
484     				last = i;
485     				last_u = j;
486     			}
487     		} else {
488     			last_u = j;
489     			for (chi = 0; chi < chl && i < 8; chi++) {
490     				ptname[i] = work[i];
491     				i++; last = i;
492     			}
493     		}
494     	}
495     	i = last;
496     	j = last_u;
497     	fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
498     	ptname[i++] = '.';
499     	for (i2 = 0; i2 < 3;) {
500     		if (!(c = de->ext[i2])) break;
501     		if (nocase)
502     			chl = fat_short2uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
503     		else
504     			chl = fat_short2lower_uni(nls_disk, &de->ext[i2], 3 - i2, &bufuname[j++]);
505     		if (chl <= 1) {
506     			i2++;
507     			ptname[i++] = (!nocase && c>='A' && c<='Z') ? c+32 : c;
508     			if (c != ' ') {
509     				last = i;
510     				last_u = j;
511     			}
512     		} else {
513     			last_u = j;
514     			for (chi = 0; chi < chl && i2 < 3; chi++) {
515     				ptname[i++] = de->ext[i2++];
516     				last = i;
517     			}
518     		}
519     	}
520     	if (!last)
521     		goto RecEnd;
522     
523     	i = last + dotoffset;
524     	j = last_u;
525     
526     	lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
527     	if (!memcmp(de->name,MSDOS_DOT,11))
528     		inum = inode->i_ino;
529     	else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
530     /*		inum = fat_parent_ino(inode,0); */
531     		inum = filp->f_dentry->d_parent->d_inode->i_ino;
532     	} else {
533     		struct inode *tmp = fat_iget(sb, ino);
534     		if (tmp) {
535     			inum = tmp->i_ino;
536     			iput(tmp);
537     		} else
538     			inum = iunique(sb, MSDOS_ROOT_INO);
539     	}
540     
541     	if (isvfat) {
542     		bufuname[j] = 0x0000;
543     		i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname))
544     			 : uni16_to_x8(bufname, bufuname, uni_xlate, nls_io);
545     	}
546     
547     	if (!long_slots||shortnames) {
548     		if (both)
549     			bufname[i] = '\0';
550     		if (filldir(dirent, bufname, i, *furrfu, inum,
551     			    (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
552     			goto FillFailed;
553     	} else {
554     		char longname[275];
555     		int long_len = utf8
556     			? utf8_wcstombs(longname, (wchar_t *) unicode, sizeof(longname))
557     			: uni16_to_x8(longname, (wchar_t *) unicode, uni_xlate,
558     				      nls_io);
559     		if (both) {
560     			memcpy(&longname[long_len+1], bufname, i);
561     			long_len += i;
562     		}
563     		if (filldir(dirent, longname, long_len, *furrfu, inum,
564     			    (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
565     			goto FillFailed;
566     	}
567     
568     RecEnd:
569     	furrfu = &lpos;
570     	filp->f_pos = cpos;
571     	goto GetNew;
572     EODir:
573     	filp->f_pos = cpos;
574     FillFailed:
575     	if (bh)
576     		fat_brelse(sb, bh);
577     	if (unicode) {
578     		free_page((unsigned long) unicode);
579     	}
580     	return 0;
581     }
582     
583     int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
584     {
585     	struct inode *inode = filp->f_dentry->d_inode;
586     	return fat_readdirx(inode, filp, dirent, filldir, 0, 0);
587     }
588     
589     static int vfat_ioctl_fill(
590     	void * buf,
591     	const char * name,
592     	int name_len,
593     	loff_t offset,
594     	ino_t ino,
595     	unsigned int d_type)
596     {
597     	struct dirent *d1 = (struct dirent *)buf;
598     	struct dirent *d2 = d1 + 1;
599     	int len, slen;
600     	int dotdir;
601     
602     	get_user(len, &d1->d_reclen);
603     	if (len != 0) {
604     		return -1;
605     	}
606     
607     	if ((name_len == 1 && name[0] == '.') ||
608     	    (name_len == 2 && name[0] == '.' && name[1] == '.')) {
609     		dotdir = 1;
610     		len = name_len;
611     	} else {
612     		dotdir = 0;
613     		len = strlen(name);
614     	}
615     	if (len != name_len) {
616     		copy_to_user(d2->d_name, name, len);
617     		put_user(0, d2->d_name + len);
618     		put_user(len, &d2->d_reclen);
619     		put_user(ino, &d2->d_ino);
620     		put_user(offset, &d2->d_off);
621     		slen = name_len - len;
622     		copy_to_user(d1->d_name, name+len+1, slen);
623     		put_user(0, d1->d_name+slen);
624     		put_user(slen, &d1->d_reclen);
625     	} else {
626     		put_user(0, d2->d_name);
627     		put_user(0, &d2->d_reclen);
628     		copy_to_user(d1->d_name, name, len);
629     		put_user(0, d1->d_name+len);
630     		put_user(len, &d1->d_reclen);
631     	}
632     	PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
633     		d1, d2, len, name_len));
634     
635     	return 0;
636     }
637     
638     int fat_dir_ioctl(struct inode * inode, struct file * filp,
639     		  unsigned int cmd, unsigned long arg)
640     {
641     	int err;
642     	/*
643     	 * We want to provide an interface for Samba to be able
644     	 * to get the short filename for a given long filename.
645     	 * Samba should use this ioctl instead of readdir() to
646     	 * get the information it needs.
647     	 */
648     	switch (cmd) {
649     	case VFAT_IOCTL_READDIR_BOTH: {
650     		struct dirent *d1 = (struct dirent *)arg;
651     		err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
652     		if (err)
653     			return err;
654     		put_user(0, &d1->d_reclen);
655     		return fat_readdirx(inode,filp,(void *)arg,
656     				    vfat_ioctl_fill, 0, 1);
657     	}
658     	case VFAT_IOCTL_READDIR_SHORT: {
659     		struct dirent *d1 = (struct dirent *)arg;
660     		put_user(0, &d1->d_reclen);
661     		err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
662     		if (err)
663     			return err;
664     		return fat_readdirx(inode,filp,(void *)arg,
665     				    vfat_ioctl_fill, 1, 1);
666     	}
667     	default:
668     		/* forward ioctl to CVF extension */
669     	       if (MSDOS_SB(inode->i_sb)->cvf_format &&
670     		   MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
671     		       return MSDOS_SB(inode->i_sb)->cvf_format
672     			       ->cvf_dir_ioctl(inode,filp,cmd,arg);
673     		return -EINVAL;
674     	}
675     
676     	return 0;
677     }
678     
679     /***** See if directory is empty */
680     int fat_dir_empty(struct inode *dir)
681     {
682     	loff_t pos;
683     	struct buffer_head *bh;
684     	struct msdos_dir_entry *de;
685     	int ino,result = 0;
686     
687     	pos = 0;
688     	bh = NULL;
689     	while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) {
690     		/* Ignore vfat longname entries */
691     		if (de->attr == ATTR_EXT)
692     			continue;
693     		if (!IS_FREE(de->name) && 
694     		    strncmp(de->name,MSDOS_DOT   , MSDOS_NAME) &&
695     		    strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
696     			result = -ENOTEMPTY;
697     			break;
698     		}
699     	}
700     	if (bh)
701     		fat_brelse(dir->i_sb, bh);
702     
703     	return result;
704     }
705     
706     /* This assumes that size of cluster is above the 32*slots */
707     
708     int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
709     		  struct msdos_dir_entry **de, int *ino)
710     {
711     	struct super_block *sb = dir->i_sb;
712     	loff_t offset, curr;
713     	int row;
714     	struct buffer_head *new_bh;
715     
716     	offset = curr = 0;
717     	*bh = NULL;
718     	row = 0;
719     	while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
720     		if (IS_FREE((*de)->name)) {
721     			if (++row == slots)
722     				return offset;
723     		} else {
724     			row = 0;
725     			offset = curr;
726     		}
727     	}
728     	if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32)) 
729     		return -ENOSPC;
730     	new_bh = fat_extend_dir(dir);
731     	if (!new_bh)
732     		return -ENOSPC;
733     	fat_brelse(sb, new_bh);
734     	do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
735     	return offset;
736     }
737     
738     int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
739     {
740     	struct super_block *sb = dir->i_sb;
741     	struct buffer_head *bh;
742     	struct msdos_dir_entry *de;
743     	__u16 date, time;
744     
745     	if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
746     	/* zeroed out, so... */
747     	fat_date_unix2dos(dir->i_mtime,&time,&date);
748     	de = (struct msdos_dir_entry*)&bh->b_data[0];
749     	memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
750     	memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
751     	de[0].attr = de[1].attr = ATTR_DIR;
752     	de[0].time = de[1].time = CT_LE_W(time);
753     	de[0].date = de[1].date = CT_LE_W(date);
754     	if (is_vfat) {	/* extra timestamps */
755     		de[0].ctime = de[1].ctime = CT_LE_W(time);
756     		de[0].adate = de[0].cdate =
757     			de[1].adate = de[1].cdate = CT_LE_W(date);
758     	}
759     	de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
760     	de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
761     	de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
762     	de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
763     	fat_mark_buffer_dirty(sb, bh);
764     	fat_brelse(sb, bh);
765     	dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
766     	mark_inode_dirty(dir);
767     
768     	return 0;
769     }
770     
771     /*
772      * Overrides for Emacs so that we follow Linus's tabbing style.
773      * Emacs will notice this stuff at the end of the file and automatically
774      * adjust the settings for this buffer only.  This must remain at the end
775      * of the file.
776      * ---------------------------------------------------------------------------
777      * Local variables:
778      * c-indent-level: 8
779      * c-brace-imaginary-offset: 0
780      * c-brace-offset: -8
781      * c-argdecl-indent: 8
782      * c-label-offset: -8
783      * c-continued-statement-offset: 8
784      * c-continued-brace-offset: 0
785      * End:
786      */
787