1/*
2 *  linux/fs/umsdos/emd.c
3 *
4 *  Written 1993 by Jacques Gelinas
5 *
6 *  Extended MS-DOS directory handling functions
7 */
8
9#include <linux/types.h>
10#include <linux/fcntl.h>
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/msdos_fs.h>
16#include <linux/umsdos_fs.h>
17#include <linux/dcache.h>
18#include <linux/pagemap.h>
19#include <linux/delay.h>
20
21void put_entry (struct umsdos_dirent *p, struct umsdos_dirent *q)
22{
23	p->name_len = q->name_len;
24	p->flags = q->flags;
25	p->nlink = cpu_to_le16(q->nlink);
26	p->uid = cpu_to_le16(q->uid);
27	p->gid = cpu_to_le16(q->gid);
28	p->atime = cpu_to_le32(q->atime);
29	p->mtime = cpu_to_le32(q->mtime);
30	p->ctime = cpu_to_le32(q->ctime);
31	p->rdev = cpu_to_le16(q->rdev);
32	p->mode = cpu_to_le16(q->mode);
33}
34
35static void get_entry(struct umsdos_dirent *p, struct umsdos_dirent *q)
36{
37	p->name_len = q->name_len;
38	p->name[p->name_len]='\0';
39	p->flags = q->flags;
40	p->nlink = le16_to_cpu (q->nlink);
41	p->uid = le16_to_cpu (q->uid);
42	p->gid = le16_to_cpu (q->gid);
43	p->atime = le32_to_cpu (q->atime);
44	p->mtime = le32_to_cpu (q->mtime);
45	p->ctime = le32_to_cpu (q->ctime);
46	p->rdev = le16_to_cpu (q->rdev);
47	p->mode = le16_to_cpu (q->mode);
48}
49
50/*
51 * Lookup the EMD dentry for a directory.
52 *
53 * Note: the caller must hold a lock on the parent directory.
54 */
55struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
56{
57	struct dentry *demd;
58
59	demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE,
60					UMSDOS_EMD_NAMELEN, 1);
61	return demd;
62}
63
64/*
65 * Check whether a directory has an EMD file.
66 *
67 * Note: the caller must hold a lock on the parent directory.
68 */
69int umsdos_have_emd(struct dentry *dir)
70{
71	struct dentry *demd = umsdos_get_emd_dentry (dir);
72	int found = 0;
73
74	if (!IS_ERR(demd)) {
75		if (demd->d_inode)
76			found = 1;
77		dput(demd);
78	}
79	return found;
80}
81
82/*
83 * Create the EMD file for a directory if it doesn't
84 * already exist. Returns 0 or an error code.
85 *
86 * Note: the caller must hold a lock on the parent directory.
87 */
88int umsdos_make_emd(struct dentry *parent)
89{
90	struct dentry *demd = umsdos_get_emd_dentry(parent);
91	int err = PTR_ERR(demd);
92
93	if (IS_ERR(demd)) {
94		printk("umsdos_make_emd: can't get dentry in %s, err=%d\n",
95			parent->d_name.name, err);
96		goto out;
97	}
98
99	/* already created? */
100	err = 0;
101	if (demd->d_inode)
102		goto out_set;
103
104Printk(("umsdos_make_emd: creating EMD %s/%s\n",
105parent->d_name.name, demd->d_name.name));
106
107	err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
108	if (err) {
109		printk (KERN_WARNING
110			"umsdos_make_emd: create %s/%s failed, err=%d\n",
111			parent->d_name.name, demd->d_name.name, err);
112	}
113out_set:
114	dput(demd);
115out:
116	return err;
117}
118
119
120/*
121 * Read an entry from the EMD file.
122 * Support variable length record.
123 * Return -EIO if error, 0 if OK.
124 *
125 * does not change {d,i}_count
126 */
127
128int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_dirent *entry)
129{
130	struct address_space *mapping = demd->d_inode->i_mapping;
131	struct page *page;
132	struct umsdos_dirent *p;
133	int offs = *pos & ~PAGE_CACHE_MASK;
134	int recsize;
135	int ret = 0;
136
137	page = read_cache_page(mapping, *pos>>PAGE_CACHE_SHIFT,
138			(filler_t*)mapping->a_ops->readpage, NULL);
139	if (IS_ERR(page))
140		goto sync_fail;
141	wait_on_page(page);
142	if (!Page_Uptodate(page))
143		goto async_fail;
144	p = (struct umsdos_dirent*)(kmap(page)+offs);
145
146	/* if this is an invalid entry (invalid name length), ignore it */
147	if( p->name_len > UMSDOS_MAXNAME )
148	{
149		printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len);
150		p->name_len = 0;
151		ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */
152	}
153
154	recsize = umsdos_evalrecsize(p->name_len);
155	if (offs + recsize > PAGE_CACHE_SIZE) {
156		struct page *page2;
157		int part = (char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare;
158		page2 = read_cache_page(mapping, 1+(*pos>>PAGE_CACHE_SHIFT),
159				(filler_t*)mapping->a_ops->readpage, NULL);
160		if (IS_ERR(page2)) {
161			kunmap(page);
162			page_cache_release(page);
163			page = page2;
164			goto sync_fail;
165		}
166		wait_on_page(page2);
167		if (!Page_Uptodate(page2)) {
168			kunmap(page);
169			page_cache_release(page2);
170			goto async_fail;
171		}
172		memcpy(entry->spare,p->spare,part);
173		memcpy(entry->spare+part,kmap(page2),
174				recsize+offs-PAGE_CACHE_SIZE);
175		kunmap(page2);
176		page_cache_release(page2);
177	} else
178		memcpy(entry->spare,p->spare,((char*)p+recsize)-p->spare);
179	get_entry(entry, p);
180	kunmap(page);
181	page_cache_release(page);
182	*pos += recsize;
183	return ret;
184async_fail:
185	page_cache_release(page);
186	page = ERR_PTR(-EIO);
187sync_fail:
188	return PTR_ERR(page);
189}
190
191
192/*
193 * Write an entry in the EMD file.
194 * Return 0 if OK, -EIO if some error.
195 *
196 * Note: the caller must hold a lock on the parent directory.
197 */
198int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
199				int free_entry)
200{
201	struct inode *dir = parent->d_inode;
202	struct umsdos_dirent *entry = &info->entry;
203	struct dentry *emd_dentry;
204	int ret;
205	struct umsdos_dirent entry0,*p;
206	struct address_space *mapping;
207	struct page *page, *page2 = NULL;
208	int offs;
209
210	emd_dentry = umsdos_get_emd_dentry(parent);
211	ret = PTR_ERR(emd_dentry);
212	if (IS_ERR(emd_dentry))
213		goto out;
214	/* make sure there's an EMD file */
215	ret = -EIO;
216	if (!emd_dentry->d_inode) {
217		printk(KERN_WARNING
218			"umsdos_writeentry: no EMD file in %s/%s\n",
219			parent->d_parent->d_name.name, parent->d_name.name);
220		goto out_dput;
221	}
222
223	if (free_entry) {
224		/* #Specification: EMD file / empty entries
225		 * Unused entries in the EMD file are identified
226		 * by the name_len field equal to 0. However to
227		 * help future extension (or bug correction :-( ),
228		 * empty entries are filled with 0.
229		 */
230		memset (&entry0, 0, sizeof (entry0));
231		entry = &entry0;
232	} else if (entry->name_len > 0) {
233		memset (entry->name + entry->name_len, '\0',
234			sizeof (entry->name) - entry->name_len);
235		/* #Specification: EMD file / spare bytes
236		 * 10 bytes are unused in each record of the EMD. They
237		 * are set to 0 all the time, so it will be possible
238		 * to do new stuff and rely on the state of those
239		 * bytes in old EMD files.
240		 */
241		memset (entry->spare, 0, sizeof (entry->spare));
242	}
243
244	/* write the entry and update the parent timestamps */
245	mapping = emd_dentry->d_inode->i_mapping;
246	offs = info->f_pos & ~PAGE_CACHE_MASK;
247	ret = -ENOMEM;
248	page = grab_cache_page(mapping, info->f_pos>>PAGE_CACHE_SHIFT);
249	if (!page)
250		goto out_dput;
251	p = (struct umsdos_dirent *) (page_address(page) + offs);
252	if (offs + info->recsize > PAGE_CACHE_SIZE) {
253		ret = mapping->a_ops->prepare_write(NULL,page,offs,
254					PAGE_CACHE_SIZE);
255		if (ret)
256			goto out_unlock;
257		page2 = grab_cache_page(mapping,
258					(info->f_pos>>PAGE_CACHE_SHIFT)+1);
259		if (!page2)
260			goto out_unlock2;
261		ret = mapping->a_ops->prepare_write(NULL,page2,0,
262					offs+info->recsize-PAGE_CACHE_SIZE);
263		if (ret)
264			goto out_unlock3;
265		put_entry (p, entry);
266		memcpy(p->spare,entry->spare,
267			(char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare);
268		memcpy(page_address(page2),
269				((char*)entry)+PAGE_CACHE_SIZE-offs,
270				offs+info->recsize-PAGE_CACHE_SIZE);
271		ret = mapping->a_ops->commit_write(NULL,page2,0,
272					offs+info->recsize-PAGE_CACHE_SIZE);
273		if (ret)
274			goto out_unlock3;
275		ret = mapping->a_ops->commit_write(NULL,page,offs,
276					PAGE_CACHE_SIZE);
277		UnlockPage(page2);
278		page_cache_release(page2);
279		if (ret)
280			goto out_unlock;
281	} else {
282		ret = mapping->a_ops->prepare_write(NULL,page,offs,
283					offs + info->recsize);
284		if (ret)
285			goto out_unlock;
286		put_entry (p, entry);
287		memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare);
288		ret = mapping->a_ops->commit_write(NULL,page,offs,
289					offs + info->recsize);
290		if (ret)
291			goto out_unlock;
292	}
293	UnlockPage(page);
294	page_cache_release(page);
295
296	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
297	mark_inode_dirty(dir);
298
299out_dput:
300	dput(emd_dentry);
301out:
302	Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));
303	return ret;
304out_unlock3:
305	UnlockPage(page2);
306	page_cache_release(page2);
307out_unlock2:
308	ClearPageUptodate(page);
309	kunmap(page);
310out_unlock:
311	UnlockPage(page);
312	page_cache_release(page);
313	printk ("UMSDOS:  problem with EMD file:  can't write\n");
314	goto out_dput;
315}
316
317/*
318 * General search, locate a name in the EMD file or an empty slot to
319 * store it. if info->entry.name_len == 0, search the first empty
320 * slot (of the proper size).
321 *
322 * Return 0 if found, -ENOENT if not found, another error code if
323 * other problem.
324 *
325 * So this routine is used to either find an existing entry or to
326 * create a new one, while making sure it is a new one. After you
327 * get -ENOENT, you make sure the entry is stuffed correctly and
328 * call umsdos_writeentry().
329 *
330 * To delete an entry, you find it, zero out the entry (memset)
331 * and call umsdos_writeentry().
332 *
333 * All this to say that umsdos_writeentry must be called after this
334 * function since it relies on the f_pos field of info.
335 *
336 * Note: the caller must hold a lock on the parent directory.
337 */
338/* #Specification: EMD file structure
339 * The EMD file uses a fairly simple layout.  It is made of records
340 * (UMSDOS_REC_SIZE == 64).  When a name can't be written in a single
341 * record, multiple contiguous records are allocated.
342 */
343
344static int umsdos_find (struct dentry *demd, struct umsdos_info *info)
345{
346	struct umsdos_dirent *entry = &info->entry;
347	int recsize = info->recsize;
348	struct inode *emd_dir;
349	int ret = -ENOENT;
350	struct {
351		off_t posok;	/* Position available to store the entry */
352		off_t one;	/* One empty position -> maybe <- large enough */
353	} empty;
354	int found = 0;
355	int empty_size = 0;
356	struct address_space *mapping;
357	filler_t *readpage;
358	struct page *page = NULL;
359	int index = -1;
360	int offs = PAGE_CACHE_SIZE,max_offs = PAGE_CACHE_SIZE;
361	char *p = NULL;
362	loff_t pos = 0;
363
364	/* make sure there's an EMD file ... */
365	ret = -ENOENT;
366	emd_dir = demd->d_inode;
367	if (!emd_dir)
368		goto out_dput;
369	mapping = emd_dir->i_mapping;
370	readpage = (filler_t*)mapping->a_ops->readpage;
371
372	empty.posok = emd_dir->i_size;
373	while (1) {
374		struct umsdos_dirent *rentry;
375		int entry_size;
376
377		if (offs >= max_offs) {
378			if (page) {
379				kunmap(page);
380				page_cache_release(page);
381				page = NULL;
382			}
383			if (pos >= emd_dir->i_size) {
384				info->f_pos = empty.posok;
385				break;
386			}
387			if (++index == (emd_dir->i_size>>PAGE_CACHE_SHIFT))
388				max_offs = emd_dir->i_size & ~PAGE_CACHE_MASK;
389			offs -= PAGE_CACHE_SIZE;
390			page = read_cache_page(mapping,index,readpage,NULL);
391			if (IS_ERR(page))
392				goto sync_fail;
393			wait_on_page(page);
394			if (!Page_Uptodate(page))
395				goto async_fail;
396			p = kmap(page);
397		}
398
399		rentry = (struct umsdos_dirent *)(p+offs);
400
401		if (rentry->name_len == 0) {
402			/* We are looking for an empty section at least */
403			/* as large as recsize. */
404			if (entry->name_len == 0) {
405				info->f_pos = pos;
406				ret = 0;
407				break;
408			}
409			offs += UMSDOS_REC_SIZE;
410			pos += UMSDOS_REC_SIZE;
411			if (found)
412				continue;
413			if (!empty_size)
414				empty.one = pos-UMSDOS_REC_SIZE;
415			empty_size += UMSDOS_REC_SIZE;
416			if (empty_size == recsize) {
417				/* Here is a large enough section. */
418				empty.posok = empty.one;
419				found = 1;
420			}
421			continue;
422		}
423
424		entry_size = umsdos_evalrecsize(rentry->name_len);
425		if (entry_size > PAGE_CACHE_SIZE)
426			goto async_fail;
427		empty_size = 0;
428		if (entry->name_len != rentry->name_len)
429			goto skip_it;
430
431		if (entry_size + offs > PAGE_CACHE_SIZE) {
432			/* Sucker spans the page boundary */
433			int len = (p+PAGE_CACHE_SIZE)-rentry->name;
434			struct page *next_page;
435			char *q;
436			next_page = read_cache_page(mapping,index+1,readpage,NULL);
437			if (IS_ERR(next_page)) {
438				page_cache_release(page);
439				page = next_page;
440				goto sync_fail;
441			}
442			wait_on_page(next_page);
443			if (!Page_Uptodate(next_page)) {
444				page_cache_release(page);
445				page = next_page;
446				goto async_fail;
447			}
448			q = kmap(next_page);
449			if (memcmp(entry->name, rentry->name, len) ||
450			    memcmp(entry->name+len, q, entry->name_len-len)) {
451				kunmap(next_page);
452				page_cache_release(next_page);
453				goto skip_it;
454			}
455			kunmap(next_page);
456			page_cache_release(next_page);
457		} else if (memcmp (entry->name, rentry->name, entry->name_len))
458			goto skip_it;
459
460		info->f_pos = pos;
461		get_entry(entry, rentry);
462		ret = 0;
463		break;
464skip_it:
465		offs+=entry_size;
466		pos+=entry_size;
467	}
468	if (page) {
469		kunmap(page);
470		page_cache_release(page);
471	}
472	umsdos_manglename (info);
473
474out_dput:
475	dput(demd);
476	return ret;
477
478async_fail:
479	page_cache_release(page);
480	page = ERR_PTR(-EIO);
481sync_fail:
482	return PTR_ERR(page);
483}
484
485
486/*
487 * Add a new entry in the EMD file.
488 * Return 0 if OK or a negative error code.
489 * Return -EEXIST if the entry already exists.
490 *
491 * Complete the information missing in info.
492 *
493 * N.B. What if the EMD file doesn't exist?
494 */
495
496int umsdos_newentry (struct dentry *parent, struct umsdos_info *info)
497{
498	int err, ret = -EEXIST;
499	struct dentry *demd = umsdos_get_emd_dentry(parent);
500
501	ret = PTR_ERR(demd);
502	if (IS_ERR(demd))
503		goto out;
504	err = umsdos_find (demd, info);
505	if (err && err == -ENOENT) {
506		ret = umsdos_writeentry (parent, info, 0);
507		Printk (("umsdos_writeentry EMD ret = %d\n", ret));
508	}
509out:
510	return ret;
511}
512
513
514/*
515 * Create a new hidden link.
516 * Return 0 if OK, an error code if not.
517 */
518
519/* #Specification: hard link / hidden name
520 * When a hard link is created, the original file is renamed
521 * to a hidden name. The name is "..LINKNNN" where NNN is a
522 * number define from the entry offset in the EMD file.
523 */
524int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info)
525{
526	int ret;
527	struct dentry *demd = umsdos_get_emd_dentry(parent);
528	ret = PTR_ERR(demd);
529	if (IS_ERR(demd))
530		goto out;
531
532	umsdos_parse ("..LINK", 6, info);
533	info->entry.name_len = 0;
534	ret = umsdos_find (demd, info);
535	if (ret == -ENOENT || ret == 0) {
536		info->entry.name_len = sprintf (info->entry.name,
537						"..LINK%ld", info->f_pos);
538		ret = 0;
539	}
540out:
541	return ret;
542}
543
544
545/*
546 * Remove an entry from the EMD file.
547 * Return 0 if OK, a negative error code otherwise.
548 *
549 * Complete the information missing in info.
550 */
551
552int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir)
553{
554	int ret;
555	struct dentry *demd = umsdos_get_emd_dentry(parent);
556
557	ret = PTR_ERR(demd);
558	if (IS_ERR(demd))
559		goto out;
560	ret = umsdos_find (demd, info);
561	if (ret)
562		goto out;
563	if (info->entry.name_len == 0)
564		goto out;
565
566	if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) {
567		if (S_ISDIR (info->entry.mode)) {
568			ret = -EISDIR;
569		} else {
570			ret = -ENOTDIR;
571		}
572		goto out;
573	}
574	ret = umsdos_writeentry (parent, info, 1);
575
576out:
577	return ret;
578}
579
580
581/*
582 * Verify that an EMD directory is empty.
583 * Return:
584 * 0 if not empty,
585 * 1 if empty (except for EMD file),
586 * 2 if empty or no EMD file.
587 */
588
589int umsdos_isempty (struct dentry *dentry)
590{
591	struct dentry *demd;
592	int ret = 2;
593	loff_t pos = 0;
594
595	demd = umsdos_get_emd_dentry(dentry);
596	if (IS_ERR(demd))
597		goto out;
598	/* If the EMD file does not exist, it is certainly empty. :-) */
599	if (!demd->d_inode)
600		goto out_dput;
601
602	ret = 1;
603	while (pos < demd->d_inode->i_size) {
604		struct umsdos_dirent entry;
605
606		if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) {
607			ret = 0;
608			break;
609		}
610		if (entry.name_len != 0) {
611			ret = 0;
612			break;
613		}
614	}
615
616out_dput:
617	dput(demd);
618out:
619	return ret;
620}
621
622/*
623 * Locate an entry in a EMD directory.
624 * Return 0 if OK, error code if not, generally -ENOENT.
625 *
626 * expect argument:
627 * 	0: anything
628 * 	1: file
629 * 	2: directory
630 */
631
632int umsdos_findentry (struct dentry *parent, struct umsdos_info *info,
633			int expect)
634{
635	int ret;
636	struct dentry *demd = umsdos_get_emd_dentry(parent);
637
638	ret = PTR_ERR(demd);
639	if (IS_ERR(demd))
640		goto out;
641	ret = umsdos_find (demd, info);
642	if (ret)
643		goto out;
644
645	switch (expect) {
646	case 1:
647		if (S_ISDIR (info->entry.mode))
648			ret = -EISDIR;
649		break;
650	case 2:
651		if (!S_ISDIR (info->entry.mode))
652			ret = -ENOTDIR;
653	}
654
655out:
656	Printk (("umsdos_findentry: returning %d\n", ret));
657	return ret;
658}
659