[BACK]Return to fatfs_fat.c CVS log [TXT][DIR] Up to [local] / prex / usr / server / fs / fatfs

Annotation of prex/usr/server/fs/fatfs/fatfs_fat.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 <errno.h>
        !            35: #include <string.h>
        !            36: #include <stdlib.h>
        !            37:
        !            38: #include "fatfs.h"
        !            39:
        !            40: /*
        !            41:  * Read the FAT entry for specified cluster.
        !            42:  */
        !            43: static int
        !            44: read_fat_entry(struct fatfsmount *fmp, u_long cl)
        !            45: {
        !            46:        u_long sec;
        !            47:        char *buf = fmp->fat_buf;
        !            48:        int err, border = 0;
        !            49:        struct buf *bp;
        !            50:
        !            51:        /* Get the sector number in FAT entry. */
        !            52:        if (FAT16(fmp))
        !            53:                sec = (cl * 2) / SEC_SIZE;
        !            54:        else {
        !            55:                sec = (cl * 3 / 2) / SEC_SIZE;
        !            56:                /*
        !            57:                 * Check if the entry data is placed at the
        !            58:                 * end of sector. If so, we have to read one
        !            59:                 * more sector to get complete FAT12 entry.
        !            60:                 */
        !            61:                if ((cl * 3 / 2) % SEC_SIZE == SEC_SIZE - 1)
        !            62:                        border = 1;
        !            63:        }
        !            64:        sec += fmp->fat_start;
        !            65:
        !            66:        /* Read first sector. */
        !            67:        if ((err = bread(fmp->dev, sec, &bp)) != 0)
        !            68:                return err;
        !            69:        memcpy(buf, bp->b_data, SEC_SIZE);
        !            70:        brelse(bp);
        !            71:
        !            72:        if (!FAT12(fmp) || border == 0)
        !            73:                return 0;
        !            74:
        !            75:        /* Read second sector for the border entry of FAT12. */
        !            76:        if ((err = bread(fmp->dev, sec + 1, &bp)) != 0)
        !            77:                return err;
        !            78:        memcpy(buf + SEC_SIZE, bp->b_data, SEC_SIZE);
        !            79:        brelse(bp);
        !            80:        return 0;
        !            81: }
        !            82:
        !            83: /*
        !            84:  * Write fat entry from buffer.
        !            85:  */
        !            86: static int
        !            87: write_fat_entry(struct fatfsmount *fmp, u_long cl)
        !            88: {
        !            89:        u_long sec;
        !            90:        char *buf = fmp->fat_buf;
        !            91:        int err, border = 0;
        !            92:        struct buf *bp;
        !            93:
        !            94:        /* Get the sector number in FAT entry. */
        !            95:        if (FAT16(fmp))
        !            96:                sec = (cl * 2) / SEC_SIZE;
        !            97:        else {
        !            98:                sec = (cl * 3 / 2) / SEC_SIZE;
        !            99:                /* Check if border entry for FAT12 */
        !           100:                if ((cl * 3 / 2) % SEC_SIZE == SEC_SIZE - 1)
        !           101:                        border = 1;
        !           102:        }
        !           103:        sec += fmp->fat_start;
        !           104:
        !           105:        /* Write first sector. */
        !           106:        bp = getblk(fmp->dev, sec);
        !           107:        memcpy(bp->b_data, buf, SEC_SIZE);
        !           108:        if ((err = bwrite(bp)) != 0)
        !           109:                return err;
        !           110:
        !           111:        if (!FAT12(fmp) || border == 0)
        !           112:                return 0;
        !           113:
        !           114:        /* Write second sector for the border entry of FAT12. */
        !           115:        bp = getblk(fmp->dev, sec + 1);
        !           116:        memcpy(bp->b_data, buf + SEC_SIZE, SEC_SIZE);
        !           117:        err = bwrite(bp);
        !           118:        return err;
        !           119: }
        !           120:
        !           121: /*
        !           122:  * Get next cluster number of FAT chain.
        !           123:  * @fmp: fat mount data
        !           124:  * @cl: previous cluster#
        !           125:  * @next: next cluster# to return
        !           126:  */
        !           127: int
        !           128: fat_next_cluster(struct fatfsmount *fmp, u_long cl, u_long *next)
        !           129: {
        !           130:        u_int offset;
        !           131:        uint16_t val;
        !           132:        int err;
        !           133:
        !           134:        /* Read FAT entry */
        !           135:        err = read_fat_entry(fmp, cl);
        !           136:        if (err)
        !           137:                return err;
        !           138:
        !           139:        /* Get offset in buffer. */
        !           140:        if (FAT16(fmp))
        !           141:                offset = (cl * 2) % SEC_SIZE;
        !           142:        else
        !           143:                offset = (cl * 3 / 2) % SEC_SIZE;
        !           144:
        !           145:        /* Pick up cluster# */
        !           146:        val = *((uint16_t *)(fmp->fat_buf + offset));
        !           147:
        !           148:        /* Adjust data for FAT12 entry */
        !           149:        if (FAT12(fmp)) {
        !           150:                if (cl & 1)
        !           151:                        val >>= 4;
        !           152:                else
        !           153:                        val &= 0xfff;
        !           154:        }
        !           155:        *next = (u_long)val;
        !           156:        DPRINTF(("fat_next_cluster: %d => %d\n", cl, *next));
        !           157:        return 0;
        !           158: }
        !           159:
        !           160: /*
        !           161:  * Set next cluster number in FAT chain.
        !           162:  * @fmp: fat mount data
        !           163:  * @cl: previous cluster#
        !           164:  * @next: cluster# to set (can be eof)
        !           165:  */
        !           166: int
        !           167: fat_set_cluster(struct fatfsmount *fmp, u_long cl, u_long next)
        !           168: {
        !           169:        u_int offset;
        !           170:        char *buf = fmp->fat_buf;
        !           171:        int err;
        !           172:        uint16_t val, tmp;
        !           173:
        !           174:        /* Read FAT entry */
        !           175:        err = read_fat_entry(fmp, cl);
        !           176:        if (err)
        !           177:                return err;
        !           178:
        !           179:        /* Get offset in buffer. */
        !           180:        if (FAT16(fmp))
        !           181:                offset = (cl * 2) % SEC_SIZE;
        !           182:        else
        !           183:                offset = (cl * 3 / 2) % SEC_SIZE;
        !           184:
        !           185:        /* Modify FAT entry for target cluster. */
        !           186:        val = (uint16_t)(next & fmp->fat_mask);
        !           187:        if (FAT12(fmp)) {
        !           188:                tmp = *((uint16_t *)(buf + offset));
        !           189:                if (cl & 1) {
        !           190:                        val <<= 4;
        !           191:                        val |= (tmp & 0xf);
        !           192:                } else {
        !           193:                        tmp &= 0xf000;
        !           194:                        val |= tmp;
        !           195:                }
        !           196:        }
        !           197:        *((uint16_t *)(buf + offset)) = val;
        !           198:
        !           199:        /* Write FAT entry */
        !           200:        err = write_fat_entry(fmp, cl);
        !           201:        return err;
        !           202: }
        !           203:
        !           204: /*
        !           205:  * Allocate free cluster in FAT chain.
        !           206:  *
        !           207:  * @fmp: fat mount data
        !           208:  * @scan_start: cluster# to scan first. If 0, use the previous used value.
        !           209:  * @free: allocated cluster# to return
        !           210:  */
        !           211: int
        !           212: fat_alloc_cluster(struct fatfsmount *fmp, u_long scan_start, u_long *free)
        !           213: {
        !           214:        u_long cl, next;
        !           215:        int err;
        !           216:
        !           217:        if (scan_start == 0)
        !           218:                scan_start = fmp->free_scan;
        !           219:
        !           220:        DPRINTF(("fat_alloc_cluster: start=%d\n", scan_start));
        !           221:
        !           222:        cl = scan_start + 1;
        !           223:        while (cl != scan_start) {
        !           224:                err = fat_next_cluster(fmp, cl, &next);
        !           225:                if (err)
        !           226:                        return err;
        !           227:                if (next == CL_FREE) {  /* free ? */
        !           228:                        DPRINTF(("fat_alloc_cluster: free cluster=%d\n", cl));
        !           229:                        *free = cl;
        !           230:                        return 0;
        !           231:                }
        !           232:                if (++cl >= fmp->last_cluster)
        !           233:                        cl = CL_FIRST;
        !           234:        }
        !           235:        return ENOSPC;          /* no space */
        !           236: }
        !           237:
        !           238: /*
        !           239:  * Deallocate needless cluster.
        !           240:  * @fmp: fat mount data
        !           241:  * @start: first cluster# of FAT chain
        !           242:  */
        !           243: int
        !           244: fat_free_clusters(struct fatfsmount *fmp, u_long start)
        !           245: {
        !           246:        int err;
        !           247:        u_long cl, next;
        !           248:
        !           249:        cl = start;
        !           250:        if (cl < CL_FIRST)
        !           251:                return EINVAL;
        !           252:
        !           253:        while (!IS_EOFCL(fmp, cl)) {
        !           254:                err = fat_next_cluster(fmp, cl, &next);
        !           255:                if (err)
        !           256:                        return err;
        !           257:                err = fat_set_cluster(fmp, cl, CL_FREE);
        !           258:                if (err)
        !           259:                        return err;
        !           260:                cl = next;
        !           261:        }
        !           262:        /* Clear eof */
        !           263:        err = fat_set_cluster(fmp, cl, CL_FREE);
        !           264:        if (err)
        !           265:                return err;
        !           266:        return 0;
        !           267: }
        !           268:
        !           269: /*
        !           270:  * Get the cluster# for the specific file offset.
        !           271:  *
        !           272:  * @fmp: fat mount data
        !           273:  * @start: start cluster# of file.
        !           274:  * @offset: file offset
        !           275:  * @cl: cluster# to return
        !           276:  */
        !           277: int
        !           278: fat_seek_cluster(struct fatfsmount *fmp, u_long start, u_long offset,
        !           279:                 u_long *cl)
        !           280: {
        !           281:        int err, i;
        !           282:        u_long c, target;
        !           283:
        !           284:        if (start > fmp->last_cluster)
        !           285:                return EIO;
        !           286:
        !           287:        c = start;
        !           288:        target = offset / fmp->cluster_size;
        !           289:        for (i = 0; i < target; i++) {
        !           290:                err = fat_next_cluster(fmp, c, &c);
        !           291:                if (err)
        !           292:                        return err;
        !           293:                if (IS_EOFCL(fmp, c))
        !           294:                        return EIO;
        !           295:        }
        !           296:        *cl = c;
        !           297:        return 0;
        !           298: }
        !           299:
        !           300: /*
        !           301:  * Expand file size.
        !           302:  *
        !           303:  * @fmp: fat mount data
        !           304:  * @cl: cluster# of target file.
        !           305:  * @size: new size of file in bytes.
        !           306:  */
        !           307: int
        !           308: fat_expand_file(struct fatfsmount *fmp, u_long cl, int size)
        !           309: {
        !           310:        int i, cl_len, alloc, err;
        !           311:        u_long next;
        !           312:
        !           313:        alloc = 0;
        !           314:        cl_len = size / fmp->cluster_size + 1;
        !           315:
        !           316:        for (i = 0; i < cl_len; i++) {
        !           317:                err = fat_next_cluster(fmp, cl, &next);
        !           318:                if (err)
        !           319:                        return err;
        !           320:                if (alloc || next >= fmp->fat_eof) {
        !           321:                        err = fat_alloc_cluster(fmp, cl, &next);
        !           322:                        if (err)
        !           323:                                return err;
        !           324:                        alloc = 1;
        !           325:                }
        !           326:                if (alloc) {
        !           327:                        err = fat_set_cluster(fmp, cl, next);
        !           328:                        if (err)
        !           329:                                return err;
        !           330:                }
        !           331:                cl = next;
        !           332:        }
        !           333:        if (alloc)
        !           334:                fat_set_cluster(fmp, cl, fmp->fat_eof); /* add eof */
        !           335:        DPRINTF(("fat_expand_file: new size=%d\n", size));
        !           336:        return 0;
        !           337: }
        !           338:
        !           339: /*
        !           340:  * Expand directory size.
        !           341:  *
        !           342:  * @fmp: fat mount data
        !           343:  * @cl: cluster# of target directory
        !           344:  * @new_cl: cluster# for new directory to return
        !           345:  *
        !           346:  * Note: The root directory can not be expanded.
        !           347:  */
        !           348: int
        !           349: fat_expand_dir(struct fatfsmount *fmp, u_long cl, u_long *new_cl)
        !           350: {
        !           351:        int err;
        !           352:        u_long next;
        !           353:
        !           354:        /* Find last cluster number of FAT chain. */
        !           355:        while (!IS_EOFCL(fmp, cl)) {
        !           356:                err = fat_next_cluster(fmp, cl, &next);
        !           357:                if (err)
        !           358:                        return err;
        !           359:                cl = next;
        !           360:        }
        !           361:
        !           362:        err = fat_alloc_cluster(fmp, cl, &next);
        !           363:        if (err)
        !           364:                return err;
        !           365:
        !           366:        err = fat_set_cluster(fmp, cl, next);
        !           367:        if (err)
        !           368:                return err;
        !           369:
        !           370:        err = fat_set_cluster(fmp, next, fmp->fat_eof);
        !           371:        if (err)
        !           372:                return err;
        !           373:
        !           374:        *new_cl = next;
        !           375:        return 0;
        !           376: }

CVSweb