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 
put_entry(struct umsdos_dirent * p,struct umsdos_dirent * q)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 
get_entry(struct umsdos_dirent * p,struct umsdos_dirent * q)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  */
umsdos_get_emd_dentry(struct dentry * parent)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  */
umsdos_have_emd(struct dentry * dir)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  */
umsdos_make_emd(struct dentry * parent)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 
umsdos_emd_dir_readentry(struct dentry * demd,loff_t * pos,struct umsdos_dirent * entry)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  */
umsdos_writeentry(struct dentry * parent,struct umsdos_info * info,int free_entry)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 
umsdos_find(struct dentry * demd,struct umsdos_info * info)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 
umsdos_newentry(struct dentry * parent,struct umsdos_info * info)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  */
umsdos_newhidden(struct dentry * parent,struct umsdos_info * info)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 
umsdos_delentry(struct dentry * parent,struct umsdos_info * info,int isdir)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 
umsdos_isempty(struct dentry * dentry)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 
umsdos_findentry(struct dentry * parent,struct umsdos_info * info,int expect)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