Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/fs/fatfs/fatfs_fat.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_fat_entry
  2. write_fat_entry
  3. fat_next_cluster
  4. fat_set_cluster
  5. fat_alloc_cluster
  6. fat_free_clusters
  7. fat_seek_cluster
  8. fat_expand_file
  9. fat_expand_dir

   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 <sys/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 error, 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 ((error = bread(fmp->dev, sec, &bp)) != 0)
  68                 return error;
  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 ((error = bread(fmp->dev, sec + 1, &bp)) != 0)
  77                 return error;
  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 error, 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 ((error = bwrite(bp)) != 0)
 109                 return error;
 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         error = bwrite(bp);
 118         return error;
 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 error;
 133 
 134         /* Read FAT entry */
 135         error = read_fat_entry(fmp, cl);
 136         if (error)
 137                 return error;
 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 error;
 172         uint16_t val, tmp;
 173 
 174         /* Read FAT entry */
 175         error = read_fat_entry(fmp, cl);
 176         if (error)
 177                 return error;
 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         error = write_fat_entry(fmp, cl);
 201         return error;
 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 error;
 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                 error = fat_next_cluster(fmp, cl, &next);
 225                 if (error)
 226                         return error;
 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 error;
 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                 error = fat_next_cluster(fmp, cl, &next);
 255                 if (error)
 256                         return error;
 257                 error = fat_set_cluster(fmp, cl, CL_FREE);
 258                 if (error)
 259                         return error;
 260                 cl = next;
 261         }
 262         /* Clear eof */
 263         error = fat_set_cluster(fmp, cl, CL_FREE);
 264         if (error)
 265                 return error;
 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 error, 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                 error = fat_next_cluster(fmp, c, &c);
 291                 if (error)
 292                         return error;
 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, error;
 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                 error = fat_next_cluster(fmp, cl, &next);
 318                 if (error)
 319                         return error;
 320                 if (alloc || next >= fmp->fat_eof) {
 321                         error = fat_alloc_cluster(fmp, cl, &next);
 322                         if (error)
 323                                 return error;
 324                         alloc = 1;
 325                 }
 326                 if (alloc) {
 327                         error = fat_set_cluster(fmp, cl, next);
 328                         if (error)
 329                                 return error;
 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 error;
 352         u_long next;
 353 
 354         /* Find last cluster number of FAT chain. */
 355         while (!IS_EOFCL(fmp, cl)) {
 356                 error = fat_next_cluster(fmp, cl, &next);
 357                 if (error)
 358                         return error;
 359                 cl = next;
 360         }
 361 
 362         error = fat_alloc_cluster(fmp, cl, &next);
 363         if (error)
 364                 return error;
 365 
 366         error = fat_set_cluster(fmp, cl, next);
 367         if (error)
 368                 return error;
 369 
 370         error = fat_set_cluster(fmp, next, fmp->fat_eof);
 371         if (error)
 372                 return error;
 373 
 374         *new_cl = next;
 375         return 0;
 376 }

/* [<][>][^][v][top][bottom][index][help] */