Linux 2.2.0
[davej-history.git] / fs / umsdos / emd.c
blob6a4e99c04f951f5ac4faa9a8b47cb6a21cbc6fbe
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 MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
38 ret = fat_file_read (filp, buf, count, &filp->f_pos);
39 set_fs (old_fs);
40 return ret;
45 * Write to file from kernel space.
46 * Does the real job, assumes all structures are initialized!
50 ssize_t umsdos_file_write_kmem_real (struct file * filp,
51 const char *buf,
52 size_t count)
54 mm_segment_t old_fs = get_fs ();
55 ssize_t ret;
57 /* note: i_binary=2 is for CVF-FAT. We put it here, instead of
58 * umsdos_file_write_kmem, since it is also wise not to compress
59 * symlinks (in the unlikely event that they are > 512 bytes and
60 * can be compressed.
61 * FIXME: should we set it when reading symlinks too?
64 MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
66 set_fs (KERNEL_DS);
67 ret = fat_file_write (filp, buf, count, &filp->f_pos);
68 set_fs (old_fs);
69 if (ret < 0) {
70 printk(KERN_WARNING "umsdos_file_write: ret=%d\n", ret);
71 goto out;
73 #ifdef UMSDOS_PARANOIA
74 if (ret != count)
75 printk(KERN_WARNING "umsdos_file_write: count=%u, ret=%u\n", count, ret);
76 #endif
77 out:
78 return ret;
83 * Write to a file from kernel space.
86 ssize_t umsdos_file_write_kmem (struct file *filp,
87 const char *buf,
88 size_t count)
90 ssize_t ret;
92 ret = umsdos_file_write_kmem_real (filp, buf, count);
93 return ret;
99 * Write a block of bytes into one EMD file.
100 * The block of data is NOT in user space.
102 * Return 0 if OK, a negative error code if not.
104 * Note: buffer is in kernel memory, not in user space.
107 ssize_t umsdos_emd_dir_write ( struct file *filp,
108 char *buf,
109 size_t count)
111 int written;
113 #ifdef __BIG_ENDIAN
114 struct umsdos_dirent *d = (struct umsdos_dirent *) buf;
116 d->nlink = cpu_to_le16 (d->nlink);
117 d->uid = cpu_to_le16 (d->uid);
118 d->gid = cpu_to_le16 (d->gid);
119 d->atime = cpu_to_le32 (d->atime);
120 d->mtime = cpu_to_le32 (d->mtime);
121 d->ctime = cpu_to_le32 (d->ctime);
122 d->rdev = cpu_to_le16 (d->rdev);
123 d->mode = cpu_to_le16 (d->mode);
124 #endif
126 filp->f_flags = 0;
127 Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %d, %Ld\n",
128 filp, buf, count, filp->f_pos));
129 written = umsdos_file_write_kmem (filp, buf, count);
131 #ifdef __BIG_ENDIAN
132 d->nlink = le16_to_cpu (d->nlink);
133 d->uid = le16_to_cpu (d->uid);
134 d->gid = le16_to_cpu (d->gid);
135 d->atime = le32_to_cpu (d->atime);
136 d->mtime = le32_to_cpu (d->mtime);
137 d->ctime = le32_to_cpu (d->ctime);
138 d->rdev = le16_to_cpu (d->rdev);
139 d->mode = le16_to_cpu (d->mode);
140 #endif
142 #ifdef UMSDOS_PARANOIA
143 if (written != count)
144 printk(KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n",
145 written, count);
146 #endif
148 return (written != count) ? -EIO : 0;
154 * Read a block of bytes from one EMD file.
155 * The block of data is NOT in user space.
156 * Return 0 if OK, -EIO if any error.
158 /* buffer in kernel memory, not in user space */
160 ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count)
162 ssize_t sizeread, ret = 0;
164 #ifdef __BIG_ENDIAN
165 struct umsdos_dirent *d = (struct umsdos_dirent *) buf;
167 #endif
169 filp->f_flags = 0;
170 sizeread = umsdos_file_read_kmem (filp, buf, count);
171 if (sizeread != count) {
172 printk (KERN_WARNING
173 "UMSDOS: EMD problem, pos=%Ld, count=%d, read=%d\n",
174 filp->f_pos, count, sizeread);
175 ret = -EIO;
177 #ifdef __BIG_ENDIAN
178 d->nlink = le16_to_cpu (d->nlink);
179 d->uid = le16_to_cpu (d->uid);
180 d->gid = le16_to_cpu (d->gid);
181 d->atime = le32_to_cpu (d->atime);
182 d->mtime = le32_to_cpu (d->mtime);
183 d->ctime = le32_to_cpu (d->ctime);
184 d->rdev = le16_to_cpu (d->rdev);
185 d->mode = le16_to_cpu (d->mode);
186 #endif
187 return ret;
192 * Lookup the EMD dentry for a directory.
194 * Note: the caller must hold a lock on the parent directory.
196 struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
198 struct dentry *demd;
200 demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE,
201 UMSDOS_EMD_NAMELEN, 1);
202 return demd;
206 * Check whether a directory has an EMD file.
208 * Note: the caller must hold a lock on the parent directory.
210 int umsdos_have_emd(struct dentry *dir)
212 struct dentry *demd = umsdos_get_emd_dentry (dir);
213 int found = 0;
215 if (!IS_ERR(demd)) {
216 if (demd->d_inode)
217 found = 1;
218 dput(demd);
220 return found;
224 * Create the EMD file for a directory if it doesn't
225 * already exist. Returns 0 or an error code.
227 * Note: the caller must hold a lock on the parent directory.
229 int umsdos_make_emd(struct dentry *parent)
231 struct dentry *demd = umsdos_get_emd_dentry(parent);
232 int err = PTR_ERR(demd);
234 if (IS_ERR(demd)) {
235 printk("umsdos_make_emd: can't get dentry in %s, err=%d\n",
236 parent->d_name.name, err);
237 goto out;
240 /* already created? */
241 err = 0;
242 if (demd->d_inode)
243 goto out_set;
245 Printk(("umsdos_make_emd: creating EMD %s/%s\n",
246 parent->d_name.name, demd->d_name.name));
248 err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
249 if (err) {
250 printk (KERN_WARNING
251 "umsdos_make_emd: create %s/%s failed, err=%d\n",
252 parent->d_name.name, demd->d_name.name, err);
253 goto out_dput;
255 out_set:
256 parent->d_inode->u.umsdos_i.i_emd_dir = demd->d_inode->i_ino;
258 out_dput:
259 dput(demd);
260 out:
261 return err;
266 * Read an entry from the EMD file.
267 * Support variable length record.
268 * Return -EIO if error, 0 if OK.
270 * does not change {d,i}_count
273 int umsdos_emd_dir_readentry (struct file *filp, struct umsdos_dirent *entry)
275 int ret;
277 Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: entering.\n"));
279 ret = umsdos_emd_dir_read (filp, (char *) entry, UMSDOS_REC_SIZE);
280 if (ret == 0) { /* if no error */
281 /* Variable size record. Maybe, we have to read some more */
282 int recsize = umsdos_evalrecsize (entry->name_len);
284 if (recsize > UMSDOS_REC_SIZE) {
285 Printk ((KERN_DEBUG "umsdos_emd_dir_readentry /mn/: %d > %d!\n",
286 recsize, UMSDOS_REC_SIZE));
287 ret = umsdos_emd_dir_read (filp,
288 ((char *) entry) + UMSDOS_REC_SIZE,
289 recsize - UMSDOS_REC_SIZE);
292 Printk (("umsdos_emd_dir_readentry /mn/: ret=%d.\n", ret));
293 if (entry && ret == 0) {
294 Printk (("umsdos_emd_dir_readentry /mn/: returning len=%d,name=%.*s\n",
295 (int) entry->name_len, (int) entry->name_len, entry->name));
297 return ret;
303 * Write an entry in the EMD file.
304 * Return 0 if OK, -EIO if some error.
306 * Note: the caller must hold a lock on the parent directory.
308 static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
309 int free_entry)
311 struct inode *dir = parent->d_inode;
312 struct umsdos_dirent *entry = &info->entry;
313 struct dentry *emd_dentry;
314 int ret;
315 struct umsdos_dirent entry0;
316 struct file filp;
318 emd_dentry = umsdos_get_emd_dentry(parent);
319 ret = PTR_ERR(emd_dentry);
320 if (IS_ERR(emd_dentry))
321 goto out;
322 /* make sure there's an EMD file */
323 ret = -EIO;
324 if (!emd_dentry->d_inode) {
325 printk(KERN_WARNING
326 "umsdos_writeentry: no EMD file in %s/%s\n",
327 parent->d_parent->d_name.name, parent->d_name.name);
328 goto out_dput;
331 if (free_entry) {
332 /* #Specification: EMD file / empty entries
333 * Unused entries in the EMD file are identified
334 * by the name_len field equal to 0. However to
335 * help future extension (or bug correction :-( ),
336 * empty entries are filled with 0.
338 memset (&entry0, 0, sizeof (entry0));
339 entry = &entry0;
340 } else if (entry->name_len > 0) {
341 memset (entry->name + entry->name_len, '\0',
342 sizeof (entry->name) - entry->name_len);
343 /* #Specification: EMD file / spare bytes
344 * 10 bytes are unused in each record of the EMD. They
345 * are set to 0 all the time, so it will be possible
346 * to do new stuff and rely on the state of those
347 * bytes in old EMD files.
349 memset (entry->spare, 0, sizeof (entry->spare));
352 fill_new_filp (&filp, emd_dentry);
353 filp.f_pos = info->f_pos;
354 filp.f_reada = 0;
355 filp.f_flags = O_RDWR;
357 /* write the entry and update the parent timestamps */
358 ret = umsdos_emd_dir_write (&filp, (char *) entry, info->recsize);
359 if (!ret) {
360 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
361 mark_inode_dirty(dir);
362 } else
363 printk ("UMSDOS: problem with EMD file: can't write\n");
365 out_dput:
366 dput(emd_dentry);
367 out:
368 Printk (("umsdos_writeentry /mn/: returning %d...\n", ret));
369 return ret;
374 #define CHUNK_SIZE (8*UMSDOS_REC_SIZE)
375 struct find_buffer {
376 char buffer[CHUNK_SIZE];
377 int pos; /* read offset in buffer */
378 int size; /* Current size of buffer */
379 struct file filp;
385 * Fill the read buffer and take care of the bytes remaining inside.
386 * Unread bytes are simply moved to the beginning.
388 * Return -ENOENT if EOF, 0 if OK, a negative error code if any problem.
390 * Note: the caller must hold a lock on the parent directory.
393 static int umsdos_fillbuf (struct find_buffer *buf)
395 struct inode *inode = buf->filp.f_dentry->d_inode;
396 int mustmove = buf->size - buf->pos;
397 int mustread, remain;
398 int ret = -ENOENT;
400 if (mustmove > 0) {
401 memcpy (buf->buffer, buf->buffer + buf->pos, mustmove);
403 buf->pos = 0;
404 mustread = CHUNK_SIZE - mustmove;
405 remain = inode->i_size - buf->filp.f_pos;
406 if (remain < mustread)
407 mustread = remain;
408 if (mustread > 0) {
409 ret = umsdos_emd_dir_read (&buf->filp, buf->buffer + mustmove,
410 mustread);
411 if (ret == 0)
412 buf->size = mustmove + mustread;
413 } else if (mustmove) {
414 buf->size = mustmove;
415 ret = 0;
417 return ret;
423 * General search, locate a name in the EMD file or an empty slot to
424 * store it. if info->entry.name_len == 0, search the first empty
425 * slot (of the proper size).
427 * Return 0 if found, -ENOENT if not found, another error code if
428 * other problem.
430 * So this routine is used to either find an existing entry or to
431 * create a new one, while making sure it is a new one. After you
432 * get -ENOENT, you make sure the entry is stuffed correctly and
433 * call umsdos_writeentry().
435 * To delete an entry, you find it, zero out the entry (memset)
436 * and call umsdos_writeentry().
438 * All this to say that umsdos_writeentry must be called after this
439 * function since it relies on the f_pos field of info.
441 * Note: the caller must hold a lock on the parent directory.
443 /* #Specification: EMD file structure
444 * The EMD file uses a fairly simple layout. It is made of records
445 * (UMSDOS_REC_SIZE == 64). When a name can't be written in a single
446 * record, multiple contiguous records are allocated.
449 static int umsdos_find (struct dentry *parent, struct umsdos_info *info)
451 struct umsdos_dirent *entry = &info->entry;
452 int recsize = info->recsize;
453 struct dentry *demd;
454 struct inode *emd_dir;
455 int ret = -ENOENT;
456 struct find_buffer buf;
457 struct {
458 off_t posok; /* Position available to store the entry */
459 int found; /* A valid empty position has been found. */
460 off_t one; /* One empty position -> maybe <- large enough */
461 int onesize; /* size of empty region starting at one */
462 } empty;
464 Printk (("umsdos_find: locating %s in %s/%s\n",
465 entry->name, parent->d_parent->d_name.name, parent->d_name.name));
468 * Lookup the EMD file in the parent directory.
470 demd = umsdos_get_emd_dentry(parent);
471 ret = PTR_ERR(demd);
472 if (IS_ERR(demd))
473 goto out;
474 /* make sure there's an EMD file ... */
475 ret = -ENOENT;
476 emd_dir = demd->d_inode;
477 if (!emd_dir)
478 goto out_dput;
480 Printk(("umsdos_find: found EMD file %s/%s, ino=%p\n",
481 demd->d_parent->d_name.name, demd->d_name.name, emd_dir));
483 fill_new_filp (&buf.filp, demd);
485 buf.pos = 0;
486 buf.size = 0;
488 empty.found = 0;
489 empty.posok = emd_dir->i_size;
490 empty.onesize = 0;
491 while (1) {
492 struct umsdos_dirent *rentry = (struct umsdos_dirent *)
493 (buf.buffer + buf.pos);
494 int file_pos = buf.filp.f_pos - buf.size + buf.pos;
496 if (buf.pos == buf.size) {
497 ret = umsdos_fillbuf (&buf);
498 if (ret < 0) {
499 /* Not found, so note where it can be added */
500 info->f_pos = empty.posok;
501 break;
503 } else if (rentry->name_len == 0) {
504 /* We are looking for an empty section at least */
505 /* as large as recsize. */
506 if (entry->name_len == 0) {
507 info->f_pos = file_pos;
508 ret = 0;
509 break;
510 } else if (!empty.found) {
511 if (empty.onesize == 0) {
512 /* This is the first empty record of a section. */
513 empty.one = file_pos;
515 /* grow the empty section */
516 empty.onesize += UMSDOS_REC_SIZE;
517 if (empty.onesize == recsize) {
518 /* Here is a large enough section. */
519 empty.posok = empty.one;
520 empty.found = 1;
523 buf.pos += UMSDOS_REC_SIZE;
524 } else {
525 int entry_size = umsdos_evalrecsize (rentry->name_len);
527 if (buf.pos + entry_size > buf.size) {
528 ret = umsdos_fillbuf (&buf);
529 if (ret < 0) {
530 /* Not found, so note where it can be added */
531 info->f_pos = empty.posok;
532 break;
534 } else {
535 empty.onesize = 0; /* Reset the free slot search. */
536 if (entry->name_len == rentry->name_len
537 && memcmp (entry->name, rentry->name, rentry->name_len) == 0) {
538 info->f_pos = file_pos;
539 *entry = *rentry;
540 ret = 0;
541 break;
542 } else {
543 buf.pos += entry_size;
548 Printk(("umsdos_find: ready to mangle %s, len=%d, pos=%ld\n",
549 entry->name, entry->name_len, (long)info->f_pos));
550 umsdos_manglename (info);
552 out_dput:
553 dput(demd);
555 out:
556 Printk (("umsdos_find: returning %d\n", ret));
557 return ret;
562 * Add a new entry in the EMD file.
563 * Return 0 if OK or a negative error code.
564 * Return -EEXIST if the entry already exists.
566 * Complete the information missing in info.
568 * N.B. What if the EMD file doesn't exist?
571 int umsdos_newentry (struct dentry *parent, struct umsdos_info *info)
573 int err, ret = -EEXIST;
575 err = umsdos_find (parent, info);
576 if (err && err == -ENOENT) {
577 ret = umsdos_writeentry (parent, info, 0);
578 Printk (("umsdos_writeentry EMD ret = %d\n", ret));
580 return ret;
585 * Create a new hidden link.
586 * Return 0 if OK, an error code if not.
589 /* #Specification: hard link / hidden name
590 * When a hard link is created, the original file is renamed
591 * to a hidden name. The name is "..LINKNNN" where NNN is a
592 * number define from the entry offset in the EMD file.
594 int umsdos_newhidden (struct dentry *parent, struct umsdos_info *info)
596 int ret;
598 umsdos_parse ("..LINK", 6, info);
599 info->entry.name_len = 0;
600 ret = umsdos_find (parent, info);
601 if (ret == -ENOENT || ret == 0) {
602 info->entry.name_len = sprintf (info->entry.name,
603 "..LINK%ld", info->f_pos);
604 ret = 0;
606 return ret;
611 * Remove an entry from the EMD file.
612 * Return 0 if OK, a negative error code otherwise.
614 * Complete the information missing in info.
617 int umsdos_delentry (struct dentry *parent, struct umsdos_info *info, int isdir)
619 int ret;
621 ret = umsdos_find (parent, info);
622 if (ret)
623 goto out;
624 if (info->entry.name_len == 0)
625 goto out;
627 if ((isdir != 0) != (S_ISDIR (info->entry.mode) != 0)) {
628 if (S_ISDIR (info->entry.mode)) {
629 ret = -EISDIR;
630 } else {
631 ret = -ENOTDIR;
633 goto out;
635 ret = umsdos_writeentry (parent, info, 1);
637 out:
638 return ret;
643 * Verify that an EMD directory is empty.
644 * Return:
645 * 0 if not empty,
646 * 1 if empty (except for EMD file),
647 * 2 if empty or no EMD file.
650 int umsdos_isempty (struct dentry *dentry)
652 struct dentry *demd;
653 int ret = 2;
654 struct file filp;
656 demd = umsdos_get_emd_dentry(dentry);
657 if (IS_ERR(demd))
658 goto out;
659 /* If the EMD file does not exist, it is certainly empty. :-) */
660 if (!demd->d_inode)
661 goto out_dput;
663 fill_new_filp (&filp, demd);
664 filp.f_flags = O_RDONLY;
666 ret = 1;
667 while (filp.f_pos < demd->d_inode->i_size) {
668 struct umsdos_dirent entry;
670 if (umsdos_emd_dir_readentry (&filp, &entry) != 0) {
671 ret = 0;
672 break;
674 if (entry.name_len != 0) {
675 ret = 0;
676 break;
680 out_dput:
681 dput(demd);
682 out:
683 Printk(("umsdos_isempty: checked %s/%s, empty=%d\n",
684 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
686 return ret;
690 * Locate an entry in a EMD directory.
691 * Return 0 if OK, error code if not, generally -ENOENT.
693 * expect argument:
694 * 0: anything
695 * 1: file
696 * 2: directory
699 int umsdos_findentry (struct dentry *parent, struct umsdos_info *info,
700 int expect)
702 int ret;
704 ret = umsdos_find (parent, info);
705 if (ret)
706 goto out;
708 switch (expect) {
709 case 1:
710 if (S_ISDIR (info->entry.mode))
711 ret = -EISDIR;
712 break;
713 case 2:
714 if (!S_ISDIR (info->entry.mode))
715 ret = -ENOTDIR;
718 out:
719 Printk (("umsdos_findentry: returning %d\n", ret));
720 return ret;