2 * linux/fs/umsdos/emd.c
4 * Written 1993 by Jacques Gelinas
6 * Extended MS-DOS directory handling functions
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
,
34 mm_segment_t old_fs
= get_fs ();
37 ret
= fat_file_read (filp
, buf
, count
, &filp
->f_pos
);
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
,
53 mm_segment_t old_fs
= get_fs ();
57 ret
= fat_file_write (filp
, buf
, count
, &filp
->f_pos
);
60 printk(KERN_WARNING
"umsdos_file_write: ret=%d\n", ret
);
63 #ifdef UMSDOS_PARANOIA
65 printk(KERN_WARNING
"umsdos_file_write: count=%u, ret=%u\n", count
, ret
);
73 * Write to a file from kernel space.
76 ssize_t
umsdos_file_write_kmem (struct file
*filp
,
82 ret
= umsdos_file_write_kmem_real (filp
, buf
, count
);
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
,
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
);
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
);
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
);
132 #ifdef UMSDOS_PARANOIA
133 if (written
!= count
)
134 printk(KERN_ERR
"umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n",
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;
155 struct umsdos_dirent
*d
= (struct umsdos_dirent
*) buf
;
160 sizeread
= umsdos_file_read_kmem (filp
, buf
, count
);
161 if (sizeread
!= count
) {
163 "UMSDOS: EMD problem, pos=%Ld, count=%d, read=%d\n",
164 filp
->f_pos
, count
, sizeread
);
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
);
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
)
190 demd
= umsdos_lookup_dentry(parent
, UMSDOS_EMD_FILE
,
191 UMSDOS_EMD_NAMELEN
, 1);
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
);
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
);
225 printk("umsdos_make_emd: can't get dentry in %s, err=%d\n",
226 parent
->d_name
.name
, err
);
230 /* already created? */
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);
241 "umsdos_make_emd: create %s/%s failed, err=%d\n",
242 parent
->d_name
.name
, demd
->d_name
.name
, 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
)
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
));
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
,
297 struct inode
*dir
= parent
->d_inode
;
298 struct umsdos_dirent
*entry
= &info
->entry
;
299 struct dentry
*emd_dentry
;
301 struct umsdos_dirent entry0
;
304 emd_dentry
= umsdos_get_emd_dentry(parent
);
305 ret
= PTR_ERR(emd_dentry
);
306 if (IS_ERR(emd_dentry
))
308 /* make sure there's an EMD file */
310 if (!emd_dentry
->d_inode
) {
312 "umsdos_writeentry: no EMD file in %s/%s\n",
313 parent
->d_parent
->d_name
.name
, parent
->d_name
.name
);
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
));
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
;
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
);
346 dir
->i_ctime
= dir
->i_mtime
= CURRENT_TIME
;
347 mark_inode_dirty(dir
);
349 printk ("UMSDOS: problem with EMD file: can't write\n");
354 Printk (("umsdos_writeentry /mn/: returning %d...\n", ret
));
360 #define CHUNK_SIZE (8*UMSDOS_REC_SIZE)
362 char buffer
[CHUNK_SIZE
];
363 int pos
; /* read offset in buffer */
364 int size
; /* Current size of buffer */
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
;
387 memcpy (buf
->buffer
, buf
->buffer
+ buf
->pos
, mustmove
);
390 mustread
= CHUNK_SIZE
- mustmove
;
391 remain
= inode
->i_size
- buf
->filp
.f_pos
;
392 if (remain
< mustread
)
395 ret
= umsdos_emd_dir_read (&buf
->filp
, buf
->buffer
+ mustmove
,
398 buf
->size
= mustmove
+ mustread
;
399 } else if (mustmove
) {
400 buf
->size
= mustmove
;
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
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
;
440 struct inode
*emd_dir
;
442 struct find_buffer buf
;
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 */
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
);
460 /* make sure there's an EMD file ... */
462 emd_dir
= demd
->d_inode
;
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
);
475 empty
.posok
= emd_dir
->i_size
;
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
);
485 /* Not found, so note where it can be added */
486 info
->f_pos
= empty
.posok
;
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
;
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
;
509 buf
.pos
+= UMSDOS_REC_SIZE
;
511 int entry_size
= umsdos_evalrecsize (rentry
->name_len
);
513 if (buf
.pos
+ entry_size
> buf
.size
) {
514 ret
= umsdos_fillbuf (&buf
);
516 /* Not found, so note where it can be added */
517 info
->f_pos
= empty
.posok
;
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
;
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
);
542 Printk (("umsdos_find: returning %d\n", 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
));
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
)
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
);
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
)
607 ret
= umsdos_find (parent
, info
);
610 if (info
->entry
.name_len
== 0)
613 if ((isdir
!= 0) != (S_ISDIR (info
->entry
.mode
) != 0)) {
614 if (S_ISDIR (info
->entry
.mode
)) {
621 ret
= umsdos_writeentry (parent
, info
, 1);
629 * Verify that an EMD directory is empty.
632 * 1 if empty (except for EMD file),
633 * 2 if empty or no EMD file.
636 int umsdos_isempty (struct dentry
*dentry
)
642 demd
= umsdos_get_emd_dentry(dentry
);
645 /* If the EMD file does not exist, it is certainly empty. :-) */
649 fill_new_filp (&filp
, demd
);
650 filp
.f_flags
= O_RDONLY
;
653 while (filp
.f_pos
< demd
->d_inode
->i_size
) {
654 struct umsdos_dirent entry
;
656 if (umsdos_emd_dir_readentry (&filp
, &entry
) != 0) {
660 if (entry
.name_len
!= 0) {
669 Printk(("umsdos_isempty: checked %s/%s, empty=%d\n",
670 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
));
676 * Locate an entry in a EMD directory.
677 * Return 0 if OK, error code if not, generally -ENOENT.
685 int umsdos_findentry (struct dentry
*parent
, struct umsdos_info
*info
,
690 ret
= umsdos_find (parent
, info
);
696 if (S_ISDIR (info
->entry
.mode
))
700 if (!S_ISDIR (info
->entry
.mode
))
705 Printk (("umsdos_findentry: returning %d\n", ret
));