Annotation of prex/usr/server/fs/fatfs/fatfs_vnops.c, Revision 1.1.1.1
1.1 nbrk 1: /*
2: * Copyright (c) 2005-2008, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: #include <prex/prex.h>
31:
32: #include <sys/vnode.h>
33: #include <sys/file.h>
34: #include <sys/mount.h>
35: #include <sys/dirent.h>
36: #include <sys/buf.h>
37:
38: #include <ctype.h>
39: #include <unistd.h>
40: #include <errno.h>
41: #include <string.h>
42: #include <stdlib.h>
43: #include <fcntl.h>
44:
45: #include "fatfs.h"
46:
47: /*
48: * Time bits: 15-11 hours (0-23), 10-5 min, 4-0 sec /2
49: * Date bits: 15-9 year - 1980, 8-5 month, 4-0 day
50: */
51: #define TEMP_DATE 0x3021
52: #define TEMP_TIME 0
53:
54: #define fatfs_open ((vnop_open_t)vop_nullop)
55: #define fatfs_close ((vnop_close_t)vop_nullop)
56: static int fatfs_read (vnode_t, file_t, void *, size_t, size_t *);
57: static int fatfs_write (vnode_t, file_t, void *, size_t, size_t *);
58: #define fatfs_seek ((vnop_seek_t)vop_nullop)
59: #define fatfs_ioctl ((vnop_ioctl_t)vop_einval)
60: #define fatfs_fsync ((vnop_fsync_t)vop_nullop)
61: static int fatfs_readdir(vnode_t, file_t, struct dirent *);
62: static int fatfs_lookup (vnode_t, char *, vnode_t);
63: static int fatfs_create (vnode_t, char *, mode_t);
64: static int fatfs_remove (vnode_t, vnode_t, char *);
65: static int fatfs_rename (vnode_t, vnode_t, char *, vnode_t, vnode_t, char *);
66: static int fatfs_mkdir (vnode_t, char *, mode_t);
67: static int fatfs_rmdir (vnode_t, vnode_t, char *);
68: static int fatfs_getattr(vnode_t, struct vattr *);
69: static int fatfs_setattr(vnode_t, struct vattr *);
70: static int fatfs_inactive(vnode_t);
71: static int fatfs_truncate(vnode_t);
72:
73: /*
74: * vnode operations
75: */
76: struct vnops fatfs_vnops = {
77: fatfs_open, /* open */
78: fatfs_close, /* close */
79: fatfs_read, /* read */
80: fatfs_write, /* write */
81: fatfs_seek, /* seek */
82: fatfs_ioctl, /* ioctl */
83: fatfs_fsync, /* fsync */
84: fatfs_readdir, /* readdir */
85: fatfs_lookup, /* lookup */
86: fatfs_create, /* create */
87: fatfs_remove, /* remove */
88: fatfs_rename, /* remame */
89: fatfs_mkdir, /* mkdir */
90: fatfs_rmdir, /* rmdir */
91: fatfs_getattr, /* getattr */
92: fatfs_setattr, /* setattr */
93: fatfs_inactive, /* inactive */
94: fatfs_truncate, /* truncate */
95: };
96:
97: /*
98: * Read one cluster to buffer.
99: */
100: static int
101: fat_read_cluster(struct fatfsmount *fmp, u_long cluster)
102: {
103: u_long sec;
104: size_t size;
105:
106: sec = cl_to_sec(fmp, cluster);
107: size = fmp->sec_per_cl * SEC_SIZE;
108: return device_read(fmp->dev, fmp->io_buf, &size, sec);
109: }
110:
111: /*
112: * Write one cluster from buffer.
113: */
114: static int
115: fat_write_cluster(struct fatfsmount *fmp, u_long cluster)
116: {
117: u_long sec;
118: size_t size;
119:
120: sec = cl_to_sec(fmp, cluster);
121: size = fmp->sec_per_cl * SEC_SIZE;
122: return device_write(fmp->dev, fmp->io_buf, &size, sec);
123: }
124:
125: /*
126: * Lookup vnode for the specified file/directory.
127: * The vnode data will be set properly.
128: */
129: static int
130: fatfs_lookup(vnode_t dvp, char *name, vnode_t vp)
131: {
132: struct fatfsmount *fmp;
133: struct fat_dirent *de;
134: struct fatfs_node *np;
135: int err;
136:
137: if (*name == '\0')
138: return ENOENT;
139:
140: fmp = vp->v_mount->m_data;
141: mutex_lock(&fmp->lock);
142:
143: DPRINTF(("fatfs_lookup: name=%s\n", name));
144:
145: np = vp->v_data;
146: err = fatfs_lookup_node(dvp, name, np);
147: if (err) {
148: DPRINTF(("fatfs_lookup: failed!! name=%s\n", name));
149: mutex_unlock(&fmp->lock);
150: return err;
151: }
152: de = &np->dirent;
153: vp->v_type = IS_DIR(de) ? VDIR : VREG;
154: fat_attr_to_mode(de->attr, &vp->v_mode);
155: vp->v_mode = ALLPERMS;
156: vp->v_size = de->size;
157: vp->v_blkno = de->cluster;
158:
159: DPRINTF(("fatfs_lookup: cl=%d\n", de->cluster));
160: mutex_unlock(&fmp->lock);
161: return 0;
162: }
163:
164: static int
165: fatfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
166: {
167: struct fatfsmount *fmp;
168: int nr_read, nr_copy, buf_pos, err;
169: u_long cl, file_pos;
170:
171: DPRINTF(("fatfs_read: vp=%x\n", vp));
172:
173: *result = 0;
174: fmp = vp->v_mount->m_data;
175:
176: if (vp->v_type == VDIR)
177: return EISDIR;
178: if (vp->v_type != VREG)
179: return EINVAL;
180:
181: /* Check if current file position is already end of file. */
182: file_pos = fp->f_offset;
183: if (file_pos >= vp->v_size)
184: return 0;
185:
186: mutex_lock(&fmp->lock);
187:
188: /* Get the actual read size. */
189: if (vp->v_size - file_pos < size)
190: size = vp->v_size - file_pos;
191:
192: /* Seek to the cluster for the file offset */
193: err = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl);
194: if (err)
195: goto out;
196:
197: /* Read and copy data */
198: nr_read = 0;
199: buf_pos = file_pos % fmp->cluster_size;
200: do {
201: if (fat_read_cluster(fmp, cl)) {
202: err = EIO;
203: goto out;
204: }
205:
206: nr_copy = fmp->cluster_size;
207: if (buf_pos > 0)
208: nr_copy -= buf_pos;
209: if (buf_pos + size < fmp->cluster_size)
210: nr_copy = size;
211: memcpy(buf, fmp->io_buf + buf_pos, nr_copy);
212:
213: file_pos += nr_copy;
214: nr_read += nr_copy;
215: size -= nr_copy;
216: if (size <= 0)
217: break;
218:
219: err = fat_next_cluster(fmp, cl, &cl);
220: if (err)
221: goto out;
222:
223: buf = (void *)((u_long)buf + nr_copy);
224: buf_pos = 0;
225: } while (!IS_EOFCL(fmp, cl));
226:
227: fp->f_offset = file_pos;
228: *result = nr_read;
229: err = 0;
230: out:
231: mutex_unlock(&fmp->lock);
232: return err;
233: }
234:
235: static int
236: fatfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
237: {
238: struct fatfsmount *fmp;
239: struct fatfs_node *np;
240: struct fat_dirent *de;
241: int nr_copy, nr_write, buf_pos, i, cl_size, err;
242: u_long file_pos, end_pos;
243: u_long cl;
244:
245: DPRINTF(("fatfs_write: vp=%x\n", vp));
246:
247: *result = 0;
248: fmp = vp->v_mount->m_data;
249:
250: if (vp->v_type == VDIR)
251: return EISDIR;
252: if (vp->v_type != VREG)
253: return EINVAL;
254:
255: mutex_lock(&fmp->lock);
256:
257: /* Check if file position exceeds the end of file. */
258: end_pos = vp->v_size;
259: file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset;
260: if (file_pos + size > end_pos) {
261: /* Expand the file size before writing to it */
262: end_pos = file_pos + size;
263: err = fat_expand_file(fmp, vp->v_blkno, end_pos);
264: if (err) {
265: err = EIO;
266: goto out;
267: }
268:
269: /* Update directory entry */
270: np = vp->v_data;
271: de = &np->dirent;
272: de->size = end_pos;
273: err = fatfs_put_node(fmp, np);
274: if (err)
275: goto out;
276: vp->v_size = end_pos;
277: }
278:
279: /* Seek to the cluster for the file offset */
280: err = fat_seek_cluster(fmp, vp->v_blkno, file_pos, &cl);
281: if (err)
282: goto out;
283:
284: buf_pos = file_pos % fmp->cluster_size;
285: cl_size = size / fmp->cluster_size + 1;
286: nr_write = 0;
287: i = 0;
288: do {
289: /* First and last cluster must be read before write */
290: if (i == 0 || i == cl_size) {
291: if (fat_read_cluster(fmp, cl)) {
292: err = EIO;
293: goto out;
294: }
295: }
296: nr_copy = fmp->cluster_size;
297: if (buf_pos > 0)
298: nr_copy -= buf_pos;
299: if (buf_pos + size < fmp->cluster_size)
300: nr_copy = size;
301: memcpy(fmp->io_buf + buf_pos, buf, nr_copy);
302:
303: if (fat_write_cluster(fmp, cl)) {
304: err = EIO;
305: goto out;
306: }
307: file_pos += nr_copy;
308: nr_write += nr_copy;
309: size -= nr_copy;
310: if (size <= 0)
311: break;
312:
313: err = fat_next_cluster(fmp, cl, &cl);
314: if (err)
315: goto out;
316:
317: buf = (void *)((u_long)buf + nr_copy);
318: buf_pos = 0;
319: i++;
320: } while (!IS_EOFCL(fmp, cl));
321:
322: fp->f_offset = file_pos;
323:
324: /*
325: * XXX: Todo!
326: * de.time = ?
327: * de.date = ?
328: * if (dirent_set(fp, &de))
329: * return EIO;
330: */
331: *result = nr_write;
332: err = 0;
333: out:
334: mutex_unlock(&fmp->lock);
335: return err;
336: }
337:
338: static int
339: fatfs_readdir(vnode_t vp, file_t fp, struct dirent *dir)
340: {
341: struct fatfsmount *fmp;
342: struct fatfs_node np;
343: struct fat_dirent *de;
344: int err;
345:
346: fmp = vp->v_mount->m_data;
347: mutex_lock(&fmp->lock);
348:
349: err = fatfs_get_node(vp, fp->f_offset, &np);
350: if (err)
351: goto out;
352: de = &np.dirent;
353: fat_restore_name((char *)&de->name, dir->d_name);
354:
355: if (de->attr & FA_SUBDIR)
356: dir->d_type = DT_DIR;
357: else if (de->attr & FA_DEVICE)
358: dir->d_type = DT_BLK;
359: else
360: dir->d_type = DT_REG;
361:
362: dir->d_fileno = fp->f_offset;
363: dir->d_namlen = strlen(dir->d_name);
364:
365: fp->f_offset++;
366: err = 0;
367: out:
368: mutex_unlock(&fmp->lock);
369: return err;
370: }
371:
372: /*
373: * Create empty file.
374: */
375: static int
376: fatfs_create(vnode_t dvp, char *name, mode_t mode)
377: {
378: struct fatfsmount *fmp;
379: struct fatfs_node np;
380: struct fat_dirent *de;
381: u_long cl;
382: int err;
383:
384: DPRINTF(("fatfs_create: %s\n", name));
385:
386: if (!S_ISREG(mode))
387: return EINVAL;
388:
389: if (!fat_valid_name(name))
390: return EINVAL;
391:
392: fmp = dvp->v_mount->m_data;
393: mutex_lock(&fmp->lock);
394:
395: /* Allocate free cluster for new file. */
396: err = fat_alloc_cluster(fmp, 0, &cl);
397: if (err)
398: goto out;
399:
400: de = &np.dirent;
401: memset(de, 0, sizeof(struct fat_dirent));
402: fat_convert_name(name, (char *)de->name);
403: de->cluster = cl;
404: de->time = TEMP_TIME;
405: de->date = TEMP_DATE;
406: fat_mode_to_attr(mode, &de->attr);
407: err = fatfs_add_node(dvp, &np);
408: if (err)
409: goto out;
410: err = fat_set_cluster(fmp, cl, fmp->fat_eof);
411: out:
412: mutex_unlock(&fmp->lock);
413: return err;
414: }
415:
416: static int
417: fatfs_remove(vnode_t dvp, vnode_t vp, char *name)
418: {
419: struct fatfsmount *fmp;
420: struct fatfs_node np;
421: struct fat_dirent *de;
422: int err;
423:
424: if (*name == '\0')
425: return ENOENT;
426:
427: fmp = dvp->v_mount->m_data;
428: mutex_lock(&fmp->lock);
429:
430: err = fatfs_lookup_node(dvp, name, &np);
431: if (err)
432: goto out;
433: de = &np.dirent;
434: if (IS_DIR(de)) {
435: err = EISDIR;
436: goto out;
437: }
438: if (!IS_FILE(de)) {
439: err = EPERM;
440: goto out;
441: }
442:
443: /* Remove clusters */
444: err = fat_free_clusters(fmp, de->cluster);
445: if (err)
446: goto out;
447:
448: /* remove directory */
449: de->name[0] = 0xe5;
450: err = fatfs_put_node(fmp, &np);
451: out:
452: mutex_unlock(&fmp->lock);
453: return err;
454: }
455:
456: static int
457: fatfs_rename(vnode_t dvp1, vnode_t vp1, char *name1,
458: vnode_t dvp2, vnode_t vp2, char *name2)
459: {
460: struct fatfsmount *fmp;
461: struct fatfs_node np1;
462: struct fat_dirent *de1, *de2;
463: int err;
464:
465: fmp = dvp1->v_mount->m_data;
466: mutex_lock(&fmp->lock);
467:
468: err = fatfs_lookup_node(dvp1, name1, &np1);
469: if (err)
470: goto out;
471: de1 = &np1.dirent;
472:
473: if (IS_FILE(de1)) {
474: /* Remove destination file, first */
475: err = fatfs_remove(dvp2, vp1, name2);
476: if (err == EIO)
477: goto out;
478:
479: /* Change file name of directory entry */
480: fat_convert_name(name2, (char *)de1->name);
481:
482: /* Same directory ? */
483: if (dvp1 == dvp2) {
484: /* Change the name of existing file */
485: err = fatfs_put_node(fmp, &np1);
486: if (err)
487: goto out;
488: } else {
489: /* Create new directory entry */
490: err = fatfs_add_node(dvp2, &np1);
491: if (err)
492: goto out;
493:
494: /* Remove souce file */
495: err = fatfs_remove(dvp1, vp2, name1);
496: if (err)
497: goto out;
498: }
499: } else {
500:
501: /* remove destination directory */
502: err = fatfs_rmdir(dvp2, NULL, name2);
503: if (err == EIO)
504: goto out;
505:
506: /* Change file name of directory entry */
507: fat_convert_name(name2, (char *)de1->name);
508:
509: /* Same directory ? */
510: if (dvp1 == dvp2) {
511: /* Change the name of existing directory */
512: err = fatfs_put_node(fmp, &np1);
513: if (err)
514: goto out;
515: } else {
516: /* Create new directory entry */
517: err = fatfs_add_node(dvp2, &np1);
518: if (err)
519: goto out;
520:
521: /* Update "." and ".." for renamed directory */
522: if (fat_read_cluster(fmp, de1->cluster)) {
523: err = EIO;
524: goto out;
525: }
526:
527: de2 = (struct fat_dirent *)fmp->io_buf;
528: de2->cluster = de1->cluster;
529: de2->time = TEMP_TIME;
530: de2->date = TEMP_DATE;
531: de2++;
532: de2->cluster = dvp2->v_blkno;
533: de2->time = TEMP_TIME;
534: de2->date = TEMP_DATE;
535:
536: if (fat_write_cluster(fmp, de1->cluster)) {
537: err = EIO;
538: goto out;
539: }
540:
541: /* Remove souce directory */
542: err = fatfs_rmdir(dvp1, NULL, name1);
543: if (err)
544: goto out;
545: }
546: }
547: out:
548: mutex_unlock(&fmp->lock);
549: return err;
550: }
551:
552: static int
553: fatfs_mkdir(vnode_t dvp, char *name, mode_t mode)
554: {
555: struct fatfsmount *fmp;
556: struct fatfs_node np;
557: struct fat_dirent *de;
558: u_long cl;
559: int err;
560:
561: if (!S_ISDIR(mode))
562: return EINVAL;
563:
564: if (!fat_valid_name(name))
565: return ENOTDIR;
566:
567: fmp = dvp->v_mount->m_data;
568: mutex_lock(&fmp->lock);
569:
570: /* Allocate free cluster for directory data */
571: err = fat_alloc_cluster(fmp, 0, &cl);
572: if (err)
573: goto out;
574:
575: memset(&np, 0, sizeof(struct fatfs_node));
576: de = &np.dirent;
577: fat_convert_name(name, (char *)&de->name);
578: de->cluster = cl;
579: de->time = TEMP_TIME;
580: de->date = TEMP_DATE;
581: fat_mode_to_attr(mode, &de->attr);
582: err = fatfs_add_node(dvp, &np);
583: if (err)
584: goto out;
585:
586: /* Initialize "." and ".." for new directory */
587: memset(fmp->io_buf, 0, fmp->cluster_size);
588:
589: de = (struct fat_dirent *)fmp->io_buf;
590: memcpy(de->name, ". ", 11);
591: de->attr = FA_SUBDIR;
592: de->cluster = cl;
593: de->time = TEMP_TIME;
594: de->date = TEMP_DATE;
595: de++;
596: memcpy(de->name, ".. ", 11);
597: de->attr = FA_SUBDIR;
598: de->cluster = dvp->v_blkno;
599: de->time = TEMP_TIME;
600: de->date = TEMP_DATE;
601:
602: if (fat_write_cluster(fmp, cl)) {
603: err = EIO;
604: goto out;
605: }
606: /* Add eof */
607: err = fat_set_cluster(fmp, cl, fmp->fat_eof);
608: out:
609: mutex_unlock(&fmp->lock);
610: return err;
611: }
612:
613: /*
614: * remove can be done only with empty directory
615: */
616: static int
617: fatfs_rmdir(vnode_t dvp, vnode_t vp, char *name)
618: {
619: struct fatfsmount *fmp;
620: struct fatfs_node np;
621: struct fat_dirent *de;
622: int err;
623:
624: if (*name == '\0')
625: return ENOENT;
626:
627: fmp = dvp->v_mount->m_data;
628: mutex_lock(&fmp->lock);
629:
630: err = fatfs_lookup_node(dvp, name, &np);
631: if (err)
632: goto out;
633:
634: de = &np.dirent;
635: if (!IS_DIR(de)) {
636: err = ENOTDIR;
637: goto out;
638: }
639:
640: /* Remove clusters */
641: err = fat_free_clusters(fmp, de->cluster);
642: if (err)
643: goto out;
644:
645: /* remove directory */
646: de->name[0] = 0xe5;
647:
648: err = fatfs_put_node(fmp, &np);
649: out:
650: mutex_unlock(&fmp->lock);
651: return err;
652: }
653:
654: static int
655: fatfs_getattr(vnode_t vp, struct vattr *vap)
656: {
657: /* XXX */
658: return 0;
659: }
660:
661: static int
662: fatfs_setattr(vnode_t vp, struct vattr *vap)
663: {
664: /* XXX */
665: return 0;
666: }
667:
668:
669: static int
670: fatfs_inactive(vnode_t vp)
671: {
672:
673: free(vp->v_data);
674: return 0;
675: }
676:
677: static int
678: fatfs_truncate(vnode_t vp)
679: {
680: struct fatfsmount *fmp;
681: struct fatfs_node *np;
682: struct fat_dirent *de;
683: int err;
684:
685: fmp = vp->v_mount->m_data;
686: mutex_lock(&fmp->lock);
687:
688: np = vp->v_data;
689: de = &np->dirent;
690:
691: /* Remove clusters */
692: err = fat_free_clusters(fmp, de->cluster);
693: if (err)
694: goto out;
695:
696: de->size = 0;
697:
698: err = fatfs_put_node(fmp, np);
699: if (err)
700: goto out;
701:
702: vp->v_size = 0;
703: out:
704: mutex_unlock(&fmp->lock);
705: return err;
706: }
707:
708: int
709: fatfs_init(void)
710: {
711: return 0;
712: }
CVSweb