CD exfat support for Tomato. https://github.com/dorimanx/exfat-nofuse.
[tomato.git] / release / src-rt / linux / linux-2.6 / fs / exfat / exfat_core.c
blob2ab28dc32da211e171a1733d08fd8726efb8e47f
1 /* Some of the source code in this file came from "linux/fs/fat/misc.c". */
2 /*
3 * linux/fs/fat/misc.c
5 * Written 1992,1993 by Werner Almesberger
6 * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
7 * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
8 */
11 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 /************************************************************************/
29 /* */
30 /* PROJECT : exFAT & FAT12/16/32 File System */
31 /* FILE : exfat.c */
32 /* PURPOSE : exFAT File Manager */
33 /* */
34 /*----------------------------------------------------------------------*/
35 /* NOTES */
36 /* */
37 /*----------------------------------------------------------------------*/
38 /* REVISION HISTORY (Ver 0.9) */
39 /* */
40 /* - 2010.11.15 [Joosun Hahn] : first writing */
41 /* */
42 /************************************************************************/
44 #include <linux/version.h>
46 #include "exfat_config.h"
47 #include "exfat_global.h"
48 #include "exfat_data.h"
49 #include "exfat_oal.h"
51 #include "exfat_blkdev.h"
52 #include "exfat_cache.h"
53 #include "exfat_nls.h"
54 #include "exfat_api.h"
55 #include "exfat_super.h"
56 #include "exfat.h"
58 #include <linux/blkdev.h>
60 /*----------------------------------------------------------------------*/
61 /* Constant & Macro Definitions */
62 /*----------------------------------------------------------------------*/
64 #define THERE_IS_MBR 0 /* if there is no MBR (e.g. memory card),
65 set this macro to 0 */
67 #if (THERE_IS_MBR == 1)
68 #include "exfat_part.h"
69 #endif
71 #define DELAYED_SYNC 0
73 #define ELAPSED_TIME 0
75 #if (ELAPSED_TIME == 1)
76 #include <linux/time.h>
78 static UINT32 __t1, __t2;
79 static UINT32 get_current_msec(void)
81 struct timeval tm;
82 do_gettimeofday(&tm);
83 return (UINT32)(tm.tv_sec*1000000 + tm.tv_usec);
85 #define TIME_START() do {__t1 = get_current_msec(); } while (0)
86 #define TIME_END() do {__t2 = get_current_msec(); } while (0)
87 #define PRINT_TIME(n) do {printk("[EXFAT] Elapsed time %d = %d (usec)\n", n, (__t2 - __t1)); } while (0)
88 #else
89 #define TIME_START()
90 #define TIME_END()
91 #define PRINT_TIME(n)
92 #endif
94 static void __set_sb_dirty(struct super_block *sb)
96 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
97 sb->s_dirt = 1;
98 #else
99 struct exfat_sb_info *sbi = EXFAT_SB(sb);
100 sbi->s_dirt = 1;
101 #endif
104 /*----------------------------------------------------------------------*/
105 /* Global Variable Definitions */
106 /*----------------------------------------------------------------------*/
108 extern UINT8 uni_upcase[];
110 /*----------------------------------------------------------------------*/
111 /* Local Variable Definitions */
112 /*----------------------------------------------------------------------*/
114 static UINT8 name_buf[MAX_PATH_LENGTH *MAX_CHARSET_SIZE];
116 static INT8 *reserved_names[] = {
117 "AUX ", "CON ", "NUL ", "PRN ",
118 "COM1 ", "COM2 ", "COM3 ", "COM4 ",
119 "COM5 ", "COM6 ", "COM7 ", "COM8 ", "COM9 ",
120 "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ",
121 "LPT5 ", "LPT6 ", "LPT7 ", "LPT8 ", "LPT9 ",
122 NULL
125 static UINT8 free_bit[] = {
126 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */
127 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */
128 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */
129 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */
130 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */
131 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */
132 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */
133 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */
134 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */
135 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */
136 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */
137 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */
138 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */
141 static UINT8 used_bit[] = {
142 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */
143 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */
144 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */
145 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */
146 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */
147 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */
148 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */
149 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */
150 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */
151 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */
152 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */
153 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */
154 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */
157 /*======================================================================*/
158 /* Global Function Definitions */
159 /*======================================================================*/
161 /* ffsInit : roll back to the initial state of the file system */
162 INT32 ffsInit(void)
164 INT32 ret;
166 ret = bdev_init();
167 if (ret)
168 return ret;
170 ret = fs_init();
171 if (ret)
172 return ret;
174 return FFS_SUCCESS;
175 } /* end of ffsInit */
177 /* ffsShutdown : make free all memory-alloced global buffers */
178 INT32 ffsShutdown(void)
180 INT32 ret;
181 ret = fs_shutdown();
182 if (ret)
183 return ret;
185 ret = bdev_shutdown();
186 if (ret)
187 return ret;
189 return FFS_SUCCESS;
190 } /* end of ffsShutdown */
192 /* ffsMountVol : mount the file system volume */
193 INT32 ffsMountVol(struct super_block *sb, INT32 drv)
195 INT32 i, ret;
196 #if (THERE_IS_MBR == 1)
197 MBR_SECTOR_T *p_mbr;
198 PART_ENTRY_T *p_pte;
199 #endif
200 PBR_SECTOR_T *p_pbr;
201 struct buffer_head *tmp_bh = NULL;
202 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
203 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
205 PRINTK("[EXFAT] trying to mount...\n");
207 p_fs->drv = drv;
208 p_fs->dev_ejected = FALSE;
210 /* open the block device */
211 if (bdev_open(sb))
212 return FFS_MEDIAERR;
214 if (p_bd->sector_size < sb->s_blocksize)
215 return FFS_MEDIAERR;
216 if (p_bd->sector_size > sb->s_blocksize)
217 sb_set_blocksize(sb, p_bd->sector_size);
219 /* read Sector 0 */
220 if (sector_read(sb, 0, &tmp_bh, 1) != FFS_SUCCESS)
221 return FFS_MEDIAERR;
223 #if (THERE_IS_MBR == 1)
224 if (buf[0] != 0xEB) {
225 /* MBR is read */
226 p_mbr = (MBR_SECTOR_T *) tmp_bh->b_data;
228 /* check the validity of MBR */
229 if (GET16_A(p_mbr->signature) != MBR_SIGNATURE) {
230 brelse(tmp_bh);
231 bdev_close(sb);
232 return FFS_FORMATERR;
235 p_pte = (PART_ENTRY_T *) p_mbr->partition + 0;
236 p_fs->PBR_sector = GET32(p_pte->start_sector);
237 p_fs->num_sectors = GET32(p_pte->num_sectors);
239 if (p_fs->num_sectors == 0) {
240 brelse(tmp_bh);
241 bdev_close(sb);
242 return FFS_ERROR;
245 /* read PBR */
246 if (sector_read(sb, p_fs->PBR_sector, &tmp_bh, 1) != FFS_SUCCESS) {
247 bdev_close(sb);
248 return FFS_MEDIAERR;
250 } else {
251 #endif
252 /* PRB is read */
253 p_fs->PBR_sector = 0;
254 #if (THERE_IS_MBR == 1)
256 #endif
258 p_pbr = (PBR_SECTOR_T *) tmp_bh->b_data;
260 /* check the validity of PBR */
261 if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) {
262 brelse(tmp_bh);
263 bdev_close(sb);
264 return FFS_FORMATERR;
267 /* fill fs_stuct */
268 for (i = 0; i < 53; i++)
269 if (p_pbr->bpb[i])
270 break;
272 if (i < 53) {
273 if (GET16(p_pbr->bpb+11)) /* num_fat_sectors */
274 ret = fat16_mount(sb, p_pbr);
275 else
276 ret = fat32_mount(sb, p_pbr);
277 } else {
278 ret = exfat_mount(sb, p_pbr);
281 brelse(tmp_bh);
283 if (ret) {
284 bdev_close(sb);
285 return ret;
288 if (p_fs->vol_type == EXFAT) {
289 ret = load_alloc_bitmap(sb);
290 if (ret) {
291 bdev_close(sb);
292 return ret;
294 ret = load_upcase_table(sb);
295 if (ret) {
296 free_alloc_bitmap(sb);
297 bdev_close(sb);
298 return ret;
302 if (p_fs->dev_ejected) {
303 if (p_fs->vol_type == EXFAT) {
304 free_upcase_table(sb);
305 free_alloc_bitmap(sb);
307 bdev_close(sb);
308 return FFS_MEDIAERR;
311 PRINTK("[EXFAT] mounted successfully\n");
312 return FFS_SUCCESS;
313 } /* end of ffsMountVol */
315 /* ffsUmountVol : umount the file system volume */
316 INT32 ffsUmountVol(struct super_block *sb)
318 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
320 PRINTK("[EXFAT] trying to unmount...\n");
322 fs_sync(sb, 0);
323 fs_set_vol_flags(sb, VOL_CLEAN);
325 if (p_fs->vol_type == EXFAT) {
326 free_upcase_table(sb);
327 free_alloc_bitmap(sb);
330 FAT_release_all(sb);
331 buf_release_all(sb);
333 /* close the block device */
334 bdev_close(sb);
336 if (p_fs->dev_ejected) {
337 PRINTK( "[EXFAT] unmounted with media errors. "
338 "device's already ejected.\n");
339 return FFS_MEDIAERR;
342 PRINTK("[EXFAT] unmounted successfully\n");
343 return FFS_SUCCESS;
344 } /* end of ffsUmountVol */
346 /* ffsGetVolInfo : get the information of a file system volume */
347 INT32 ffsGetVolInfo(struct super_block *sb, VOL_INFO_T *info)
349 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
351 if (p_fs->used_clusters == (UINT32) ~0)
352 p_fs->used_clusters = p_fs->fs_func->count_used_clusters(sb);
354 info->FatType = p_fs->vol_type;
355 info->ClusterSize = p_fs->cluster_size;
356 info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */
357 info->UsedClusters = p_fs->used_clusters;
358 info->FreeClusters = info->NumClusters - info->UsedClusters;
360 if (p_fs->dev_ejected)
361 return FFS_MEDIAERR;
363 return FFS_SUCCESS;
364 } /* end of ffsGetVolInfo */
366 /* ffsSyncVol : synchronize all file system volumes */
367 INT32 ffsSyncVol(struct super_block *sb, INT32 do_sync)
369 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
371 /* synchronize the file system */
372 fs_sync(sb, do_sync);
373 fs_set_vol_flags(sb, VOL_CLEAN);
375 if (p_fs->dev_ejected)
376 return FFS_MEDIAERR;
378 return FFS_SUCCESS;
379 } /* end of ffsSyncVol */
381 /*----------------------------------------------------------------------*/
382 /* File Operation Functions */
383 /*----------------------------------------------------------------------*/
385 /* ffsLookupFile : lookup a file */
386 INT32 ffsLookupFile(struct inode *inode, UINT8 *path, FILE_ID_T *fid)
388 INT32 ret, dentry, num_entries;
389 CHAIN_T dir;
390 UNI_NAME_T uni_name;
391 DOS_NAME_T dos_name;
392 DENTRY_T *ep, *ep2;
393 ENTRY_SET_CACHE_T *es=NULL;
394 struct super_block *sb = inode->i_sb;
395 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
397 PRINTK("ffsLookupFile entered\n");
399 /* check the validity of directory name in the given pathname */
400 ret = resolve_path(inode, path, &dir, &uni_name);
401 if (ret)
402 return ret;
404 ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, &dos_name);
405 if (ret)
406 return ret;
408 /* search the file name for directories */
409 dentry = p_fs->fs_func->find_dir_entry(sb, &dir, &uni_name, num_entries, &dos_name, TYPE_ALL);
410 if (dentry < -1)
411 return FFS_NOTFOUND;
413 fid->dir.dir = dir.dir;
414 fid->dir.size = dir.size;
415 fid->dir.flags = dir.flags;
416 fid->entry = dentry;
418 if (dentry == -1) {
419 fid->type = TYPE_DIR;
420 fid->rwoffset = 0;
421 fid->hint_last_off = -1;
423 fid->attr = ATTR_SUBDIR;
424 fid->flags = 0x01;
425 fid->size = 0;
426 fid->start_clu = p_fs->root_dir;
427 } else {
428 if (p_fs->vol_type == EXFAT) {
429 es = get_entry_set_in_dir(sb, &dir, dentry, ES_2_ENTRIES, &ep);
430 if (!es)
431 return FFS_MEDIAERR;
432 ep2 = ep+1;
433 } else {
434 ep = get_entry_in_dir(sb, &dir, dentry, NULL);
435 if (!ep)
436 return FFS_MEDIAERR;
437 ep2 = ep;
440 fid->type = p_fs->fs_func->get_entry_type(ep);
441 fid->rwoffset = 0;
442 fid->hint_last_off = -1;
443 fid->attr = p_fs->fs_func->get_entry_attr(ep);
445 fid->size = p_fs->fs_func->get_entry_size(ep2);
446 if ((fid->type == TYPE_FILE) && (fid->size == 0)) {
447 fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
448 fid->start_clu = CLUSTER_32(~0);
449 } else {
450 fid->flags = p_fs->fs_func->get_entry_flag(ep2);
451 fid->start_clu = p_fs->fs_func->get_entry_clu0(ep2);
454 if (p_fs->vol_type == EXFAT)
455 release_entry_set(es);
458 if (p_fs->dev_ejected)
459 return FFS_MEDIAERR;
461 PRINTK("ffsLookupFile exited successfully\n");
463 return FFS_SUCCESS;
464 } /* end of ffsLookupFile */
466 /* ffsCreateFile : create a file */
467 INT32 ffsCreateFile(struct inode *inode, UINT8 *path, UINT8 mode, FILE_ID_T *fid)
469 INT32 ret/*, dentry*/;
470 CHAIN_T dir;
471 UNI_NAME_T uni_name;
472 struct super_block *sb = inode->i_sb;
473 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
475 /* check the validity of directory name in the given pathname */
476 ret = resolve_path(inode, path, &dir, &uni_name);
477 if (ret)
478 return ret;
480 fs_set_vol_flags(sb, VOL_DIRTY);
482 /* create a new file */
483 ret = create_file(inode, &dir, &uni_name, mode, fid);
485 #if (DELAYED_SYNC == 0)
486 fs_sync(sb, 0);
487 fs_set_vol_flags(sb, VOL_CLEAN);
488 #endif
490 if (p_fs->dev_ejected)
491 return FFS_MEDIAERR;
493 return ret;
494 } /* end of ffsCreateFile */
496 /* ffsReadFile : read data from a opened file */
497 INT32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 count, UINT64 *rcount)
499 INT32 offset, sec_offset, clu_offset;
500 UINT32 clu, LogSector;
501 UINT64 oneblkread, read_bytes;
502 struct buffer_head *tmp_bh = NULL;
503 struct super_block *sb = inode->i_sb;
504 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
505 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
507 /* check if the given file ID is opened */
508 if (fid->type != TYPE_FILE)
509 return FFS_PERMISSIONERR;
511 if (fid->rwoffset > fid->size)
512 fid->rwoffset = fid->size;
514 if (count > (fid->size - fid->rwoffset))
515 count = fid->size - fid->rwoffset;
517 if (count == 0) {
518 if (rcount != NULL)
519 *rcount = 0;
520 return FFS_EOF;
523 read_bytes = 0;
525 while (count > 0) {
526 clu_offset = (INT32)(fid->rwoffset >> p_fs->cluster_size_bits);
527 clu = fid->start_clu;
529 if (fid->flags == 0x03) {
530 clu += clu_offset;
531 } else {
532 /* hint information */
533 if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
534 (clu_offset >= fid->hint_last_off)) {
535 clu_offset -= fid->hint_last_off;
536 clu = fid->hint_last_clu;
539 while (clu_offset > 0) {
540 /* clu = FAT_read(sb, clu); */
541 if (FAT_read(sb, clu, &clu) == -1)
542 return FFS_MEDIAERR;
544 clu_offset--;
548 /* hint information */
549 fid->hint_last_off = (INT32)(fid->rwoffset >> p_fs->cluster_size_bits);
550 fid->hint_last_clu = clu;
552 offset = (INT32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */
553 sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */
554 offset &= p_bd->sector_size_mask; /* byte offset in sector */
556 LogSector = START_SECTOR(clu) + sec_offset;
558 oneblkread = (UINT64)(p_bd->sector_size - offset);
559 if (oneblkread > count)
560 oneblkread = count;
562 if ((offset == 0) && (oneblkread == p_bd->sector_size)) {
563 if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS)
564 goto err_out;
565 MEMCPY(((INT8 *) buffer)+read_bytes, ((INT8 *) tmp_bh->b_data), (INT32) oneblkread);
566 } else {
567 if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS)
568 goto err_out;
569 MEMCPY(((INT8 *) buffer)+read_bytes, ((INT8 *) tmp_bh->b_data)+offset, (INT32) oneblkread);
571 count -= oneblkread;
572 read_bytes += oneblkread;
573 fid->rwoffset += oneblkread;
575 brelse(tmp_bh);
577 err_out:
578 /* set the size of read bytes */
579 if (rcount != NULL)
580 *rcount = read_bytes;
582 if (p_fs->dev_ejected)
583 return FFS_MEDIAERR;
585 return FFS_SUCCESS;
586 } /* end of ffsReadFile */
588 /* ffsWriteFile : write data into a opened file */
589 INT32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, UINT64 count, UINT64 *wcount)
591 INT32 modified = FALSE, offset, sec_offset, clu_offset;
592 INT32 num_clusters, num_alloc, num_alloced = (INT32) ~0;
593 UINT32 clu, last_clu, LogSector, sector = 0;
594 UINT64 oneblkwrite, write_bytes;
595 CHAIN_T new_clu;
596 TIMESTAMP_T tm;
597 DENTRY_T *ep, *ep2;
598 ENTRY_SET_CACHE_T *es = NULL;
599 struct buffer_head *tmp_bh = NULL;
600 struct super_block *sb = inode->i_sb;
601 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
602 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
604 /* check if the given file ID is opened */
605 if (fid->type != TYPE_FILE)
606 return FFS_PERMISSIONERR;
608 if (fid->rwoffset > fid->size)
609 fid->rwoffset = fid->size;
611 if (count == 0) {
612 if (wcount != NULL)
613 *wcount = 0;
614 return FFS_SUCCESS;
617 fs_set_vol_flags(sb, VOL_DIRTY);
619 if (fid->size == 0)
620 num_clusters = 0;
621 else
622 num_clusters = (INT32)((fid->size-1) >> p_fs->cluster_size_bits) + 1;
624 write_bytes = 0;
626 while (count > 0) {
627 clu_offset = (INT32)(fid->rwoffset >> p_fs->cluster_size_bits);
628 clu = last_clu = fid->start_clu;
630 if (fid->flags == 0x03) {
631 if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) {
632 last_clu += clu_offset - 1;
634 if (clu_offset == num_clusters)
635 clu = CLUSTER_32(~0);
636 else
637 clu += clu_offset;
639 } else {
640 /* hint information */
641 if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
642 (clu_offset >= fid->hint_last_off)) {
643 clu_offset -= fid->hint_last_off;
644 clu = fid->hint_last_clu;
647 while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) {
648 last_clu = clu;
649 /* clu = FAT_read(sb, clu); */
650 if (FAT_read(sb, clu, &clu) == -1)
651 return FFS_MEDIAERR;
653 clu_offset--;
657 if (clu == CLUSTER_32(~0)) {
658 num_alloc = (INT32)((count-1) >> p_fs->cluster_size_bits) + 1;
659 new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1;
660 new_clu.size = 0;
661 new_clu.flags = fid->flags;
663 /* (1) allocate a chain of clusters */
664 num_alloced = p_fs->fs_func->alloc_cluster(sb, num_alloc, &new_clu);
665 if (num_alloced == 0)
666 break;
668 /* (2) append to the FAT chain */
669 if (last_clu == CLUSTER_32(~0)) {
670 if (new_clu.flags == 0x01)
671 fid->flags = 0x01;
672 fid->start_clu = new_clu.dir;
673 modified = TRUE;
674 } else {
675 if (new_clu.flags != fid->flags) {
676 exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters);
677 fid->flags = 0x01;
678 modified = TRUE;
680 if (new_clu.flags == 0x01)
681 FAT_write(sb, last_clu, new_clu.dir);
684 num_clusters += num_alloced;
685 clu = new_clu.dir;
688 /* hint information */
689 fid->hint_last_off = (INT32)(fid->rwoffset >> p_fs->cluster_size_bits);
690 fid->hint_last_clu = clu;
692 offset = (INT32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */
693 sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */
694 offset &= p_bd->sector_size_mask; /* byte offset in sector */
696 LogSector = START_SECTOR(clu) + sec_offset;
698 oneblkwrite = (UINT64)(p_bd->sector_size - offset);
699 if (oneblkwrite > count)
700 oneblkwrite = count;
702 if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) {
703 if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS)
704 goto err_out;
705 MEMCPY(((INT8 *) tmp_bh->b_data), ((INT8 *) buffer)+write_bytes, (INT32) oneblkwrite);
706 if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) {
707 brelse(tmp_bh);
708 goto err_out;
710 } else {
711 if ((offset > 0) || ((fid->rwoffset+oneblkwrite) < fid->size)) {
712 if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS)
713 goto err_out;
714 } else {
715 if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS)
716 goto err_out;
719 MEMCPY(((INT8 *) tmp_bh->b_data)+offset, ((INT8 *) buffer)+write_bytes, (INT32) oneblkwrite);
720 if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) {
721 brelse(tmp_bh);
722 goto err_out;
726 count -= oneblkwrite;
727 write_bytes += oneblkwrite;
728 fid->rwoffset += oneblkwrite;
730 fid->attr |= ATTR_ARCHIVE;
732 if (fid->size < fid->rwoffset) {
733 fid->size = fid->rwoffset;
734 modified = TRUE;
738 brelse(tmp_bh);
740 /* (3) update the direcoty entry */
741 if (p_fs->vol_type == EXFAT) {
742 es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep);
743 if (es == NULL)
744 goto err_out;
745 ep2 = ep+1;
746 } else {
747 ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
748 if (!ep)
749 goto err_out;
750 ep2 = ep;
753 p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY);
754 p_fs->fs_func->set_entry_attr(ep, fid->attr);
756 if (p_fs->vol_type != EXFAT)
757 buf_modify(sb, sector);
759 if (modified) {
760 if (p_fs->fs_func->get_entry_flag(ep2) != fid->flags)
761 p_fs->fs_func->set_entry_flag(ep2, fid->flags);
763 if (p_fs->fs_func->get_entry_size(ep2) != fid->size)
764 p_fs->fs_func->set_entry_size(ep2, fid->size);
766 if (p_fs->fs_func->get_entry_clu0(ep2) != fid->start_clu)
767 p_fs->fs_func->set_entry_clu0(ep2, fid->start_clu);
769 if (p_fs->vol_type != EXFAT)
770 buf_modify(sb, sector);
773 if (p_fs->vol_type == EXFAT) {
774 update_dir_checksum_with_entry_set(sb, es);
775 release_entry_set(es);
778 #if (DELAYED_SYNC == 0)
779 fs_sync(sb, 0);
780 fs_set_vol_flags(sb, VOL_CLEAN);
781 #endif
783 err_out:
784 /* set the size of written bytes */
785 if (wcount != NULL)
786 *wcount = write_bytes;
788 if (num_alloced == 0)
789 return FFS_FULL;
791 if (p_fs->dev_ejected)
792 return FFS_MEDIAERR;
794 return FFS_SUCCESS;
795 } /* end of ffsWriteFile */
797 /* ffsTruncateFile : resize the file length */
798 INT32 ffsTruncateFile(struct inode *inode, UINT64 old_size, UINT64 new_size)
800 INT32 num_clusters;
801 UINT32 last_clu = CLUSTER_32(0), sector = 0;
802 CHAIN_T clu;
803 TIMESTAMP_T tm;
804 DENTRY_T *ep, *ep2;
805 struct super_block *sb = inode->i_sb;
806 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
807 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
808 ENTRY_SET_CACHE_T *es=NULL;
810 /* check if the given file ID is opened */
811 if (fid->type != TYPE_FILE)
812 return FFS_PERMISSIONERR;
814 if (fid->size != old_size) {
815 printk(KERN_ERR "[EXFAT] truncate : can't skip it because of "
816 "size-mismatch(old:%lld->fid:%lld).\n"
817 ,old_size, fid->size);
820 if (old_size <= new_size)
821 return FFS_SUCCESS;
823 fs_set_vol_flags(sb, VOL_DIRTY);
825 clu.dir = fid->start_clu;
826 clu.size = (INT32)((old_size-1) >> p_fs->cluster_size_bits) + 1;
827 clu.flags = fid->flags;
829 if (new_size > 0) {
830 num_clusters = (INT32)((new_size-1) >> p_fs->cluster_size_bits) + 1;
832 if (clu.flags == 0x03) {
833 clu.dir += num_clusters;
834 } else {
835 while (num_clusters > 0) {
836 last_clu = clu.dir;
837 if (FAT_read(sb, clu.dir, &(clu.dir)) == -1)
838 return FFS_MEDIAERR;
839 num_clusters--;
843 clu.size -= num_clusters;
846 fid->size = new_size;
847 fid->attr |= ATTR_ARCHIVE;
848 if (new_size == 0) {
849 fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
850 fid->start_clu = CLUSTER_32(~0);
853 /* (1) update the directory entry */
854 if (p_fs->vol_type == EXFAT) {
855 es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep);
856 if (es == NULL)
857 return FFS_MEDIAERR;
858 ep2 = ep+1;
859 } else {
860 ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
861 if (!ep)
862 return FFS_MEDIAERR;
863 ep2 = ep;
866 p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY);
867 p_fs->fs_func->set_entry_attr(ep, fid->attr);
869 p_fs->fs_func->set_entry_size(ep2, new_size);
870 if (new_size == 0) {
871 p_fs->fs_func->set_entry_flag(ep2, 0x01);
872 p_fs->fs_func->set_entry_clu0(ep2, CLUSTER_32(0));
875 if (p_fs->vol_type != EXFAT)
876 buf_modify(sb, sector);
877 else {
878 update_dir_checksum_with_entry_set(sb, es);
879 release_entry_set(es);
882 /* (2) cut off from the FAT chain */
883 if (last_clu != CLUSTER_32(0)) {
884 if (fid->flags == 0x01)
885 FAT_write(sb, last_clu, CLUSTER_32(~0));
888 /* (3) free the clusters */
889 p_fs->fs_func->free_cluster(sb, &clu, 0);
891 /* hint information */
892 fid->hint_last_off = -1;
893 if (fid->rwoffset > fid->size) {
894 fid->rwoffset = fid->size;
897 #if (DELAYED_SYNC == 0)
898 fs_sync(sb, 0);
899 fs_set_vol_flags(sb, VOL_CLEAN);
900 #endif
902 if (p_fs->dev_ejected)
903 return FFS_MEDIAERR;
905 return FFS_SUCCESS;
906 } /* end of ffsTruncateFile */
908 static void update_parent_info( FILE_ID_T *fid, struct inode *parent_inode)
910 FS_INFO_T *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info);
911 FILE_ID_T *parent_fid = &(EXFAT_I(parent_inode)->fid);
913 if (unlikely((parent_fid->flags != fid->dir.flags)
914 || (parent_fid->size != (fid->dir.size<<p_fs->cluster_size_bits))
915 || (parent_fid->start_clu != fid->dir.dir))) {
917 fid->dir.dir = parent_fid->start_clu;
918 fid->dir.flags = parent_fid->flags;
919 fid->dir.size = ((parent_fid->size + (p_fs->cluster_size-1))
920 >> p_fs->cluster_size_bits);
924 /* ffsMoveFile : move(rename) a old file into a new file */
925 INT32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry)
927 INT32 ret;
928 INT32 dentry;
929 CHAIN_T olddir, newdir;
930 CHAIN_T *p_dir=NULL;
931 UNI_NAME_T uni_name;
932 DENTRY_T *ep;
933 struct super_block *sb = old_parent_inode->i_sb;
934 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
935 UINT8 *new_path = (UINT8 *) new_dentry->d_name.name;
936 struct inode *new_inode = new_dentry->d_inode;
937 int num_entries;
938 FILE_ID_T *new_fid = NULL;
939 INT32 new_entry=0;
941 /* check the validity of pointer parameters */
942 if ((new_path == NULL) || (*new_path == '\0'))
943 return FFS_ERROR;
945 update_parent_info(fid, old_parent_inode);
947 olddir.dir = fid->dir.dir;
948 olddir.size = fid->dir.size;
949 olddir.flags = fid->dir.flags;
951 dentry = fid->entry;
953 /* check if the old file is "." or ".." */
954 if (p_fs->vol_type != EXFAT) {
955 if ((olddir.dir != p_fs->root_dir) && (dentry < 2))
956 return FFS_PERMISSIONERR;
959 ep = get_entry_in_dir(sb, &olddir, dentry, NULL);
960 if (!ep)
961 return FFS_MEDIAERR;
963 if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY)
964 return FFS_PERMISSIONERR;
966 /* check whether new dir is existing directory and empty */
967 if (new_inode) {
968 UINT32 entry_type;
970 ret = FFS_MEDIAERR;
971 new_fid = &EXFAT_I(new_inode)->fid;
973 update_parent_info(new_fid, new_parent_inode);
975 p_dir = &(new_fid->dir);
976 new_entry = new_fid->entry;
977 ep = get_entry_in_dir(sb, p_dir, new_entry, NULL);
978 if (!ep)
979 goto out;
981 entry_type = p_fs->fs_func->get_entry_type(ep);
983 if (entry_type == TYPE_DIR) {
984 CHAIN_T new_clu;
985 new_clu.dir = new_fid->start_clu;
986 new_clu.size = (INT32)((new_fid->size-1) >> p_fs->cluster_size_bits) + 1;
987 new_clu.flags = new_fid->flags;
989 if (!is_dir_empty(sb, &new_clu))
990 return FFS_FILEEXIST;
994 /* check the validity of directory name in the given new pathname */
995 ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name);
996 if (ret)
997 return ret;
999 fs_set_vol_flags(sb, VOL_DIRTY);
1001 if (olddir.dir == newdir.dir)
1002 ret = rename_file(new_parent_inode, &olddir, dentry, &uni_name, fid);
1003 else
1004 ret = move_file(new_parent_inode, &olddir, dentry, &newdir, &uni_name, fid);
1006 if ((ret == FFS_SUCCESS) && new_inode) {
1007 /* delete entries of new_dir */
1008 ep = get_entry_in_dir(sb, p_dir, new_entry, NULL);
1009 if (!ep)
1010 goto out;
1012 num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, new_entry, ep);
1013 if (num_entries < 0)
1014 goto out;
1015 p_fs->fs_func->delete_dir_entry(sb, p_dir, new_entry, 0, num_entries+1);
1017 out:
1018 #if (DELAYED_SYNC == 0)
1019 fs_sync(sb, 0);
1020 fs_set_vol_flags(sb, VOL_CLEAN);
1021 #endif
1023 if (p_fs->dev_ejected)
1024 return FFS_MEDIAERR;
1026 return ret;
1027 } /* end of ffsMoveFile */
1029 /* ffsRemoveFile : remove a file */
1030 INT32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid)
1032 INT32 dentry;
1033 CHAIN_T dir, clu_to_free;
1034 DENTRY_T *ep;
1035 struct super_block *sb = inode->i_sb;
1036 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1038 dir.dir = fid->dir.dir;
1039 dir.size = fid->dir.size;
1040 dir.flags = fid->dir.flags;
1042 dentry = fid->entry;
1044 ep = get_entry_in_dir(sb, &dir, dentry, NULL);
1045 if (!ep)
1046 return FFS_MEDIAERR;
1048 if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY)
1049 return FFS_PERMISSIONERR;
1051 fs_set_vol_flags(sb, VOL_DIRTY);
1053 /* (1) update the directory entry */
1054 remove_file(inode, &dir, dentry);
1056 clu_to_free.dir = fid->start_clu;
1057 clu_to_free.size = (INT32)((fid->size-1) >> p_fs->cluster_size_bits) + 1;
1058 clu_to_free.flags = fid->flags;
1060 /* (2) free the clusters */
1061 p_fs->fs_func->free_cluster(sb, &clu_to_free, 0);
1063 fid->size = 0;
1064 fid->start_clu = CLUSTER_32(~0);
1065 fid->flags = (p_fs->vol_type == EXFAT)? 0x03: 0x01;
1067 #if (DELAYED_SYNC == 0)
1068 fs_sync(sb, 0);
1069 fs_set_vol_flags(sb, VOL_CLEAN);
1070 #endif
1072 if (p_fs->dev_ejected)
1073 return FFS_MEDIAERR;
1075 return FFS_SUCCESS;
1076 } /* end of ffsRemoveFile */
1078 /* ffsSetAttr : set the attribute of a given file */
1079 INT32 ffsSetAttr(struct inode *inode, UINT32 attr)
1081 UINT32 type, sector = 0;
1082 DENTRY_T *ep;
1083 struct super_block *sb = inode->i_sb;
1084 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1085 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
1086 UINT8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
1087 ENTRY_SET_CACHE_T *es = NULL;
1089 if (fid->attr == attr) {
1090 if (p_fs->dev_ejected)
1091 return FFS_MEDIAERR;
1092 return FFS_SUCCESS;
1095 if (is_dir) {
1096 if ((fid->dir.dir == p_fs->root_dir) &&
1097 (fid->entry == -1)) {
1098 if (p_fs->dev_ejected)
1099 return FFS_MEDIAERR;
1100 return FFS_SUCCESS;
1104 /* get the directory entry of given file */
1105 if (p_fs->vol_type == EXFAT) {
1106 es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep);
1107 if (es == NULL)
1108 return FFS_MEDIAERR;
1109 } else {
1110 ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
1111 if (!ep)
1112 return FFS_MEDIAERR;
1115 type = p_fs->fs_func->get_entry_type(ep);
1117 if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) ||
1118 ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) {
1119 INT32 err;
1120 if (p_fs->dev_ejected)
1121 err = FFS_MEDIAERR;
1122 else
1123 err = FFS_ERROR;
1125 if (p_fs->vol_type == EXFAT)
1126 release_entry_set(es);
1127 return err;
1130 fs_set_vol_flags(sb, VOL_DIRTY);
1132 /* set the file attribute */
1133 fid->attr = attr;
1134 p_fs->fs_func->set_entry_attr(ep, attr);
1136 if (p_fs->vol_type != EXFAT)
1137 buf_modify(sb, sector);
1138 else {
1139 update_dir_checksum_with_entry_set(sb, es);
1140 release_entry_set(es);
1143 #if (DELAYED_SYNC == 0)
1144 fs_sync(sb, 0);
1145 fs_set_vol_flags(sb, VOL_CLEAN);
1146 #endif
1148 if (p_fs->dev_ejected)
1149 return FFS_MEDIAERR;
1151 return FFS_SUCCESS;
1152 } /* end of ffsSetAttr */
1154 /* ffsGetStat : get the information of a given file */
1155 INT32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info)
1157 UINT32 sector = 0;
1158 INT32 count;
1159 CHAIN_T dir;
1160 UNI_NAME_T uni_name;
1161 TIMESTAMP_T tm;
1162 DENTRY_T *ep, *ep2;
1163 struct super_block *sb = inode->i_sb;
1164 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1165 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
1166 ENTRY_SET_CACHE_T *es=NULL;
1167 UINT8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
1169 PRINTK("ffsGetStat entered\n");
1171 if (is_dir) {
1172 if ((fid->dir.dir == p_fs->root_dir) &&
1173 (fid->entry == -1)) {
1174 info->Attr = ATTR_SUBDIR;
1175 MEMSET((INT8 *) &info->CreateTimestamp, 0, sizeof(DATE_TIME_T));
1176 MEMSET((INT8 *) &info->ModifyTimestamp, 0, sizeof(DATE_TIME_T));
1177 MEMSET((INT8 *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T));
1178 STRCPY(info->ShortName, ".");
1179 STRCPY(info->Name, ".");
1181 dir.dir = p_fs->root_dir;
1182 dir.flags = 0x01;
1184 if (p_fs->root_dir == CLUSTER_32(0)) /* FAT16 root_dir */
1185 info->Size = p_fs->dentries_in_root << DENTRY_SIZE_BITS;
1186 else
1187 info->Size = count_num_clusters(sb, &dir) << p_fs->cluster_size_bits;
1189 count = count_dos_name_entries(sb, &dir, TYPE_DIR);
1190 if (count < 0)
1191 return FFS_MEDIAERR;
1192 info->NumSubdirs = count;
1194 if (p_fs->dev_ejected)
1195 return FFS_MEDIAERR;
1196 return FFS_SUCCESS;
1200 /* get the directory entry of given file or directory */
1201 if (p_fs->vol_type == EXFAT) {
1202 es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_2_ENTRIES, &ep);
1203 if (es == NULL)
1204 return FFS_MEDIAERR;
1205 ep2 = ep+1;
1206 } else {
1207 ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
1208 if (!ep)
1209 return FFS_MEDIAERR;
1210 ep2 = ep;
1211 buf_lock(sb, sector);
1214 /* set FILE_INFO structure using the acquired DENTRY_T */
1215 info->Attr = p_fs->fs_func->get_entry_attr(ep);
1217 p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE);
1218 info->CreateTimestamp.Year = tm.year;
1219 info->CreateTimestamp.Month = tm.mon;
1220 info->CreateTimestamp.Day = tm.day;
1221 info->CreateTimestamp.Hour = tm.hour;
1222 info->CreateTimestamp.Minute = tm.min;
1223 info->CreateTimestamp.Second = tm.sec;
1224 info->CreateTimestamp.MilliSecond = 0;
1226 p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY);
1227 info->ModifyTimestamp.Year = tm.year;
1228 info->ModifyTimestamp.Month = tm.mon;
1229 info->ModifyTimestamp.Day = tm.day;
1230 info->ModifyTimestamp.Hour = tm.hour;
1231 info->ModifyTimestamp.Minute = tm.min;
1232 info->ModifyTimestamp.Second = tm.sec;
1233 info->ModifyTimestamp.MilliSecond = 0;
1235 MEMSET((INT8 *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T));
1237 *(uni_name.name) = 0x0;
1238 /* XXX this is very bad for exfat cuz name is already included in es.
1239 API should be revised */
1240 p_fs->fs_func->get_uni_name_from_ext_entry(sb, &(fid->dir), fid->entry, uni_name.name);
1241 if (*(uni_name.name) == 0x0)
1242 get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1);
1243 nls_uniname_to_cstring(sb, info->Name, &uni_name);
1245 if (p_fs->vol_type == EXFAT) {
1246 info->NumSubdirs = 2;
1247 } else {
1248 buf_unlock(sb, sector);
1249 get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0);
1250 nls_uniname_to_cstring(sb, info->ShortName, &uni_name);
1251 info->NumSubdirs = 0;
1254 info->Size = p_fs->fs_func->get_entry_size(ep2);
1256 if (p_fs->vol_type == EXFAT)
1257 release_entry_set(es);
1259 if (is_dir) {
1260 dir.dir = fid->start_clu;
1261 dir.flags = 0x01;
1263 if (info->Size == 0)
1264 info->Size = (UINT64) count_num_clusters(sb, &dir) << p_fs->cluster_size_bits;
1266 count = count_dos_name_entries(sb, &dir, TYPE_DIR);
1267 if (count < 0)
1268 return FFS_MEDIAERR;
1269 info->NumSubdirs += count;
1272 if (p_fs->dev_ejected)
1273 return FFS_MEDIAERR;
1275 PRINTK("ffsGetStat exited successfully\n");
1276 return FFS_SUCCESS;
1277 } /* end of ffsGetStat */
1279 /* ffsSetStat : set the information of a given file */
1280 INT32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info)
1282 UINT32 sector = 0;
1283 TIMESTAMP_T tm;
1284 DENTRY_T *ep, *ep2;
1285 ENTRY_SET_CACHE_T *es=NULL;
1286 struct super_block *sb = inode->i_sb;
1287 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1288 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
1289 UINT8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
1291 if (is_dir) {
1292 if ((fid->dir.dir == p_fs->root_dir) &&
1293 (fid->entry == -1)) {
1294 if (p_fs->dev_ejected)
1295 return FFS_MEDIAERR;
1296 return FFS_SUCCESS;
1300 fs_set_vol_flags(sb, VOL_DIRTY);
1302 /* get the directory entry of given file or directory */
1303 if (p_fs->vol_type == EXFAT) {
1304 es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep);
1305 if (es == NULL)
1306 return FFS_MEDIAERR;
1307 ep2 = ep+1;
1308 } else {
1309 /* for other than exfat */
1310 ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
1311 if (!ep)
1312 return FFS_MEDIAERR;
1313 ep2 = ep;
1317 p_fs->fs_func->set_entry_attr(ep, info->Attr);
1319 /* set FILE_INFO structure using the acquired DENTRY_T */
1320 tm.sec = info->CreateTimestamp.Second;
1321 tm.min = info->CreateTimestamp.Minute;
1322 tm.hour = info->CreateTimestamp.Hour;
1323 tm.day = info->CreateTimestamp.Day;
1324 tm.mon = info->CreateTimestamp.Month;
1325 tm.year = info->CreateTimestamp.Year;
1326 p_fs->fs_func->set_entry_time(ep, &tm, TM_CREATE);
1328 tm.sec = info->ModifyTimestamp.Second;
1329 tm.min = info->ModifyTimestamp.Minute;
1330 tm.hour = info->ModifyTimestamp.Hour;
1331 tm.day = info->ModifyTimestamp.Day;
1332 tm.mon = info->ModifyTimestamp.Month;
1333 tm.year = info->ModifyTimestamp.Year;
1334 p_fs->fs_func->set_entry_time(ep, &tm, TM_MODIFY);
1337 p_fs->fs_func->set_entry_size(ep2, info->Size);
1339 if (p_fs->vol_type != EXFAT) {
1340 buf_modify(sb, sector);
1341 } else {
1342 update_dir_checksum_with_entry_set(sb, es);
1343 release_entry_set(es);
1346 if (p_fs->dev_ejected)
1347 return FFS_MEDIAERR;
1349 return FFS_SUCCESS;
1350 } /* end of ffsSetStat */
1352 INT32 ffsMapCluster(struct inode *inode, INT32 clu_offset, UINT32 *clu)
1354 INT32 num_clusters, num_alloced, modified = FALSE;
1355 UINT32 last_clu, sector = 0;
1356 CHAIN_T new_clu;
1357 DENTRY_T *ep;
1358 ENTRY_SET_CACHE_T *es = NULL;
1359 struct super_block *sb = inode->i_sb;
1360 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1361 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
1363 fid->rwoffset = (INT64)(clu_offset) << p_fs->cluster_size_bits;
1365 if (EXFAT_I(inode)->mmu_private == 0)
1366 num_clusters = 0;
1367 else
1368 num_clusters = (INT32)((EXFAT_I(inode)->mmu_private-1) >> p_fs->cluster_size_bits) + 1;
1370 *clu = last_clu = fid->start_clu;
1372 if (fid->flags == 0x03) {
1373 if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) {
1374 last_clu += clu_offset - 1;
1376 if (clu_offset == num_clusters)
1377 *clu = CLUSTER_32(~0);
1378 else
1379 *clu += clu_offset;
1381 } else {
1382 /* hint information */
1383 if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
1384 (clu_offset >= fid->hint_last_off)) {
1385 clu_offset -= fid->hint_last_off;
1386 *clu = fid->hint_last_clu;
1389 while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) {
1390 last_clu = *clu;
1391 if (FAT_read(sb, *clu, clu) == -1)
1392 return FFS_MEDIAERR;
1393 clu_offset--;
1397 if (*clu == CLUSTER_32(~0)) {
1398 fs_set_vol_flags(sb, VOL_DIRTY);
1400 new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1;
1401 new_clu.size = 0;
1402 new_clu.flags = fid->flags;
1404 /* (1) allocate a cluster */
1405 num_alloced = p_fs->fs_func->alloc_cluster(sb, 1, &new_clu);
1406 if (num_alloced < 1)
1407 return FFS_FULL;
1409 /* (2) append to the FAT chain */
1410 if (last_clu == CLUSTER_32(~0)) {
1411 if (new_clu.flags == 0x01)
1412 fid->flags = 0x01;
1413 fid->start_clu = new_clu.dir;
1414 modified = TRUE;
1415 } else {
1416 if (new_clu.flags != fid->flags) {
1417 exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters);
1418 fid->flags = 0x01;
1419 modified = TRUE;
1421 if (new_clu.flags == 0x01)
1422 FAT_write(sb, last_clu, new_clu.dir);
1425 *clu = new_clu.dir;
1427 if (p_fs->vol_type == EXFAT) {
1428 es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep);
1429 if (es == NULL)
1430 return FFS_MEDIAERR;
1431 /* get stream entry */
1432 ep++;
1435 /* (3) update directory entry */
1436 if (modified) {
1437 if (p_fs->vol_type != EXFAT) {
1438 ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, &sector);
1439 if (!ep)
1440 return FFS_MEDIAERR;
1443 if (p_fs->fs_func->get_entry_flag(ep) != fid->flags)
1444 p_fs->fs_func->set_entry_flag(ep, fid->flags);
1446 if (p_fs->fs_func->get_entry_clu0(ep) != fid->start_clu)
1447 p_fs->fs_func->set_entry_clu0(ep, fid->start_clu);
1449 if (p_fs->vol_type != EXFAT)
1450 buf_modify(sb, sector);
1453 if (p_fs->vol_type == EXFAT) {
1454 update_dir_checksum_with_entry_set(sb, es);
1455 release_entry_set(es);
1458 /* add number of new blocks to inode */
1459 inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9);
1462 /* hint information */
1463 fid->hint_last_off = (INT32)(fid->rwoffset >> p_fs->cluster_size_bits);
1464 fid->hint_last_clu = *clu;
1466 if (p_fs->dev_ejected)
1467 return FFS_MEDIAERR;
1469 return FFS_SUCCESS;
1470 } /* end of ffsMapCluster */
1472 /*----------------------------------------------------------------------*/
1473 /* Directory Operation Functions */
1474 /*----------------------------------------------------------------------*/
1476 /* ffsCreateDir : create(make) a directory */
1477 INT32 ffsCreateDir(struct inode *inode, UINT8 *path, FILE_ID_T *fid)
1479 INT32 ret/*, dentry*/;
1480 CHAIN_T dir;
1481 UNI_NAME_T uni_name;
1482 struct super_block *sb = inode->i_sb;
1483 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1485 PRINTK("ffsCreateDir entered\n");
1487 /* check the validity of directory name in the given old pathname */
1488 ret = resolve_path(inode, path, &dir, &uni_name);
1489 if (ret)
1490 return ret;
1492 fs_set_vol_flags(sb, VOL_DIRTY);
1494 ret = create_dir(inode, &dir, &uni_name, fid);
1496 #if (DELAYED_SYNC == 0)
1497 fs_sync(sb, 0);
1498 fs_set_vol_flags(sb, VOL_CLEAN);
1499 #endif
1501 if (p_fs->dev_ejected)
1502 return FFS_MEDIAERR;
1504 return ret;
1505 } /* end of ffsCreateDir */
1507 /* ffsReadDir : read a directory entry from the opened directory */
1508 INT32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry)
1510 INT32 i, dentry, clu_offset;
1511 INT32 dentries_per_clu, dentries_per_clu_bits = 0;
1512 UINT32 type, sector;
1513 CHAIN_T dir, clu;
1514 UNI_NAME_T uni_name;
1515 TIMESTAMP_T tm;
1516 DENTRY_T *ep;
1517 struct super_block *sb = inode->i_sb;
1518 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1519 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
1521 /* check if the given file ID is opened */
1522 if (fid->type != TYPE_DIR)
1523 return FFS_PERMISSIONERR;
1525 if (fid->entry == -1) {
1526 dir.dir = p_fs->root_dir;
1527 dir.flags = 0x01;
1528 } else {
1529 dir.dir = fid->start_clu;
1530 dir.size = (INT32)(fid->size >> p_fs->cluster_size_bits);
1531 dir.flags = fid->flags;
1534 dentry = (INT32) fid->rwoffset;
1536 if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */
1537 dentries_per_clu = p_fs->dentries_in_root;
1539 if (dentry == dentries_per_clu) {
1540 clu.dir = CLUSTER_32(~0);
1541 } else {
1542 clu.dir = dir.dir;
1543 clu.size = dir.size;
1544 clu.flags = dir.flags;
1546 } else {
1547 dentries_per_clu = p_fs->dentries_per_clu;
1548 dentries_per_clu_bits = my_log2(dentries_per_clu);
1550 clu_offset = dentry >> dentries_per_clu_bits;
1551 clu.dir = dir.dir;
1552 clu.size = dir.size;
1553 clu.flags = dir.flags;
1555 if (clu.flags == 0x03) {
1556 clu.dir += clu_offset;
1557 clu.size -= clu_offset;
1558 } else {
1559 /* hint_information */
1560 if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
1561 (clu_offset >= fid->hint_last_off)) {
1562 clu_offset -= fid->hint_last_off;
1563 clu.dir = fid->hint_last_clu;
1566 while (clu_offset > 0) {
1567 /* clu.dir = FAT_read(sb, clu.dir); */
1568 if (FAT_read(sb, clu.dir, &(clu.dir)) == -1)
1569 return FFS_MEDIAERR;
1571 clu_offset--;
1576 while (clu.dir != CLUSTER_32(~0)) {
1577 if (p_fs->dev_ejected)
1578 break;
1580 if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */
1581 i = dentry % dentries_per_clu;
1582 else
1583 i = dentry & (dentries_per_clu-1);
1585 for ( ; i < dentries_per_clu; i++, dentry++) {
1586 ep = get_entry_in_dir(sb, &clu, i, &sector);
1587 if (!ep)
1588 return FFS_MEDIAERR;
1590 type = p_fs->fs_func->get_entry_type(ep);
1592 if (type == TYPE_UNUSED)
1593 break;
1595 if ((type != TYPE_FILE) && (type != TYPE_DIR))
1596 continue;
1598 buf_lock(sb, sector);
1599 dir_entry->Attr = p_fs->fs_func->get_entry_attr(ep);
1601 p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE);
1602 dir_entry->CreateTimestamp.Year = tm.year;
1603 dir_entry->CreateTimestamp.Month = tm.mon;
1604 dir_entry->CreateTimestamp.Day = tm.day;
1605 dir_entry->CreateTimestamp.Hour = tm.hour;
1606 dir_entry->CreateTimestamp.Minute = tm.min;
1607 dir_entry->CreateTimestamp.Second = tm.sec;
1608 dir_entry->CreateTimestamp.MilliSecond = 0;
1610 p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY);
1611 dir_entry->ModifyTimestamp.Year = tm.year;
1612 dir_entry->ModifyTimestamp.Month = tm.mon;
1613 dir_entry->ModifyTimestamp.Day = tm.day;
1614 dir_entry->ModifyTimestamp.Hour = tm.hour;
1615 dir_entry->ModifyTimestamp.Minute = tm.min;
1616 dir_entry->ModifyTimestamp.Second = tm.sec;
1617 dir_entry->ModifyTimestamp.MilliSecond = 0;
1619 MEMSET((INT8 *) &dir_entry->AccessTimestamp, 0, sizeof(DATE_TIME_T));
1621 *(uni_name.name) = 0x0;
1622 p_fs->fs_func->get_uni_name_from_ext_entry(sb, &dir, dentry, uni_name.name);
1623 if (*(uni_name.name) == 0x0)
1624 get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1);
1625 nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name);
1626 buf_unlock(sb, sector);
1628 if (p_fs->vol_type == EXFAT) {
1629 ep = get_entry_in_dir(sb, &clu, i+1, NULL);
1630 if (!ep)
1631 return FFS_MEDIAERR;
1632 } else {
1633 get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0);
1634 nls_uniname_to_cstring(sb, dir_entry->ShortName, &uni_name);
1637 dir_entry->Size = p_fs->fs_func->get_entry_size(ep);
1639 /* hint information */
1640 if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */
1641 } else {
1642 fid->hint_last_off = dentry >> dentries_per_clu_bits;
1643 fid->hint_last_clu = clu.dir;
1646 fid->rwoffset = (INT64) ++dentry;
1648 if (p_fs->dev_ejected)
1649 return FFS_MEDIAERR;
1651 return FFS_SUCCESS;
1654 if (dir.dir == CLUSTER_32(0))
1655 break; /* FAT16 root_dir */
1657 if (clu.flags == 0x03) {
1658 if ((--clu.size) > 0)
1659 clu.dir++;
1660 else
1661 clu.dir = CLUSTER_32(~0);
1662 } else {
1663 /* clu.dir = FAT_read(sb, clu.dir); */
1664 if (FAT_read(sb, clu.dir, &(clu.dir)) == -1)
1665 return FFS_MEDIAERR;
1669 *(dir_entry->Name) = '\0';
1671 fid->rwoffset = (INT64) ++dentry;
1673 if (p_fs->dev_ejected)
1674 return FFS_MEDIAERR;
1676 return FFS_SUCCESS;
1677 } /* end of ffsReadDir */
1679 /* ffsRemoveDir : remove a directory */
1680 INT32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid)
1682 INT32 dentry;
1683 CHAIN_T dir, clu_to_free;
1684 struct super_block *sb = inode->i_sb;
1685 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1687 dir.dir = fid->dir.dir;
1688 dir.size = fid->dir.size;
1689 dir.flags = fid->dir.flags;
1691 dentry = fid->entry;
1693 /* check if the file is "." or ".." */
1694 if (p_fs->vol_type != EXFAT) {
1695 if ((dir.dir != p_fs->root_dir) && (dentry < 2))
1696 return FFS_PERMISSIONERR;
1699 clu_to_free.dir = fid->start_clu;
1700 clu_to_free.size = (INT32)((fid->size-1) >> p_fs->cluster_size_bits) + 1;
1701 clu_to_free.flags = fid->flags;
1703 if (!is_dir_empty(sb, &clu_to_free))
1704 return FFS_FILEEXIST;
1706 fs_set_vol_flags(sb, VOL_DIRTY);
1708 /* (1) update the directory entry */
1709 remove_file(inode, &dir, dentry);
1711 /* (2) free the clusters */
1712 p_fs->fs_func->free_cluster(sb, &clu_to_free, 1);
1714 fid->size = 0;
1715 fid->start_clu = CLUSTER_32(~0);
1716 fid->flags = (p_fs->vol_type == EXFAT)? 0x03: 0x01;
1718 #if (DELAYED_SYNC == 0)
1719 fs_sync(sb, 0);
1720 fs_set_vol_flags(sb, VOL_CLEAN);
1721 #endif
1723 if (p_fs->dev_ejected)
1724 return FFS_MEDIAERR;
1726 return FFS_SUCCESS;
1727 } /* end of ffsRemoveDir */
1729 /*======================================================================*/
1730 /* Local Function Definitions */
1731 /*======================================================================*/
1734 * File System Management Functions
1737 INT32 fs_init(void)
1739 /* critical check for system requirement on size of DENTRY_T structure */
1740 if (sizeof(DENTRY_T) != DENTRY_SIZE) {
1741 return FFS_ALIGNMENTERR;
1744 if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE) {
1745 return FFS_ALIGNMENTERR;
1748 if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE) {
1749 return FFS_ALIGNMENTERR;
1752 if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE) {
1753 return FFS_ALIGNMENTERR;
1756 if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE) {
1757 return FFS_ALIGNMENTERR;
1760 if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE) {
1761 return FFS_ALIGNMENTERR;
1764 if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE) {
1765 return FFS_ALIGNMENTERR;
1768 if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE) {
1769 return FFS_ALIGNMENTERR;
1772 if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE) {
1773 return FFS_ALIGNMENTERR;
1776 return FFS_SUCCESS;
1777 } /* end of fs_init */
1779 INT32 fs_shutdown(void)
1781 return FFS_SUCCESS;
1782 } /* end of fs_shutdown */
1784 void fs_set_vol_flags(struct super_block *sb, UINT32 new_flag)
1786 PBR_SECTOR_T *p_pbr;
1787 BPBEX_T *p_bpb;
1788 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1790 if (p_fs->vol_flag == new_flag)
1791 return;
1793 p_fs->vol_flag = new_flag;
1795 if (p_fs->vol_type == EXFAT) {
1796 if (p_fs->pbr_bh == NULL) {
1797 if (sector_read(sb, p_fs->PBR_sector, &(p_fs->pbr_bh), 1) != FFS_SUCCESS)
1798 return;
1801 p_pbr = (PBR_SECTOR_T *) p_fs->pbr_bh->b_data;
1802 p_bpb = (BPBEX_T *) p_pbr->bpb;
1803 SET16(p_bpb->vol_flags, (UINT16) new_flag);
1805 /* XXX duyoung
1806 what can we do here? (cuz fs_set_vol_flags() is void) */
1807 if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh)))
1808 sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1);
1809 else
1810 sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0);
1812 } /* end of fs_set_vol_flags */
1814 void fs_sync(struct super_block *sb, INT32 do_sync)
1816 if (do_sync)
1817 bdev_sync(sb);
1818 } /* end of fs_sync */
1820 void fs_error(struct super_block *sb)
1822 struct exfat_mount_options *opts = &EXFAT_SB(sb)->options;
1824 if (opts->errors == EXFAT_ERRORS_PANIC)
1825 panic("[EXFAT] Filesystem panic from previous error\n");
1826 else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & MS_RDONLY)) {
1827 sb->s_flags |= MS_RDONLY;
1828 printk(KERN_ERR "[EXFAT] Filesystem has been set read-only\n");
1833 * Cluster Management Functions
1836 INT32 clear_cluster(struct super_block *sb, UINT32 clu)
1838 UINT32 s, n;
1839 INT32 ret = FFS_SUCCESS;
1840 struct buffer_head *tmp_bh = NULL;
1841 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1842 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
1844 if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */
1845 s = p_fs->root_start_sector;
1846 n = p_fs->data_start_sector;
1847 } else {
1848 s = START_SECTOR(clu);
1849 n = s + p_fs->sectors_per_clu;
1852 for ( ; s < n; s++) {
1853 if ((ret = sector_read(sb, s, &tmp_bh, 0)) != FFS_SUCCESS)
1854 return ret;
1856 MEMSET((INT8 *) tmp_bh->b_data, 0x0, p_bd->sector_size);
1857 if ((ret = sector_write(sb, s, tmp_bh, 0)) !=FFS_SUCCESS)
1858 break;
1861 brelse(tmp_bh);
1862 return ret;
1863 } /* end of clear_cluster */
1865 INT32 fat_alloc_cluster(struct super_block *sb, INT32 num_alloc, CHAIN_T *p_chain)
1867 INT32 i, num_clusters = 0;
1868 UINT32 new_clu, last_clu = CLUSTER_32(~0), read_clu;
1869 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1871 new_clu = p_chain->dir;
1872 if (new_clu == CLUSTER_32(~0))
1873 new_clu = p_fs->clu_srch_ptr;
1874 else if (new_clu >= p_fs->num_clusters)
1875 new_clu = 2;
1877 __set_sb_dirty(sb);
1879 p_chain->dir = CLUSTER_32(~0);
1881 for (i = 2; i < p_fs->num_clusters; i++) {
1882 if (FAT_read(sb, new_clu, &read_clu) != 0)
1883 return 0;
1885 if (read_clu == CLUSTER_32(0)) {
1886 FAT_write(sb, new_clu, CLUSTER_32(~0));
1887 num_clusters++;
1889 if (p_chain->dir == CLUSTER_32(~0))
1890 p_chain->dir = new_clu;
1891 else
1892 FAT_write(sb, last_clu, new_clu);
1894 last_clu = new_clu;
1896 if ((--num_alloc) == 0) {
1897 p_fs->clu_srch_ptr = new_clu;
1898 if (p_fs->used_clusters != (UINT32) ~0)
1899 p_fs->used_clusters += num_clusters;
1901 return(num_clusters);
1904 if ((++new_clu) >= p_fs->num_clusters)
1905 new_clu = 2;
1908 p_fs->clu_srch_ptr = new_clu;
1909 if (p_fs->used_clusters != (UINT32) ~0)
1910 p_fs->used_clusters += num_clusters;
1912 return(num_clusters);
1913 } /* end of fat_alloc_cluster */
1915 INT32 exfat_alloc_cluster(struct super_block *sb, INT32 num_alloc, CHAIN_T *p_chain)
1917 INT32 num_clusters = 0;
1918 UINT32 hint_clu, new_clu, last_clu = CLUSTER_32(~0);
1919 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1921 hint_clu = p_chain->dir;
1922 if (hint_clu == CLUSTER_32(~0)) {
1923 hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr-2);
1924 if (hint_clu == CLUSTER_32(~0))
1925 return 0;
1926 } else if (hint_clu >= p_fs->num_clusters) {
1927 hint_clu = 2;
1928 p_chain->flags = 0x01;
1931 __set_sb_dirty(sb);
1933 p_chain->dir = CLUSTER_32(~0);
1935 while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUSTER_32(~0)) {
1936 if (new_clu != hint_clu) {
1937 if (p_chain->flags == 0x03) {
1938 exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters);
1939 p_chain->flags = 0x01;
1943 if (set_alloc_bitmap(sb, new_clu-2) != FFS_SUCCESS)
1944 return 0;
1946 num_clusters++;
1948 if (p_chain->flags == 0x01)
1949 FAT_write(sb, new_clu, CLUSTER_32(~0));
1951 if (p_chain->dir == CLUSTER_32(~0)) {
1952 p_chain->dir = new_clu;
1953 } else {
1954 if (p_chain->flags == 0x01)
1955 FAT_write(sb, last_clu, new_clu);
1957 last_clu = new_clu;
1959 if ((--num_alloc) == 0) {
1960 p_fs->clu_srch_ptr = hint_clu;
1961 if (p_fs->used_clusters != (UINT32) ~0)
1962 p_fs->used_clusters += num_clusters;
1964 p_chain->size += num_clusters;
1965 return(num_clusters);
1968 hint_clu = new_clu + 1;
1969 if (hint_clu >= p_fs->num_clusters) {
1970 hint_clu = 2;
1972 if (p_chain->flags == 0x03) {
1973 exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters);
1974 p_chain->flags = 0x01;
1979 p_fs->clu_srch_ptr = hint_clu;
1980 if (p_fs->used_clusters != (UINT32) ~0)
1981 p_fs->used_clusters += num_clusters;
1983 p_chain->size += num_clusters;
1984 return(num_clusters);
1985 } /* end of exfat_alloc_cluster */
1987 void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, INT32 do_relse)
1989 INT32 num_clusters = 0;
1990 UINT32 clu, prev;
1991 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
1992 INT32 i;
1993 UINT32 sector;
1995 if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
1996 return;
1997 __set_sb_dirty(sb);
1998 clu = p_chain->dir;
2000 if (p_chain->size <= 0)
2001 return;
2003 do {
2004 if (p_fs->dev_ejected)
2005 break;
2007 if (do_relse) {
2008 sector = START_SECTOR(clu);
2009 for (i = 0; i < p_fs->sectors_per_clu; i++) {
2010 buf_release(sb, sector+i);
2014 prev = clu;
2015 if (FAT_read(sb, clu, &clu) == -1)
2016 break;
2018 FAT_write(sb, prev, CLUSTER_32(0));
2019 num_clusters++;
2021 } while (clu != CLUSTER_32(~0));
2023 if (p_fs->used_clusters != (UINT32) ~0)
2024 p_fs->used_clusters -= num_clusters;
2025 } /* end of fat_free_cluster */
2027 void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, INT32 do_relse)
2029 INT32 num_clusters = 0;
2030 UINT32 clu;
2031 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2032 INT32 i;
2033 UINT32 sector;
2035 if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
2036 return;
2038 if (p_chain->size <= 0) {
2039 printk(KERN_ERR "[EXFAT] free_cluster : skip free-req clu:%u, "
2040 "because of zero-size truncation\n"
2041 ,p_chain->dir);
2042 return;
2045 __set_sb_dirty(sb);
2046 clu = p_chain->dir;
2048 if (p_chain->flags == 0x03) {
2049 do {
2050 if (do_relse) {
2051 sector = START_SECTOR(clu);
2052 for (i = 0; i < p_fs->sectors_per_clu; i++) {
2053 buf_release(sb, sector+i);
2057 if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS)
2058 break;
2059 clu++;
2061 num_clusters++;
2062 } while (num_clusters < p_chain->size);
2063 } else {
2064 do {
2065 if (p_fs->dev_ejected)
2066 break;
2068 if (do_relse) {
2069 sector = START_SECTOR(clu);
2070 for (i = 0; i < p_fs->sectors_per_clu; i++) {
2071 buf_release(sb, sector+i);
2075 if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS)
2076 break;
2078 if (FAT_read(sb, clu, &clu) == -1)
2079 break;
2080 num_clusters++;
2081 } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0)));
2084 if (p_fs->used_clusters != (UINT32) ~0)
2085 p_fs->used_clusters -= num_clusters;
2086 } /* end of exfat_free_cluster */
2088 UINT32 find_last_cluster(struct super_block *sb, CHAIN_T *p_chain)
2090 UINT32 clu, next;
2091 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2093 clu = p_chain->dir;
2095 if (p_chain->flags == 0x03) {
2096 clu += p_chain->size - 1;
2097 } else {
2098 while((FAT_read(sb, clu, &next) == 0) && (next != CLUSTER_32(~0))) {
2099 if (p_fs->dev_ejected)
2100 break;
2101 clu = next;
2105 return(clu);
2106 } /* end of find_last_cluster */
2108 INT32 count_num_clusters(struct super_block *sb, CHAIN_T *p_chain)
2110 INT32 i, count = 0;
2111 UINT32 clu;
2112 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2114 if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
2115 return 0;
2117 clu = p_chain->dir;
2119 if (p_chain->flags == 0x03) {
2120 count = p_chain->size;
2121 } else {
2122 for (i = 2; i < p_fs->num_clusters; i++) {
2123 count++;
2124 if (FAT_read(sb, clu, &clu) != 0)
2125 return 0;
2126 if (clu == CLUSTER_32(~0))
2127 break;
2131 return(count);
2132 } /* end of count_num_clusters */
2134 INT32 fat_count_used_clusters(struct super_block *sb)
2136 INT32 i, count = 0;
2137 UINT32 clu;
2138 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2140 for (i = 2; i < p_fs->num_clusters; i++) {
2141 if (FAT_read(sb, i, &clu) != 0)
2142 break;
2143 if (clu != CLUSTER_32(0))
2144 count++;
2147 return(count);
2148 } /* end of fat_count_used_clusters */
2150 INT32 exfat_count_used_clusters(struct super_block *sb)
2152 INT32 i, map_i, map_b, count = 0;
2153 UINT8 k;
2154 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2155 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
2157 map_i = map_b = 0;
2159 for (i = 2; i < p_fs->num_clusters; i += 8) {
2160 k = *(((UINT8 *) p_fs->vol_amap[map_i]->b_data) + map_b);
2161 count += used_bit[k];
2163 if ((++map_b) >= p_bd->sector_size) {
2164 map_i++;
2165 map_b = 0;
2169 return(count);
2170 } /* end of exfat_count_used_clusters */
2172 void exfat_chain_cont_cluster(struct super_block *sb, UINT32 chain, INT32 len)
2174 if (len == 0)
2175 return;
2177 while (len > 1) {
2178 FAT_write(sb, chain, chain+1);
2179 chain++;
2180 len--;
2182 FAT_write(sb, chain, CLUSTER_32(~0));
2183 } /* end of exfat_chain_cont_cluster */
2186 * Allocation Bitmap Management Functions
2189 INT32 load_alloc_bitmap(struct super_block *sb)
2191 INT32 i, j, ret;
2192 UINT32 map_size;
2193 UINT32 type, sector;
2194 CHAIN_T clu;
2195 BMAP_DENTRY_T *ep;
2196 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2197 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
2199 clu.dir = p_fs->root_dir;
2200 clu.flags = 0x01;
2202 while (clu.dir != CLUSTER_32(~0)) {
2203 if (p_fs->dev_ejected)
2204 break;
2206 for (i = 0; i < p_fs->dentries_per_clu; i++) {
2207 ep = (BMAP_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL);
2208 if (!ep)
2209 return FFS_MEDIAERR;
2211 type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep);
2213 if (type == TYPE_UNUSED)
2214 break;
2215 if (type != TYPE_BITMAP)
2216 continue;
2218 if (ep->flags == 0x0) {
2219 p_fs->map_clu = GET32_A(ep->start_clu);
2220 map_size = (UINT32) GET64_A(ep->size);
2222 p_fs->map_sectors = ((map_size-1) >> p_bd->sector_size_bits) + 1;
2224 p_fs->vol_amap = (struct buffer_head **) MALLOC(sizeof(struct buffer_head *) * p_fs->map_sectors);
2225 if (p_fs->vol_amap == NULL)
2226 return FFS_MEMORYERR;
2228 sector = START_SECTOR(p_fs->map_clu);
2230 for (j = 0; j < p_fs->map_sectors; j++) {
2231 p_fs->vol_amap[j] = NULL;
2232 ret = sector_read(sb, sector+j, &(p_fs->vol_amap[j]), 1);
2233 if (ret != FFS_SUCCESS) {
2234 /* release all buffers and free vol_amap */
2235 i=0;
2236 while (i < j)
2237 brelse(p_fs->vol_amap[i++]);
2239 FREE(p_fs->vol_amap);
2240 p_fs->vol_amap = NULL;
2241 return ret;
2245 p_fs->pbr_bh = NULL;
2246 return FFS_SUCCESS;
2250 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
2251 return FFS_MEDIAERR;
2254 return FFS_FORMATERR;
2255 } /* end of load_alloc_bitmap */
2257 void free_alloc_bitmap(struct super_block *sb)
2259 INT32 i;
2260 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2262 brelse(p_fs->pbr_bh);
2264 for (i = 0; i < p_fs->map_sectors; i++) {
2265 __brelse(p_fs->vol_amap[i]);
2268 FREE(p_fs->vol_amap);
2269 p_fs->vol_amap = NULL;
2270 } /* end of free_alloc_bitmap */
2272 INT32 set_alloc_bitmap(struct super_block *sb, UINT32 clu)
2274 INT32 i, b;
2275 UINT32 sector;
2276 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2277 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
2279 i = clu >> (p_bd->sector_size_bits + 3);
2280 b = clu & ((p_bd->sector_size << 3) - 1);
2282 sector = START_SECTOR(p_fs->map_clu) + i;
2284 Bitmap_set((UINT8 *) p_fs->vol_amap[i]->b_data, b);
2286 return (sector_write(sb, sector, p_fs->vol_amap[i], 0));
2287 } /* end of set_alloc_bitmap */
2289 INT32 clr_alloc_bitmap(struct super_block *sb, UINT32 clu)
2291 INT32 i, b;
2292 UINT32 sector;
2293 #if EXFAT_CONFIG_DISCARD
2294 struct exfat_sb_info *sbi = EXFAT_SB(sb);
2295 struct exfat_mount_options *opts = &sbi->options;
2296 int ret;
2297 #endif /* EXFAT_CONFIG_DISCARD */
2298 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2299 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
2301 i = clu >> (p_bd->sector_size_bits + 3);
2302 b = clu & ((p_bd->sector_size << 3) - 1);
2304 sector = START_SECTOR(p_fs->map_clu) + i;
2306 Bitmap_clear((UINT8 *) p_fs->vol_amap[i]->b_data, b);
2308 return (sector_write(sb, sector, p_fs->vol_amap[i], 0));
2310 #if EXFAT_CONFIG_DISCARD
2311 if (opts->discard) {
2312 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
2313 ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits));
2314 #else
2315 ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits), GFP_NOFS, 0);
2316 #endif
2317 if (ret == -EOPNOTSUPP) {
2318 printk(KERN_WARNING "discard not supported by device, disabling");
2319 opts->discard = 0;
2322 #endif /* EXFAT_CONFIG_DISCARD */
2323 } /* end of clr_alloc_bitmap */
2325 UINT32 test_alloc_bitmap(struct super_block *sb, UINT32 clu)
2327 INT32 i, map_i, map_b;
2328 UINT32 clu_base, clu_free;
2329 UINT8 k, clu_mask;
2330 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2331 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
2333 clu_base = (clu & ~(0x7)) + 2;
2334 clu_mask = (1 << (clu - clu_base + 2)) - 1;
2336 map_i = clu >> (p_bd->sector_size_bits + 3);
2337 map_b = (clu >> 3) & p_bd->sector_size_mask;
2339 for (i = 2; i < p_fs->num_clusters; i += 8) {
2340 k = *(((UINT8 *) p_fs->vol_amap[map_i]->b_data) + map_b);
2341 if (clu_mask > 0) {
2342 k |= clu_mask;
2343 clu_mask = 0;
2345 if (k < 0xFF) {
2346 clu_free = clu_base + free_bit[k];
2347 if (clu_free < p_fs->num_clusters)
2348 return(clu_free);
2350 clu_base += 8;
2352 if (((++map_b) >= p_bd->sector_size) || (clu_base >= p_fs->num_clusters)) {
2353 if ((++map_i) >= p_fs->map_sectors) {
2354 clu_base = 2;
2355 map_i = 0;
2357 map_b = 0;
2361 return(CLUSTER_32(~0));
2362 } /* end of test_alloc_bitmap */
2364 void sync_alloc_bitmap(struct super_block *sb)
2366 INT32 i;
2367 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2369 if (p_fs->vol_amap == NULL)
2370 return;
2372 for (i = 0; i < p_fs->map_sectors; i++) {
2373 sync_dirty_buffer(p_fs->vol_amap[i]);
2375 } /* end of sync_alloc_bitmap */
2378 * Upcase table Management Functions
2380 INT32 __load_upcase_table(struct super_block *sb, UINT32 sector, UINT32 num_sectors, UINT32 utbl_checksum)
2382 INT32 i, ret = FFS_ERROR;
2383 UINT32 j;
2384 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2385 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
2386 struct buffer_head *tmp_bh = NULL;
2388 UINT8 skip = FALSE;
2389 UINT32 index = 0;
2390 UINT16 uni = 0;
2391 UINT16 **upcase_table;
2393 UINT32 checksum = 0;
2395 upcase_table = p_fs->vol_utbl = (UINT16 **) MALLOC(UTBL_COL_COUNT * sizeof(UINT16 *));
2396 if(upcase_table == NULL)
2397 return FFS_MEMORYERR;
2398 MEMSET(upcase_table, 0, UTBL_COL_COUNT * sizeof(UINT16 *));
2400 num_sectors += sector;
2402 while(sector < num_sectors) {
2403 ret = sector_read(sb, sector, &tmp_bh, 1);
2404 if (ret != FFS_SUCCESS) {
2405 PRINTK("sector read (0x%X)fail\n", sector);
2406 goto error;
2408 sector++;
2410 for(i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) {
2411 uni = GET16(((UINT8 *) tmp_bh->b_data)+i);
2413 checksum = ((checksum & 1) ? 0x80000000 : 0 ) + (checksum >> 1) + *(((UINT8 *) tmp_bh->b_data)+i);
2414 checksum = ((checksum & 1) ? 0x80000000 : 0 ) + (checksum >> 1) + *(((UINT8 *) tmp_bh->b_data)+(i+1));
2416 if(skip) {
2417 PRINTK("skip from 0x%X ", index);
2418 index += uni;
2419 PRINTK("to 0x%X (amount of 0x%X)\n", index, uni);
2420 skip = FALSE;
2421 } else if(uni == index)
2422 index++;
2423 else if(uni == 0xFFFF)
2424 skip = TRUE;
2425 else { /* uni != index , uni != 0xFFFF */
2426 UINT16 col_index = get_col_index(index);
2428 if(upcase_table[col_index]== NULL) {
2429 PRINTK("alloc = 0x%X\n", col_index);
2430 upcase_table[col_index] = (UINT16 *) MALLOC(UTBL_ROW_COUNT * sizeof(UINT16));
2431 if(upcase_table[col_index] == NULL) {
2432 ret = FFS_MEMORYERR;
2433 goto error;
2436 for(j = 0 ; j < UTBL_ROW_COUNT ; j++)
2437 upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
2440 upcase_table[col_index][get_row_index(index)] = uni;
2441 index++;
2445 if(index >= 0xFFFF && utbl_checksum == checksum) {
2446 if(tmp_bh)
2447 brelse(tmp_bh);
2448 return FFS_SUCCESS;
2450 ret = FFS_ERROR;
2451 error:
2452 if(tmp_bh)
2453 brelse(tmp_bh);
2454 free_upcase_table(sb);
2455 return ret;
2458 INT32 __load_default_upcase_table(struct super_block *sb)
2460 INT32 i, ret = FFS_ERROR;
2461 UINT32 j;
2462 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2464 UINT8 skip = FALSE;
2465 UINT32 index = 0;
2466 UINT16 uni = 0;
2467 UINT16 **upcase_table;
2469 upcase_table = p_fs->vol_utbl = (UINT16 **) MALLOC(UTBL_COL_COUNT * sizeof(UINT16 *));
2470 if(upcase_table == NULL)
2471 return FFS_MEMORYERR;
2472 MEMSET(upcase_table, 0, UTBL_COL_COUNT * sizeof(UINT16 *));
2474 for(i = 0; index <= 0xFFFF && i < NUM_UPCASE*2; i += 2) {
2475 uni = GET16(uni_upcase + i);
2476 if(skip) {
2477 PRINTK("skip from 0x%X ", index);
2478 index += uni;
2479 PRINTK("to 0x%X (amount of 0x%X)\n", index, uni);
2480 skip = FALSE;
2481 } else if(uni == index)
2482 index++;
2483 else if(uni == 0xFFFF)
2484 skip = TRUE;
2485 else { /* uni != index , uni != 0xFFFF */
2486 UINT16 col_index = get_col_index(index);
2488 if(upcase_table[col_index]== NULL) {
2489 PRINTK("alloc = 0x%X\n", col_index);
2490 upcase_table[col_index] = (UINT16 *) MALLOC(UTBL_ROW_COUNT * sizeof(UINT16));
2491 if(upcase_table[col_index] == NULL) {
2492 ret = FFS_MEMORYERR;
2493 goto error;
2496 for(j = 0 ; j < UTBL_ROW_COUNT ; j++)
2497 upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
2500 upcase_table[col_index][get_row_index(index)] = uni;
2501 index ++;
2505 if(index >= 0xFFFF)
2506 return FFS_SUCCESS;
2508 error:
2509 /* FATAL error: default upcase table has error */
2510 free_upcase_table(sb);
2511 return ret;
2514 INT32 load_upcase_table(struct super_block *sb)
2516 INT32 i;
2517 UINT32 tbl_clu, tbl_size;
2518 UINT32 type, sector, num_sectors;
2519 CHAIN_T clu;
2520 CASE_DENTRY_T *ep;
2521 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2522 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
2524 clu.dir = p_fs->root_dir;
2525 clu.flags = 0x01;
2527 if (p_fs->dev_ejected)
2528 return FFS_MEDIAERR;
2530 while (clu.dir != CLUSTER_32(~0)) {
2531 for (i = 0; i < p_fs->dentries_per_clu; i++) {
2532 ep = (CASE_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL);
2533 if (!ep)
2534 return FFS_MEDIAERR;
2536 type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep);
2538 if (type == TYPE_UNUSED)
2539 break;
2540 if (type != TYPE_UPCASE)
2541 continue;
2543 tbl_clu = GET32_A(ep->start_clu);
2544 tbl_size = (UINT32) GET64_A(ep->size);
2546 sector = START_SECTOR(tbl_clu);
2547 num_sectors = ((tbl_size-1) >> p_bd->sector_size_bits) + 1;
2548 if(__load_upcase_table(sb, sector, num_sectors, GET32_A(ep->checksum)) != FFS_SUCCESS)
2549 break;
2550 else
2551 return FFS_SUCCESS;
2553 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
2554 return FFS_MEDIAERR;
2556 /* load default upcase table */
2557 return __load_default_upcase_table(sb);
2558 } /* end of load_upcase_table */
2560 void free_upcase_table(struct super_block *sb)
2562 UINT32 i;
2563 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
2564 UINT16 **upcase_table;
2566 upcase_table = p_fs->vol_utbl;
2567 for(i = 0 ; i < UTBL_COL_COUNT ; i ++)
2568 FREE(upcase_table[i]);
2570 FREE(p_fs->vol_utbl);
2572 p_fs->vol_utbl = NULL;
2573 } /* end of free_upcase_table */
2576 * Directory Entry Management Functions
2579 UINT32 fat_get_entry_type(DENTRY_T *p_entry)
2581 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2583 if (*(ep->name) == 0x0)
2584 return TYPE_UNUSED;
2586 else if (*(ep->name) == 0xE5)
2587 return TYPE_DELETED;
2589 else if (ep->attr == ATTR_EXTEND)
2590 return TYPE_EXTEND;
2592 else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_VOLUME)
2593 return TYPE_VOLUME;
2595 else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_SUBDIR)
2596 return TYPE_DIR;
2598 return TYPE_FILE;
2599 } /* end of fat_get_entry_type */
2601 UINT32 exfat_get_entry_type(DENTRY_T *p_entry)
2603 FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
2605 if (ep->type == 0x0) {
2606 return TYPE_UNUSED;
2607 } else if (ep->type < 0x80) {
2608 return TYPE_DELETED;
2609 } else if (ep->type == 0x80) {
2610 return TYPE_INVALID;
2611 } else if (ep->type < 0xA0) {
2612 if (ep->type == 0x81) {
2613 return TYPE_BITMAP;
2614 } else if (ep->type == 0x82) {
2615 return TYPE_UPCASE;
2616 } else if (ep->type == 0x83) {
2617 return TYPE_VOLUME;
2618 } else if (ep->type == 0x85) {
2619 if (GET16_A(ep->attr) & ATTR_SUBDIR)
2620 return TYPE_DIR;
2621 else
2622 return TYPE_FILE;
2624 return TYPE_CRITICAL_PRI;
2625 } else if (ep->type < 0xC0) {
2626 if (ep->type == 0xA0) {
2627 return TYPE_GUID;
2628 } else if (ep->type == 0xA1) {
2629 return TYPE_PADDING;
2630 } else if (ep->type == 0xA2) {
2631 return TYPE_ACLTAB;
2633 return TYPE_BENIGN_PRI;
2634 } else if (ep->type < 0xE0) {
2635 if (ep->type == 0xC0) {
2636 return TYPE_STREAM;
2637 } else if (ep->type == 0xC1) {
2638 return TYPE_EXTEND;
2639 } else if (ep->type == 0xC2) {
2640 return TYPE_ACL;
2642 return TYPE_CRITICAL_SEC;
2645 return TYPE_BENIGN_SEC;
2646 } /* end of exfat_get_entry_type */
2648 void fat_set_entry_type(DENTRY_T *p_entry, UINT32 type)
2650 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2652 if (type == TYPE_UNUSED)
2653 *(ep->name) = 0x0;
2655 else if (type == TYPE_DELETED)
2656 *(ep->name) = 0xE5;
2658 else if (type == TYPE_EXTEND)
2659 ep->attr = ATTR_EXTEND;
2661 else if (type == TYPE_DIR)
2662 ep->attr = ATTR_SUBDIR;
2664 else if (type == TYPE_FILE)
2665 ep->attr = ATTR_ARCHIVE;
2667 else if (type == TYPE_SYMLINK)
2668 ep->attr = ATTR_ARCHIVE | ATTR_SYMLINK;
2669 } /* end of fat_set_entry_type */
2671 void exfat_set_entry_type(DENTRY_T *p_entry, UINT32 type)
2673 FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
2675 if (type == TYPE_UNUSED) {
2676 ep->type = 0x0;
2677 } else if (type == TYPE_DELETED) {
2678 ep->type &= ~0x80;
2679 } else if (type == TYPE_STREAM) {
2680 ep->type = 0xC0;
2681 } else if (type == TYPE_EXTEND) {
2682 ep->type = 0xC1;
2683 } else if (type == TYPE_BITMAP) {
2684 ep->type = 0x81;
2685 } else if (type == TYPE_UPCASE) {
2686 ep->type = 0x82;
2687 } else if (type == TYPE_VOLUME) {
2688 ep->type = 0x83;
2689 } else if (type == TYPE_DIR) {
2690 ep->type = 0x85;
2691 SET16_A(ep->attr, ATTR_SUBDIR);
2692 } else if (type == TYPE_FILE) {
2693 ep->type = 0x85;
2694 SET16_A(ep->attr, ATTR_ARCHIVE);
2695 } else if (type == TYPE_SYMLINK) {
2696 ep->type = 0x85;
2697 SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK);
2699 } /* end of exfat_set_entry_type */
2701 UINT32 fat_get_entry_attr(DENTRY_T *p_entry)
2703 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2704 return((UINT32) ep->attr);
2705 } /* end of fat_get_entry_attr */
2707 UINT32 exfat_get_entry_attr(DENTRY_T *p_entry)
2709 FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
2710 return((UINT32) GET16_A(ep->attr));
2711 } /* end of exfat_get_entry_attr */
2713 void fat_set_entry_attr(DENTRY_T *p_entry, UINT32 attr)
2715 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2716 ep->attr = (UINT8) attr;
2717 } /* end of fat_set_entry_attr */
2719 void exfat_set_entry_attr(DENTRY_T *p_entry, UINT32 attr)
2721 FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
2722 SET16_A(ep->attr, (UINT16) attr);
2723 } /* end of exfat_set_entry_attr */
2725 UINT8 fat_get_entry_flag(DENTRY_T *p_entry)
2727 return 0x01;
2728 } /* end of fat_get_entry_flag */
2730 UINT8 exfat_get_entry_flag(DENTRY_T *p_entry)
2732 STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
2733 return(ep->flags);
2734 } /* end of exfat_get_entry_flag */
2736 void fat_set_entry_flag(DENTRY_T *p_entry, UINT8 flags)
2738 } /* end of fat_set_entry_flag */
2740 void exfat_set_entry_flag(DENTRY_T *p_entry, UINT8 flags)
2742 STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
2743 ep->flags = flags;
2744 } /* end of exfat_set_entry_flag */
2746 UINT32 fat_get_entry_clu0(DENTRY_T *p_entry)
2748 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2749 return((GET32_A(ep->start_clu_hi) << 16) | GET16_A(ep->start_clu_lo));
2750 } /* end of fat_get_entry_clu0 */
2752 UINT32 exfat_get_entry_clu0(DENTRY_T *p_entry)
2754 STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
2755 return(GET32_A(ep->start_clu));
2756 } /* end of exfat_get_entry_clu0 */
2758 void fat_set_entry_clu0(DENTRY_T *p_entry, UINT32 start_clu)
2760 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2761 SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu));
2762 SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16));
2763 } /* end of fat_set_entry_clu0 */
2765 void exfat_set_entry_clu0(DENTRY_T *p_entry, UINT32 start_clu)
2767 STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
2768 SET32_A(ep->start_clu, start_clu);
2769 } /* end of exfat_set_entry_clu0 */
2771 UINT64 fat_get_entry_size(DENTRY_T *p_entry)
2773 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2774 return((UINT64) GET32_A(ep->size));
2775 } /* end of fat_get_entry_size */
2777 UINT64 exfat_get_entry_size(DENTRY_T *p_entry)
2779 STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
2780 return(GET64_A(ep->valid_size));
2781 } /* end of exfat_get_entry_size */
2783 void fat_set_entry_size(DENTRY_T *p_entry, UINT64 size)
2785 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2786 SET32_A(ep->size, (UINT32) size);
2787 } /* end of fat_set_entry_size */
2789 void exfat_set_entry_size(DENTRY_T *p_entry, UINT64 size)
2791 STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry;
2792 SET64_A(ep->valid_size, size);
2793 SET64_A(ep->size, size);
2794 } /* end of exfat_set_entry_size */
2796 void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, UINT8 mode)
2798 UINT16 t = 0x00, d = 0x21;
2799 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2801 switch (mode) {
2802 case TM_CREATE:
2803 t = GET16_A(ep->create_time);
2804 d = GET16_A(ep->create_date);
2805 break;
2806 case TM_MODIFY:
2807 t = GET16_A(ep->modify_time);
2808 d = GET16_A(ep->modify_date);
2809 break;
2812 tp->sec = (t & 0x001F) << 1;
2813 tp->min = (t >> 5) & 0x003F;
2814 tp->hour = (t >> 11);
2815 tp->day = (d & 0x001F);
2816 tp->mon = (d >> 5) & 0x000F;
2817 tp->year = (d >> 9);
2818 } /* end of fat_get_entry_time */
2820 void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, UINT8 mode)
2822 UINT16 t = 0x00, d = 0x21;
2823 FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
2825 switch (mode) {
2826 case TM_CREATE:
2827 t = GET16_A(ep->create_time);
2828 d = GET16_A(ep->create_date);
2829 break;
2830 case TM_MODIFY:
2831 t = GET16_A(ep->modify_time);
2832 d = GET16_A(ep->modify_date);
2833 break;
2834 case TM_ACCESS:
2835 t = GET16_A(ep->access_time);
2836 d = GET16_A(ep->access_date);
2837 break;
2840 tp->sec = (t & 0x001F) << 1;
2841 tp->min = (t >> 5) & 0x003F;
2842 tp->hour = (t >> 11);
2843 tp->day = (d & 0x001F);
2844 tp->mon = (d >> 5) & 0x000F;
2845 tp->year = (d >> 9);
2846 } /* end of exfat_get_entry_time */
2848 void fat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, UINT8 mode)
2850 UINT16 t, d;
2851 DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry;
2853 t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
2854 d = (tp->year << 9) | (tp->mon << 5) | tp->day;
2856 switch (mode) {
2857 case TM_CREATE:
2858 SET16_A(ep->create_time, t);
2859 SET16_A(ep->create_date, d);
2860 break;
2861 case TM_MODIFY:
2862 SET16_A(ep->modify_time, t);
2863 SET16_A(ep->modify_date, d);
2864 break;
2866 } /* end of fat_set_entry_time */
2868 void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, UINT8 mode)
2870 UINT16 t, d;
2871 FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
2873 t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
2874 d = (tp->year << 9) | (tp->mon << 5) | tp->day;
2876 switch (mode) {
2877 case TM_CREATE:
2878 SET16_A(ep->create_time, t);
2879 SET16_A(ep->create_date, d);
2880 break;
2881 case TM_MODIFY:
2882 SET16_A(ep->modify_time, t);
2883 SET16_A(ep->modify_date, d);
2884 break;
2885 case TM_ACCESS:
2886 SET16_A(ep->access_time, t);
2887 SET16_A(ep->access_date, d);
2888 break;
2890 } /* end of exfat_set_entry_time */
2892 INT32 fat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT32 type,
2893 UINT32 start_clu, UINT64 size)
2895 UINT32 sector;
2896 DOS_DENTRY_T *dos_ep;
2898 dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, &sector);
2899 if (!dos_ep)
2900 return FFS_MEDIAERR;
2902 init_dos_entry(dos_ep, type, start_clu);
2903 buf_modify(sb, sector);
2905 return FFS_SUCCESS;
2906 } /* end of fat_init_dir_entry */
2908 INT32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT32 type,
2909 UINT32 start_clu, UINT64 size)
2911 UINT32 sector;
2912 UINT8 flags;
2913 FILE_DENTRY_T *file_ep;
2914 STRM_DENTRY_T *strm_ep;
2916 flags = (type == TYPE_FILE) ? 0x01 : 0x03;
2918 /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */
2919 file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, &sector);
2920 if (!file_ep)
2921 return FFS_MEDIAERR;
2923 strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, &sector);
2924 if (!strm_ep)
2925 return FFS_MEDIAERR;
2927 init_file_entry(file_ep, type);
2928 buf_modify(sb, sector);
2930 init_strm_entry(strm_ep, flags, start_clu, size);
2931 buf_modify(sb, sector);
2933 return FFS_SUCCESS;
2934 } /* end of exfat_init_dir_entry */
2936 INT32 fat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, INT32 num_entries,
2937 UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname)
2939 INT32 i;
2940 UINT32 sector;
2941 UINT8 chksum;
2942 UINT16 *uniname = p_uniname->name;
2943 DOS_DENTRY_T *dos_ep;
2944 EXT_DENTRY_T *ext_ep;
2946 dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, &sector);
2947 if (!dos_ep)
2948 return FFS_MEDIAERR;
2950 dos_ep->lcase = p_dosname->name_case;
2951 MEMCPY(dos_ep->name, p_dosname->name, DOS_NAME_LENGTH);
2952 buf_modify(sb, sector);
2954 if ((--num_entries) > 0) {
2955 chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0);
2957 for (i = 1; i < num_entries; i++) {
2958 ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, &sector);
2959 if (!ext_ep)
2960 return FFS_MEDIAERR;
2962 init_ext_entry(ext_ep, i, chksum, uniname);
2963 buf_modify(sb, sector);
2964 uniname += 13;
2967 ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, &sector);
2968 if (!ext_ep)
2969 return FFS_MEDIAERR;
2971 init_ext_entry(ext_ep, i+0x40, chksum, uniname);
2972 buf_modify(sb, sector);
2975 return FFS_SUCCESS;
2976 } /* end of fat_init_ext_entry */
2978 INT32 exfat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, INT32 num_entries,
2979 UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname)
2981 INT32 i;
2982 UINT32 sector;
2983 UINT16 *uniname = p_uniname->name;
2984 FILE_DENTRY_T *file_ep;
2985 STRM_DENTRY_T *strm_ep;
2986 NAME_DENTRY_T *name_ep;
2988 file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, &sector);
2989 if (!file_ep)
2990 return FFS_MEDIAERR;
2992 file_ep->num_ext = (UINT8)(num_entries - 1);
2993 buf_modify(sb, sector);
2995 strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, &sector);
2996 if (!strm_ep)
2997 return FFS_MEDIAERR;
2999 strm_ep->name_len = p_uniname->name_len;
3000 SET16_A(strm_ep->name_hash, p_uniname->name_hash);
3001 buf_modify(sb, sector);
3003 for (i = 2; i < num_entries; i++) {
3004 name_ep = (NAME_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+i, &sector);
3005 if (!name_ep)
3006 return FFS_MEDIAERR;
3008 init_name_entry(name_ep, uniname);
3009 buf_modify(sb, sector);
3010 uniname += 15;
3013 update_dir_checksum(sb, p_dir, entry);
3015 return FFS_SUCCESS;
3016 } /* end of exfat_init_ext_entry */
3018 void init_dos_entry(DOS_DENTRY_T *ep, UINT32 type, UINT32 start_clu)
3020 TIMESTAMP_T tm, *tp;
3022 fat_set_entry_type((DENTRY_T *) ep, type);
3023 SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu));
3024 SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16));
3025 SET32_A(ep->size, 0);
3027 tp = tm_current(&tm);
3028 fat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE);
3029 fat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY);
3030 SET16_A(ep->access_date, 0);
3031 ep->create_time_ms = 0;
3032 } /* end of init_dos_entry */
3034 void init_ext_entry(EXT_DENTRY_T *ep, INT32 order, UINT8 chksum, UINT16 *uniname)
3036 INT32 i;
3037 UINT8 end = FALSE;
3039 fat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND);
3040 ep->order = (UINT8) order;
3041 ep->sysid = 0;
3042 ep->checksum = chksum;
3043 SET16_A(ep->start_clu, 0);
3045 for (i = 0; i < 10; i += 2) {
3046 if (!end) {
3047 SET16(ep->unicode_0_4+i, *uniname);
3048 if (*uniname == 0x0)
3049 end = TRUE;
3050 else
3051 uniname++;
3052 } else {
3053 SET16(ep->unicode_0_4+i, 0xFFFF);
3057 for (i = 0; i < 12; i += 2) {
3058 if (!end) {
3059 SET16_A(ep->unicode_5_10+i, *uniname);
3060 if (*uniname == 0x0)
3061 end = TRUE;
3062 else
3063 uniname++;
3064 } else {
3065 SET16_A(ep->unicode_5_10+i, 0xFFFF);
3069 for (i = 0; i < 4; i += 2) {
3070 if (!end) {
3071 SET16_A(ep->unicode_11_12+i, *uniname);
3072 if (*uniname == 0x0)
3073 end = TRUE;
3074 else
3075 uniname++;
3076 } else {
3077 SET16_A(ep->unicode_11_12+i, 0xFFFF);
3080 } /* end of init_ext_entry */
3082 void init_file_entry(FILE_DENTRY_T *ep, UINT32 type)
3084 TIMESTAMP_T tm, *tp;
3086 exfat_set_entry_type((DENTRY_T *) ep, type);
3088 tp = tm_current(&tm);
3089 exfat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE);
3090 exfat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY);
3091 exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS);
3092 ep->create_time_ms = 0;
3093 ep->modify_time_ms = 0;
3094 ep->access_time_ms = 0;
3095 } /* end of init_file_entry */
3097 void init_strm_entry(STRM_DENTRY_T *ep, UINT8 flags, UINT32 start_clu, UINT64 size)
3099 exfat_set_entry_type((DENTRY_T *) ep, TYPE_STREAM);
3100 ep->flags = flags;
3101 SET32_A(ep->start_clu, start_clu);
3102 SET64_A(ep->valid_size, size);
3103 SET64_A(ep->size, size);
3104 } /* end of init_strm_entry */
3106 void init_name_entry(NAME_DENTRY_T *ep, UINT16 *uniname)
3108 INT32 i;
3110 exfat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND);
3111 ep->flags = 0x0;
3113 for (i = 0; i < 30; i++, i++) {
3114 SET16_A(ep->unicode_0_14+i, *uniname);
3115 if (*uniname == 0x0)
3116 break;
3117 uniname++;
3119 } /* end of init_name_entry */
3121 void fat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, INT32 order, INT32 num_entries)
3123 INT32 i;
3124 UINT32 sector;
3125 DENTRY_T *ep;
3126 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3128 for (i = num_entries-1; i >= order; i--) {
3129 ep = get_entry_in_dir(sb, p_dir, entry-i, &sector);
3130 if (!ep)
3131 return;
3133 p_fs->fs_func->set_entry_type(ep, TYPE_DELETED);
3134 buf_modify(sb, sector);
3136 } /* end of fat_delete_dir_entry */
3138 void exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, INT32 order, INT32 num_entries)
3140 INT32 i;
3141 UINT32 sector;
3142 DENTRY_T *ep;
3143 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3145 for (i = order; i < num_entries; i++) {
3146 ep = get_entry_in_dir(sb, p_dir, entry+i, &sector);
3147 if (!ep)
3148 return;
3150 p_fs->fs_func->set_entry_type(ep, TYPE_DELETED);
3151 buf_modify(sb, sector);
3153 } /* end of exfat_delete_dir_entry */
3155 void update_dir_checksum(struct super_block *sb, CHAIN_T *p_dir, INT32 entry)
3157 INT32 i, num_entries;
3158 UINT32 sector;
3159 UINT16 chksum;
3160 FILE_DENTRY_T *file_ep;
3161 DENTRY_T *ep;
3163 file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, &sector);
3164 if (!file_ep)
3165 return;
3167 buf_lock(sb, sector);
3169 num_entries = (INT32) file_ep->num_ext + 1;
3170 chksum = calc_checksum_2byte((void *) file_ep, DENTRY_SIZE, 0, CS_DIR_ENTRY);
3172 for (i = 1; i < num_entries; i++) {
3173 ep = get_entry_in_dir(sb, p_dir, entry+i, NULL);
3174 if (!ep) {
3175 buf_unlock(sb, sector);
3176 return;
3179 chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, CS_DEFAULT);
3182 SET16_A(file_ep->checksum, chksum);
3183 buf_modify(sb, sector);
3184 buf_unlock(sb, sector);
3185 } /* end of update_dir_checksum */
3187 void update_dir_checksum_with_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es)
3189 DENTRY_T *ep;
3190 UINT16 chksum = 0;
3191 INT32 chksum_type = CS_DIR_ENTRY, i;
3193 ep = (DENTRY_T *)&(es->__buf);
3194 for (i=0; i < es->num_entries; i++) {
3195 PRINTK ("update_dir_checksum_with_entry_set ep %p\n", ep);
3196 chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type);
3197 ep++;
3198 chksum_type = CS_DEFAULT;
3201 ep = (DENTRY_T *)&(es->__buf);
3202 SET16_A(((FILE_DENTRY_T *)ep)->checksum, chksum);
3203 write_whole_entry_set(sb, es);
3206 static INT32 _walk_fat_chain (struct super_block *sb, CHAIN_T *p_dir, INT32 byte_offset, UINT32 *clu)
3208 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3209 INT32 clu_offset;
3210 UINT32 cur_clu;
3212 clu_offset = byte_offset >> p_fs->cluster_size_bits;
3213 cur_clu = p_dir->dir;
3215 if (p_dir->flags == 0x03) {
3216 cur_clu += clu_offset;
3217 } else {
3218 while (clu_offset > 0) {
3219 if (FAT_read(sb, cur_clu, &cur_clu) == -1)
3220 return FFS_MEDIAERR;
3221 clu_offset--;
3225 if (clu)
3226 *clu = cur_clu;
3227 return FFS_SUCCESS;
3229 INT32 find_location(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT32 *sector, INT32 *offset)
3231 INT32 off, ret;
3232 UINT32 clu=0;
3233 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3234 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
3236 off = entry << DENTRY_SIZE_BITS;
3238 if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */
3239 *offset = off & p_bd->sector_size_mask;
3240 *sector = off >> p_bd->sector_size_bits;
3241 *sector += p_fs->root_start_sector;
3242 } else {
3243 ret =_walk_fat_chain(sb, p_dir, off, &clu);
3244 if (ret != FFS_SUCCESS)
3245 return ret;
3247 off &= p_fs->cluster_size - 1; /* byte offset in cluster */
3249 *offset = off & p_bd->sector_size_mask; /* byte offset in sector */
3250 *sector = off >> p_bd->sector_size_bits; /* sector offset in cluster */
3251 *sector += START_SECTOR(clu);
3253 return FFS_SUCCESS;
3254 } /* end of find_location */
3256 DENTRY_T *get_entry_with_sector(struct super_block *sb, UINT32 sector, INT32 offset)
3258 UINT8 *buf;
3260 buf = buf_getblk(sb, sector);
3262 if (buf == NULL)
3263 return NULL;
3265 return((DENTRY_T *)(buf + offset));
3266 } /* end of get_entry_with_sector */
3268 DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT32 *sector)
3270 INT32 off;
3271 UINT32 sec;
3272 UINT8 *buf;
3274 if (find_location(sb, p_dir, entry, &sec, &off) != FFS_SUCCESS)
3275 return NULL;
3277 buf = buf_getblk(sb, sec);
3279 if (buf == NULL)
3280 return NULL;
3282 if (sector != NULL)
3283 *sector = sec;
3284 return((DENTRY_T *)(buf + off));
3285 } /* end of get_entry_in_dir */
3288 /* returns a set of dentries for a file or dir.
3289 * Note that this is a copy (dump) of dentries so that user should call write_entry_set()
3290 * to apply changes made in this entry set to the real device.
3291 * in:
3292 * sb+p_dir+entry: indicates a file/dir
3293 * type: specifies how many dentries should be included.
3294 * out:
3295 * file_ep: will point the first dentry(= file dentry) on success
3296 * return:
3297 * pointer of entry set on success,
3298 * NULL on failure.
3301 #define ES_MODE_STARTED 0
3302 #define ES_MODE_GET_FILE_ENTRY 1
3303 #define ES_MODE_GET_STRM_ENTRY 2
3304 #define ES_MODE_GET_NAME_ENTRY 3
3305 #define ES_MODE_GET_CRITICAL_SEC_ENTRY 4
3306 ENTRY_SET_CACHE_T *get_entry_set_in_dir (struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT32 type, DENTRY_T **file_ep)
3308 INT32 off, ret, byte_offset;
3309 UINT32 clu=0;
3310 UINT32 sec, entry_type;
3311 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3312 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
3313 ENTRY_SET_CACHE_T *es = NULL;
3314 DENTRY_T *ep, *pos;
3315 UINT8 *buf;
3316 UINT8 num_entries;
3317 INT32 mode = ES_MODE_STARTED;
3319 PRINTK("get_entry_set_in_dir entered\n");
3320 PRINTK("p_dir dir %u flags %x size %d\n", p_dir->dir, p_dir->flags, p_dir->size);
3322 byte_offset = entry << DENTRY_SIZE_BITS;
3323 ret =_walk_fat_chain(sb, p_dir, byte_offset, &clu);
3324 if (ret != FFS_SUCCESS)
3325 return NULL;
3328 byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */
3330 off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */
3331 sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */
3332 sec += START_SECTOR(clu);
3334 buf = buf_getblk(sb, sec);
3335 if (buf == NULL)
3336 goto err_out;
3339 ep = (DENTRY_T *)(buf + off);
3340 entry_type = p_fs->fs_func->get_entry_type(ep);
3342 if ((entry_type != TYPE_FILE)
3343 && (entry_type != TYPE_DIR))
3344 goto err_out;
3346 if (type == ES_ALL_ENTRIES)
3347 num_entries = ((FILE_DENTRY_T *)ep)->num_ext+1;
3348 else
3349 num_entries = type;
3351 PRINTK("trying to malloc %x bytes for %d entries\n", offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T), num_entries);
3352 es = MALLOC(offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T));
3353 if (es == NULL)
3354 goto err_out;
3356 es->num_entries = num_entries;
3357 es->sector = sec;
3358 es->offset = off;
3359 es->alloc_flag = p_dir->flags;
3361 pos = (DENTRY_T *) &(es->__buf);
3363 while(num_entries) {
3364 /* instead of copying whole sector, we will check every entry.
3365 * this will provide minimum stablity and consistancy.
3368 entry_type = p_fs->fs_func->get_entry_type(ep);
3370 if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED))
3371 goto err_out;
3373 switch(mode) {
3374 case ES_MODE_STARTED:
3375 if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR))
3376 mode = ES_MODE_GET_FILE_ENTRY;
3377 else
3378 goto err_out;
3379 break;
3380 case ES_MODE_GET_FILE_ENTRY:
3381 if (entry_type == TYPE_STREAM)
3382 mode = ES_MODE_GET_STRM_ENTRY;
3383 else
3384 goto err_out;
3385 break;
3386 case ES_MODE_GET_STRM_ENTRY:
3387 if (entry_type == TYPE_EXTEND)
3388 mode = ES_MODE_GET_NAME_ENTRY;
3389 else
3390 goto err_out;
3391 break;
3392 case ES_MODE_GET_NAME_ENTRY:
3393 if (entry_type == TYPE_EXTEND)
3394 break;
3395 else if (entry_type == TYPE_STREAM)
3396 goto err_out;
3397 else if (entry_type & TYPE_CRITICAL_SEC)
3398 mode = ES_MODE_GET_CRITICAL_SEC_ENTRY;
3399 else
3400 goto err_out;
3401 break;
3402 case ES_MODE_GET_CRITICAL_SEC_ENTRY:
3403 if ((entry_type == TYPE_EXTEND) || (entry_type == TYPE_STREAM))
3404 goto err_out;
3405 else if ((entry_type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC)
3406 goto err_out;
3407 break;
3410 COPY_DENTRY(pos, ep);
3412 if (--num_entries == 0)
3413 break;
3415 if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < (off & p_bd->sector_size_mask)) {
3416 /* get the next sector */
3417 if (IS_LAST_SECTOR_IN_CLUSTER(sec)) {
3418 if (es->alloc_flag == 0x03) {
3419 clu++;
3420 } else {
3421 if (FAT_read(sb, clu, &clu) == -1)
3422 goto err_out;
3424 sec = START_SECTOR(clu);
3425 } else {
3426 sec++;
3428 buf = buf_getblk(sb, sec);
3429 if (buf == NULL)
3430 goto err_out;
3431 off = 0;
3432 ep = (DENTRY_T *)(buf);
3433 } else {
3434 ep++;
3435 off += DENTRY_SIZE;
3437 pos++;
3440 if (file_ep)
3441 *file_ep = (DENTRY_T *)&(es->__buf);
3443 PRINTK("es sec %u offset %d flags %d, num_entries %u buf ptr %p\n",
3444 es->sector, es->offset, es->alloc_flag, es->num_entries, &(es->__buf));
3445 PRINTK("get_entry_set_in_dir exited %p\n", es);
3446 return es;
3447 err_out:
3448 PRINTK("get_entry_set_in_dir exited NULL (es %p)\n", es);
3449 FREE(es);
3450 return NULL;
3453 void release_entry_set (ENTRY_SET_CACHE_T *es)
3455 PRINTK("release_entry_set %p\n", es);
3456 FREE(es);
3460 static INT32 __write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es, UINT32 sec, INT32 off, UINT32 count)
3462 INT32 num_entries, buf_off = (off - es->offset);
3463 UINT32 remaining_byte_in_sector, copy_entries;
3464 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3465 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
3466 UINT32 clu;
3467 UINT8 *buf, *esbuf = (UINT8 *)&(es->__buf);
3469 PRINTK("__write_partial_entries_in_entry_set entered\n");
3470 PRINTK("es %p sec %u off %d count %d\n", es, sec, off, count);
3471 num_entries = count;
3473 while(num_entries) {
3474 /* white per sector base */
3475 remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off;
3476 copy_entries = MIN(remaining_byte_in_sector>> DENTRY_SIZE_BITS , num_entries);
3477 buf = buf_getblk(sb, sec);
3478 if (buf == NULL)
3479 goto err_out;
3480 PRINTK("es->buf %p buf_off %u\n", esbuf, buf_off);
3481 PRINTK("copying %d entries from %p to sector %u\n", copy_entries, (esbuf + buf_off), sec);
3482 MEMCPY(buf + off, esbuf + buf_off, copy_entries << DENTRY_SIZE_BITS);
3483 buf_modify(sb, sec);
3484 num_entries -= copy_entries;
3486 if (num_entries) {
3487 /* get next sector */
3488 if (IS_LAST_SECTOR_IN_CLUSTER(sec)) {
3489 clu = GET_CLUSTER_FROM_SECTOR(sec);
3490 if (es->alloc_flag == 0x03) {
3491 clu++;
3492 } else {
3493 if (FAT_read(sb, clu, &clu) == -1)
3494 goto err_out;
3496 sec = START_SECTOR(clu);
3497 } else {
3498 sec++;
3500 off = 0;
3501 buf_off += copy_entries << DENTRY_SIZE_BITS;
3505 PRINTK("__write_partial_entries_in_entry_set exited successfully\n");
3506 return FFS_SUCCESS;
3507 err_out:
3508 PRINTK("__write_partial_entries_in_entry_set failed\n");
3509 return FFS_ERROR;
3512 /* write back all entries in entry set */
3513 INT32 write_whole_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es)
3515 return (__write_partial_entries_in_entry_set(sb, es, es->sector,es->offset, es->num_entries));
3518 /* write back some entries in entry set */
3519 INT32 write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es, DENTRY_T *ep, UINT32 count)
3521 INT32 ret, byte_offset, off;
3522 UINT32 clu=0, sec;
3523 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3524 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
3525 CHAIN_T dir;
3527 /* vaidity check */
3528 if (ep + count > ((DENTRY_T *)&(es->__buf)) + es->num_entries)
3529 return FFS_ERROR;
3531 dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector);
3532 dir.flags = es->alloc_flag;
3533 dir.size = 0xffffffff; /* XXX */
3535 byte_offset = (es->sector - START_SECTOR(dir.dir)) << p_bd->sector_size_bits;
3536 byte_offset += ((INT32 *)ep - (INT32 *)&(es->__buf)) + es->offset;
3538 ret =_walk_fat_chain(sb, &dir, byte_offset, &clu);
3539 if (ret != FFS_SUCCESS)
3540 return ret;
3541 byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */
3542 off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */
3543 sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */
3544 sec += START_SECTOR(clu);
3545 return (__write_partial_entries_in_entry_set(sb, es, sec, off, count));
3548 /* search EMPTY CONTINUOUS "num_entries" entries */
3549 INT32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 num_entries)
3551 INT32 i, dentry, num_empty = 0;
3552 INT32 dentries_per_clu;
3553 UINT32 type;
3554 CHAIN_T clu;
3555 DENTRY_T *ep;
3556 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3558 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
3559 dentries_per_clu = p_fs->dentries_in_root;
3560 else
3561 dentries_per_clu = p_fs->dentries_per_clu;
3563 if (p_fs->hint_uentry.dir == p_dir->dir) {
3564 if (p_fs->hint_uentry.entry == -1)
3565 return -1;
3567 clu.dir = p_fs->hint_uentry.clu.dir;
3568 clu.size = p_fs->hint_uentry.clu.size;
3569 clu.flags = p_fs->hint_uentry.clu.flags;
3571 dentry = p_fs->hint_uentry.entry;
3572 } else {
3573 p_fs->hint_uentry.entry = -1;
3575 clu.dir = p_dir->dir;
3576 clu.size = p_dir->size;
3577 clu.flags = p_dir->flags;
3579 dentry = 0;
3582 while (clu.dir != CLUSTER_32(~0)) {
3583 if (p_fs->dev_ejected)
3584 break;
3586 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
3587 i = dentry % dentries_per_clu;
3588 else
3589 i = dentry & (dentries_per_clu-1);
3591 for ( ; i < dentries_per_clu; i++, dentry++) {
3592 ep = get_entry_in_dir(sb, &clu, i, NULL);
3593 if (!ep)
3594 return -1;
3596 type = p_fs->fs_func->get_entry_type(ep);
3598 if (type == TYPE_UNUSED) {
3599 num_empty++;
3600 if (p_fs->hint_uentry.entry == -1) {
3601 p_fs->hint_uentry.dir = p_dir->dir;
3602 p_fs->hint_uentry.entry = dentry;
3604 p_fs->hint_uentry.clu.dir = clu.dir;
3605 p_fs->hint_uentry.clu.size = clu.size;
3606 p_fs->hint_uentry.clu.flags = clu.flags;
3608 } else if (type == TYPE_DELETED) {
3609 num_empty++;
3610 } else {
3611 num_empty = 0;
3614 if (num_empty >= num_entries) {
3615 p_fs->hint_uentry.dir = CLUSTER_32(~0);
3616 p_fs->hint_uentry.entry = -1;
3618 if (p_fs->vol_type == EXFAT)
3619 return(dentry - (num_entries-1));
3620 else
3621 return(dentry);
3625 if (p_dir->dir == CLUSTER_32(0))
3626 break; /* FAT16 root_dir */
3628 if (clu.flags == 0x03) {
3629 if ((--clu.size) > 0)
3630 clu.dir++;
3631 else
3632 clu.dir = CLUSTER_32(~0);
3633 } else {
3634 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
3635 return -1;
3639 return -1;
3640 } /* end of search_deleted_or_unused_entry */
3642 INT32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, INT32 num_entries)
3644 INT32 ret, dentry;
3645 UINT32 last_clu, sector;
3646 UINT64 size = 0;
3647 CHAIN_T clu;
3648 DENTRY_T *ep = NULL;
3649 struct super_block *sb = inode->i_sb;
3650 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3651 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
3653 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
3654 return(search_deleted_or_unused_entry(sb, p_dir, num_entries));
3656 while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) {
3657 if (p_fs->dev_ejected)
3658 break;
3660 if (p_fs->vol_type == EXFAT) {
3661 if (p_dir->dir != p_fs->root_dir) {
3662 size = i_size_read(inode);
3666 last_clu = find_last_cluster(sb, p_dir);
3667 clu.dir = last_clu + 1;
3668 clu.size = 0;
3669 clu.flags = p_dir->flags;
3671 /* (1) allocate a cluster */
3672 ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu);
3673 if (ret < 1)
3674 return -1;
3676 if (clear_cluster(sb, clu.dir) != FFS_SUCCESS)
3677 return -1;
3679 /* (2) append to the FAT chain */
3680 if (clu.flags != p_dir->flags) {
3681 exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size);
3682 p_dir->flags = 0x01;
3683 p_fs->hint_uentry.clu.flags = 0x01;
3685 if (clu.flags == 0x01)
3686 FAT_write(sb, last_clu, clu.dir);
3688 if (p_fs->hint_uentry.entry == -1) {
3689 p_fs->hint_uentry.dir = p_dir->dir;
3690 p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS);
3692 p_fs->hint_uentry.clu.dir = clu.dir;
3693 p_fs->hint_uentry.clu.size = 0;
3694 p_fs->hint_uentry.clu.flags = clu.flags;
3696 p_fs->hint_uentry.clu.size++;
3697 p_dir->size++;
3699 /* (3) update the directory entry */
3700 if (p_fs->vol_type == EXFAT) {
3701 if (p_dir->dir != p_fs->root_dir) {
3702 size += p_fs->cluster_size;
3704 ep = get_entry_in_dir(sb, &(fid->dir), fid->entry+1, &sector);
3705 if (!ep)
3706 return -1;
3707 p_fs->fs_func->set_entry_size(ep, size);
3708 p_fs->fs_func->set_entry_flag(ep, p_dir->flags);
3709 buf_modify(sb, sector);
3711 update_dir_checksum(sb, &(fid->dir), fid->entry);
3715 i_size_write(inode, i_size_read(inode)+p_fs->cluster_size);
3716 EXFAT_I(inode)->mmu_private += p_fs->cluster_size;
3717 EXFAT_I(inode)->fid.size += p_fs->cluster_size;
3718 EXFAT_I(inode)->fid.flags = p_dir->flags;
3719 inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9);
3722 return(dentry);
3723 } /* end of find_empty_entry */
3725 /* return values of fat_find_dir_entry()
3726 >= 0 : return dir entiry position with the name in dir
3727 -1 : (root dir, ".") it is the root dir itself
3728 -2 : entry with the name does not exist */
3729 INT32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, INT32 num_entries, DOS_NAME_T *p_dosname, UINT32 type)
3731 INT32 i, dentry = 0, len;
3732 INT32 order = 0, is_feasible_entry = TRUE, has_ext_entry = FALSE;
3733 INT32 dentries_per_clu;
3734 UINT32 entry_type;
3735 UINT16 entry_uniname[14], *uniname = NULL, unichar;
3736 CHAIN_T clu;
3737 DENTRY_T *ep;
3738 DOS_DENTRY_T *dos_ep;
3739 EXT_DENTRY_T *ext_ep;
3740 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3742 if (p_dir->dir == p_fs->root_dir) {
3743 if ((!nls_uniname_cmp(sb, p_uniname->name, (UINT16 *) UNI_CUR_DIR_NAME)) ||
3744 (!nls_uniname_cmp(sb, p_uniname->name, (UINT16 *) UNI_PAR_DIR_NAME)))
3745 return -1; // special case, root directory itself
3748 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
3749 dentries_per_clu = p_fs->dentries_in_root;
3750 else
3751 dentries_per_clu = p_fs->dentries_per_clu;
3753 clu.dir = p_dir->dir;
3754 clu.flags = p_dir->flags;
3756 while (clu.dir != CLUSTER_32(~0)) {
3757 if (p_fs->dev_ejected)
3758 break;
3760 for (i = 0; i < dentries_per_clu; i++, dentry++) {
3761 ep = get_entry_in_dir(sb, &clu, i, NULL);
3762 if (!ep)
3763 return -2;
3765 entry_type = p_fs->fs_func->get_entry_type(ep);
3767 if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) {
3768 if ((type == TYPE_ALL) || (type == entry_type)) {
3769 if (is_feasible_entry && has_ext_entry)
3770 return(dentry);
3772 dos_ep = (DOS_DENTRY_T *) ep;
3773 if (!nls_dosname_cmp(sb, p_dosname->name, dos_ep->name))
3774 return(dentry);
3776 is_feasible_entry = TRUE;
3777 has_ext_entry = FALSE;
3778 } else if (entry_type == TYPE_EXTEND) {
3779 if (is_feasible_entry) {
3780 ext_ep = (EXT_DENTRY_T *) ep;
3781 if (ext_ep->order > 0x40) {
3782 order = (INT32)(ext_ep->order - 0x40);
3783 uniname = p_uniname->name + 13 * (order-1);
3784 } else {
3785 order = (INT32) ext_ep->order;
3786 uniname -= 13;
3789 len = extract_uni_name_from_ext_entry(ext_ep, entry_uniname, order);
3791 unichar = *(uniname+len);
3792 *(uniname+len) = 0x0;
3794 if (nls_uniname_cmp(sb, uniname, entry_uniname)) {
3795 is_feasible_entry = FALSE;
3798 *(uniname+len) = unichar;
3800 has_ext_entry = TRUE;
3801 } else if (entry_type == TYPE_UNUSED) {
3802 return -2;
3803 } else {
3804 is_feasible_entry = TRUE;
3805 has_ext_entry = FALSE;
3809 if (p_dir->dir == CLUSTER_32(0))
3810 break; /* FAT16 root_dir */
3812 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
3813 return -2;
3816 return -2;
3817 } /* end of fat_find_dir_entry */
3819 /* return values of exfat_find_dir_entry()
3820 >= 0 : return dir entiry position with the name in dir
3821 -1 : (root dir, ".") it is the root dir itself
3822 -2 : entry with the name does not exist */
3823 INT32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, INT32 num_entries, DOS_NAME_T *p_dosname, UINT32 type)
3825 INT32 i, dentry = 0, num_ext_entries = 0, len;
3826 INT32 order = 0, is_feasible_entry = FALSE;
3827 INT32 dentries_per_clu, num_empty = 0;
3828 UINT32 entry_type;
3829 UINT16 entry_uniname[16], *uniname = NULL, unichar;
3830 CHAIN_T clu;
3831 DENTRY_T *ep;
3832 FILE_DENTRY_T *file_ep;
3833 STRM_DENTRY_T *strm_ep;
3834 NAME_DENTRY_T *name_ep;
3835 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3837 if (p_dir->dir == p_fs->root_dir) {
3838 if ((!nls_uniname_cmp(sb, p_uniname->name, (UINT16 *) UNI_CUR_DIR_NAME)) ||
3839 (!nls_uniname_cmp(sb, p_uniname->name, (UINT16 *) UNI_PAR_DIR_NAME)))
3840 return -1; // special case, root directory itself
3843 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
3844 dentries_per_clu = p_fs->dentries_in_root;
3845 else
3846 dentries_per_clu = p_fs->dentries_per_clu;
3848 clu.dir = p_dir->dir;
3849 clu.size = p_dir->size;
3850 clu.flags = p_dir->flags;
3852 p_fs->hint_uentry.dir = p_dir->dir;
3853 p_fs->hint_uentry.entry = -1;
3855 while (clu.dir != CLUSTER_32(~0)) {
3856 if (p_fs->dev_ejected)
3857 break;
3859 for (i = 0; i < dentries_per_clu; i++, dentry++) {
3860 ep = get_entry_in_dir(sb, &clu, i, NULL);
3861 if (!ep)
3862 return -2;
3864 entry_type = p_fs->fs_func->get_entry_type(ep);
3866 if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) {
3867 is_feasible_entry = FALSE;
3869 if (p_fs->hint_uentry.entry == -1) {
3870 num_empty++;
3872 if (num_empty == 1) {
3873 p_fs->hint_uentry.clu.dir = clu.dir;
3874 p_fs->hint_uentry.clu.size = clu.size;
3875 p_fs->hint_uentry.clu.flags = clu.flags;
3877 if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) {
3878 p_fs->hint_uentry.entry = dentry - (num_empty-1);
3882 if (entry_type == TYPE_UNUSED) {
3883 return -2;
3885 } else {
3886 num_empty = 0;
3888 if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) {
3889 if ((type == TYPE_ALL) || (type == entry_type)) {
3890 file_ep = (FILE_DENTRY_T *) ep;
3891 num_ext_entries = file_ep->num_ext;
3892 is_feasible_entry = TRUE;
3893 } else {
3894 is_feasible_entry = FALSE;
3896 } else if (entry_type == TYPE_STREAM) {
3897 if (is_feasible_entry) {
3898 strm_ep = (STRM_DENTRY_T *) ep;
3899 if (p_uniname->name_len == strm_ep->name_len) {
3900 order = 1;
3901 } else {
3902 is_feasible_entry = FALSE;
3905 } else if (entry_type == TYPE_EXTEND) {
3906 if (is_feasible_entry) {
3907 name_ep = (NAME_DENTRY_T *) ep;
3909 if ((++order) == 2)
3910 uniname = p_uniname->name;
3911 else
3912 uniname += 15;
3914 len = extract_uni_name_from_name_entry(name_ep, entry_uniname, order);
3916 unichar = *(uniname+len);
3917 *(uniname+len) = 0x0;
3919 if (nls_uniname_cmp(sb, uniname, entry_uniname)) {
3920 is_feasible_entry = FALSE;
3921 } else if (order == num_ext_entries) {
3922 p_fs->hint_uentry.dir = CLUSTER_32(~0);
3923 p_fs->hint_uentry.entry = -1;
3924 return(dentry - (num_ext_entries));
3927 *(uniname+len) = unichar;
3929 } else {
3930 is_feasible_entry = FALSE;
3935 if (p_dir->dir == CLUSTER_32(0))
3936 break; /* FAT16 root_dir */
3938 if (clu.flags == 0x03) {
3939 if ((--clu.size) > 0)
3940 clu.dir++;
3941 else
3942 clu.dir = CLUSTER_32(~0);
3943 } else {
3944 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
3945 return -2;
3949 return -2;
3950 } /* end of exfat_find_dir_entry */
3952 /* returns -1 on error */
3953 INT32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, DENTRY_T *p_entry)
3955 INT32 count = 0;
3956 UINT8 chksum;
3957 DOS_DENTRY_T *dos_ep = (DOS_DENTRY_T *) p_entry;
3958 EXT_DENTRY_T *ext_ep;
3959 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3961 chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0);
3963 for (entry--; entry >= 0; entry--) {
3964 ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL);
3965 if (!ext_ep)
3966 return -1;
3968 if ((p_fs->fs_func->get_entry_type((DENTRY_T *) ext_ep) == TYPE_EXTEND) &&
3969 (ext_ep->checksum == chksum)) {
3970 count++;
3971 if (ext_ep->order > 0x40)
3972 return(count);
3973 } else {
3974 return(count);
3978 return(count);
3979 } /* end of fat_count_ext_entries */
3981 /* returns -1 on error */
3982 INT32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, DENTRY_T *p_entry)
3984 INT32 i, count = 0;
3985 UINT32 type;
3986 FILE_DENTRY_T *file_ep = (FILE_DENTRY_T *) p_entry;
3987 DENTRY_T *ext_ep;
3988 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
3990 for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) {
3991 ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL);
3992 if (!ext_ep)
3993 return -1;
3995 type = p_fs->fs_func->get_entry_type(ext_ep);
3996 if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) {
3997 count++;
3998 } else {
3999 return(count);
4003 return(count);
4004 } /* end of exfat_count_ext_entries */
4006 /* returns -1 on error */
4007 INT32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, UINT32 type)
4009 INT32 i, count = 0;
4010 INT32 dentries_per_clu;
4011 UINT32 entry_type;
4012 CHAIN_T clu;
4013 DENTRY_T *ep;
4014 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4016 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
4017 dentries_per_clu = p_fs->dentries_in_root;
4018 else
4019 dentries_per_clu = p_fs->dentries_per_clu;
4021 clu.dir = p_dir->dir;
4022 clu.size = p_dir->size;
4023 clu.flags = p_dir->flags;
4025 while (clu.dir != CLUSTER_32(~0)) {
4026 if (p_fs->dev_ejected)
4027 break;
4029 for (i = 0; i < dentries_per_clu; i++) {
4030 ep = get_entry_in_dir(sb, &clu, i, NULL);
4031 if (!ep)
4032 return -1;
4034 entry_type = p_fs->fs_func->get_entry_type(ep);
4036 if (entry_type == TYPE_UNUSED)
4037 return(count);
4038 if (!(type & TYPE_CRITICAL_PRI) && !(type & TYPE_BENIGN_PRI))
4039 continue;
4041 if ((type == TYPE_ALL) || (type == entry_type))
4042 count++;
4045 if (p_dir->dir == CLUSTER_32(0))
4046 break; /* FAT16 root_dir */
4048 if (clu.flags == 0x03) {
4049 if ((--clu.size) > 0)
4050 clu.dir++;
4051 else
4052 clu.dir = CLUSTER_32(~0);
4053 } else {
4054 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
4055 return -1;
4059 return(count);
4060 } /* end of count_dos_name_entries */
4062 BOOL is_dir_empty(struct super_block *sb, CHAIN_T *p_dir)
4064 INT32 i, count = 0;
4065 INT32 dentries_per_clu;
4066 UINT32 type;
4067 CHAIN_T clu;
4068 DENTRY_T *ep;
4069 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4071 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
4072 dentries_per_clu = p_fs->dentries_in_root;
4073 else
4074 dentries_per_clu = p_fs->dentries_per_clu;
4076 clu.dir = p_dir->dir;
4077 clu.size = p_dir->size;
4078 clu.flags = p_dir->flags;
4080 while (clu.dir != CLUSTER_32(~0)) {
4081 if (p_fs->dev_ejected)
4082 break;
4084 for (i = 0; i < dentries_per_clu; i++) {
4085 ep = get_entry_in_dir(sb, &clu, i, NULL);
4086 if (!ep)
4087 break;
4089 type = p_fs->fs_func->get_entry_type(ep);
4091 if (type == TYPE_UNUSED)
4092 return TRUE;
4093 if ((type != TYPE_FILE) && (type != TYPE_DIR))
4094 continue;
4096 if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */
4097 return FALSE;
4098 } else {
4099 if (p_fs->vol_type == EXFAT)
4100 return FALSE;
4101 if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2))
4102 return FALSE;
4106 if (p_dir->dir == CLUSTER_32(0))
4107 break; /* FAT16 root_dir */
4109 if (clu.flags == 0x03) {
4110 if ((--clu.size) > 0)
4111 clu.dir++;
4112 else
4113 clu.dir = CLUSTER_32(~0);
4114 } else {
4115 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
4116 break;
4120 return TRUE;
4121 } /* end of is_dir_empty */
4124 * Name Conversion Functions
4127 /* input : dir, uni_name
4128 output : num_of_entry, dos_name(format : aaaaaa~1.bbb) */
4129 INT32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, INT32 *entries, DOS_NAME_T *p_dosname)
4131 INT32 ret, num_entries, lossy = FALSE;
4132 INT8 **r;
4133 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4135 num_entries = p_fs->fs_func->calc_num_entries(p_uniname);
4136 if (num_entries == 0)
4137 return FFS_INVALIDPATH;
4139 if (p_fs->vol_type != EXFAT) {
4140 nls_uniname_to_dosname(sb, p_dosname, p_uniname, &lossy);
4142 if (lossy) {
4143 ret = fat_generate_dos_name(sb, p_dir, p_dosname);
4144 if (ret)
4145 return ret;
4146 } else {
4147 for (r = reserved_names; *r; r++) {
4148 if (!STRNCMP((void *) p_dosname->name, *r, 8))
4149 return FFS_INVALIDPATH;
4152 if (p_dosname->name_case != 0xFF)
4153 num_entries = 1;
4156 if (num_entries > 1)
4157 p_dosname->name_case = 0x0;
4160 *entries = num_entries;
4162 return FFS_SUCCESS;
4163 } /* end of get_num_entries_and_dos_name */
4165 void get_uni_name_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, UINT8 mode)
4167 DOS_NAME_T dos_name;
4169 if (mode == 0x0)
4170 dos_name.name_case = 0x0;
4171 else
4172 dos_name.name_case = ep->lcase;
4174 MEMCPY(dos_name.name, ep->name, DOS_NAME_LENGTH);
4175 nls_dosname_to_uniname(sb, p_uniname, &dos_name);
4176 } /* end of get_uni_name_from_dos_entry */
4178 void fat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT16 *uniname)
4180 INT32 i;
4181 EXT_DENTRY_T *ep;
4182 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4184 for (entry--, i = 1; entry >= 0; entry--, i++) {
4185 ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL);
4186 if (!ep)
4187 return;
4189 if (p_fs->fs_func->get_entry_type((DENTRY_T *) ep) == TYPE_EXTEND) {
4190 extract_uni_name_from_ext_entry(ep, uniname, i);
4191 if (ep->order > 0x40)
4192 return;
4193 } else {
4194 return;
4197 uniname += 13;
4199 } /* end of fat_get_uni_name_from_ext_entry */
4201 void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, INT32 entry, UINT16 *uniname)
4203 INT32 i;
4204 DENTRY_T *ep;
4205 ENTRY_SET_CACHE_T *es;
4206 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4208 es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep);
4209 if (es == NULL || es->num_entries < 3) {
4210 if(es) {
4211 release_entry_set(es);
4213 return;
4216 ep += 2;
4219 * First entry : file entry
4220 * Second entry : stream-extension entry
4221 * Third entry : first file-name entry
4222 * So, the index of first file-name dentry should start from 2.
4224 for (i = 2; i < es->num_entries; i++, ep++) {
4225 if (p_fs->fs_func->get_entry_type(ep) == TYPE_EXTEND) {
4226 extract_uni_name_from_name_entry((NAME_DENTRY_T *)ep, uniname, i);
4227 } else {
4228 /* end of name entry */
4229 goto out;
4231 uniname += 15;
4234 out:
4235 release_entry_set(es);
4236 } /* end of exfat_get_uni_name_from_ext_entry */
4238 INT32 extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, UINT16 *uniname, INT32 order)
4240 INT32 i, len = 0;
4242 for (i = 0; i < 10; i += 2) {
4243 *uniname = GET16(ep->unicode_0_4+i);
4244 if (*uniname == 0x0)
4245 return(len);
4246 uniname++;
4247 len++;
4250 if (order < 20) {
4251 for (i = 0; i < 12; i += 2) {
4252 *uniname = GET16_A(ep->unicode_5_10+i);
4253 if (*uniname == 0x0)
4254 return(len);
4255 uniname++;
4256 len++;
4258 } else {
4259 for (i = 0; i < 8; i += 2) {
4260 *uniname = GET16_A(ep->unicode_5_10+i);
4261 if (*uniname == 0x0)
4262 return(len);
4263 uniname++;
4264 len++;
4266 *uniname = 0x0; /* uniname[MAX_NAME_LENGTH-1] */
4267 return(len);
4270 for (i = 0; i < 4; i += 2) {
4271 *uniname = GET16_A(ep->unicode_11_12+i);
4272 if (*uniname == 0x0)
4273 return(len);
4274 uniname++;
4275 len++;
4278 *uniname = 0x0;
4279 return(len);
4281 } /* end of extract_uni_name_from_ext_entry */
4283 INT32 extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, UINT16 *uniname, INT32 order)
4285 INT32 i, len = 0;
4287 for (i = 0; i < 30; i += 2) {
4288 *uniname = GET16_A(ep->unicode_0_14+i);
4289 if (*uniname == 0x0)
4290 return(len);
4291 uniname++;
4292 len++;
4295 *uniname = 0x0;
4296 return(len);
4298 } /* end of extract_uni_name_from_name_entry */
4300 INT32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname)
4302 INT32 i, j, count = 0, count_begin = FALSE;
4303 INT32 dentries_per_clu;
4304 UINT32 type;
4305 UINT8 bmap[128/* 1 ~ 1023 */];
4306 CHAIN_T clu;
4307 DOS_DENTRY_T *ep;
4308 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4310 Bitmap_clear_all(bmap, 128);
4311 Bitmap_set(bmap, 0);
4313 if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
4314 dentries_per_clu = p_fs->dentries_in_root;
4315 else
4316 dentries_per_clu = p_fs->dentries_per_clu;
4318 clu.dir = p_dir->dir;
4319 clu.flags = p_dir->flags;
4321 while (clu.dir != CLUSTER_32(~0)) {
4322 if (p_fs->dev_ejected)
4323 break;
4325 for (i = 0; i < dentries_per_clu; i++) {
4326 ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL);
4327 if (!ep)
4328 return FFS_MEDIAERR;
4330 type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep);
4332 if (type == TYPE_UNUSED)
4333 break;
4334 if ((type != TYPE_FILE) && (type != TYPE_DIR))
4335 continue;
4337 count = 0;
4338 count_begin = FALSE;
4340 for (j = 0; j < 8; j++) {
4341 if (ep->name[j] == ' ')
4342 break;
4344 if (ep->name[j] == '~') {
4345 count_begin = TRUE;
4346 } else if (count_begin) {
4347 if ((ep->name[j] >= '0') && (ep->name[j] <= '9')) {
4348 count = count * 10 + (ep->name[j] - '0');
4349 } else {
4350 count = 0;
4351 count_begin = FALSE;
4356 if ((count > 0) && (count < 1024))
4357 Bitmap_set(bmap, count);
4360 if (p_dir->dir == CLUSTER_32(0))
4361 break; /* FAT16 root_dir */
4363 if (FAT_read(sb, clu.dir, &(clu.dir)) != 0)
4364 return FFS_MEDIAERR;
4367 count = 0;
4368 for (i = 0; i < 128; i++) {
4369 if (bmap[i] != 0xFF) {
4370 for (j = 0; j < 8; j++) {
4371 if (Bitmap_test(&(bmap[i]), j) == 0) {
4372 count = (i << 3) + j;
4373 break;
4376 if (count != 0)
4377 break;
4381 if ((count == 0) || (count >= 1024))
4382 return FFS_FILEEXIST;
4383 else
4384 fat_attach_count_to_dos_name(p_dosname->name, count);
4386 /* Now dos_name has DOS~????.EXT */
4387 return FFS_SUCCESS;
4388 } /* end of generate_dos_name */
4390 void fat_attach_count_to_dos_name(UINT8 *dosname, INT32 count)
4392 INT32 i, j, length;
4393 INT8 str_count[6];
4395 str_count[0] = '~';
4396 str_count[1] = '\0';
4397 my_itoa(&(str_count[1]), count);
4398 length = STRLEN(str_count);
4400 i = j = 0;
4401 while (j <= (8 - length)) {
4402 i = j;
4403 if (dosname[j] == ' ')
4404 break;
4405 if (dosname[j] & 0x80)
4406 j += 2;
4407 else
4408 j++;
4411 for (j = 0; j < length; i++, j++)
4412 dosname[i] = (UINT8) str_count[j];
4414 if (i == 7)
4415 dosname[7] = ' ';
4417 } /* end of attach_count_to_dos_name */
4419 INT32 fat_calc_num_entries(UNI_NAME_T *p_uniname)
4421 INT32 len;
4423 len = p_uniname->name_len;
4424 if (len == 0)
4425 return 0;
4427 /* 1 dos name entry + extended entries */
4428 return((len-1) / 13 + 2);
4430 } /* end of calc_num_enties */
4432 INT32 exfat_calc_num_entries(UNI_NAME_T *p_uniname)
4434 INT32 len;
4436 len = p_uniname->name_len;
4437 if (len == 0)
4438 return 0;
4440 /* 1 file entry + 1 stream entry + name entries */
4441 return((len-1) / 15 + 3);
4443 } /* end of exfat_calc_num_enties */
4445 UINT8 calc_checksum_1byte(void *data, INT32 len, UINT8 chksum)
4447 INT32 i;
4448 UINT8 *c = (UINT8 *) data;
4450 for (i = 0; i < len; i++, c++)
4451 chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c;
4453 return(chksum);
4454 } /* end of calc_checksum_1byte */
4456 UINT16 calc_checksum_2byte(void *data, INT32 len, UINT16 chksum, INT32 type)
4458 INT32 i;
4459 UINT8 *c = (UINT8 *) data;
4461 switch (type) {
4462 case CS_DIR_ENTRY:
4463 for (i = 0; i < len; i++, c++) {
4464 if ((i == 2) || (i == 3))
4465 continue;
4466 chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (UINT16) *c;
4468 break;
4469 default
4471 for (i = 0; i < len; i++, c++) {
4472 chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (UINT16) *c;
4476 return(chksum);
4477 } /* end of calc_checksum_2byte */
4479 UINT32 calc_checksum_4byte(void *data, INT32 len, UINT32 chksum, INT32 type)
4481 INT32 i;
4482 UINT8 *c = (UINT8 *) data;
4484 switch (type) {
4485 case CS_PBR_SECTOR:
4486 for (i = 0; i < len; i++, c++) {
4487 if ((i == 106) || (i == 107) || (i == 112))
4488 continue;
4489 chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (UINT32) *c;
4491 break;
4492 default
4494 for (i = 0; i < len; i++, c++) {
4495 chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (UINT32) *c;
4499 return(chksum);
4500 } /* end of calc_checksum_4byte */
4503 * Name Resolution Functions
4506 /* return values of resolve_path()
4507 > 0 : return the length of the path
4508 < 0 : return error */
4509 INT32 resolve_path(struct inode *inode, UINT8 *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname)
4511 INT32 lossy = FALSE;
4512 struct super_block *sb = inode->i_sb;
4513 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4514 FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
4516 if (STRLEN(path) >= (MAX_NAME_LENGTH * MAX_CHARSET_SIZE))
4517 return(FFS_INVALIDPATH);
4519 STRCPY(name_buf, path);
4521 nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy);
4522 if (lossy)
4523 return(FFS_INVALIDPATH);
4525 fid->size = i_size_read(inode);
4527 p_dir->dir = fid->start_clu;
4528 p_dir->size = (INT32)(fid->size >> p_fs->cluster_size_bits);
4529 p_dir->flags = fid->flags;
4531 return(FFS_SUCCESS);
4535 * File Operation Functions
4537 static FS_FUNC_T fat_fs_func = {
4538 .alloc_cluster = fat_alloc_cluster,
4539 .free_cluster = fat_free_cluster,
4540 .count_used_clusters = fat_count_used_clusters,
4542 .init_dir_entry = fat_init_dir_entry,
4543 .init_ext_entry = fat_init_ext_entry,
4544 .find_dir_entry = fat_find_dir_entry,
4545 .delete_dir_entry = fat_delete_dir_entry,
4546 .get_uni_name_from_ext_entry = fat_get_uni_name_from_ext_entry,
4547 .count_ext_entries = fat_count_ext_entries,
4548 .calc_num_entries = fat_calc_num_entries,
4550 .get_entry_type = fat_get_entry_type,
4551 .set_entry_type = fat_set_entry_type,
4552 .get_entry_attr = fat_get_entry_attr,
4553 .set_entry_attr = fat_set_entry_attr,
4554 .get_entry_flag = fat_get_entry_flag,
4555 .set_entry_flag = fat_set_entry_flag,
4556 .get_entry_clu0 = fat_get_entry_clu0,
4557 .set_entry_clu0 = fat_set_entry_clu0,
4558 .get_entry_size = fat_get_entry_size,
4559 .set_entry_size = fat_set_entry_size,
4560 .get_entry_time = fat_get_entry_time,
4561 .set_entry_time = fat_set_entry_time,
4565 INT32 fat16_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr)
4567 INT32 num_reserved, num_root_sectors;
4568 BPB16_T *p_bpb = (BPB16_T *) p_pbr->bpb;
4569 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4570 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
4572 if (p_bpb->num_fats == 0)
4573 return FFS_FORMATERR;
4575 num_root_sectors = GET16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS;
4576 num_root_sectors = ((num_root_sectors-1) >> p_bd->sector_size_bits) + 1;
4578 p_fs->sectors_per_clu = p_bpb->sectors_per_clu;
4579 p_fs->sectors_per_clu_bits = my_log2(p_bpb->sectors_per_clu);
4580 p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits;
4581 p_fs->cluster_size = 1 << p_fs->cluster_size_bits;
4583 p_fs->num_FAT_sectors = GET16(p_bpb->num_fat_sectors);
4585 p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved);
4586 if (p_bpb->num_fats == 1)
4587 p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
4588 else
4589 p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors;
4591 p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors;
4592 p_fs->data_start_sector = p_fs->root_start_sector + num_root_sectors;
4594 p_fs->num_sectors = GET16(p_bpb->num_sectors);
4595 if (p_fs->num_sectors == 0)
4596 p_fs->num_sectors = GET32(p_bpb->num_huge_sectors);
4598 num_reserved = p_fs->data_start_sector - p_fs->PBR_sector;
4599 p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >> p_fs->sectors_per_clu_bits) + 2;
4600 /* because the cluster index starts with 2 */
4602 if (p_fs->num_clusters < FAT12_THRESHOLD)
4603 p_fs->vol_type = FAT12;
4604 else
4605 p_fs->vol_type = FAT16;
4606 p_fs->vol_id = GET32(p_bpb->vol_serial);
4608 p_fs->root_dir = 0;
4609 p_fs->dentries_in_root = GET16(p_bpb->num_root_entries);
4610 p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS);
4612 p_fs->vol_flag = VOL_CLEAN;
4613 p_fs->clu_srch_ptr = 2;
4614 p_fs->used_clusters = (UINT32) ~0;
4616 p_fs->fs_func = &fat_fs_func;
4618 return FFS_SUCCESS;
4619 } /* end of fat16_mount */
4621 INT32 fat32_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr)
4623 INT32 num_reserved;
4624 BPB32_T *p_bpb = (BPB32_T *) p_pbr->bpb;
4625 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4626 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
4628 if (p_bpb->num_fats == 0)
4629 return FFS_FORMATERR;
4631 p_fs->sectors_per_clu = p_bpb->sectors_per_clu;
4632 p_fs->sectors_per_clu_bits = my_log2(p_bpb->sectors_per_clu);
4633 p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits;
4634 p_fs->cluster_size = 1 << p_fs->cluster_size_bits;
4636 p_fs->num_FAT_sectors = GET32(p_bpb->num_fat32_sectors);
4638 p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved);
4639 if (p_bpb->num_fats == 1)
4640 p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
4641 else
4642 p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors;
4644 p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors;
4645 p_fs->data_start_sector = p_fs->root_start_sector;
4647 p_fs->num_sectors = GET32(p_bpb->num_huge_sectors);
4648 num_reserved = p_fs->data_start_sector - p_fs->PBR_sector;
4650 p_fs->num_clusters = ((p_fs->num_sectors-num_reserved) >> p_fs->sectors_per_clu_bits) + 2;
4651 /* because the cluster index starts with 2 */
4653 p_fs->vol_type = FAT32;
4654 p_fs->vol_id = GET32(p_bpb->vol_serial);
4656 p_fs->root_dir = GET32(p_bpb->root_cluster);
4657 p_fs->dentries_in_root = 0;
4658 p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS);
4660 p_fs->vol_flag = VOL_CLEAN;
4661 p_fs->clu_srch_ptr = 2;
4662 p_fs->used_clusters = (UINT32) ~0;
4664 p_fs->fs_func = &fat_fs_func;
4666 return FFS_SUCCESS;
4667 } /* end of fat32_mount */
4669 static FS_FUNC_T exfat_fs_func = {
4670 .alloc_cluster = exfat_alloc_cluster,
4671 .free_cluster = exfat_free_cluster,
4672 .count_used_clusters = exfat_count_used_clusters,
4674 .init_dir_entry = exfat_init_dir_entry,
4675 .init_ext_entry = exfat_init_ext_entry,
4676 .find_dir_entry = exfat_find_dir_entry,
4677 .delete_dir_entry = exfat_delete_dir_entry,
4678 .get_uni_name_from_ext_entry = exfat_get_uni_name_from_ext_entry,
4679 .count_ext_entries = exfat_count_ext_entries,
4680 .calc_num_entries = exfat_calc_num_entries,
4682 .get_entry_type = exfat_get_entry_type,
4683 .set_entry_type = exfat_set_entry_type,
4684 .get_entry_attr = exfat_get_entry_attr,
4685 .set_entry_attr = exfat_set_entry_attr,
4686 .get_entry_flag = exfat_get_entry_flag,
4687 .set_entry_flag = exfat_set_entry_flag,
4688 .get_entry_clu0 = exfat_get_entry_clu0,
4689 .set_entry_clu0 = exfat_set_entry_clu0,
4690 .get_entry_size = exfat_get_entry_size,
4691 .set_entry_size = exfat_set_entry_size,
4692 .get_entry_time = exfat_get_entry_time,
4693 .set_entry_time = exfat_set_entry_time,
4696 INT32 exfat_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr)
4698 BPBEX_T *p_bpb = (BPBEX_T *) p_pbr->bpb;
4699 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4700 BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info);
4702 if (p_bpb->num_fats == 0)
4703 return FFS_FORMATERR;
4705 p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits;
4706 p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits;
4707 p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits;
4708 p_fs->cluster_size = 1 << p_fs->cluster_size_bits;
4710 p_fs->num_FAT_sectors = GET32(p_bpb->fat_length);
4712 p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset);
4713 if (p_bpb->num_fats == 1)
4714 p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
4715 else
4716 p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors;
4718 p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset);
4719 p_fs->data_start_sector = p_fs->root_start_sector;
4721 p_fs->num_sectors = GET64(p_bpb->vol_length);
4722 p_fs->num_clusters = GET32(p_bpb->clu_count) + 2;
4723 /* because the cluster index starts with 2 */
4725 p_fs->vol_type = EXFAT;
4726 p_fs->vol_id = GET32(p_bpb->vol_serial);
4728 p_fs->root_dir = GET32(p_bpb->root_cluster);
4729 p_fs->dentries_in_root = 0;
4730 p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS);
4732 p_fs->vol_flag = (UINT32) GET16(p_bpb->vol_flags);
4733 p_fs->clu_srch_ptr = 2;
4734 p_fs->used_clusters = (UINT32) ~0;
4736 p_fs->fs_func = &exfat_fs_func;
4738 return FFS_SUCCESS;
4739 } /* end of exfat_mount */
4741 INT32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid)
4743 INT32 ret, dentry, num_entries;
4744 UINT64 size;
4745 CHAIN_T clu;
4746 DOS_NAME_T dos_name, dot_name;
4747 struct super_block *sb = inode->i_sb;
4748 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4750 ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name);
4751 if (ret)
4752 return ret;
4754 /* find_empty_entry must be called before alloc_cluster */
4755 dentry = find_empty_entry(inode, p_dir, num_entries);
4756 if (dentry < 0)
4757 return FFS_FULL;
4759 clu.dir = CLUSTER_32(~0);
4760 clu.size = 0;
4761 clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
4763 /* (1) allocate a cluster */
4764 ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu);
4765 if (ret < 1)
4766 return FFS_FULL;
4768 ret = clear_cluster(sb, clu.dir);
4769 if (ret != FFS_SUCCESS)
4770 return ret;
4772 if (p_fs->vol_type == EXFAT) {
4773 size = p_fs->cluster_size;
4774 } else {
4775 size = 0;
4777 /* initialize the . and .. entry
4778 Information for . points to itself
4779 Information for .. points to parent dir */
4781 dot_name.name_case = 0x0;
4782 MEMCPY(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH);
4784 ret = p_fs->fs_func->init_dir_entry(sb, &clu, 0, TYPE_DIR, clu.dir, 0);
4785 if (ret != FFS_SUCCESS)
4786 return ret;
4788 ret = p_fs->fs_func->init_ext_entry(sb, &clu, 0, 1, NULL, &dot_name);
4789 if (ret != FFS_SUCCESS)
4790 return ret;
4792 MEMCPY(dot_name.name, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH);
4794 if (p_dir->dir == p_fs->root_dir)
4795 ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, CLUSTER_32(0), 0);
4796 else
4797 ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, p_dir->dir, 0);
4799 if (ret != FFS_SUCCESS)
4800 return ret;
4802 ret = p_fs->fs_func->init_ext_entry(sb, &clu, 1, 1, NULL, &dot_name);
4803 if (ret != FFS_SUCCESS)
4804 return ret;
4807 /* (2) update the directory entry */
4808 /* make sub-dir entry in parent directory */
4809 ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, size);
4810 if (ret != FFS_SUCCESS)
4811 return ret;
4813 ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name);
4814 if (ret != FFS_SUCCESS)
4815 return ret;
4817 fid->dir.dir = p_dir->dir;
4818 fid->dir.size = p_dir->size;
4819 fid->dir.flags = p_dir->flags;
4820 fid->entry = dentry;
4822 fid->attr = ATTR_SUBDIR;
4823 fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
4824 fid->size = size;
4825 fid->start_clu = clu.dir;
4827 fid->type= TYPE_DIR;
4828 fid->rwoffset = 0;
4829 fid->hint_last_off = -1;
4831 return FFS_SUCCESS;
4832 } /* end of create_dir */
4834 INT32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, UINT8 mode, FILE_ID_T *fid)
4836 INT32 ret, dentry, num_entries;
4837 DOS_NAME_T dos_name;
4838 struct super_block *sb = inode->i_sb;
4839 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4841 ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name);
4842 if (ret)
4843 return ret;
4845 /* find_empty_entry must be called before alloc_cluster() */
4846 dentry = find_empty_entry(inode, p_dir, num_entries);
4847 if (dentry < 0)
4848 return FFS_FULL;
4850 /* (1) update the directory entry */
4851 /* fill the dos name directory entry information of the created file.
4852 the first cluster is not determined yet. (0) */
4853 ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, CLUSTER_32(0), 0);
4854 if (ret != FFS_SUCCESS)
4855 return ret;
4857 ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name);
4858 if (ret != FFS_SUCCESS)
4859 return ret;
4861 fid->dir.dir = p_dir->dir;
4862 fid->dir.size = p_dir->size;
4863 fid->dir.flags = p_dir->flags;
4864 fid->entry = dentry;
4866 fid->attr = ATTR_ARCHIVE | mode;
4867 fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
4868 fid->size = 0;
4869 fid->start_clu = CLUSTER_32(~0);
4871 fid->type= TYPE_FILE;
4872 fid->rwoffset = 0;
4873 fid->hint_last_off = -1;
4875 return FFS_SUCCESS;
4876 } /* end of create_file */
4878 void remove_file(struct inode *inode, CHAIN_T *p_dir, INT32 entry)
4880 INT32 num_entries;
4881 UINT32 sector;
4882 DENTRY_T *ep;
4883 struct super_block *sb = inode->i_sb;
4884 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4886 ep = get_entry_in_dir(sb, p_dir, entry, &sector);
4887 if (!ep)
4888 return;
4890 buf_lock(sb, sector);
4892 /* buf_lock() before call count_ext_entries() */
4893 num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, entry, ep);
4894 if (num_entries < 0) {
4895 buf_unlock(sb, sector);
4896 return;
4898 num_entries++;
4900 buf_unlock(sb, sector);
4902 /* (1) update the directory entry */
4903 p_fs->fs_func->delete_dir_entry(sb, p_dir, entry, 0, num_entries);
4904 } /* end of remove_file */
4906 INT32 rename_file(struct inode *inode, CHAIN_T *p_dir, INT32 oldentry, UNI_NAME_T *p_uniname, FILE_ID_T *fid)
4908 INT32 ret, newentry = -1, num_old_entries, num_new_entries;
4909 UINT32 sector_old, sector_new;
4910 DOS_NAME_T dos_name;
4911 DENTRY_T *epold, *epnew;
4912 struct super_block *sb = inode->i_sb;
4913 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
4915 epold = get_entry_in_dir(sb, p_dir, oldentry, &sector_old);
4916 if (!epold)
4917 return FFS_MEDIAERR;
4919 buf_lock(sb, sector_old);
4921 /* buf_lock() before call count_ext_entries() */
4922 num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, oldentry, epold);
4923 if (num_old_entries < 0) {
4924 buf_unlock(sb, sector_old);
4925 return FFS_MEDIAERR;
4927 num_old_entries++;
4929 ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_new_entries, &dos_name);
4930 if (ret) {
4931 buf_unlock(sb, sector_old);
4932 return ret;
4935 if (num_old_entries < num_new_entries) {
4936 newentry = find_empty_entry(inode, p_dir, num_new_entries);
4937 if (newentry < 0) {
4938 buf_unlock(sb, sector_old);
4939 return FFS_FULL;
4942 epnew = get_entry_in_dir(sb, p_dir, newentry, &sector_new);
4943 if (!epnew) {
4944 buf_unlock(sb, sector_old);
4945 return FFS_MEDIAERR;
4948 MEMCPY((void *) epnew, (void *) epold, DENTRY_SIZE);
4949 if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) {
4950 p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE);
4951 fid->attr |= ATTR_ARCHIVE;
4953 buf_modify(sb, sector_new);
4954 buf_unlock(sb, sector_old);
4956 if (p_fs->vol_type == EXFAT) {
4957 epold = get_entry_in_dir(sb, p_dir, oldentry+1, &sector_old);
4958 buf_lock(sb, sector_old);
4959 epnew = get_entry_in_dir(sb, p_dir, newentry+1, &sector_new);
4961 if (!epold || !epnew) {
4962 buf_unlock(sb, sector_old);
4963 return FFS_MEDIAERR;
4966 MEMCPY((void *) epnew, (void *) epold, DENTRY_SIZE);
4967 buf_modify(sb, sector_new);
4968 buf_unlock(sb, sector_old);
4971 ret = p_fs->fs_func->init_ext_entry(sb, p_dir, newentry, num_new_entries, p_uniname, &dos_name);
4972 if (ret != FFS_SUCCESS)
4973 return ret;
4975 p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, 0, num_old_entries);
4976 fid->entry = newentry;
4977 } else {
4978 if (p_fs->fs_func->get_entry_type(epold) == TYPE_FILE) {
4979 p_fs->fs_func->set_entry_attr(epold, p_fs->fs_func->get_entry_attr(epold) | ATTR_ARCHIVE);
4980 fid->attr |= ATTR_ARCHIVE;
4982 buf_modify(sb, sector_old);
4983 buf_unlock(sb, sector_old);
4985 ret = p_fs->fs_func->init_ext_entry(sb, p_dir, oldentry, num_new_entries, p_uniname, &dos_name);
4986 if (ret != FFS_SUCCESS)
4987 return ret;
4989 p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, num_new_entries, num_old_entries);
4992 return FFS_SUCCESS;
4993 } /* end of rename_file */
4995 INT32 move_file(struct inode *inode, CHAIN_T *p_olddir, INT32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid)
4997 INT32 ret, newentry, num_new_entries, num_old_entries;
4998 UINT32 sector_mov, sector_new;
4999 CHAIN_T clu;
5000 DOS_NAME_T dos_name;
5001 DENTRY_T *epmov, *epnew;
5002 struct super_block *sb = inode->i_sb;
5003 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
5005 epmov = get_entry_in_dir(sb, p_olddir, oldentry, &sector_mov);
5006 if (!epmov)
5007 return FFS_MEDIAERR;
5009 /* check if the source and target directory is the same */
5010 if (p_fs->fs_func->get_entry_type(epmov) == TYPE_DIR &&
5011 p_fs->fs_func->get_entry_clu0(epmov) == p_newdir->dir)
5012 return FFS_INVALIDPATH;
5014 buf_lock(sb, sector_mov);
5016 /* buf_lock() before call count_ext_entries() */
5017 num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_olddir, oldentry, epmov);
5018 if (num_old_entries < 0) {
5019 buf_unlock(sb, sector_mov);
5020 return FFS_MEDIAERR;
5022 num_old_entries++;
5024 ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, &num_new_entries, &dos_name);
5025 if (ret) {
5026 buf_unlock(sb, sector_mov);
5027 return ret;
5030 newentry = find_empty_entry(inode, p_newdir, num_new_entries);
5031 if (newentry < 0) {
5032 buf_unlock(sb, sector_mov);
5033 return FFS_FULL;
5036 epnew = get_entry_in_dir(sb, p_newdir, newentry, &sector_new);
5037 if (!epnew) {
5038 buf_unlock(sb, sector_mov);
5039 return FFS_MEDIAERR;
5042 MEMCPY((void *) epnew, (void *) epmov, DENTRY_SIZE);
5043 if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) {
5044 p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE);
5045 fid->attr |= ATTR_ARCHIVE;
5047 buf_modify(sb, sector_new);
5048 buf_unlock(sb, sector_mov);
5050 if (p_fs->vol_type == EXFAT) {
5051 epmov = get_entry_in_dir(sb, p_olddir, oldentry+1, &sector_mov);
5052 buf_lock(sb, sector_mov);
5053 epnew = get_entry_in_dir(sb, p_newdir, newentry+1, &sector_new);
5054 if (!epmov || !epnew) {
5055 buf_unlock(sb, sector_mov);
5056 return FFS_MEDIAERR;
5059 MEMCPY((void *) epnew, (void *) epmov, DENTRY_SIZE);
5060 buf_modify(sb, sector_new);
5061 buf_unlock(sb, sector_mov);
5062 } else if (p_fs->fs_func->get_entry_type(epnew) == TYPE_DIR) {
5063 /* change ".." pointer to new parent dir */
5064 clu.dir = p_fs->fs_func->get_entry_clu0(epnew);
5065 clu.flags = 0x01;
5067 epnew = get_entry_in_dir(sb, &clu, 1, &sector_new);
5068 if (!epnew)
5069 return FFS_MEDIAERR;
5071 if (p_newdir->dir == p_fs->root_dir)
5072 p_fs->fs_func->set_entry_clu0(epnew, CLUSTER_32(0));
5073 else
5074 p_fs->fs_func->set_entry_clu0(epnew, p_newdir->dir);
5075 buf_modify(sb, sector_new);
5078 ret = p_fs->fs_func->init_ext_entry(sb, p_newdir, newentry, num_new_entries, p_uniname, &dos_name);
5079 if (ret != FFS_SUCCESS)
5080 return ret;
5082 p_fs->fs_func->delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries);
5084 fid->dir.dir = p_newdir->dir;
5085 fid->dir.size = p_newdir->size;
5086 fid->dir.flags = p_newdir->flags;
5088 fid->entry = newentry;
5090 return FFS_SUCCESS;
5091 } /* end of move_file */
5094 * Sector Read/Write Functions
5097 INT32 sector_read(struct super_block *sb, UINT32 sec, struct buffer_head **bh, INT32 read)
5099 INT32 ret = FFS_MEDIAERR;
5100 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
5102 if ((sec >= (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) {
5103 PRINT("[EXFAT] sector_read: out of range error! (sec = %d)\n", sec);
5104 fs_error(sb);
5105 return ret;
5108 if (!p_fs->dev_ejected) {
5109 ret = bdev_read(sb, sec, bh, 1, read);
5110 if (ret != FFS_SUCCESS)
5111 p_fs->dev_ejected = TRUE;
5114 return ret;
5115 } /* end of sector_read */
5117 INT32 sector_write(struct super_block *sb, UINT32 sec, struct buffer_head *bh, INT32 sync)
5119 INT32 ret = FFS_MEDIAERR;
5120 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
5122 if (sec >= (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) {
5123 PRINT("[EXFAT] sector_write: out of range error! (sec = %d)\n", sec);
5124 fs_error(sb);
5125 return ret;
5127 if (bh == NULL) {
5128 PRINT("[EXFAT] sector_write: bh is NULL!\n");
5129 fs_error(sb);
5130 return ret;
5133 if (!p_fs->dev_ejected) {
5134 ret = bdev_write(sb, sec, bh, 1, sync);
5135 if (ret != FFS_SUCCESS)
5136 p_fs->dev_ejected = TRUE;
5139 return ret;
5140 } /* end of sector_write */
5142 INT32 multi_sector_read(struct super_block *sb, UINT32 sec, struct buffer_head **bh, INT32 num_secs, INT32 read)
5144 INT32 ret = FFS_MEDIAERR;
5145 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
5147 if (((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) {
5148 PRINT("[EXFAT] multi_sector_read: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs);
5149 fs_error(sb);
5150 return ret;
5153 if (!p_fs->dev_ejected) {
5154 ret = bdev_read(sb, sec, bh, num_secs, read);
5155 if (ret != FFS_SUCCESS)
5156 p_fs->dev_ejected = TRUE;
5159 return ret;
5160 } /* end of multi_sector_read */
5162 INT32 multi_sector_write(struct super_block *sb, UINT32 sec, struct buffer_head *bh, INT32 num_secs, INT32 sync)
5164 INT32 ret = FFS_MEDIAERR;
5165 FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info);
5167 if ((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) {
5168 PRINT("[EXFAT] multi_sector_write: out of range error! (sec = %d, num_secs = %d)\n", sec, num_secs);
5169 fs_error(sb);
5170 return ret;
5172 if (bh == NULL) {
5173 PRINT("[EXFAT] multi_sector_write: bh is NULL!\n");
5174 fs_error(sb);
5175 return ret;
5178 if (!p_fs->dev_ejected) {
5179 ret = bdev_write(sb, sec, bh, num_secs, sync);
5180 if (ret != FFS_SUCCESS)
5181 p_fs->dev_ejected = TRUE;
5184 return ret;
5185 } /* end of multi_sector_write */
5187 /* end of exfat_core.c */