Linux-2.4.0-test2
[davej-history.git] / fs / umsdos / emd.c
blobd9b00e8c96ee1b905721379a66b5a164815f0116
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>
19 #include <asm/uaccess.h>
21 #include <asm/delay.h>
25 * Read a file into kernel space memory
26 * returns how many bytes read (from fat_file_read)
29 ssize_t umsdos_file_read_kmem ( struct file *filp,
30 char *buf,
31 size_t count)
33 ssize_t ret;
34 mm_segment_t old_fs = get_fs ();
36 set_fs (KERNEL_DS);
37 ret = fat_file_read (filp, buf, count, &filp->f_pos);
38 set_fs (old_fs);
39 return ret;
44 * Write to file from kernel space.
45 * Does the real job, assumes all structures are initialized!
49 ssize_t umsdos_file_write_kmem_real (struct file * filp,
50 const char *buf,
51 size_t count)
53 mm_segment_t old_fs = get_fs ();
54 ssize_t ret;
56 set_fs (KERNEL_DS);
57 ret = fat_file_write (filp, buf, count, &filp->f_pos);
58 set_fs (old_fs);
59 if (ret < 0) {
60 printk(KERN_WARNING "umsdos_file_write: ret=%d\n", ret);
61 goto out;
63 #ifdef UMSDOS_PARANOIA
64 if (ret != count)
65 printk(KERN_WARNING "umsdos_file_write: count=%u, ret=%u\n", count, ret);
66 #endif
67 out:
68 return ret;
73 * Write to a file from kernel space.
76 ssize_t umsdos_file_write_kmem (struct file *filp,
77 const char *buf,
78 size_t count)
80 ssize_t ret;
82 ret = umsdos_file_write_kmem_real (filp, buf, count);
83 return ret;
89 * Write a block of bytes into one EMD file.
90 * The block of data is NOT in user space.
92 * Return 0 if OK, a negative error code if not.
94 * Note: buffer is in kernel memory, not in user space.
97 ssize_t umsdos_emd_dir_write ( struct file *filp,
98 char *buf,
99 size_t count)
101 int written;
103 #ifdef __BIG_ENDIAN
104 struct umsdos_dirent *d = (struct umsdos_dirent *) buf;
106 d->nlink = cpu_to_le16 (d->nlink);
107 d->uid = cpu_to_le16 (d->uid);
108 d->gid = cpu_to_le16 (d->gid);
109 d->atime = cpu_to_le32 (d->atime);
110 d->mtime = cpu_to_le32 (d->mtime);
111 d->ctime = cpu_to_le32 (d->ctime);
112 d->rdev = cpu_to_le16 (d->rdev);
113 d->mode = cpu_to_le16 (d->mode);
114 #endif
116 filp->f_flags = 0;
117 Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %d, %Ld\n",
118 filp, buf, count, filp->f_pos));
119 written = umsdos_file_write_kmem (filp, buf, count);
121 #ifdef __BIG_ENDIAN
122 d->nlink = le16_to_cpu (d->nlink);
123 d->uid = le16_to_cpu (d->uid);
124 d->gid = le16_to_cpu (d->gid);
125 d->atime = le32_to_cpu (d->atime);
126 d->mtime = le32_to_cpu (d->mtime);
127 d->ctime = le32_to_cpu (d->ctime);
128 d->rdev = le16_to_cpu (d->rdev);
129 d->mode = le16_to_cpu (d->mode);
130 #endif
132 #ifdef UMSDOS_PARANOIA
133 if (written != count)
134 printk(KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n",
135 written, count);
136 #endif
138 return (written != count) ? -EIO : 0;
144 * Read a block of bytes from one EMD file.
145 * The block of data is NOT in user space.
146 * Return 0 if OK, -EIO if any error.
148 /* buffer in kernel memory, not in user space */
150 ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count)
152 ssize_t sizeread, ret = 0;
154 #ifdef __BIG_ENDIAN
155 struct umsdos_dirent *d = (struct umsdos_dirent *) buf;
157 #endif
159 filp->f_flags = 0;
160 sizeread = umsdos_file_read_kmem (filp, buf, count);
161 if (sizeread != count) {
162 printk (KERN_WARNING
163 "UMSDOS: EMD problem, pos=%Ld, count=%d, read=%d\n",
164 filp->f_pos, count, sizeread);
165 ret = -EIO;
167 #ifdef __BIG_ENDIAN
168 d->nlink = le16_to_cpu (d->nlink);
169 d->uid = le16_to_cpu (d->uid);
170 d->gid = le16_to_cpu (d->gid);
171 d->atime = le32_to_cpu (d->atime);
172 d->mtime = le32_to_cpu (d->mtime);
173 d->ctime = le32_to_cpu (d->ctime);
174 d->rdev = le16_to_cpu (d->rdev);
175 d->mode = le16_to_cpu (d->mode);
176 #endif
177 return ret;
182 * Lookup the EMD dentry for a directory.
184 * Note: the caller must hold a lock on the parent directory.
186 struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
188 struct dentry *demd;
190 demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE,
191 UMSDOS_EMD_NAMELEN, 1);
192 return demd;
196 * Check whether a directory has an EMD file.
198 * Note: the caller must hold a lock on the parent directory.
200 int umsdos_have_emd(struct dentry *dir)
202 struct dentry *demd = umsdos_get_emd_dentry (dir);
203 int found = 0;
205 if (!IS_ERR(demd)) {
206 if (demd->d_inode)
207 found = 1;
208 dput(demd);
210 return found;
214 * Create the EMD file for a directory if it doesn't
215 * already exist. Returns 0 or an error code.
217 * Note: the caller must hold a lock on the parent directory.
219 int umsdos_make_emd(struct dentry *parent)
221 struct dentry *demd = umsdos_get_emd_dentry(parent);
222 int err = PTR_ERR(demd);
224 if (IS_ERR(demd)) {
225 printk("umsdos_make_emd: can't get dentry in %s, err=%d\n",
226 parent->d_name.name, err);
227 goto out;
230 /* already created? */
231 err = 0;
232 if (demd->d_inode)
233 goto out_set;
235 Printk(("umsdos_make_emd: creating EMD %s/%s\n",
236 parent->d_name.name, demd->d_name.name));
238 err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
239 if (err) {
240 printk (KERN_WARNING
241 "umsdos_make_emd: create %s/%s failed, err=%d\n",
242 parent->d_name.name, demd->d_name.name, err);
244 out_set:
245 dput(demd);
246 out:
247 return err;
252 * Read an entry from the EMD file.
253 * Support variable length record.
254 * Return -EIO if error, 0 if OK.
256 * does not change {d,i}_count
259 int umsdos_emd_dir_readentry (struct file *filp, struct umsdos_dirent *entry)
261 int ret;
263 Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n"));
265 ret = umsdos_emd_dir_read (filp, (char *) entry, UMSDOS_REC_SIZE);
266 if (ret == 0) { /* if no error */
267 /* Variable size record. Maybe, we have to read some more */
268 int recsize = umsdos_evalrecsize (entry->name_len);
270 if (recsize > UMSDOS_REC_SIZE) {
271 Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: %d > %d!\n",
272 recsize, UMSDOS_REC_SIZE));
273 ret = umsdos_emd_dir_read (filp,
274 ((char *) entry) + UMSDOS_REC_SIZE,
275 recsize - UMSDOS_REC_SIZE);
278 Printk (("umsdos_emd_dir_readentry /mn/: ret=%d.\n", ret));
279 if (entry && ret == 0) {
280 Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n",
281 (int) entry->name_len, (int) entry->name_len, entry->name));
283 return ret;
289 * Write an entry in the EMD file.
290 * Return 0 if OK, -EIO if some error.
292 * Note: the caller must hold a lock on the parent directory.
294 static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
295 int free_entry)
297 struct inode *dir = parent->d_inode;
298 struct umsdos_dirent *entry = &info->entry;
299 struct dentry *emd_dentry;
300 int ret;
301 struct umsdos_dirent entry0;
302 struct file filp;
304 emd_dentry = umsdos_get_emd_dentry(parent);
305 ret = PTR_ERR(emd_dentry);
306 if (IS_ERR(emd_dentry))
307 goto out;
308 /* make sure there's an EMD file */
309 ret = -EIO;
310 if (!emd_dentry->d_inode) {
311 printk(KERN_WARNING
312 "umsdos_writeentry: no EMD file in %s/%s\n",
313 parent->d_parent->d_name.name, parent->d_name.name);
314 goto out_dput;
317 if (free_entry) {
318 /* #Specification: EMD file / empty entries
319 * Unused entries in the EMD file are identified
320 * by the name_len field equal to 0. However to
321 * help future extension (or bug correction :-( ),
322 * empty entries are filled with 0.
324 memset (&entry0, 0, sizeof (entry0));
325 entry = &entry0;
326 } else if (entry->name_len > 0) {
327 memset (entry->name + entry->name_len, '\0',
328 sizeof (entry->name) - entry->name_len);
329 /* #Specification: EMD file / spare bytes
330 * 10 bytes are unused in each record of the EMD. They
331 * are set to 0 all the time, so it will be possible
332 * to do new stuff and rely on the state of those
333 * bytes in old EMD files.
335 memset (entry->spare, 0, sizeof (entry->spare));
338 fill_new_filp (&filp, emd_dentry);
339 filp.f_pos = info->f_pos;
340 filp.f_reada = 0;
341 filp.f_flags = O_RDWR;
343 /* write the entry and update the parent timestamps */
344 ret = umsdos_emd_dir_write (&filp, (char *) entry, info->recsize);
345 if (!ret) {
346 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
347 mark_inode_dirty(dir);
348 } else
349 printk ("UMSDOS: problem with EMD file: can't write\n");
351 out_dput:
352 dput(emd_dentry);
353 out:
354 Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));
355 return ret;
360 #define CHUNK_SIZE (8*UMSDOS_REC_SIZE)
361 struct find_buffer {
362 char buffer[CHUNK_SIZE];
363 int pos; /* read offset in buffer */
364 int size; /* Current size of buffer */
365 struct file filp;
371 * Fill the read buffer and take care of the bytes remaining inside.
372 * Unread bytes are simply moved to the beginning.
374 * Return -ENOENT if EOF, 0 if OK, a negative error code if any problem.
376 * Note: the caller must hold a lock on the parent directory.
379 static int umsdos_fillbuf (struct find_buffer *buf)
381 struct inode *inode = buf->filp.f_dentry->d_inode;
382 int mustmove = buf->size - buf->pos;
383 int mustread, remain;
384 int ret = -ENOENT;
386 if (mustmove > 0) {
387 memcpy (buf->buffer, buf->buffer + buf->pos, mustmove);
389 buf->pos = 0;
390 mustread = CHUNK_SIZE - mustmove;
391 remain = inode->i_size - buf->filp.f_pos;
392 if (remain < mustread)
393 mustread = remain;
394 if (mustread > 0) {
395 ret = umsdos_emd_dir_read (&buf->filp, buf->buffer + mustmove,
396 mustread);
397 if (ret == 0)
398 buf->size = mustmove + mustread;
399 } else if (mustmove) {
400 buf->size = mustmove;
401 ret = 0;
403 return ret;
409 * General search, locate a name in the EMD file or an empty slot to
410 * store it. if info->entry.name_len == 0, search the first empty
411 * slot (of the proper size).
413 * Return 0 if found, -ENOENT if not found, another error code if
414 * other problem.
416 * So this routine is used to either find an existing entry or to
417 * create a new one, while making sure it is a new one. After you
418 * get -ENOENT, you make sure the entry is stuffed correctly and
419 * call umsdos_writeentry().
421 * To delete an entry, you find it, zero out the entry (memset)
422 * and call umsdos_writeentry().
424 * All this to say that umsdos_writeentry must be called after this
425 * function since it relies on the f_pos field of info.
427 * Note: the caller must hold a lock on the parent directory.
429 /* #Specification: EMD file structure
430 * The EMD file uses a fairly simple layout. It is made of records
431 * (UMSDOS_REC_SIZE == 64). When a name can't be written in a single
432 * record, multiple contiguous records are allocated.
435 static int umsdos_find (struct dentry *parent, struct umsdos_info *info)
437 struct umsdos_dirent *entry = &info->entry;
438 int recsize = info->recsize;
439 struct dentry *demd;
440 struct inode *emd_dir;
441 int ret = -ENOENT;
442 struct find_buffer buf;
443 struct {
444 off_t posok; /* Position available to store the entry */
445 int found; /* A valid empty position has been found. */
446 off_t one; /* One empty position -> maybe <- large enough */
447 int onesize; /* size of empty region starting at one */
448 } empty;
450 Printk (("umsdos_find: locating %s in %s/%s\n",
451 entry->name, parent->d_parent->d_name.name, parent->d_name.name));
454 * Lookup the EMD file in the parent directory.
456 demd = umsdos_get_emd_dentry(parent);
457 ret = PTR_ERR(demd);
458 if (IS_ERR(demd))
459 goto out;
460 /* make sure there's an EMD file ... */
461 ret = -ENOENT;
462 emd_dir = demd->d_inode;
463 if (!emd_dir)
464 goto out_dput;
466 Printk(("umsdos_find: found EMD file %s/%s, ino=%p\n",
467 demd->d_parent->d_name.name, demd->d_name.name, emd_dir));
469 fill_new_filp (&buf.filp, demd);
471 buf.pos = 0;
472 buf.size = 0;
474 empty.found = 0;
475 empty.posok = emd_dir->i_size;
476 empty.onesize = 0;
477 while (1) {
478 struct umsdos_dirent *rentry = (struct umsdos_dirent *)
479 (buf.buffer + buf.pos);
480 int file_pos = buf.filp.f_pos - buf.size + buf.pos;
482 if (buf.pos == buf.size) {
483 ret = umsdos_fillbuf (&buf);
484 if (ret < 0) {
485 /* Not found, so note where it can be added */
486 info->f_pos = empty.posok;
487 break;
489 } else if (rentry->name_len == 0) {
490 /* We are looking for an empty section at least */
491 /* as large as recsize. */
492 if (entry->name_len == 0) {
493 info->f_pos = file_pos;
494 ret = 0;
495 break;
496 } else if (!empty.found) {
497 if (empty.onesize == 0) {
498 /* This is the first empty record of a section. */
499 empty.one = file_pos;
501 /* grow the empty section */
502 empty.onesize += UMSDOS_REC_SIZE;
503 if (empty.onesize == recsize) {
504 /* Here is a large enough section. */
505 empty.posok = empty.one;
506 empty.found = 1;
509 buf.pos += UMSDOS_REC_SIZE;
510 } else {
511 int entry_size = umsdos_evalrecsize (rentry->name_len);
513 if (buf.pos + entry_size > buf.size) {
514 ret = umsdos_fillbuf (&buf);
515 if (ret < 0) {
516 /* Not found, so note where it can be added */
517 info->f_pos = empty.posok;
518 break;
520 } else {
521 empty.onesize = 0; /* Reset the free slot search. */
522 if (entry->name_len == rentry->name_len
523 && memcmp (entry->name, rentry->name, rentry->name_len) == 0) {
524 info->f_pos = file_pos;
525 *entry = *rentry;
526 ret = 0;
527 break;
528 } else {
529 buf.pos += entry_size;
534 Printk(("umsdos_find: ready to mangle %s, len=%d, pos=%ld\n",
535 entry->name, entry->name_len, (long)info->f_pos));
536 umsdos_manglename (info);
538 out_dput:
539 dput(demd);
541 out:
542 Printk (("umsdos_find: returning %d\n", ret));
543 return ret;
548 * Add a new entry in the EMD file.
549 * Return 0 if OK or a negative error code.
550 * Return -EEXIST if the entry already exists.
552 * Complete the information missing in info.
554 * N.B. What if the EMD file doesn't exist?
557 int umsdos_newentry (struct dentry *parent, struct umsdos_info *info)
559 int err, ret = -EEXIST;
561 err = umsdos_find (parent, info);
562 if (err && err == -ENOENT) {
563 ret = umsdos_writeentry (parent, info, 0);
564 Printk (("umsdos_writeentry EMD ret = %d\n", ret));
566 return ret;
571 * Create a new hidden link.
572 * Return 0 if OK, an error code if not.
575 /* #Specification: hard link / hidden name
576 * When a hard link is created, the original file is renamed
577 * to a hidden name. The name is "..LINKNNN" where NNN is a
578 * number define from the entry offset in the EMD file.
580 int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info)
582 int ret;
584 umsdos_parse ("..LINK", 6, info);
585 info->entry.name_len = 0;
586 ret = umsdos_find (parent, info);
587 if (ret == -ENOENT || ret == 0) {
588 info->entry.name_len = sprintf (info->entry.name,
589 "..LINK%ld", info->f_pos);
590 ret = 0;
592 return ret;
597 * Remove an entry from the EMD file.
598 * Return 0 if OK, a negative error code otherwise.
600 * Complete the information missing in info.
603 int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir)
605 int ret;
607 ret = umsdos_find (parent, info);
608 if (ret)
609 goto out;
610 if (info->entry.name_len == 0)
611 goto out;
613 if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) {
614 if (S_ISDIR (info->entry.mode)) {
615 ret = -EISDIR;
616 } else {
617 ret = -ENOTDIR;
619 goto out;
621 ret = umsdos_writeentry (parent, info, 1);
623 out:
624 return ret;
629 * Verify that an EMD directory is empty.
630 * Return:
631 * 0 if not empty,
632 * 1 if empty (except for EMD file),
633 * 2 if empty or no EMD file.
636 int umsdos_isempty (struct dentry *dentry)
638 struct dentry *demd;
639 int ret = 2;
640 struct file filp;
642 demd = umsdos_get_emd_dentry(dentry);
643 if (IS_ERR(demd))
644 goto out;
645 /* If the EMD file does not exist, it is certainly empty. :-) */
646 if (!demd->d_inode)
647 goto out_dput;
649 fill_new_filp (&filp, demd);
650 filp.f_flags = O_RDONLY;
652 ret = 1;
653 while (filp.f_pos < demd->d_inode->i_size) {
654 struct umsdos_dirent entry;
656 if (umsdos_emd_dir_readentry (&filp, &entry) != 0) {
657 ret = 0;
658 break;
660 if (entry.name_len != 0) {
661 ret = 0;
662 break;
666 out_dput:
667 dput(demd);
668 out:
669 Printk(("umsdos_isempty: checked %s/%s, empty=%d\n",
670 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
672 return ret;
676 * Locate an entry in a EMD directory.
677 * Return 0 if OK, error code if not, generally -ENOENT.
679 * expect argument:
680 * 0: anything
681 * 1: file
682 * 2: directory
685 int umsdos_findentry (struct dentry *parent, struct umsdos_info *info,
686 int expect)
688 int ret;
690 ret = umsdos_find (parent, info);
691 if (ret)
692 goto out;
694 switch (expect) {
695 case 1:
696 if (S_ISDIR (info->entry.mode))
697 ret = -EISDIR;
698 break;
699 case 2:
700 if (!S_ISDIR (info->entry.mode))
701 ret = -ENOTDIR;
704 out:
705 Printk (("umsdos_findentry: returning %d\n", ret));
706 return ret;