MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / fs / umsdos / emd.c
blob7fadb55b7e44171e2247e5b1dec54d989b57e307
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/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>
21 void put_entry (struct umsdos_dirent *p, struct umsdos_dirent *q)
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);
35 static void get_entry(struct umsdos_dirent *p, struct umsdos_dirent *q)
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);
52 * Lookup the EMD dentry for a directory.
54 * Note: the caller must hold a lock on the parent directory.
56 struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
58 struct dentry *demd;
60 demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE,
61 UMSDOS_EMD_NAMELEN, 1);
62 return demd;
66 * Check whether a directory has an EMD file.
68 * Note: the caller must hold a lock on the parent directory.
70 int umsdos_have_emd(struct dentry *dir)
72 struct dentry *demd = umsdos_get_emd_dentry (dir);
73 int found = 0;
75 if (!IS_ERR(demd)) {
76 if (demd->d_inode)
77 found = 1;
78 dput(demd);
80 return found;
84 * Create the EMD file for a directory if it doesn't
85 * already exist. Returns 0 or an error code.
87 * Note: the caller must hold a lock on the parent directory.
89 int umsdos_make_emd(struct dentry *parent)
91 struct dentry *demd = umsdos_get_emd_dentry(parent);
92 int err = PTR_ERR(demd);
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;
100 /* already created? */
101 err = 0;
102 if (demd->d_inode)
103 goto out_set;
105 Printk(("umsdos_make_emd: creating EMD %s/%s\n",
106 parent->d_name.name, demd->d_name.name));
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);
114 out_set:
115 dput(demd);
116 out:
117 return err;
122 * Read an entry from the EMD file.
123 * Support variable length record.
124 * Return -EIO if error, 0 if OK.
126 * does not change {d,i}_count
129 int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_dirent *entry)
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;
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);
147 /* if this is an invalid entry (invalid name length), ignore it */
148 if( p->name_len > UMSDOS_MAXNAME )
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' ?! */
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;
168 wait_on_page_locked(page2);
169 if (!PageUptodate(page2)) {
170 kunmap(page);
171 page_cache_release(page2);
172 goto async_fail;
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);
195 * Write an entry in the EMD file.
196 * Return 0 if OK, -EIO if some error.
198 * Note: the caller must hold a lock on the parent directory.
200 int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
201 int free_entry)
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;
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;
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.
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.
243 memset (entry->spare, 0, sizeof (entry->spare));
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;
295 unlock_page(page);
296 page_cache_release(page);
298 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
299 mark_inode_dirty(dir);
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;
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).
324 * Return 0 if found, -ENOENT if not found, another error code if
325 * other problem.
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().
332 * To delete an entry, you find it, zero out the entry (memset)
333 * and call umsdos_writeentry().
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.
338 * Note: the caller must hold a lock on the parent directory.
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.
346 static int umsdos_find (struct dentry *demd, struct umsdos_info *info)
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;
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;
374 empty.posok = emd_dir->i_size;
375 while (1) {
376 struct umsdos_dirent *rentry;
377 int entry_size;
379 if (offs >= max_offs) {
380 if (page) {
381 kunmap(page);
382 page_cache_release(page);
383 page = NULL;
385 if (pos >= emd_dir->i_size) {
386 info->f_pos = empty.posok;
387 break;
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);
401 rentry = (struct umsdos_dirent *)(p+offs);
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;
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;
423 continue;
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;
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;
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;
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;
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;
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;
470 if (page) {
471 kunmap(page);
472 page_cache_release(page);
474 umsdos_manglename (info);
476 out_dput:
477 dput(demd);
478 return ret;
480 async_fail:
481 page_cache_release(page);
482 page = ERR_PTR(-EIO);
483 sync_fail:
484 return PTR_ERR(page);
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.
493 * Complete the information missing in info.
495 * N.B. What if the EMD file doesn't exist?
498 int umsdos_newentry (struct dentry *parent, struct umsdos_info *info)
500 int err, ret = -EEXIST;
501 struct dentry *demd = umsdos_get_emd_dentry(parent);
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));
511 out:
512 return ret;
517 * Create a new hidden link.
518 * Return 0 if OK, an error code if not.
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.
526 int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info)
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;
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;
542 out:
543 return ret;
548 * Remove an entry from the EMD file.
549 * Return 0 if OK, a negative error code otherwise.
551 * Complete the information missing in info.
554 int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir)
556 int ret;
557 struct dentry *demd = umsdos_get_emd_dentry(parent);
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;
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;
574 goto out;
576 ret = umsdos_writeentry (parent, info, 1);
578 out:
579 return ret;
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.
591 int umsdos_isempty (struct dentry *dentry)
593 struct dentry *demd;
594 int ret = 2;
595 loff_t pos = 0;
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;
604 ret = 1;
605 while (pos < demd->d_inode->i_size) {
606 struct umsdos_dirent entry;
608 if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0) {
609 ret = 0;
610 break;
612 if (entry.name_len != 0) {
613 ret = 0;
614 break;
618 out_dput:
619 dput(demd);
620 out:
621 return ret;
625 * Locate an entry in a EMD directory.
626 * Return 0 if OK, error code if not, generally -ENOENT.
628 * expect argument:
629 * 0: anything
630 * 1: file
631 * 2: directory
634 int umsdos_findentry (struct dentry *parent, struct umsdos_info *info,
635 int expect)
637 int ret;
638 struct dentry *demd = umsdos_get_emd_dentry(parent);
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;
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;
657 out:
658 Printk (("umsdos_findentry: returning %d\n", ret));
659 return ret;