ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / 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/time.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, NULL);
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_locked(page);
143         if (!PageUptodate(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_locked(page2);
169                 if (!PageUptodate(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                 unlock_page(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         unlock_page(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         unlock_page(page2);
308         page_cache_release(page2);
309 out_unlock2:
310         ClearPageUptodate(page);
311         kunmap(page);
312 out_unlock:
313         unlock_page(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_locked(page);
396                         if (!PageUptodate(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_locked(next_page);
445                         if (!PageUptodate(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 }