Annotation of prex/usr/server/fs/fatfs/fatfs_node.c, Revision 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: #include <sys/buf.h>
! 32:
! 33: #include <ctype.h>
! 34: #include <string.h>
! 35: #include <unistd.h>
! 36: #include <errno.h>
! 37: #include <stdlib.h>
! 38:
! 39: #include "fatfs.h"
! 40:
! 41: /*
! 42: * Read directory entry to buffer, with cache.
! 43: */
! 44: static int
! 45: fat_read_dirent(struct fatfsmount *fmp, u_long sec)
! 46: {
! 47: struct buf *bp;
! 48: int err;
! 49:
! 50: if ((err = bread(fmp->dev, sec, &bp)) != 0)
! 51: return err;
! 52: memcpy(fmp->dir_buf, bp->b_data, SEC_SIZE);
! 53: brelse(bp);
! 54: return 0;
! 55: }
! 56:
! 57: /*
! 58: * Write directory entry from buffer.
! 59: */
! 60: static int
! 61: fat_write_dirent(struct fatfsmount *fmp, u_long sec)
! 62: {
! 63: struct buf *bp;
! 64:
! 65: bp = getblk(fmp->dev, sec);
! 66: memcpy(bp->b_data, fmp->dir_buf, SEC_SIZE);
! 67: return bwrite(bp);
! 68: }
! 69:
! 70: /*
! 71: * Find directory entry in specified sector.
! 72: * The fat vnode data is filled if success.
! 73: *
! 74: * @fmp: fatfs mount point
! 75: * @sec: sector#
! 76: * @name: file name
! 77: * @node: pointer to fat node
! 78: */
! 79: static int
! 80: fat_lookup_dirent(struct fatfsmount *fmp, u_long sec, char *name,
! 81: struct fatfs_node *np)
! 82: {
! 83: struct fat_dirent *de;
! 84: int err, i;
! 85:
! 86: err = fat_read_dirent(fmp, sec);
! 87: if (err)
! 88: return err;
! 89:
! 90: de = (struct fat_dirent *)fmp->dir_buf;
! 91:
! 92: for (i = 0; i < DIR_PER_SEC; i++) {
! 93: /* Find specific file or directory name */
! 94: if (IS_EMPTY(de))
! 95: return ENOENT;
! 96: if (!IS_VOL(de) &&
! 97: !fat_compare_name((char *)de->name, name)) {
! 98: /* Found. Fill the fat vnode data. */
! 99: *(&np->dirent) = *de;
! 100: np->sector = sec;
! 101: np->offset = sizeof(struct fat_dirent) * i;
! 102: DPRINTF(("fat_lookup_dirent: found sec=%d\n", sec));
! 103: return 0;
! 104: }
! 105: if (!IS_DELETED(de))
! 106: DPRINTF(("fat_lookup_dirent: %s\n", de->name));
! 107: de++;
! 108: }
! 109: return EAGAIN;
! 110: }
! 111:
! 112: /*
! 113: * Find directory entry for specified name in directory.
! 114: * The fat vnode data is filled if success.
! 115: *
! 116: * @dvp: vnode for directory.
! 117: * @name: file name
! 118: * @np: pointer to fat node
! 119: */
! 120: int
! 121: fatfs_lookup_node(vnode_t dvp, char *name, struct fatfs_node *np)
! 122: {
! 123: struct fatfsmount *fmp;
! 124: char fat_name[12];
! 125: u_long cl, sec;
! 126: int i, err;
! 127:
! 128: if (name == NULL)
! 129: return ENOENT;
! 130:
! 131: DPRINTF(("fat_lookup_denode: cl=%d name=%s\n", dvp->v_blkno, name));
! 132:
! 133: fat_convert_name(name, fat_name);
! 134: *(fat_name + 11) = '\0';
! 135:
! 136: fmp = (struct fatfsmount *)dvp->v_mount->m_data;
! 137: cl = dvp->v_blkno;
! 138: if (cl == CL_ROOT) {
! 139: /* Search entry in root directory */
! 140: for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
! 141: err = fat_lookup_dirent(fmp, sec, fat_name, np);
! 142: if (err != EAGAIN)
! 143: return err;
! 144: }
! 145: } else {
! 146: /* Search entry in sub directory */
! 147: while (!IS_EOFCL(fmp, cl)) {
! 148: sec = cl_to_sec(fmp, cl);
! 149: for (i = 0; i < fmp->sec_per_cl; i++) {
! 150: err = fat_lookup_dirent(fmp, sec, fat_name,
! 151: np);
! 152: if (err != EAGAIN)
! 153: return err;
! 154: sec++;
! 155: }
! 156: err = fat_next_cluster(fmp, cl, &cl);
! 157: if (err)
! 158: return err;
! 159: }
! 160: }
! 161: return ENOENT;
! 162: }
! 163:
! 164: /*
! 165: * Get directory entry for specified index in sector.
! 166: * The directory entry is filled if success.
! 167: *
! 168: * @fmp: fatfs mount point
! 169: * @sec: sector#
! 170: * @target: target index
! 171: * @index: current index
! 172: * @np: pointer to fat node
! 173: */
! 174: static int
! 175: fat_get_dirent(struct fatfsmount *fmp, u_long sec, int target, int *index,
! 176: struct fatfs_node *np)
! 177: {
! 178: struct fat_dirent *de;
! 179: int err, i;
! 180:
! 181: err = fat_read_dirent(fmp, sec);
! 182: if (err)
! 183: return err;
! 184:
! 185: de = (struct fat_dirent *)fmp->dir_buf;
! 186: for (i = 0; i < DIR_PER_SEC; i++) {
! 187: if (IS_EMPTY(de))
! 188: return ENOENT;
! 189: if (!IS_DELETED(de) && !IS_VOL(de)) {
! 190: /* valid file */
! 191: if (*index == target) {
! 192: *(&np->dirent) = *de;
! 193: np->sector = sec;
! 194: np->offset = sizeof(struct fat_dirent) * i;
! 195: DPRINTF(("fat_get_dirent: found index=%d\n", *index));
! 196: return 0;
! 197: }
! 198: (*index)++;
! 199: }
! 200: DPRINTF(("fat_get_dirent: %s\n", de->name));
! 201: de++;
! 202: }
! 203: return EAGAIN;
! 204: }
! 205:
! 206: /*
! 207: * Get directory entry for specified index.
! 208: *
! 209: * @dvp: vnode for directory.
! 210: * @index: index of the entry
! 211: * @np: pointer to fat node
! 212: */
! 213: int
! 214: fatfs_get_node(vnode_t dvp, int index, struct fatfs_node *np)
! 215: {
! 216: struct fatfsmount *fmp;
! 217: u_long cl, sec;
! 218: int i, cur_index, err;
! 219:
! 220: fmp = (struct fatfsmount *)dvp->v_mount->m_data;
! 221: cl = dvp->v_blkno;
! 222: cur_index = 0;
! 223:
! 224: DPRINTF(("fatfs_get_node: index=%d\n", index));
! 225:
! 226: if (cl == CL_ROOT) {
! 227: /* Get entry from the root directory */
! 228: for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
! 229: err = fat_get_dirent(fmp, sec, index, &cur_index, np);
! 230: if (err != EAGAIN)
! 231: return err;
! 232: }
! 233: } else {
! 234: /* Get entry from the sub directory */
! 235: while (!IS_EOFCL(fmp, cl)) {
! 236: sec = cl_to_sec(fmp, cl);
! 237: for (i = 0; i < fmp->sec_per_cl; i++) {
! 238: err = fat_get_dirent(fmp, sec, index,
! 239: &cur_index, np);
! 240: if (err != EAGAIN)
! 241: return err;
! 242: sec++;
! 243: }
! 244: err = fat_next_cluster(fmp, cl, &cl);
! 245: if (err)
! 246: return err;
! 247: }
! 248: }
! 249: return ENOENT;
! 250: }
! 251:
! 252: /*
! 253: * Find empty directory entry and put new entry on it.
! 254: *
! 255: * @fmp: fatfs mount point
! 256: * @sec: sector#
! 257: * @np: pointer to fat node
! 258: */
! 259: static int
! 260: fat_add_dirent(struct fatfsmount *fmp, u_long sec, struct fatfs_node *np)
! 261: {
! 262: struct fat_dirent *de;
! 263: int err, i;
! 264:
! 265: err = fat_read_dirent(fmp, sec);
! 266: if (err)
! 267: return err;
! 268:
! 269: de = (struct fat_dirent *)fmp->dir_buf;
! 270: for (i = 0; i < DIR_PER_SEC; i++) {
! 271: if (IS_DELETED(de) || IS_EMPTY(de))
! 272: goto found;
! 273: DPRINTF(("fat_add_dirent: scan %s\n", de->name));
! 274: de++;
! 275: }
! 276: return ENOENT;
! 277:
! 278: found:
! 279: DPRINTF(("fat_add_dirent: found. sec=%d\n", sec));
! 280: memcpy(de, &np->dirent, sizeof(struct fat_dirent));
! 281: err = fat_write_dirent(fmp, sec);
! 282: return err;
! 283: }
! 284:
! 285: /*
! 286: * Find empty directory entry and put new entry on it.
! 287: * This search is done only in directory of specified cluster.
! 288: * @dvp: vnode for directory.
! 289: * @np: pointer to fat node
! 290: */
! 291: int
! 292: fatfs_add_node(vnode_t dvp, struct fatfs_node *np)
! 293: {
! 294: struct fatfsmount *fmp;
! 295: u_long cl, sec;
! 296: int i, err;
! 297: u_long next;
! 298:
! 299: fmp = (struct fatfsmount *)dvp->v_mount->m_data;
! 300: cl = dvp->v_blkno;
! 301:
! 302: DPRINTF(("fatfs_add_node: cl=%d\n", cl));
! 303:
! 304: if (cl == CL_ROOT) {
! 305: /* Add entry in root directory */
! 306: for (sec = fmp->root_start; sec < fmp->data_start; sec++) {
! 307: err = fat_add_dirent(fmp, sec, np);
! 308: if (err != ENOENT)
! 309: return err;
! 310: }
! 311: } else {
! 312: /* Search entry in sub directory */
! 313: while (!IS_EOFCL(fmp, cl)) {
! 314: sec = cl_to_sec(fmp, cl);
! 315: for (i = 0; i < fmp->sec_per_cl; i++) {
! 316: err = fat_add_dirent(fmp, sec, np);
! 317: if (err != ENOENT)
! 318: return err;
! 319: sec++;
! 320: }
! 321: err = fat_next_cluster(fmp, cl, &next);
! 322: if (err)
! 323: return err;
! 324: cl = next;
! 325: }
! 326: /* No entry found, add one more free cluster for directory */
! 327: DPRINTF(("fatfs_add_node: expand dir\n"));
! 328: err = fat_expand_dir(fmp, cl, &next);
! 329: if (err)
! 330: return err;
! 331:
! 332: /* Initialize free cluster. */
! 333: memset(fmp->dir_buf, 0, SEC_SIZE);
! 334: sec = cl_to_sec(fmp, next);
! 335: for (i = 0; i < fmp->sec_per_cl; i++) {
! 336: err = fat_write_dirent(fmp, sec);
! 337: if (err)
! 338: return err;
! 339: sec++;
! 340: }
! 341: /* Try again */
! 342: sec = cl_to_sec(fmp, next);
! 343: err = fat_add_dirent(fmp, sec, np);
! 344: return err;
! 345: }
! 346: return ENOENT;
! 347: }
! 348:
! 349: /*
! 350: * Put directory entry.
! 351: * @fmp: fat mount data
! 352: * @np: pointer to fat node
! 353: */
! 354: int
! 355: fatfs_put_node(struct fatfsmount *fmp, struct fatfs_node *np)
! 356: {
! 357: int err;
! 358:
! 359: err = fat_read_dirent(fmp, np->sector);
! 360: if (err)
! 361: return err;
! 362:
! 363: memcpy(fmp->dir_buf + np->offset, &np->dirent,
! 364: sizeof(struct fat_dirent));
! 365:
! 366: err = fat_write_dirent(fmp, np->sector);
! 367: return err;
! 368: }
! 369:
CVSweb