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