|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/server/fs/fatfs/fatfs_fat.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |