File: /usr/src/linux/fs/umsdos/emd.c

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