From ee41d9c0bd4f7de161c424ca3e09dcd35e9fa9b9 Mon Sep 17 00:00:00 2001 From: payton Date: Thu, 23 Nov 2023 15:41:13 +0800 Subject: [PATCH 1/5] =?UTF-8?q?1.qlog=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sf_app/code/source/app/sf_service.c | 78 +++++++++++++------ .../sf_app/code/source/storeMng/sf_storeMng.c | 2 +- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/code/application/source/sf_app/code/source/app/sf_service.c b/code/application/source/sf_app/code/source/app/sf_service.c index 5ed2ed0cb..432881dd2 100755 --- a/code/application/source/sf_app/code/source/app/sf_service.c +++ b/code/application/source/sf_app/code/source/app/sf_service.c @@ -78,6 +78,11 @@ SF_THREAD_S ThumbSend = { .TskId = -1, }; +SF_THREAD_S QlogTsk = { + .IsRun = 0, + .TskId = -1, +}; + SINT32 app_ttyusb_IsOpen(void) { int retryTime = 0; int retryFlag = 0; @@ -147,26 +152,53 @@ SF_BOOL app_disconnect_4g_module(void) { #if SF_QLOG_ENABLE static SINT16 app_Qlog_procress(void) { - SINT16 s32ret = SF_SUCCESS; + SINT16 s32ret = SF_SUCCESS; - char qlogPath[128] = {0}; - char qlogDirCmd[128] = {0}; - time_t timep; - struct tm *p; - time(&timep); - p = gmtime(&timep); - if (access("/mnt/sd/qlog", F_OK) != 0) { + char qlogPath[128] = {0}; + char qlogDirCmd[128] = {0}; + time_t timep; + struct tm *p; + if(SF_FAILURE == sf_check_sd()) + { + MLOGE("ERROR sf_check_sd\n"); + return SF_FAILURE; + } + + time(&timep); + p = gmtime(&timep); + if (access("/mnt/sd/qlog", F_OK) != 0) { s32ret = mkdir("/mnt/sd/qlog", S_IRWXU); if (s32ret != 0) - return s32ret; - } - sprintf(qlogPath, "%04d%02d%02d%02d%02d%02d", p->tm_year + 1900, - p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); - sprintf(qlogDirCmd, "/usr/bin/QLog -s %s%s &", QLOG_PATH, qlogPath); - MLOGD("%s\n", qlogDirCmd); - s32ret = system(qlogDirCmd); + return s32ret; + } + sprintf(qlogPath, "%04d%02d%02d%02d%02d%02d", p->tm_year + 1900, + p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); + sprintf(qlogDirCmd, "/usr/bin/QLog -s %s%s &", QLOG_PATH, qlogPath); + MLOGD("%s\n", qlogDirCmd); + s32ret = system(qlogDirCmd); + while (sf_app_while_flag()) + { + sf_sleep_ms(200); + if (sf_sd_status_get() != SF_SD_OK) + { + break; + } + } + s32ret = system("killall QLog"); + QlogTsk.IsRun = 0; + MLOGI("exit QlogTsk.IsRun:%d\n", QlogTsk.IsRun); + return s32ret; +} - return s32ret; +void sf_app_qlog_start(void) +{ + MLOGI("QlogTsk.IsRun:%d\n", QlogTsk.IsRun); + if (!QlogTsk.IsRun) + { + pthread_create(&QlogTsk.TskId, NULL, (void *)app_Qlog_procress, NULL); + QlogTsk.IsRun = 1; + SF_MUTEX_INIT_LOCK(QlogTsk.mutexLock); + } } #endif @@ -1413,7 +1445,7 @@ static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) #if SF_QLOG_ENABLE if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + sf_app_qlog_start(); #endif s32ret = sf_4G_sim_init(pfnParam); @@ -1527,7 +1559,7 @@ static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) #if SF_QLOG_ENABLE if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + sf_app_qlog_start(); #endif @@ -1584,7 +1616,7 @@ static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) #if SF_QLOG_ENABLE if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + sf_app_qlog_start(); #endif s32ret = sf_4G_sim_init(pfnParam); @@ -1618,7 +1650,7 @@ static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) #if SF_QLOG_ENABLE if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + sf_app_qlog_start(); #endif s32ret = sf_4G_sim_init(pfnParam); @@ -1669,7 +1701,7 @@ static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) #if SF_QLOG_ENABLE if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + sf_app_qlog_start(); #endif @@ -1809,7 +1841,7 @@ static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) #if SF_QLOG_ENABLE if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + sf_app_qlog_start(); #endif s32ret = sf_4G_sim_init(pfnParam); @@ -1969,7 +2001,7 @@ SINT32 sf_module_reboot_reg_net(void) #if SF_QLOG_ENABLE if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + sf_app_qlog_start(); #endif s32ret = sf_4G_sim_init(&stpfncallback); diff --git a/code/application/source/sf_app/code/source/storeMng/sf_storeMng.c b/code/application/source/sf_app/code/source/storeMng/sf_storeMng.c index 53f9108bd..d13ab4996 100644 --- a/code/application/source/sf_app/code/source/storeMng/sf_storeMng.c +++ b/code/application/source/sf_app/code/source/storeMng/sf_storeMng.c @@ -384,7 +384,7 @@ SINT32 sf_sd_loopremove(const char *path) SF_SD_STATUS_E sf_sd_status_get(void) { - MLOGI("SdStatus:%d\n", SdStatus); + //MLOGI("SdStatus:%d\n", SdStatus); return SdStatus; } From a685df607b49263e099e2c7e96eb905a49ff847c Mon Sep 17 00:00:00 2001 From: payton Date: Thu, 23 Nov 2023 15:45:32 +0800 Subject: [PATCH 2/5] =?UTF-8?q?1.exfat=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../init.d/S07_SysInit | 2 + .../source/cardv/SrcCode/System/SysStrg_Exe.c | 112 +- code/driver/source/Makefile | 1 + code/driver/source/fs/exfat/.gitignore | 7 + code/driver/source/fs/exfat/Kconfig | 39 + code/driver/source/fs/exfat/LICENSE | 339 ++ code/driver/source/fs/exfat/Makefile | 37 + code/driver/source/fs/exfat/README.md | 98 + .../source/fs/exfat/Untitled Project.IAB | Bin 0 -> 94208 bytes .../source/fs/exfat/Untitled Project.IAD | Bin 0 -> 1248 bytes .../source/fs/exfat/Untitled Project.IMB | Bin 0 -> 24576 bytes .../source/fs/exfat/Untitled Project.IMD | Bin 0 -> 568 bytes .../source/fs/exfat/Untitled Project.PFI | Bin 0 -> 84 bytes .../source/fs/exfat/Untitled Project.PO | Bin 0 -> 776 bytes .../source/fs/exfat/Untitled Project.PR | Bin 0 -> 7064 bytes .../source/fs/exfat/Untitled Project.PRI | Bin 0 -> 43016 bytes .../source/fs/exfat/Untitled Project.PS | Bin 0 -> 201236 bytes .../fs/exfat/Untitled Project.SearchResults | 501 ++ .../source/fs/exfat/Untitled Project.WK3 | Bin 0 -> 90102 bytes code/driver/source/fs/exfat/dkms.conf | 7 + code/driver/source/fs/exfat/exfat-km.mk | 11 + code/driver/source/fs/exfat/exfat_api.c | 528 ++ code/driver/source/fs/exfat/exfat_api.h | 206 + code/driver/source/fs/exfat/exfat_bitmap.c | 63 + code/driver/source/fs/exfat/exfat_bitmap.h | 55 + code/driver/source/fs/exfat/exfat_blkdev.c | 197 + code/driver/source/fs/exfat/exfat_blkdev.h | 73 + code/driver/source/fs/exfat/exfat_cache.c | 784 +++ code/driver/source/fs/exfat/exfat_cache.h | 85 + code/driver/source/fs/exfat/exfat_config.h | 69 + code/driver/source/fs/exfat/exfat_core.c | 5138 +++++++++++++++++ code/driver/source/fs/exfat/exfat_core.h | 671 +++ code/driver/source/fs/exfat/exfat_data.c | 77 + code/driver/source/fs/exfat/exfat_data.h | 58 + code/driver/source/fs/exfat/exfat_nls.c | 448 ++ code/driver/source/fs/exfat/exfat_nls.h | 91 + code/driver/source/fs/exfat/exfat_oal.c | 196 + code/driver/source/fs/exfat/exfat_oal.h | 74 + code/driver/source/fs/exfat/exfat_super.c | 2753 +++++++++ code/driver/source/fs/exfat/exfat_super.h | 173 + code/driver/source/fs/exfat/exfat_upcase.c | 405 ++ code/driver/source/fs/exfat/exfat_version.h | 19 + code/lib/external/Makefile | 16 +- .../make_post.sh | 1 + .../source/cardv/SrcCode/System/SysStrg_Exe.c | 4 +- 45 files changed, 13328 insertions(+), 10 deletions(-) create mode 100755 code/driver/source/fs/exfat/.gitignore create mode 100755 code/driver/source/fs/exfat/Kconfig create mode 100755 code/driver/source/fs/exfat/LICENSE create mode 100755 code/driver/source/fs/exfat/Makefile create mode 100755 code/driver/source/fs/exfat/README.md create mode 100755 code/driver/source/fs/exfat/Untitled Project.IAB create mode 100755 code/driver/source/fs/exfat/Untitled Project.IAD create mode 100755 code/driver/source/fs/exfat/Untitled Project.IMB create mode 100755 code/driver/source/fs/exfat/Untitled Project.IMD create mode 100755 code/driver/source/fs/exfat/Untitled Project.PFI create mode 100755 code/driver/source/fs/exfat/Untitled Project.PO create mode 100755 code/driver/source/fs/exfat/Untitled Project.PR create mode 100755 code/driver/source/fs/exfat/Untitled Project.PRI create mode 100755 code/driver/source/fs/exfat/Untitled Project.PS create mode 100755 code/driver/source/fs/exfat/Untitled Project.SearchResults create mode 100755 code/driver/source/fs/exfat/Untitled Project.WK3 create mode 100755 code/driver/source/fs/exfat/dkms.conf create mode 100755 code/driver/source/fs/exfat/exfat-km.mk create mode 100755 code/driver/source/fs/exfat/exfat_api.c create mode 100755 code/driver/source/fs/exfat/exfat_api.h create mode 100755 code/driver/source/fs/exfat/exfat_bitmap.c create mode 100755 code/driver/source/fs/exfat/exfat_bitmap.h create mode 100755 code/driver/source/fs/exfat/exfat_blkdev.c create mode 100755 code/driver/source/fs/exfat/exfat_blkdev.h create mode 100755 code/driver/source/fs/exfat/exfat_cache.c create mode 100755 code/driver/source/fs/exfat/exfat_cache.h create mode 100755 code/driver/source/fs/exfat/exfat_config.h create mode 100755 code/driver/source/fs/exfat/exfat_core.c create mode 100755 code/driver/source/fs/exfat/exfat_core.h create mode 100755 code/driver/source/fs/exfat/exfat_data.c create mode 100755 code/driver/source/fs/exfat/exfat_data.h create mode 100755 code/driver/source/fs/exfat/exfat_nls.c create mode 100755 code/driver/source/fs/exfat/exfat_nls.h create mode 100755 code/driver/source/fs/exfat/exfat_oal.c create mode 100755 code/driver/source/fs/exfat/exfat_oal.h create mode 100755 code/driver/source/fs/exfat/exfat_super.c create mode 100755 code/driver/source/fs/exfat/exfat_super.h create mode 100755 code/driver/source/fs/exfat/exfat_upcase.c create mode 100755 code/driver/source/fs/exfat/exfat_version.h diff --git a/BSP/root-fs/rootfs/etc_Model/etc_565_HUNTING_EVB_LINUX_4G_S550/init.d/S07_SysInit b/BSP/root-fs/rootfs/etc_Model/etc_565_HUNTING_EVB_LINUX_4G_S550/init.d/S07_SysInit index fab776891..7a29d54bc 100755 --- a/BSP/root-fs/rootfs/etc_Model/etc_565_HUNTING_EVB_LINUX_4G_S550/init.d/S07_SysInit +++ b/BSP/root-fs/rootfs/etc_Model/etc_565_HUNTING_EVB_LINUX_4G_S550/init.d/S07_SysInit @@ -11,6 +11,8 @@ SF_ADC_MUXA=224 SF_ADC_MUXB=225 DELAY=0.003 +insmod /etc/lib/modules/$KERVER/extra/fs/exfat/exfat.ko + echo ${SF_ADC_MUXA} > /sys/class/gpio/export echo ${SF_ADC_MUXB} > /sys/class/gpio/export diff --git a/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c b/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c index 2c87e66f0..2b27918ab 100644 --- a/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c +++ b/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c @@ -131,6 +131,7 @@ static FST_FS_TYPE m_GxStrgType = FST_FS_TYPE_UITRON; #if (FWS_FUNC == ENABLE) static void *mp_fwsrv_work_buf = NULL; #endif +static BOOL g_bSupportExfat = FALSE; /////////////////////////////////////////////////////////////////////////////// // // EMBMEM @@ -359,6 +360,8 @@ void System_OnStrgInit_FS(void) GxStrg_SetConfigEx(0, FILE_CFG_MAX_OPEN_FILE, 10); #endif + GxStrg_SetConfigEx(0, FILE_CFG_SUPPORT_EXFAT, TRUE); + g_bSupportExfat = TRUE; //set the device node of msdc mode for emmc only #if (defined(_EMBMEM_EMMC_) && !defined(__FREERTOS)) emmc_set_dev_node("/dev/mmcblk2p5"); //This devicde node is related to storate-partition, it is last rootfslX logical partition. Using "cat /proc/nvt_info/emmc" to get. @@ -586,14 +589,64 @@ void Card_DetBusy(void) } #if (FSCK_FUNC == ENABLE) +int search_str_in_file(char *path, char *str) +{ + FILE *fp = NULL; + UINT32 u32ize = 0; + int found = 0; + char *pStrSrc = NULL; + + fp = fopen(path, "r"); + if (fp) { + fseek(fp, 0, SEEK_END); + u32ize = ftell(fp); // take file size + fseek(fp, 0, SEEK_SET); // move to position zero + pStrSrc = (char *)malloc(u32ize * sizeof(char)); + + if (pStrSrc) { + fread(pStrSrc, 1, u32ize, fp); + if (strstr(pStrSrc, str)) { + found = 1; + } + free(pStrSrc); + } + + fclose(fp); + fp = NULL; + pStrSrc = NULL; + u32ize = 0; + } + + return found; +} + +int System_check_mmcblk0p1(void) +{ + SysMain_system("ls /dev/mmcblk0p1 > /tmp/lsdev.txt"); + vos_util_delay_ms(100); + if (search_str_in_file("/tmp/lsdev.txt", "/dev/mmcblk0p1")) { + return 1; + } else { + return 0; + } +} + int System_mount_storage(char *pMountPath) { int ret = 0; time_t t, t_local, t_gmt; struct tm tt_local, tt_gmt; char opts[20]; - char *pDevSrc = "/dev/mmcblk0p1"; - char *pFileSysType = "vfat"; + char *pDevSrc; + char *pFileSysType = "vfat"; + char *pFileSysExType = "exfat"; + BOOL bexfat = FALSE; + + if (System_check_mmcblk0p1()) { + pDevSrc = "/dev/mmcblk0p1"; + } else { + pDevSrc = "/dev/mmcblk0"; + } time(&t); localtime_r(&t, &tt_local); @@ -604,8 +657,47 @@ int System_mount_storage(char *pMountPath) snprintf(opts, 19, "time_offset=%d", (t_local-t_gmt)/60); DBG_IND("gtime=%d, ltime=%d, diff=%d, m=%d, %s\r\n", t_gmt, t_local, (t_local-t_gmt), (t_local-t_gmt)/60, opts); + { + long long DevSize = 0; + int fd = 0; + long long size = 0; + + DevSize = 0;//set to zero first + + fd = open(pDevSrc, O_RDONLY); + if(fd < 0) { + DBG_ERR("open %s: errno = %d, errmsg = %s\r\n", pDevSrc, errno, strerror(errno)); + } else { + if(ioctl(fd, BLKGETSIZE64, &size) < 0) { + DBG_ERR("ioctl BLKGETSIZE64 failed\r\n"); + } + + if (0 != close(fd)) { + DBG_ERR("close %s: errno = %d, errmsg = %s\r\n", pDevSrc, errno, strerror(errno)); + } + } + + DBG_DUMP("%s: %s size = %lld\r\n", __func__, pDevSrc, size); + + DevSize = size; + + //original SD card + if(g_bSupportExfat && DevSize > 32*1024*1024*1024LL) + { + bexfat = TRUE; + } + else + { + bexfat = FALSE; + } + } + // mount sd card - ret = mount(pDevSrc, pMountPath, pFileSysType, MS_DIRSYNC, opts); + if (bexfat == FALSE) { + ret = mount(pDevSrc, pMountPath, pFileSysType, MS_DIRSYNC, opts); + } else { + ret = mount(pDevSrc, pMountPath, pFileSysExType, MS_DIRSYNC, opts); + } if(ret) { if (errno == EBUSY) { @@ -636,6 +728,7 @@ int System_umount_storage(char *pMountPath) } #endif + INT32 System_OnStrgInsert(VControl *pCtrl, UINT32 paramNum, UINT32 *paramArray) { UINT32 stg_id = paramArray[0]; @@ -660,8 +753,15 @@ INT32 System_OnStrgInsert(VControl *pCtrl, UINT32 paramNum, UINT32 *paramArray) System_umount_storage(pMountPath); /*Under normal situation, fsck checking doesn't need to print the message via UART port. We sotre the message to /tmp/fsck.txt (on DRAM). */ - SysMain_system("fsck.fat -a /dev/mmcblk0p1 > /tmp/fsck.txt"); //Store to /tmp/fsck.txt and use "cat /tmp/fsck.txt". - //SysMain_system("fsck.fat -a /dev/mmcblk0p1"); //The fsck ckecking will print the message directly. + if (System_check_mmcblk0p1()) { + DBG_IND("fsck /dev/mmcblk0p1\r\n"); + SysMain_system("fsck.fat -a /dev/mmcblk0p1 > /tmp/fsck.txt"); //Store to /tmp/fsck.txt and use "cat /tmp/fsck.txt". + //SysMain_system("fsck.fat -a /dev/mmcblk0p1"); //The fsck checking will print the message directly. + } else { + DBG_IND("no /dev/mmcblk0p1, try to fsck /dev/mmcblk0\r\n"); + SysMain_system("fsck.fat -a /dev/mmcblk0 > /tmp/fsck.txt"); //Store to /tmp/fsck.txt and use "cat /tmp/fsck.txt". + //SysMain_system("fsck.fat -a /dev/mmcblk0"); //The fsck checking will print the message directly. + } ret_val = System_mount_storage(pMountPath); if (ret_val) { @@ -722,7 +822,7 @@ INT32 System_OnStrgInsert(VControl *pCtrl, UINT32 paramNum, UINT32 *paramArray) dcfParm.WorkbuffSize = POOL_SIZE_DCF_BUFFER; DCF_Open(&dcfParm); -// DCF_ScanObj(); + // DCF_ScanObj(); } #endif diff --git a/code/driver/source/Makefile b/code/driver/source/Makefile index 8aff395ef..ab237b184 100755 --- a/code/driver/source/Makefile +++ b/code/driver/source/Makefile @@ -46,6 +46,7 @@ obj-m += \ msdcnvt/msdcnvt_custom_si/ \ touch/touch_gt911/ \ mcu/ \ + fs/exfat/ \ #obj-m += net/bcmdhd.100.10.545.x/ \ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += debug/nvt_data_breakpoint/ diff --git a/code/driver/source/fs/exfat/.gitignore b/code/driver/source/fs/exfat/.gitignore new file mode 100755 index 000000000..241505f47 --- /dev/null +++ b/code/driver/source/fs/exfat/.gitignore @@ -0,0 +1,7 @@ +*.cmd +*.ko +*.mod.c +modules.order +Module.symvers +*.o +.tmp_versions diff --git a/code/driver/source/fs/exfat/Kconfig b/code/driver/source/fs/exfat/Kconfig new file mode 100755 index 000000000..78b32aa2c --- /dev/null +++ b/code/driver/source/fs/exfat/Kconfig @@ -0,0 +1,39 @@ +config EXFAT_FS + tristate "exFAT fs support" + select NLS + help + This adds support for the exFAT file system. + +config EXFAT_DISCARD + bool "enable discard support" + depends on EXFAT_FS + default y + +config EXFAT_DELAYED_SYNC + bool "enable delayed sync" + depends on EXFAT_FS + default n + +config EXFAT_KERNEL_DEBUG + bool "enable kernel debug features via ioctl" + depends on EXFAT_FS + default n + +config EXFAT_DEBUG_MSG + bool "print debug messages" + depends on EXFAT_FS + default n + +config EXFAT_DEFAULT_CODEPAGE + int "Default codepage for exFAT" + default 437 + depends on EXFAT_FS + help + This option should be set to the codepage of your exFAT filesystems. + +config EXFAT_DEFAULT_IOCHARSET + string "Default iocharset for exFAT" + default "utf8" + depends on EXFAT_FS + help + Set this to the default input/output character set you'd like exFAT to use. diff --git a/code/driver/source/fs/exfat/LICENSE b/code/driver/source/fs/exfat/LICENSE new file mode 100755 index 000000000..d159169d1 --- /dev/null +++ b/code/driver/source/fs/exfat/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/code/driver/source/fs/exfat/Makefile b/code/driver/source/fs/exfat/Makefile new file mode 100755 index 000000000..52bcee4b9 --- /dev/null +++ b/code/driver/source/fs/exfat/Makefile @@ -0,0 +1,37 @@ +obj-m += exfat.o +exfat-objs := exfat_core.o exfat_super.o exfat_api.o exfat_blkdev.o exfat_cache.o \ + exfat_data.o exfat_bitmap.o exfat_nls.o exfat_oal.o exfat_upcase.o +ccflags-y += -I$(NVT_DRIVER_DIR)/include + +ifeq ($(KERNELRELEASE),) +PWD := $(shell pwd) +KERVER ?= $(NVT_LINUX_VER) +KDIR ?= $(KERNELDIR) +MDIR ?= $(KERNELDIR)/_install_modules/lib/modules/$(KERVER)/extra +MODPATH := $(shell echo $(PWD) | awk -F'linux-driver/' '{print $$NF}') +MODNAME := $(shell echo $(obj-m:.o=.ko)) + +modules: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +modules_install: + @if [ -z $(NVT_MOD_INSTALL) ]; then \ + rm -f $(MDIR)/$(MODPATH)/$(MODNAME); \ + install -m644 -b -D $(MODNAME) ${MDIR}/$(MODPATH)/$(MODNAME); \ + cd $(KDIR)/_install_modules/lib/modules/$(KERVER)/; depmod -b $(KDIR)/_install_modules/ -a $(KERVER); \ + else \ + mkdir -p $(NVT_MOD_INSTALL)/lib/modules/$(KERVER); \ + install -m644 -b -D $(MODNAME) $(NVT_MOD_INSTALL)/lib/modules/$(KERVER)/extra/$(MODPATH)/$(MODNAME); \ + fi + +clean: + @SRC="`find . -name "*.c" ! -name "*.mod.c"`"; \ + if [ "$$SRC" ]; then \ + rm -rf .tmp_versions Module.symvers modules.order `find . -type f -name "*.mod.c" -o -name ".*.cmd" -o -name "*.o" -o -name "*.ko" -o -name "modules.order" -o -name *~`; \ + echo ">>> Clean"; \ + else \ + echo ">>> Skip"; \ + fi \ + +.PHONY: modules modules_install clean +endif diff --git a/code/driver/source/fs/exfat/README.md b/code/driver/source/fs/exfat/README.md new file mode 100755 index 000000000..feab40038 --- /dev/null +++ b/code/driver/source/fs/exfat/README.md @@ -0,0 +1,98 @@ +exfat-nofuse +============ + +Linux non-fuse read/write kernel driver for the exFAT, FAT12, FAT16 and vfat (FAT32) file systems.
+Originally ported from Android kernel v3.0. + +Kudos to ksv1986 for the mutex patch!
+Thanks to JackNorris for being awesome and providing the clear_inode() patch.
+
+Big thanks to lqs for completing the driver!
+Big thanks to benpicco for fixing 3.11.y compatibility! + + +Special thanks to github user AndreiLux for spreading the word about the leak!
+ + +Installing as a stand-alone module: +==================================== + + make + sudo make install + +To load the driver manually, run this as root: + + modprobe exfat + +You may also specify custom toolchains by using CROSS_COMPILE flag, in my case: +>CROSS_COMPILE=../dorimanx-SG2-I9100-Kernel/android-toolchain/bin/arm-eabi- + +Installing as a part of the kernel: +====================================== + +Let's take [linux] as the path to your kernel source dir... + + cd [linux] + cp -rvf exfat-nofuse [linux]/fs/exfat + +edit [linux]/fs/Kconfig +``` + menu "DOS/FAT/NT Filesystems" + + source "fs/fat/Kconfig" + +source "fs/exfat/Kconfig" + source "fs/ntfs/Kconfig" + endmenu +``` + + +edit [linux]/fs/Makefile +``` + obj-$(CONFIG_FAT_FS) += fat/ + +obj-$(CONFIG_EXFAT_FS) += exfat/ + obj-$(CONFIG_BFS_FS) += bfs/ +``` + + cd [linux] + make menuconfig + +Go to: +> File systems > DOS/FAT/NT +> check exfat as MODULE (M) +> (437) Default codepage for exFAT +> (utf8) Default iocharset for exFAT + +> ESC to main menu +> Save an Alternate Configuration File +> ESC ESC + +build your kernel + +Have fun. + + +Installing as a DKMS module: +================================= + +You can have even more fun with exfat-nofuse by installing it as a DKMS module has the main advantage of being auto-compiled (and thus, possibly surviving) between kernel upgrades. + +First, get dkms. On Ubuntu this should be: + + sudo apt install dkms + +Then copy the root of this repository to /usr/share: + + sudo cp -R . /usr/src/exfat-1.2.8 (or whatever version number declared on dkms.conf is) + sudo dkms add -m exfat -v 1.2.8 + +Build and load the module: + + sudo dkms build -m exfat -v 1.2.8 + sudo dkms install -m exfat -v 1.2.8 + +Now you have a proper dkms module that will work for a long time... hopefully. + + + +Free Software for the Free Minds! +================================= diff --git a/code/driver/source/fs/exfat/Untitled Project.IAB b/code/driver/source/fs/exfat/Untitled Project.IAB new file mode 100755 index 0000000000000000000000000000000000000000..9b2f9be2d6e4605dfa88550caaf872f3cc82284f GIT binary patch literal 94208 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'zJ{Fn8hnhn*AQUl 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 c*Z4KJ^VlJaE7FaqjQkd(V0I?e&Qa%5Yjz@}Lo7 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 MJkaEU|D*^01^Pl0{{R30 literal 0 HcmV?d00001 diff --git a/code/driver/source/fs/exfat/Untitled Project.IMD b/code/driver/source/fs/exfat/Untitled Project.IMD new file mode 100755 index 0000000000000000000000000000000000000000..38b402ec3d2745249fad2bdc5f83e068c86264d6 GIT binary patch literal 568 zcmbOv!oVQQV8qP8$S|Nl0BFAq(||ewY&jc{1Yr#z{sMH91=x=VnW1@yDLQ9agdAwP@Mrn-8v?Oy&;hSt{|Bn5a9q+=Kx|rKqmu(AdFp|n3oS? hF9i_+Ky?8i1_HcbW?*0eazSCCaqJmWgV}4aUjYuN8@~Vm literal 0 HcmV?d00001 diff --git a/code/driver/source/fs/exfat/Untitled Project.PFI b/code/driver/source/fs/exfat/Untitled Project.PFI new file mode 100755 index 0000000000000000000000000000000000000000..763d7e82d1c0cff399f73963647df7354376640d GIT binary patch literal 84 zcmWN|%ME}q48TxRX!#Wg&>=b$`_F-;JUKZ8U{Hc@gg&`v70p^8R=a6ebq;&#Qh49? I(W~am4?@@hhX4Qo literal 0 HcmV?d00001 diff --git a/code/driver/source/fs/exfat/Untitled Project.PO b/code/driver/source/fs/exfat/Untitled Project.PO new file mode 100755 index 0000000000000000000000000000000000000000..f1b04896f803c5b2f67c3ffb49354b4fbd8356ad GIT binary patch literal 776 zcmXpMXJC+JFkFMdG&M9ZHI2{7 z%qy*kFHXshFHO$LOo~a)Pf3kQDatHMEs815FD*(=jY%txNv%jrEI~JR$nY01F)(Bd t8Q0Rrp#>tcz)&C$Z~?WkK((Hbf6a7(`vnstl%E2mC465ny*T!a2>{S~Bf|gy literal 0 HcmV?d00001 diff --git a/code/driver/source/fs/exfat/Untitled Project.PR b/code/driver/source/fs/exfat/Untitled Project.PR new file mode 100755 index 0000000000000000000000000000000000000000..e77694cfaf7f281ef48e3520edf0867ffd3e875a GIT binary patch literal 7064 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 literal 0 HcmV?d00001 diff --git a/code/driver/source/fs/exfat/Untitled Project.PS b/code/driver/source/fs/exfat/Untitled Project.PS new file mode 100755 index 0000000000000000000000000000000000000000..369c24441a69d510f28333a5f3fceb04c2f53b7f GIT binary patch literal 201236 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 +Exfat_api.c: err = ffsLookupFile(inode, path, fid); +Exfat_api.c:int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsCreateFile(inode, path, mode, fid); +Exfat_api.c:int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsReadFile(inode, fid, buffer, count, rcount); +Exfat_api.c:int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsWriteFile(inode, fid, buffer, count, wcount); +Exfat_api.c:int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: DPRINTK("FsTruncateFile entered (inode %p size %llu)\n", inode, new_size); +Exfat_api.c: err = ffsTruncateFile(inode, old_size, new_size); +Exfat_api.c:int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +Exfat_api.c:int FsRemoveFile(struct inode *inode, FILE_ID_T *fid) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsRemoveFile(inode, fid); +Exfat_api.c:int FsSetAttr(struct inode *inode, u32 attr) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsSetAttr(inode, attr); +Exfat_api.c:int FsReadStat(struct inode *inode, DIR_ENTRY_T *info) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsGetStat(inode, info); +Exfat_api.c:int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: DPRINTK("FsWriteStat entered (inode %p info %p\n", inode, info); +Exfat_api.c: err = ffsSetStat(inode, info); +Exfat_api.c:int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsMapCluster(inode, clu_offset, clu); +Exfat_api.c:int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsCreateDir(inode, path, fid); +Exfat_api.c:int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsReadDir(inode, dir_entry); +Exfat_api.c:int FsRemoveDir(struct inode *inode, FILE_ID_T *fid) +Exfat_api.c: struct super_block *sb = inode->i_sb; +Exfat_api.c: err = ffsRemoveDir(inode, fid); +Exfat_api.h: int FsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); +Exfat_api.h: int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); +Exfat_api.h: int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); +Exfat_api.h: int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); +Exfat_api.h: int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); +Exfat_api.h: int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); +Exfat_api.h: int FsRemoveFile(struct inode *inode, FILE_ID_T *fid); +Exfat_api.h: int FsSetAttr(struct inode *inode, u32 attr); +Exfat_api.h: int FsReadStat(struct inode *inode, DIR_ENTRY_T *info); +Exfat_api.h: int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info); +Exfat_api.h: int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); +Exfat_api.h: int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); +Exfat_api.h: int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry); +Exfat_api.h: int FsRemoveDir(struct inode *inode, FILE_ID_T *fid); +Exfat_core.c:s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: ret = resolve_path(inode, path, &dir, &uni_name); +Exfat_core.c:s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: ret = resolve_path(inode, path, &dir, &uni_name); +Exfat_core.c: ret = create_file(inode, &dir, &uni_name, mode, fid); +Exfat_core.c:s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c:s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c:s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c:static void update_parent_info(FILE_ID_T *fid, struct inode *parent_inode) +Exfat_core.c:s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +Exfat_core.c: struct inode *new_inode = new_dentry->d_inode; +Exfat_core.c:s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: remove_file(inode, &dir, dentry); +Exfat_core.c:s32 ffsSetAttr(struct inode *inode, u32 attr) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c:s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c:s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c:s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c: if (EXFAT_I(inode)->mmu_private == 0) +Exfat_core.c: num_clusters = (s32)((EXFAT_I(inode)->mmu_private-1) >> p_fs->cluster_size_bits) + 1; +Exfat_core.c: /* add number of new blocks to inode */ +Exfat_core.c: inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); +Exfat_core.c:s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: ret = resolve_path(inode, path, &dir, &uni_name); +Exfat_core.c: ret = create_dir(inode, &dir, &uni_name, fid); +Exfat_core.c:s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c:s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: remove_file(inode, &dir, dentry); +Exfat_core.c:s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c: size = i_size_read(inode); +Exfat_core.c: i_size_write(inode, i_size_read(inode)+p_fs->cluster_size); +Exfat_core.c: EXFAT_I(inode)->mmu_private += p_fs->cluster_size; +Exfat_core.c: EXFAT_I(inode)->fid.size += p_fs->cluster_size; +Exfat_core.c: EXFAT_I(inode)->fid.flags = p_dir->flags; +Exfat_core.c: inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); +Exfat_core.c:s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_core.c: fid->size = i_size_read(inode); +Exfat_core.c:s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: dentry = find_empty_entry(inode, p_dir, num_entries); +Exfat_core.c:s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: dentry = find_empty_entry(inode, p_dir, num_entries); +Exfat_core.c:void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c:s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 oldentry, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: newentry = find_empty_entry(inode, p_dir, num_new_entries); +Exfat_core.c:s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +Exfat_core.c: struct super_block *sb = inode->i_sb; +Exfat_core.c: newentry = find_empty_entry(inode, p_newdir, num_new_entries); +Exfat_core.h:s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); +Exfat_core.h:s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); +Exfat_core.h:s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); +Exfat_core.h:s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); +Exfat_core.h:s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); +Exfat_core.h:s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); +Exfat_core.h:s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid); +Exfat_core.h:s32 ffsSetAttr(struct inode *inode, u32 attr); +Exfat_core.h:s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info); +Exfat_core.h:s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info); +Exfat_core.h:s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); +Exfat_core.h:s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); +Exfat_core.h:s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_ent); +Exfat_core.h:s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid); +Exfat_core.h:s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries); +Exfat_core.h:s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname); +Exfat_core.h:s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +Exfat_core.h:s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid); +Exfat_core.h:void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry); +Exfat_core.h:s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 old_entry, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +Exfat_core.h:s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +Exfat_super.c:/* Some of the source code in this file came from "linux/fs/fat/file.c","linux/fs/fat/inode.c" and "linux/fs/fat/misc.c". */ +Exfat_super.c: * linux/fs/fat/inode.c +Exfat_super.c:static void _exfat_truncate(struct inode *inode, loff_t old_size); +Exfat_super.c:static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); +Exfat_super.c:static int exfat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +Exfat_super.c:static int exfat_sync_inode(struct inode *inode); +Exfat_super.c:static struct inode *exfat_build_inode(struct super_block *sb, FILE_ID_T *fid, loff_t i_pos); +Exfat_super.c:static void exfat_detach(struct inode *inode); +Exfat_super.c:static void exfat_attach(struct inode *inode, loff_t i_pos); +Exfat_super.c:static int exfat_write_inode(struct inode *inode, int wait); +Exfat_super.c:static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); +Exfat_super.c:static int exfat_d_hash(const struct dentry *dentry, const struct inode *inode, +Exfat_super.c:static int exfat_d_hashi(const struct dentry *dentry, const struct inode *inode, +Exfat_super.c:static int exfat_cmpi(const struct dentry *parent, const struct inode *pinode, +Exfat_super.c: const struct dentry *dentry, const struct inode *inode, +Exfat_super.c:static int exfat_cmp(const struct dentry *parent, const struct inode *pinode, +Exfat_super.c: const struct dentry *dentry, const struct inode *inode, +Exfat_super.c: struct inode *inode = file_inode(filp); +Exfat_super.c: struct inode *inode = filp->f_path.dentry->d_inode; +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { +Exfat_super.c: if (inode->i_ino == EXFAT_ROOT_INO) +Exfat_super.c: inum = inode->i_ino; +Exfat_super.c: EXFAT_I(inode)->fid.size = i_size_read(inode); +Exfat_super.c: EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; +Exfat_super.c: err = FsReadDir(inode, &de); +Exfat_super.c: cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; +Exfat_super.c: inum = inode->i_ino; +Exfat_super.c: loff_t i_pos = ((loff_t) EXFAT_I(inode)->fid.start_clu << 32) | +Exfat_super.c: ((EXFAT_I(inode)->fid.rwoffset-1) & 0xffffffff); +Exfat_super.c: struct inode *tmp = exfat_iget(sb, i_pos); +Exfat_super.c:static int exfat_ioctl_volume_id(struct inode *dir) +Exfat_super.c:static int exfat_generic_ioctl(struct inode *inode, struct file *filp, +Exfat_super.c: struct inode *inode = filp->f_path.dentry->d_inode; +Exfat_super.c: struct inode *inode = filp->f_dentry->d_inode; +Exfat_super.c: return exfat_ioctl_volume_id(inode); +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: struct inode *inode = filp->f_mapping->host; +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c:static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, +Exfat_super.c:static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, +Exfat_super.c:static int exfat_create(struct inode *dir, struct dentry *dentry, int mode, +Exfat_super.c: struct inode *inode; +Exfat_super.c: inode = exfat_build_inode(sb, &fid, i_pos); +Exfat_super.c: if (IS_ERR(inode)) { +Exfat_super.c: err = PTR_ERR(inode); +Exfat_super.c: INC_IVERSION(inode); +Exfat_super.c: inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); +Exfat_super.c: d_instantiate(dentry, inode); +Exfat_super.c:static int exfat_find(struct inode *dir, struct qstr *qname, +Exfat_super.c:static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, +Exfat_super.c:static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, +Exfat_super.c: struct inode *inode; +Exfat_super.c: inode = NULL; +Exfat_super.c: inode = exfat_build_inode(sb, &fid, i_pos); +Exfat_super.c: if (IS_ERR(inode)) { +Exfat_super.c: err = PTR_ERR(inode); +Exfat_super.c: i_mode = inode->i_mode; +Exfat_super.c: if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) { +Exfat_super.c: EXFAT_I(inode)->target = kmalloc(i_size_read(inode)+1, GFP_KERNEL); +Exfat_super.c: if (!EXFAT_I(inode)->target) { +Exfat_super.c: FsReadFile(dir, &fid, EXFAT_I(inode)->target, i_size_read(inode), &ret); +Exfat_super.c: *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; +Exfat_super.c: alias = d_find_alias(inode); +Exfat_super.c: iput(inode); +Exfat_super.c: dentry = d_splice_alias(inode, dentry); +Exfat_super.c: dentry = d_splice_alias(inode, dentry); +Exfat_super.c:static int exfat_unlink(struct inode *dir, struct dentry *dentry) +Exfat_super.c: struct inode *inode = dentry->d_inode; +Exfat_super.c: EXFAT_I(inode)->fid.size = i_size_read(inode); +Exfat_super.c: err = FsRemoveFile(dir, &(EXFAT_I(inode)->fid)); +Exfat_super.c: clear_nlink(inode); +Exfat_super.c: inode->i_mtime = inode->i_atime = current_time(inode); +Exfat_super.c: exfat_detach(inode); +Exfat_super.c: remove_inode_hash(inode); +Exfat_super.c:static int exfat_symlink(struct inode *dir, struct dentry *dentry, const char *target) +Exfat_super.c: struct inode *inode; +Exfat_super.c: inode = exfat_build_inode(sb, &fid, i_pos); +Exfat_super.c: if (IS_ERR(inode)) { +Exfat_super.c: err = PTR_ERR(inode); +Exfat_super.c: INC_IVERSION(inode); +Exfat_super.c: inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); +Exfat_super.c: EXFAT_I(inode)->target = kmalloc(len+1, GFP_KERNEL); +Exfat_super.c: if (!EXFAT_I(inode)->target) { +Exfat_super.c: memcpy(EXFAT_I(inode)->target, target, len+1); +Exfat_super.c: d_instantiate(dentry, inode); +Exfat_super.c:static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +Exfat_super.c:static int exfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) +Exfat_super.c: struct inode *inode; +Exfat_super.c: inode = exfat_build_inode(sb, &fid, i_pos); +Exfat_super.c: if (IS_ERR(inode)) { +Exfat_super.c: err = PTR_ERR(inode); +Exfat_super.c: INC_IVERSION(inode); +Exfat_super.c: inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); +Exfat_super.c: d_instantiate(dentry, inode); +Exfat_super.c:static int exfat_rmdir(struct inode *dir, struct dentry *dentry) +Exfat_super.c: struct inode *inode = dentry->d_inode; +Exfat_super.c: EXFAT_I(inode)->fid.size = i_size_read(inode); +Exfat_super.c: err = FsRemoveDir(dir, &(EXFAT_I(inode)->fid)); +Exfat_super.c: clear_nlink(inode); +Exfat_super.c: inode->i_mtime = inode->i_atime = current_time(inode); +Exfat_super.c: exfat_detach(inode); +Exfat_super.c: remove_inode_hash(inode); +Exfat_super.c:static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, +Exfat_super.c: struct inode *new_dir, struct dentry *new_dentry, +Exfat_super.c:static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, +Exfat_super.c: struct inode *new_dir, struct dentry *new_dentry) +Exfat_super.c: struct inode *old_inode, *new_inode; +Exfat_super.c:static int exfat_cont_expand(struct inode *inode, loff_t size) +Exfat_super.c: struct address_space *mapping = inode->i_mapping; +Exfat_super.c: loff_t start = i_size_read(inode), count = size - i_size_read(inode); +Exfat_super.c: err = generic_cont_expand_simple(inode, size); +Exfat_super.c: inode->i_ctime = inode->i_mtime = current_time(inode); +Exfat_super.c: mark_inode_dirty(inode); +Exfat_super.c: if (IS_SYNC(inode)) { +Exfat_super.c: err2 = write_inode_now(inode, 1); +Exfat_super.c:static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) +Exfat_super.c: if (!uid_eq(current_fsuid(), inode->i_uid)) +Exfat_super.c: if (current_fsuid() != inode->i_uid) +Exfat_super.c: if (in_group_p(inode->i_gid)) +Exfat_super.c: struct inode *inode, umode_t *mode_ptr) +Exfat_super.c: i_mode = inode->i_mode; +Exfat_super.c: if (exfat_mode_can_hold_ro(inode)) { +Exfat_super.c: /* If exfat_mode_can_hold_ro(inode) is false, can't change w bits. */ +Exfat_super.c: struct inode *inode = dentry->d_inode; +Exfat_super.c: && (attr->ia_size > i_size_read(inode))) { +Exfat_super.c: error = exfat_cont_expand(inode, attr->ia_size); +Exfat_super.c: && exfat_allow_set_time(sbi, inode)) { +Exfat_super.c: error = inode_change_ok(inode, attr); +Exfat_super.c: if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) +Exfat_super.c: EXFAT_I(inode)->fid.size = i_size_read(inode); +Exfat_super.c: error = inode_setattr(inode, attr); +Exfat_super.c: old_size = i_size_read(inode); +Exfat_super.c: down_write(&EXFAT_I(inode)->truncate_lock); +Exfat_super.c: truncate_setsize(inode, attr->ia_size); +Exfat_super.c: _exfat_truncate(inode, old_size); +Exfat_super.c: up_write(&EXFAT_I(inode)->truncate_lock); +Exfat_super.c: truncate_setsize(inode, attr->ia_size); +Exfat_super.c: _exfat_truncate(inode, old_size); +Exfat_super.c: setattr_copy(inode, attr); +Exfat_super.c: mark_inode_dirty(inode); +Exfat_super.c: struct inode *inode = path->dentry->d_inode; +Exfat_super.c: struct inode *inode = dentry->d_inode; +Exfat_super.c: generic_fillattr(inode, stat); +Exfat_super.c: stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; +Exfat_super.c:static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) +Exfat_super.c: struct exfat_inode_info *ei = EXFAT_I(inode); +Exfat_super.c:static int exfat_file_release(struct inode *inode, struct file *filp) +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: EXFAT_I(inode)->fid.size = i_size_read(inode); +Exfat_super.c:static void _exfat_truncate(struct inode *inode, loff_t old_size) +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) +Exfat_super.c: EXFAT_I(inode)->mmu_private = i_size_read(inode); +Exfat_super.c: if (EXFAT_I(inode)->fid.start_clu == 0) +Exfat_super.c: err = FsTruncateFile(inode, old_size, i_size_read(inode)); +Exfat_super.c: inode->i_ctime = inode->i_mtime = current_time(inode); +Exfat_super.c: if (IS_DIRSYNC(inode)) +Exfat_super.c: (void) exfat_sync_inode(inode); +Exfat_super.c: mark_inode_dirty(inode); +Exfat_super.c: inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) +Exfat_super.c:static void exfat_truncate(struct inode *inode) +Exfat_super.c: _exfat_truncate(inode, i_size_read(inode)); +Exfat_super.c:static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: if (inode->i_ino == EXFAT_ROOT_INO) { +Exfat_super.c: last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; +Exfat_super.c: EXFAT_I(inode)->fid.size = i_size_read(inode); +Exfat_super.c: err = FsMapCluster(inode, clu_offset, &cluster); +Exfat_super.c:static int exfat_get_block(struct inode *inode, sector_t iblock, +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; +Exfat_super.c: err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); +Exfat_super.c: EXFAT_I(inode)->mmu_private += max_blocks << sb->s_blocksize_bits; +Exfat_super.c: struct inode *inode = mapping->host; +Exfat_super.c: if (to > i_size_read(inode)) { +Exfat_super.c: truncate_pagecache(inode, i_size_read(inode)); +Exfat_super.c: truncate_pagecache(inode, to, i_size_read(inode)); +Exfat_super.c: EXFAT_I(inode)->fid.size = i_size_read(inode); +Exfat_super.c: _exfat_truncate(inode, i_size_read(inode)); +Exfat_super.c: struct inode *inode = mapping->host; +Exfat_super.c: FILE_ID_T *fid = &(EXFAT_I(inode)->fid); +Exfat_super.c: inode->i_mtime = inode->i_ctime = current_time(inode); +Exfat_super.c: mark_inode_dirty(inode); +Exfat_super.c: struct inode *inode = iocb->ki_filp->f_mapping->host; +Exfat_super.c: if (EXFAT_I(inode)->mmu_private < +Exfat_super.c: if (EXFAT_I(inode)->mmu_private < (offset + iov_length(iov, nr_segs))) +Exfat_super.c: if (EXFAT_I(inode)->mmu_private < (offset + iov_iter_count(iter))) +Exfat_super.c: if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter)) +Exfat_super.c: ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); +Exfat_super.c: ret = blockdev_direct_IO(iocb, inode, iter, +Exfat_super.c: ret = blockdev_direct_IO(rw, iocb, inode, iter, +Exfat_super.c: ret = blockdev_direct_IO(rw, iocb, inode, iter, +Exfat_super.c: ret = blockdev_direct_IO(rw, iocb, inode, iov, +Exfat_super.c: ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, +Exfat_super.c:static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) +Exfat_super.c: struct inode *inode = NULL; +Exfat_super.c: inode = igrab(&info->vfs_inode); +Exfat_super.c: if (inode) +Exfat_super.c: return inode; +Exfat_super.c:static void exfat_attach(struct inode *inode, loff_t i_pos) +Exfat_super.c: struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); +Exfat_super.c: EXFAT_I(inode)->i_pos = i_pos; +Exfat_super.c: hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); +Exfat_super.c:static void exfat_detach(struct inode *inode) +Exfat_super.c: struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); +Exfat_super.c: hlist_del_init(&EXFAT_I(inode)->i_hash_fat); +Exfat_super.c: EXFAT_I(inode)->i_pos = 0; +Exfat_super.c:/* doesn't deal with root inode */ +Exfat_super.c:static int exfat_fill_inode(struct inode *inode, FILE_ID_T *fid) +Exfat_super.c: struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); +Exfat_super.c: memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(FILE_ID_T)); +Exfat_super.c: FsReadStat(inode, &info); +Exfat_super.c: EXFAT_I(inode)->i_pos = 0; +Exfat_super.c: EXFAT_I(inode)->target = NULL; +Exfat_super.c: inode->i_uid = sbi->options.fs_uid; +Exfat_super.c: inode->i_gid = sbi->options.fs_gid; +Exfat_super.c: INC_IVERSION(inode); +Exfat_super.c: inode->i_generation = get_seconds(); +Exfat_super.c: inode->i_generation &= ~1; +Exfat_super.c: inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); +Exfat_super.c: inode->i_op = &exfat_dir_inode_operations; +Exfat_super.c: inode->i_fop = &exfat_dir_operations; +Exfat_super.c: i_size_write(inode, info.Size); +Exfat_super.c: EXFAT_I(inode)->mmu_private = i_size_read(inode); +Exfat_super.c: set_nlink(inode, info.NumSubdirs); +Exfat_super.c: inode->i_nlink = info.NumSubdirs; +Exfat_super.c: inode->i_generation |= 1; +Exfat_super.c: inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); +Exfat_super.c: inode->i_op = &exfat_symlink_inode_operations; +Exfat_super.c: i_size_write(inode, info.Size); +Exfat_super.c: EXFAT_I(inode)->mmu_private = i_size_read(inode); +Exfat_super.c: inode->i_generation |= 1; +Exfat_super.c: inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); +Exfat_super.c: inode->i_op = &exfat_file_inode_operations; +Exfat_super.c: inode->i_fop = &exfat_file_operations; +Exfat_super.c: inode->i_mapping->a_ops = &exfat_aops; +Exfat_super.c: inode->i_mapping->nrpages = 0; +Exfat_super.c: i_size_write(inode, info.Size); +Exfat_super.c: EXFAT_I(inode)->mmu_private = i_size_read(inode); +Exfat_super.c: exfat_save_attr(inode, info.Attr); +Exfat_super.c: inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) +Exfat_super.c: exfat_time_fat2unix(sbi, &inode->i_mtime, &info.ModifyTimestamp); +Exfat_super.c: exfat_time_fat2unix(sbi, &inode->i_ctime, &info.CreateTimestamp); +Exfat_super.c: exfat_time_fat2unix(sbi, &inode->i_atime, &info.AccessTimestamp); +Exfat_super.c:static struct inode *exfat_build_inode(struct super_block *sb, +Exfat_super.c: struct inode *inode; +Exfat_super.c: inode = exfat_iget(sb, i_pos); +Exfat_super.c: if (inode) +Exfat_super.c: inode = new_inode(sb); +Exfat_super.c: if (!inode) { +Exfat_super.c: inode = ERR_PTR(-ENOMEM); +Exfat_super.c: inode->i_ino = iunique(sb, EXFAT_ROOT_INO); +Exfat_super.c: SET_IVERSION(inode, 1); +Exfat_super.c: err = exfat_fill_inode(inode, fid); +Exfat_super.c: iput(inode); +Exfat_super.c: inode = ERR_PTR(err); +Exfat_super.c: exfat_attach(inode, i_pos); +Exfat_super.c: insert_inode_hash(inode); +Exfat_super.c: return inode; +Exfat_super.c:static int exfat_sync_inode(struct inode *inode) +Exfat_super.c: return exfat_write_inode(inode, 0); +Exfat_super.c: return exfat_write_inode(inode, NULL); +Exfat_super.c:static struct inode *exfat_alloc_inode(struct super_block *sb) +Exfat_super.c:static void exfat_destroy_inode(struct inode *inode) +Exfat_super.c: if (EXFAT_I(inode)->target) +Exfat_super.c: kfree(EXFAT_I(inode)->target); +Exfat_super.c: EXFAT_I(inode)->target = NULL; +Exfat_super.c: kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); +Exfat_super.c:static int exfat_write_inode(struct inode *inode, int wait) +Exfat_super.c:static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: if (inode->i_ino == EXFAT_ROOT_INO) +Exfat_super.c: info.Attr = exfat_make_attr(inode); +Exfat_super.c: info.Size = i_size_read(inode); +Exfat_super.c: exfat_time_unix2fat(sbi, &inode->i_mtime, &info.ModifyTimestamp); +Exfat_super.c: exfat_time_unix2fat(sbi, &inode->i_ctime, &info.CreateTimestamp); +Exfat_super.c: exfat_time_unix2fat(sbi, &inode->i_atime, &info.AccessTimestamp); +Exfat_super.c: FsWriteStat(inode, &info); +Exfat_super.c:static void exfat_delete_inode(struct inode *inode) +Exfat_super.c: truncate_inode_pages(&inode->i_data, 0); +Exfat_super.c: clear_inode(inode); +Exfat_super.c:static void exfat_clear_inode(struct inode *inode) +Exfat_super.c: exfat_detach(inode); +Exfat_super.c: remove_inode_hash(inode); +Exfat_super.c:static void exfat_evict_inode(struct inode *inode) +Exfat_super.c: truncate_inode_pages(&inode->i_data, 0); +Exfat_super.c: if (!inode->i_nlink) +Exfat_super.c: i_size_write(inode, 0); +Exfat_super.c: invalidate_inode_buffers(inode); +Exfat_super.c: end_writeback(inode); +Exfat_super.c: clear_inode(inode); +Exfat_super.c: exfat_detach(inode); +Exfat_super.c: remove_inode_hash(inode); +Exfat_super.c:static struct inode *exfat_nfs_get_inode(struct super_block *sb, +Exfat_super.c: struct inode *inode = NULL; +Exfat_super.c: return inode; +Exfat_super.c: inode = ilookup(sb, ino); +Exfat_super.c: if (inode && generation && (inode->i_generation != generation)) { +Exfat_super.c: iput(inode); +Exfat_super.c: inode = NULL; +Exfat_super.c: return inode; +Exfat_super.c:static int exfat_read_root(struct inode *inode) +Exfat_super.c: struct super_block *sb = inode->i_sb; +Exfat_super.c: EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; +Exfat_super.c: EXFAT_I(inode)->fid.dir.flags = 0x01; +Exfat_super.c: EXFAT_I(inode)->fid.entry = -1; +Exfat_super.c: EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; +Exfat_super.c: EXFAT_I(inode)->fid.flags = 0x01; +Exfat_super.c: EXFAT_I(inode)->fid.type = TYPE_DIR; +Exfat_super.c: EXFAT_I(inode)->fid.rwoffset = 0; +Exfat_super.c: EXFAT_I(inode)->fid.hint_last_off = -1; +Exfat_super.c: EXFAT_I(inode)->target = NULL; +Exfat_super.c: FsReadStat(inode, &info); +Exfat_super.c: inode->i_uid = sbi->options.fs_uid; +Exfat_super.c: inode->i_gid = sbi->options.fs_gid; +Exfat_super.c: INC_IVERSION(inode); +Exfat_super.c: inode->i_generation = 0; +Exfat_super.c: inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO); +Exfat_super.c: inode->i_op = &exfat_dir_inode_operations; +Exfat_super.c: inode->i_fop = &exfat_dir_operations; +Exfat_super.c: i_size_write(inode, info.Size); +Exfat_super.c: inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) +Exfat_super.c: EXFAT_I(inode)->i_pos = ((loff_t) p_fs->root_dir << 32) | 0xffffffff; +Exfat_super.c: EXFAT_I(inode)->mmu_private = i_size_read(inode); +Exfat_super.c: exfat_save_attr(inode, ATTR_SUBDIR); +Exfat_super.c: inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); +Exfat_super.c: set_nlink(inode, info.NumSubdirs + 2); +Exfat_super.c: inode->i_nlink = info.NumSubdirs + 2; +Exfat_super.c: struct inode *root_inode = NULL; +Exfat_super.c: /* set up enough so that it can read an inode */ +Exfat_super.c: printk(KERN_ERR "[EXFAT] Getting the root inode failed\n"); +Exfat_super.h: struct inode *fat_inode; +Exfat_super.h: * EXFAT file system inode data in memory +Exfat_super.h: struct inode vfs_inode; +Exfat_super.h:static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) +Exfat_super.h: return container_of(inode, struct exfat_inode_info, vfs_inode); +Exfat_super.h:static inline int exfat_mode_can_hold_ro(struct inode *inode) +Exfat_super.h: struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); +Exfat_super.h: if (S_ISDIR(inode->i_mode)) +Exfat_super.h:/* Return the FAT attribute byte for this inode */ +Exfat_super.h:static inline u32 exfat_make_attr(struct inode *inode) +Exfat_super.h: if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO)) +Exfat_super.h: return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; +Exfat_super.h: return EXFAT_I(inode)->fid.attr; +Exfat_super.h:static inline void exfat_save_attr(struct inode *inode, u32 attr) +Exfat_super.h: if (exfat_mode_can_hold_ro(inode)) +Exfat_super.h: EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; +Exfat_super.h: EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); diff --git a/code/driver/source/fs/exfat/Untitled Project.WK3 b/code/driver/source/fs/exfat/Untitled Project.WK3 new file mode 100755 index 0000000000000000000000000000000000000000..eb45c3beb98bb52cf564d5c68530c569365112f4 GIT binary patch literal 90102 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 +#include +#include + +#include "exfat_version.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +extern struct semaphore z_sem; + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Function Declarations */ +/*----------------------------------------------------------------------*/ + +/*======================================================================*/ +/* Global Function Definitions */ +/* - All functions for global use have same return value format, */ +/* that is, FFS_SUCCESS on success and several FS error code on */ +/* various error condition. */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* exFAT Filesystem Init & Exit Functions */ +/*----------------------------------------------------------------------*/ + +int FsInit(void) +{ + return ffsInit(); +} + +int FsShutdown(void) +{ + return ffsShutdown(); +} + +/*----------------------------------------------------------------------*/ +/* Volume Management Functions */ +/*----------------------------------------------------------------------*/ + +/* FsMountVol : mount the file system volume */ +int FsMountVol(struct super_block *sb) +{ + int err; + + sm_P(&z_sem); + + err = buf_init(sb); + if (!err) + err = ffsMountVol(sb); + else + buf_shutdown(sb); + + sm_V(&z_sem); + + return err; +} /* end of FsMountVol */ + +/* FsUmountVol : unmount the file system volume */ +int FsUmountVol(struct super_block *sb) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&z_sem); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsUmountVol(sb); + buf_shutdown(sb); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + sm_V(&z_sem); + + return err; +} /* end of FsUmountVol */ + +/* FsGetVolInfo : get the information of a file system volume */ +int FsGetVolInfo(struct super_block *sb, VOL_INFO_T *info) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (info == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsGetVolInfo(sb, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsGetVolInfo */ + +/* FsSyncVol : synchronize a file system volume */ +int FsSyncVol(struct super_block *sb, int do_sync) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsSyncVol(sb, do_sync); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsSyncVol */ + + +/*----------------------------------------------------------------------*/ +/* File Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* FsCreateFile : create a file */ +int FsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsLookupFile(inode, path, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsLookupFile */ + +/* FsCreateFile : create a file */ +int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsCreateFile(inode, path, mode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsCreateFile */ + +int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* check the validity of pointer parameters */ + if (buffer == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsReadFile(inode, fid, buffer, count, rcount); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadFile */ + +int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* check the validity of pointer parameters */ + if (buffer == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsWriteFile(inode, fid, buffer, count, wcount); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsWriteFile */ + +/* FsTruncateFile : resize the file length */ +int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + DPRINTK("FsTruncateFile entered (inode %p size %llu)\n", inode, new_size); + + err = ffsTruncateFile(inode, old_size, new_size); + + DPRINTK("FsTruncateFile exitted (%d)\n", err); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsTruncateFile */ + +/* FsMoveFile : move(rename) a old file into a new file */ +int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +{ + int err; + struct super_block *sb = old_parent_inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsMoveFile(old_parent_inode, fid, new_parent_inode, new_dentry); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsMoveFile */ + +/* FsRemoveFile : remove a file */ +int FsRemoveFile(struct inode *inode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsRemoveFile(inode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsRemoveFile */ + +/* FsSetAttr : set the attribute of a given file */ +int FsSetAttr(struct inode *inode, u32 attr) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsSetAttr(inode, attr); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsSetAttr */ + +/* FsReadStat : get the information of a given file */ +int FsReadStat(struct inode *inode, DIR_ENTRY_T *info) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsGetStat(inode, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadStat */ + +/* FsWriteStat : set the information of a given file */ +int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + DPRINTK("FsWriteStat entered (inode %p info %p\n", inode, info); + + err = ffsSetStat(inode, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + DPRINTK("FsWriteStat exited (%d)\n", err); + + return err; +} /* end of FsWriteStat */ + +/* FsMapCluster : return the cluster number in the given cluster offset */ +int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (clu == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsMapCluster(inode, clu_offset, clu); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsMapCluster */ + +/*----------------------------------------------------------------------*/ +/* Directory Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* FsCreateDir : create(make) a directory */ +int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsCreateDir(inode, path, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsCreateDir */ + +/* FsReadDir : read a directory entry from the opened directory */ +int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (dir_entry == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsReadDir(inode, dir_entry); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadDir */ + +/* FsRemoveDir : remove a directory */ +int FsRemoveDir(struct inode *inode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsRemoveDir(inode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsRemoveDir */ + +EXPORT_SYMBOL(FsMountVol); +EXPORT_SYMBOL(FsUmountVol); +EXPORT_SYMBOL(FsGetVolInfo); +EXPORT_SYMBOL(FsSyncVol); +EXPORT_SYMBOL(FsLookupFile); +EXPORT_SYMBOL(FsCreateFile); +EXPORT_SYMBOL(FsReadFile); +EXPORT_SYMBOL(FsWriteFile); +EXPORT_SYMBOL(FsTruncateFile); +EXPORT_SYMBOL(FsMoveFile); +EXPORT_SYMBOL(FsRemoveFile); +EXPORT_SYMBOL(FsSetAttr); +EXPORT_SYMBOL(FsReadStat); +EXPORT_SYMBOL(FsWriteStat); +EXPORT_SYMBOL(FsMapCluster); +EXPORT_SYMBOL(FsCreateDir); +EXPORT_SYMBOL(FsReadDir); +EXPORT_SYMBOL(FsRemoveDir); + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG +/* FsReleaseCache: Release FAT & buf cache */ +int FsReleaseCache(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + FAT_release_all(sb); + buf_release_all(sb); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return 0; +} +/* FsReleaseCache */ + +EXPORT_SYMBOL(FsReleaseCache); +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ diff --git a/code/driver/source/fs/exfat/exfat_api.h b/code/driver/source/fs/exfat/exfat_api.h new file mode 100755 index 000000000..84bdf612a --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_api.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_api.h */ +/* PURPOSE : Header File for exFAT API Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_API_H +#define _EXFAT_API_H + +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define EXFAT_SUPER_MAGIC (0x2011BAB0L) +#define EXFAT_ROOT_INO 1 + +/* FAT types */ +#define FAT12 0x01 /* FAT12 */ +#define FAT16 0x0E /* Win95 FAT16 (LBA) */ +#define FAT32 0x0C /* Win95 FAT32 (LBA) */ +#define EXFAT 0x07 /* exFAT */ + +/* file name lengths */ +#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */ +#define MAX_PATH_DEPTH 15 /* max depth of path name */ +#define MAX_NAME_LENGTH 256 /* max len of file name including NULL */ +#define MAX_PATH_LENGTH 260 /* max len of path name including NULL */ +#define DOS_NAME_LENGTH 11 /* DOS file name length excluding NULL */ +#define DOS_PATH_LENGTH 80 /* DOS path name length excluding NULL */ + +/* file attributes */ +#define ATTR_NORMAL 0x0000 +#define ATTR_READONLY 0x0001 +#define ATTR_HIDDEN 0x0002 +#define ATTR_SYSTEM 0x0004 +#define ATTR_VOLUME 0x0008 +#define ATTR_SUBDIR 0x0010 +#define ATTR_ARCHIVE 0x0020 +#define ATTR_SYMLINK 0x0040 +#define ATTR_EXTEND 0x000F +#define ATTR_RWMASK 0x007E + +/* file creation modes */ +#define FM_REGULAR 0x00 +#define FM_SYMLINK 0x40 + +/* return values */ +#define FFS_SUCCESS 0 +#define FFS_MEDIAERR 1 +#define FFS_FORMATERR 2 +#define FFS_MOUNTED 3 +#define FFS_NOTMOUNTED 4 +#define FFS_ALIGNMENTERR 5 +#define FFS_SEMAPHOREERR 6 +#define FFS_INVALIDPATH 7 +#define FFS_INVALIDFID 8 +#define FFS_NOTFOUND 9 +#define FFS_FILEEXIST 10 +#define FFS_PERMISSIONERR 11 +#define FFS_NOTOPENED 12 +#define FFS_MAXOPENED 13 +#define FFS_FULL 14 +#define FFS_EOF 15 +#define FFS_DIRBUSY 16 +#define FFS_MEMORYERR 17 +#define FFS_NAMETOOLONG 18 +#define FFS_ERROR 19 + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct { + u16 Year; + u16 Month; + u16 Day; + u16 Hour; + u16 Minute; + u16 Second; + u16 MilliSecond; +} DATE_TIME_T; + +typedef struct { + u32 Offset; /* start sector number of the partition */ + u32 Size; /* in sectors */ +} PART_INFO_T; + +typedef struct { + u32 SecSize; /* sector size in bytes */ + u32 DevSize; /* block device size in sectors */ +} DEV_INFO_T; + +typedef struct { + u32 FatType; + u32 ClusterSize; + u32 NumClusters; + u32 FreeClusters; + u32 UsedClusters; +} VOL_INFO_T; + +/* directory structure */ +typedef struct { + u32 dir; + s32 size; + u8 flags; +} CHAIN_T; + +/* file id structure */ +typedef struct { + CHAIN_T dir; + s32 entry; + u32 type; + u32 attr; + u32 start_clu; + u64 size; + u8 flags; + s64 rwoffset; + s32 hint_last_off; + u32 hint_last_clu; +} FILE_ID_T; + +typedef struct { + char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE]; + char ShortName[DOS_NAME_LENGTH + 2]; /* used only for FAT12/16/32, not used for exFAT */ + u32 Attr; + u64 Size; + u32 NumSubdirs; + DATE_TIME_T CreateTimestamp; + DATE_TIME_T ModifyTimestamp; + DATE_TIME_T AccessTimestamp; +} DIR_ENTRY_T; + +/*======================================================================*/ +/* */ +/* API FUNCTION DECLARATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* file system initialization & shutdown functions */ + int FsInit(void); + int FsShutdown(void); + +/* volume management functions */ + int FsMountVol(struct super_block *sb); + int FsUmountVol(struct super_block *sb); + int FsGetVolInfo(struct super_block *sb, VOL_INFO_T *info); + int FsSyncVol(struct super_block *sb, int do_sync); + +/* file management functions */ + int FsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); + int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); + int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); + int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); + int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); + int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); + int FsRemoveFile(struct inode *inode, FILE_ID_T *fid); + int FsSetAttr(struct inode *inode, u32 attr); + int FsReadStat(struct inode *inode, DIR_ENTRY_T *info); + int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info); + int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); + +/* directory management functions */ + int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); + int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry); + int FsRemoveDir(struct inode *inode, FILE_ID_T *fid); + +/* debug functions */ +s32 FsReleaseCache(struct super_block *sb); + +#endif /* _EXFAT_API_H */ diff --git a/code/driver/source/fs/exfat/exfat_bitmap.c b/code/driver/source/fs/exfat/exfat_bitmap.c new file mode 100755 index 000000000..b0672dd07 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_bitmap.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_global.c */ +/* PURPOSE : exFAT Miscellaneous Functions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_bitmap.h" + +/*----------------------------------------------------------------------*/ +/* Bitmap Manipulation Functions */ +/*----------------------------------------------------------------------*/ + +#define BITMAP_LOC(v) ((v) >> 3) +#define BITMAP_SHIFT(v) ((v) & 0x07) + +s32 exfat_bitmap_test(u8 *bitmap, int i) +{ + u8 data; + + data = bitmap[BITMAP_LOC(i)]; + if ((data >> BITMAP_SHIFT(i)) & 0x01) + return 1; + return 0; +} /* end of Bitmap_test */ + +void exfat_bitmap_set(u8 *bitmap, int i) +{ + bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i)); +} /* end of Bitmap_set */ + +void exfat_bitmap_clear(u8 *bitmap, int i) +{ + bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i)); +} /* end of Bitmap_clear */ diff --git a/code/driver/source/fs/exfat/exfat_bitmap.h b/code/driver/source/fs/exfat/exfat_bitmap.h new file mode 100755 index 000000000..4f482c7b2 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_bitmap.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_global.h */ +/* PURPOSE : Header File for exFAT Global Definitions & Misc Functions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_BITMAP_H +#define _EXFAT_BITMAP_H + +#include + +/*======================================================================*/ +/* */ +/* LIBRARY FUNCTION DECLARATIONS -- OTHER UTILITY FUNCTIONS */ +/* (DO NOT CHANGE THIS PART !!) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* Bitmap Manipulation Functions */ +/*----------------------------------------------------------------------*/ + +s32 exfat_bitmap_test(u8 *bitmap, int i); +void exfat_bitmap_set(u8 *bitmap, int i); +void exfat_bitmap_clear(u8 *bitmpa, int i); + +#endif /* _EXFAT_BITMAP_H */ diff --git a/code/driver/source/fs/exfat/exfat_blkdev.c b/code/driver/source/fs/exfat/exfat_blkdev.c new file mode 100755 index 000000000..eaccfd84e --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_blkdev.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_blkdev.c */ +/* PURPOSE : exFAT Block Device Driver Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include "exfat_config.h" +#include "exfat_blkdev.h" +#include "exfat_data.h" +#include "exfat_api.h" +#include "exfat_super.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*======================================================================*/ +/* Function Definitions */ +/*======================================================================*/ + +s32 bdev_init(void) +{ + return FFS_SUCCESS; +} + +s32 bdev_shutdown(void) +{ + return FFS_SUCCESS; +} + +s32 bdev_open(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bd->opened) + return FFS_SUCCESS; + + p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); + p_bd->sector_size_bits = ilog2(p_bd->sector_size); + p_bd->sector_size_mask = p_bd->sector_size - 1; + p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >> p_bd->sector_size_bits; + + p_bd->opened = TRUE; + + return FFS_SUCCESS; +} + +s32 bdev_close(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (!p_bd->opened) + return FFS_SUCCESS; + + p_bd->opened = FALSE; + return FFS_SUCCESS; +} + +s32 bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, u32 num_secs, s32 read) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + if (*bh) + __brelse(*bh); + + if (read) + *bh = __bread(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); + else + *bh = __getblk(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); + + if (*bh) + return FFS_SUCCESS; + + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); + + return FFS_MEDIAERR; +} + +s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u32 num_secs, s32 sync) +{ + s32 count; + struct buffer_head *bh2; + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + if (secno == bh->b_blocknr) { + lock_buffer(bh); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + if (sync && (sync_dirty_buffer(bh) != 0)) + return FFS_MEDIAERR; + } else { + count = num_secs << p_bd->sector_size_bits; + + bh2 = __getblk(sb->s_bdev, secno, count); + + if (bh2 == NULL) + goto no_bh; + + lock_buffer(bh2); + memcpy(bh2->b_data, bh->b_data, count); + set_buffer_uptodate(bh2); + mark_buffer_dirty(bh2); + unlock_buffer(bh2); + if (sync && (sync_dirty_buffer(bh2) != 0)) { + __brelse(bh2); + goto no_bh; + } + __brelse(bh2); + } + + return FFS_SUCCESS; + +no_bh: + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); + + return FFS_MEDIAERR; +} + +s32 bdev_sync(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + return sync_blockdev(sb->s_bdev); +} diff --git a/code/driver/source/fs/exfat/exfat_blkdev.h b/code/driver/source/fs/exfat/exfat_blkdev.h new file mode 100755 index 000000000..3363b591c --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_blkdev.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_blkdev.h */ +/* PURPOSE : Header File for exFAT Block Device Driver Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_BLKDEV_H +#define _EXFAT_BLKDEV_H + +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Non-Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct __BD_INFO_T { + s32 sector_size; /* in bytes */ + s32 sector_size_bits; + s32 sector_size_mask; + s32 num_sectors; /* total number of sectors in this block device */ + bool opened; /* opened or not */ +} BD_INFO_T; + +/*----------------------------------------------------------------------*/ +/* External Variable Declarations */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 bdev_init(void); +s32 bdev_shutdown(void); +s32 bdev_open(struct super_block *sb); +s32 bdev_close(struct super_block *sb); +s32 bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, u32 num_secs, s32 read); +s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u32 num_secs, s32 sync); +s32 bdev_sync(struct super_block *sb); + +#endif /* _EXFAT_BLKDEV_H */ diff --git a/code/driver/source/fs/exfat/exfat_cache.c b/code/driver/source/fs/exfat/exfat_cache.c new file mode 100755 index 000000000..4130102e3 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_cache.c @@ -0,0 +1,784 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_cache.c */ +/* PURPOSE : exFAT Cache Manager */ +/* (FAT Cache & Buffer Cache) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Sung-Kwan Kim] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" + +#include "exfat_cache.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +#define sm_P(s) +#define sm_V(s) + +static s32 __FAT_read(struct super_block *sb, u32 loc, u32 *content); +static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content); + +static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, sector_t sec); +static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, sector_t sec); +static void FAT_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp); +static void FAT_cache_remove_hash(BUF_CACHE_T *bp); + +static u8 *__buf_getblk(struct super_block *sb, sector_t sec); + +static BUF_CACHE_T *buf_cache_find(struct super_block *sb, sector_t sec); +static BUF_CACHE_T *buf_cache_get(struct super_block *sb, sector_t sec); +static void buf_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp); +static void buf_cache_remove_hash(BUF_CACHE_T *bp); + +static void push_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void push_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void move_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void move_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list); + +/*======================================================================*/ +/* Cache Initialization Functions */ +/*======================================================================*/ + +s32 buf_init(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + int i; + + /* LRU list */ + p_fs->FAT_cache_lru_list.next = p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list; + + for (i = 0; i < FAT_CACHE_SIZE; i++) { + p_fs->FAT_cache_array[i].drv = -1; + p_fs->FAT_cache_array[i].sec = ~0; + p_fs->FAT_cache_array[i].flag = 0; + p_fs->FAT_cache_array[i].buf_bh = NULL; + p_fs->FAT_cache_array[i].prev = p_fs->FAT_cache_array[i].next = NULL; + push_to_mru(&(p_fs->FAT_cache_array[i]), &p_fs->FAT_cache_lru_list); + } + + p_fs->buf_cache_lru_list.next = p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list; + + for (i = 0; i < BUF_CACHE_SIZE; i++) { + p_fs->buf_cache_array[i].drv = -1; + p_fs->buf_cache_array[i].sec = ~0; + p_fs->buf_cache_array[i].flag = 0; + p_fs->buf_cache_array[i].buf_bh = NULL; + p_fs->buf_cache_array[i].prev = p_fs->buf_cache_array[i].next = NULL; + push_to_mru(&(p_fs->buf_cache_array[i]), &p_fs->buf_cache_lru_list); + } + + /* HASH list */ + for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) { + p_fs->FAT_cache_hash_list[i].drv = -1; + p_fs->FAT_cache_hash_list[i].sec = ~0; + p_fs->FAT_cache_hash_list[i].hash_next = p_fs->FAT_cache_hash_list[i].hash_prev = &(p_fs->FAT_cache_hash_list[i]); + } + + for (i = 0; i < FAT_CACHE_SIZE; i++) + FAT_cache_insert_hash(sb, &(p_fs->FAT_cache_array[i])); + + for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) { + p_fs->buf_cache_hash_list[i].drv = -1; + p_fs->buf_cache_hash_list[i].sec = ~0; + p_fs->buf_cache_hash_list[i].hash_next = p_fs->buf_cache_hash_list[i].hash_prev = &(p_fs->buf_cache_hash_list[i]); + } + + for (i = 0; i < BUF_CACHE_SIZE; i++) + buf_cache_insert_hash(sb, &(p_fs->buf_cache_array[i])); + + return FFS_SUCCESS; +} /* end of buf_init */ + +s32 buf_shutdown(struct super_block *sb) +{ + return FFS_SUCCESS; +} /* end of buf_shutdown */ + +/*======================================================================*/ +/* FAT Read/Write Functions */ +/*======================================================================*/ + +/* in : sb, loc + * out: content + * returns 0 on success + * -1 on error + */ +s32 FAT_read(struct super_block *sb, u32 loc, u32 *content) +{ + s32 ret; + + sm_P(&f_sem); + + ret = __FAT_read(sb, loc, content); + + sm_V(&f_sem); + + return ret; +} /* end of FAT_read */ + +s32 FAT_write(struct super_block *sb, u32 loc, u32 content) +{ + s32 ret; + + sm_P(&f_sem); + + ret = __FAT_write(sb, loc, content); + + sm_V(&f_sem); + + return ret; +} /* end of FAT_write */ + +static s32 __FAT_read(struct super_block *sb, u32 loc, u32 *content) +{ + s32 off; + u32 _content; + sector_t sec; + u8 *fat_sector, *fat_entry; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_fs->vol_type == FAT12) { + sec = p_fs->FAT1_start_sector + ((loc + (loc >> 1)) >> p_bd->sector_size_bits); + off = (loc + (loc >> 1)) & p_bd->sector_size_mask; + + if (off == (p_bd->sector_size-1)) { + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + _content = (u32) fat_sector[off]; + + fat_sector = FAT_getblk(sb, ++sec); + if (!fat_sector) + return -1; + + _content |= (u32) fat_sector[0] << 8; + } else { + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + _content = GET16(fat_entry); + } + + if (loc & 1) + _content >>= 4; + + _content &= 0x00000FFF; + + if (_content >= CLUSTER_16(0x0FF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else if (p_fs->vol_type == FAT16) { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-1)); + off = (loc << 1) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + _content = GET16_A(fat_entry); + + _content &= 0x0000FFFF; + + if (_content >= CLUSTER_16(0xFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else if (p_fs->vol_type == FAT32) { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + _content = GET32_A(fat_entry); + + _content &= 0x0FFFFFFF; + + if (_content >= CLUSTER_32(0x0FFFFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + _content = GET32_A(fat_entry); + + if (_content >= CLUSTER_32(0xFFFFFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } + + *content = CLUSTER_32(~0); + return 0; +} /* end of __FAT_read */ + +static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content) +{ + s32 off; + sector_t sec; + u8 *fat_sector, *fat_entry; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_fs->vol_type == FAT12) { + + content &= 0x00000FFF; + + sec = p_fs->FAT1_start_sector + ((loc + (loc >> 1)) >> p_bd->sector_size_bits); + off = (loc + (loc >> 1)) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + if (loc & 1) { /* odd */ + + content <<= 4; + + if (off == (p_bd->sector_size-1)) { + fat_sector[off] = (u8)(content | (fat_sector[off] & 0x0F)); + FAT_modify(sb, sec); + + fat_sector = FAT_getblk(sb, ++sec); + if (!fat_sector) + return -1; + + fat_sector[0] = (u8)(content >> 8); + } else { + fat_entry = &(fat_sector[off]); + content |= GET16(fat_entry) & 0x000F; + + SET16(fat_entry, content); + } + } else { /* even */ + fat_sector[off] = (u8)(content); + + if (off == (p_bd->sector_size-1)) { + fat_sector[off] = (u8)(content); + FAT_modify(sb, sec); + + fat_sector = FAT_getblk(sb, ++sec); + fat_sector[0] = (u8)((fat_sector[0] & 0xF0) | (content >> 8)); + } else { + fat_entry = &(fat_sector[off]); + content |= GET16(fat_entry) & 0xF000; + + SET16(fat_entry, content); + } + } + } + + else if (p_fs->vol_type == FAT16) { + + content &= 0x0000FFFF; + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-1)); + off = (loc << 1) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + SET16_A(fat_entry, content); + } + + else if (p_fs->vol_type == FAT32) { + + content &= 0x0FFFFFFF; + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + content |= GET32_A(fat_entry) & 0xF0000000; + + SET32_A(fat_entry, content); + } + + else { /* p_fs->vol_type == EXFAT */ + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + SET32_A(fat_entry, content); + } + + FAT_modify(sb, sec); + return 0; +} /* end of __FAT_write */ + +u8 *FAT_getblk(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = FAT_cache_find(sb, sec); + if (bp != NULL) { + move_to_mru(bp, &p_fs->FAT_cache_lru_list); + return bp->buf_bh->b_data; + } + + bp = FAT_cache_get(sb, sec); + + FAT_cache_remove_hash(bp); + + bp->drv = p_fs->drv; + bp->sec = sec; + bp->flag = 0; + + FAT_cache_insert_hash(sb, bp); + + if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) { + FAT_cache_remove_hash(bp); + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + bp->buf_bh = NULL; + + move_to_lru(bp, &p_fs->FAT_cache_lru_list); + return NULL; + } + + return bp->buf_bh->b_data; +} /* end of FAT_getblk */ + +void FAT_modify(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + bp = FAT_cache_find(sb, sec); + if (bp != NULL) + sector_write(sb, sec, bp->buf_bh, 0); +} /* end of FAT_modify */ + +void FAT_release_all(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&f_sem); + + bp = p_fs->FAT_cache_lru_list.next; + while (bp != &p_fs->FAT_cache_lru_list) { + if (bp->drv == p_fs->drv) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + } + bp = bp->next; + } + + sm_V(&f_sem); +} /* end of FAT_release_all */ + +void FAT_sync(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&f_sem); + + bp = p_fs->FAT_cache_lru_list.next; + while (bp != &p_fs->FAT_cache_lru_list) { + if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { + sync_dirty_buffer(bp->buf_bh); + bp->flag &= ~(DIRTYBIT); + } + bp = bp->next; + } + + sm_V(&f_sem); +} /* end of FAT_sync */ + +static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, sector_t sec) +{ + s32 off; + BUF_CACHE_T *bp, *hp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1); + + hp = &(p_fs->FAT_cache_hash_list[off]); + for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { + if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { + + WARN(!bp->buf_bh, "[EXFAT] FAT_cache has no bh. " + "It will make system panic.\n"); + + touch_buffer(bp->buf_bh); + return bp; + } + } + return NULL; +} /* end of FAT_cache_find */ + +static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = p_fs->FAT_cache_lru_list.prev; + + + move_to_mru(bp, &p_fs->FAT_cache_lru_list); + return bp; +} /* end of FAT_cache_get */ + +static void FAT_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp) +{ + s32 off; + BUF_CACHE_T *hp; + FS_INFO_T *p_fs; + + p_fs = &(EXFAT_SB(sb)->fs_info); + off = (bp->sec + (bp->sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE-1); + + hp = &(p_fs->FAT_cache_hash_list[off]); + bp->hash_next = hp->hash_next; + bp->hash_prev = hp; + hp->hash_next->hash_prev = bp; + hp->hash_next = bp; +} /* end of FAT_cache_insert_hash */ + +static void FAT_cache_remove_hash(BUF_CACHE_T *bp) +{ + (bp->hash_prev)->hash_next = bp->hash_next; + (bp->hash_next)->hash_prev = bp->hash_prev; +} /* end of FAT_cache_remove_hash */ + +/*======================================================================*/ +/* Buffer Read/Write Functions */ +/*======================================================================*/ + +u8 *buf_getblk(struct super_block *sb, sector_t sec) +{ + u8 *buf; + + sm_P(&b_sem); + + buf = __buf_getblk(sb, sec); + + sm_V(&b_sem); + + return buf; +} /* end of buf_getblk */ + +static u8 *__buf_getblk(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = buf_cache_find(sb, sec); + if (bp != NULL) { + move_to_mru(bp, &p_fs->buf_cache_lru_list); + return bp->buf_bh->b_data; + } + + bp = buf_cache_get(sb, sec); + + buf_cache_remove_hash(bp); + + bp->drv = p_fs->drv; + bp->sec = sec; + bp->flag = 0; + + buf_cache_insert_hash(sb, bp); + + if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) { + buf_cache_remove_hash(bp); + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + bp->buf_bh = NULL; + + move_to_lru(bp, &p_fs->buf_cache_lru_list); + return NULL; + } + + return bp->buf_bh->b_data; + +} /* end of __buf_getblk */ + +void buf_modify(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + sector_write(sb, sec, bp->buf_bh, 0); + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", + (unsigned long long)sec); + + sm_V(&b_sem); +} /* end of buf_modify */ + +void buf_lock(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + bp->flag |= LOCKBIT; + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", + (unsigned long long)sec); + + sm_V(&b_sem); +} /* end of buf_lock */ + +void buf_unlock(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + bp->flag &= ~(LOCKBIT); + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", + (unsigned long long)sec); + + sm_V(&b_sem); +} /* end of buf_unlock */ + +void buf_release(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + + move_to_lru(bp, &p_fs->buf_cache_lru_list); + } + + sm_V(&b_sem); +} /* end of buf_release */ + +void buf_release_all(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = p_fs->buf_cache_lru_list.next; + while (bp != &p_fs->buf_cache_lru_list) { + if (bp->drv == p_fs->drv) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + } + bp = bp->next; + } + + sm_V(&b_sem); +} /* end of buf_release_all */ + +void buf_sync(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = p_fs->buf_cache_lru_list.next; + while (bp != &p_fs->buf_cache_lru_list) { + if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { + sync_dirty_buffer(bp->buf_bh); + bp->flag &= ~(DIRTYBIT); + } + bp = bp->next; + } + + sm_V(&b_sem); +} /* end of buf_sync */ + +static BUF_CACHE_T *buf_cache_find(struct super_block *sb, sector_t sec) +{ + s32 off; + BUF_CACHE_T *bp, *hp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & (BUF_CACHE_HASH_SIZE - 1); + + hp = &(p_fs->buf_cache_hash_list[off]); + for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { + if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { + touch_buffer(bp->buf_bh); + return bp; + } + } + return NULL; +} /* end of buf_cache_find */ + +static BUF_CACHE_T *buf_cache_get(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = p_fs->buf_cache_lru_list.prev; + while (bp->flag & LOCKBIT) + bp = bp->prev; + + + move_to_mru(bp, &p_fs->buf_cache_lru_list); + return bp; +} /* end of buf_cache_get */ + +static void buf_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp) +{ + s32 off; + BUF_CACHE_T *hp; + FS_INFO_T *p_fs; + + p_fs = &(EXFAT_SB(sb)->fs_info); + off = (bp->sec + (bp->sec >> p_fs->sectors_per_clu_bits)) & (BUF_CACHE_HASH_SIZE-1); + + hp = &(p_fs->buf_cache_hash_list[off]); + bp->hash_next = hp->hash_next; + bp->hash_prev = hp; + hp->hash_next->hash_prev = bp; + hp->hash_next = bp; +} /* end of buf_cache_insert_hash */ + +static void buf_cache_remove_hash(BUF_CACHE_T *bp) +{ + (bp->hash_prev)->hash_next = bp->hash_next; + (bp->hash_next)->hash_prev = bp->hash_prev; +} /* end of buf_cache_remove_hash */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +static void push_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->next = list->next; + bp->prev = list; + list->next->prev = bp; + list->next = bp; +} /* end of buf_cache_push_to_mru */ + +static void push_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev = list->prev; + bp->next = list; + list->prev->next = bp; + list->prev = bp; +} /* end of buf_cache_push_to_lru */ + +static void move_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev->next = bp->next; + bp->next->prev = bp->prev; + push_to_mru(bp, list); +} /* end of buf_cache_move_to_mru */ + +static void move_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev->next = bp->next; + bp->next->prev = bp->prev; + push_to_lru(bp, list); +} /* end of buf_cache_move_to_lru */ diff --git a/code/driver/source/fs/exfat/exfat_cache.h b/code/driver/source/fs/exfat/exfat_cache.h new file mode 100755 index 000000000..540e31681 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_cache.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_cache.h */ +/* PURPOSE : Header File for exFAT Cache Manager */ +/* (FAT Cache & Buffer Cache) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Sung-Kwan Kim] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_CACHE_H +#define _EXFAT_CACHE_H + +#include +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define LOCKBIT 0x01 +#define DIRTYBIT 0x02 + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct __BUF_CACHE_T { + struct __BUF_CACHE_T *next; + struct __BUF_CACHE_T *prev; + struct __BUF_CACHE_T *hash_next; + struct __BUF_CACHE_T *hash_prev; + s32 drv; + sector_t sec; + u32 flag; + struct buffer_head *buf_bh; +} BUF_CACHE_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 buf_init(struct super_block *sb); +s32 buf_shutdown(struct super_block *sb); +s32 FAT_read(struct super_block *sb, u32 loc, u32 *content); +s32 FAT_write(struct super_block *sb, u32 loc, u32 content); +u8 *FAT_getblk(struct super_block *sb, sector_t sec); +void FAT_modify(struct super_block *sb, sector_t sec); +void FAT_release_all(struct super_block *sb); +void FAT_sync(struct super_block *sb); +u8 *buf_getblk(struct super_block *sb, sector_t sec); +void buf_modify(struct super_block *sb, sector_t sec); +void buf_lock(struct super_block *sb, sector_t sec); +void buf_unlock(struct super_block *sb, sector_t sec); +void buf_release(struct super_block *sb, sector_t sec); +void buf_release_all(struct super_block *sb); +void buf_sync(struct super_block *sb); + +#endif /* _EXFAT_CACHE_H */ diff --git a/code/driver/source/fs/exfat/exfat_config.h b/code/driver/source/fs/exfat/exfat_config.h new file mode 100755 index 000000000..33c6525e4 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_config.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_config.h */ +/* PURPOSE : Header File for exFAT Configuable Policies */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_CONFIG_H +#define _EXFAT_CONFIG_H + +/*======================================================================*/ +/* */ +/* FFS CONFIGURATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* Feature Config */ +/*----------------------------------------------------------------------*/ +#ifndef CONFIG_EXFAT_DISCARD +#define CONFIG_EXFAT_DISCARD 1 /* mount option -o discard support */ +#endif + +#ifndef CONFIG_EXFAT_DELAYED_SYNC +#define CONFIG_EXFAT_DELAYED_SYNC 0 +#endif + +#ifndef CONFIG_EXFAT_KERNEL_DEBUG +#define CONFIG_EXFAT_KERNEL_DEBUG 1 /* kernel debug features via ioctl */ +#endif + +#ifndef CONFIG_EXFAT_DEBUG_MSG +#define CONFIG_EXFAT_DEBUG_MSG 0 /* debugging message on/off */ +#endif + +#ifndef CONFIG_EXFAT_DEFAULT_CODEPAGE +#define CONFIG_EXFAT_DEFAULT_CODEPAGE 437 +#define CONFIG_EXFAT_DEFAULT_IOCHARSET "utf8" +#endif + +#endif /* _EXFAT_CONFIG_H */ diff --git a/code/driver/source/fs/exfat/exfat_core.c b/code/driver/source/fs/exfat/exfat_core.c new file mode 100755 index 000000000..143b72155 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_core.c @@ -0,0 +1,5138 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_core.c */ +/* PURPOSE : exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include + +#include "exfat_bitmap.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +#include +#include + +static void __set_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 1; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 1; +#endif +} + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +extern u8 uni_upcase[]; + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE]; + +static char *reserved_names[] = { + "AUX ", "CON ", "NUL ", "PRN ", + "COM1 ", "COM2 ", "COM3 ", "COM4 ", + "COM5 ", "COM6 ", "COM7 ", "COM8 ", "COM9 ", + "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ", + "LPT5 ", "LPT6 ", "LPT7 ", "LPT8 ", "LPT9 ", + NULL +}; + +static u8 free_bit[] = { + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */ + 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */ + 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */ + 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */ + 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */ +}; + +static u8 used_bit[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */ + 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */ + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */ + 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */ + 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */ + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */ + 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */ + 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */ + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */ + 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */ + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */ +}; + +/*======================================================================*/ +/* Global Function Definitions */ +/*======================================================================*/ + +/* ffsInit : roll back to the initial state of the file system */ +s32 ffsInit(void) +{ + s32 ret; + + ret = bdev_init(); + if (ret) + return ret; + + ret = fs_init(); + if (ret) + return ret; + + return FFS_SUCCESS; +} /* end of ffsInit */ + +/* ffsShutdown : make free all memory-alloced global buffers */ +s32 ffsShutdown(void) +{ + s32 ret; + ret = fs_shutdown(); + if (ret) + return ret; + + ret = bdev_shutdown(); + if (ret) + return ret; + + return FFS_SUCCESS; +} /* end of ffsShutdown */ + +/* ffsMountVol : mount the file system volume */ +s32 ffsMountVol(struct super_block *sb) +{ + int i, ret; + PBR_SECTOR_T *p_pbr; + struct buffer_head *tmp_bh = NULL; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + printk("[EXFAT] trying to mount...\n"); + + sm_init(&p_fs->v_sem); + p_fs->dev_ejected = FALSE; + + /* open the block device */ + if (bdev_open(sb)) + return FFS_MEDIAERR; + + if (p_bd->sector_size < sb->s_blocksize) + return FFS_MEDIAERR; + if (p_bd->sector_size > sb->s_blocksize) + sb_set_blocksize(sb, p_bd->sector_size); + + /* read Sector 0 */ + if (sector_read(sb, 0, &tmp_bh, 1) != FFS_SUCCESS) + return FFS_MEDIAERR; + + p_fs->PBR_sector = 0; + + p_pbr = (PBR_SECTOR_T *) tmp_bh->b_data; + + /* check the validity of PBR */ + if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) { + brelse(tmp_bh); + bdev_close(sb); + return FFS_FORMATERR; + } + + /* fill fs_stuct */ + for (i = 0; i < 53; i++) + if (p_pbr->bpb[i]) + break; + + if (i < 53) { + if (GET16(p_pbr->bpb+11)) /* num_fat_sectors */ + ret = fat16_mount(sb, p_pbr); + else + ret = fat32_mount(sb, p_pbr); + } else { + ret = exfat_mount(sb, p_pbr); + } + + brelse(tmp_bh); + + if (ret) { + bdev_close(sb); + return ret; + } + + if (p_fs->vol_type == EXFAT) { + ret = load_alloc_bitmap(sb); + if (ret) { + bdev_close(sb); + return ret; + } + ret = load_upcase_table(sb); + if (ret) { + free_alloc_bitmap(sb); + bdev_close(sb); + return ret; + } + } + + if (p_fs->dev_ejected) { + if (p_fs->vol_type == EXFAT) { + free_upcase_table(sb); + free_alloc_bitmap(sb); + } + bdev_close(sb); + return FFS_MEDIAERR; + } + + printk("[EXFAT] mounted successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsMountVol */ + +/* ffsUmountVol : umount the file system volume */ +s32 ffsUmountVol(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + printk("[EXFAT] trying to unmount...\n"); + + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); + + if (p_fs->vol_type == EXFAT) { + free_upcase_table(sb); + free_alloc_bitmap(sb); + } + + FAT_release_all(sb); + buf_release_all(sb); + + /* close the block device */ + bdev_close(sb); + + if (p_fs->dev_ejected) { + printk("[EXFAT] unmounted with media errors. " + "device's already ejected.\n"); + return FFS_MEDIAERR; + } + + printk("[EXFAT] unmounted successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsUmountVol */ + +/* ffsGetVolInfo : get the information of a file system volume */ +s32 ffsGetVolInfo(struct super_block *sb, VOL_INFO_T *info) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->used_clusters == (u32) ~0) + p_fs->used_clusters = p_fs->fs_func->count_used_clusters(sb); + + info->FatType = p_fs->vol_type; + info->ClusterSize = p_fs->cluster_size; + info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */ + info->UsedClusters = p_fs->used_clusters; + info->FreeClusters = info->NumClusters - info->UsedClusters; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsGetVolInfo */ + +/* ffsSyncVol : synchronize all file system volumes */ +s32 ffsSyncVol(struct super_block *sb, s32 do_sync) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* synchronize the file system */ + fs_sync(sb, do_sync); + fs_set_vol_flags(sb, VOL_CLEAN); + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSyncVol */ + +/*----------------------------------------------------------------------*/ +/* File Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* ffsLookupFile : lookup a file */ +s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + CHAIN_T dir; + UNI_NAME_T uni_name; + DOS_NAME_T dos_name; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + DPRINTK("ffsLookupFile entered\n"); + + /* check the validity of directory name in the given pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, &dos_name); + if (ret) + return ret; + + /* search the file name for directories */ + dentry = p_fs->fs_func->find_dir_entry(sb, &dir, &uni_name, num_entries, &dos_name, TYPE_ALL); + if (dentry < -1) + return FFS_NOTFOUND; + + fid->dir.dir = dir.dir; + fid->dir.size = dir.size; + fid->dir.flags = dir.flags; + fid->entry = dentry; + + if (dentry == -1) { + fid->type = TYPE_DIR; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + fid->attr = ATTR_SUBDIR; + fid->flags = 0x01; + fid->size = 0; + fid->start_clu = p_fs->root_dir; + } else { + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &dir, dentry, ES_2_ENTRIES, &ep); + if (!es) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &dir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + fid->type = p_fs->fs_func->get_entry_type(ep); + fid->rwoffset = 0; + fid->hint_last_off = -1; + fid->attr = p_fs->fs_func->get_entry_attr(ep); + + fid->size = p_fs->fs_func->get_entry_size(ep2); + if ((fid->type == TYPE_FILE) && (fid->size == 0)) { + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->start_clu = CLUSTER_32(~0); + } else { + fid->flags = p_fs->fs_func->get_entry_flag(ep2); + fid->start_clu = p_fs->fs_func->get_entry_clu0(ep2); + } + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + DPRINTK("ffsLookupFile exited successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsLookupFile */ + +/* ffsCreateFile : create a file */ +s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +{ + s32 ret/*, dentry*/; + CHAIN_T dir; + UNI_NAME_T uni_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of directory name in the given pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* create a new file */ + ret = create_file(inode, &dir, &uni_name, mode, fid); + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsCreateFile */ + +/* ffsReadFile : read data from a opened file */ +s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +{ + s32 offset, sec_offset, clu_offset; + u32 clu; + sector_t LogSector; + u64 oneblkread, read_bytes; + struct buffer_head *tmp_bh = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + + if (count > (fid->size - fid->rwoffset)) + count = fid->size - fid->rwoffset; + + if (count == 0) { + if (rcount != NULL) + *rcount = 0; + return FFS_EOF; + } + + read_bytes = 0; + + while (count > 0) { + clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + clu = fid->start_clu; + + if (fid->flags == 0x03) { + clu += clu_offset; + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu = fid->hint_last_clu; + } + + while (clu_offset > 0) { + /* clu = FAT_read(sb, clu); */ + if (FAT_read(sb, clu, &clu) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = clu; + + offset = (s32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */ + sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + offset &= p_bd->sector_size_mask; /* byte offset in sector */ + + LogSector = START_SECTOR(clu) + sec_offset; + + oneblkread = (u64)(p_bd->sector_size - offset); + if (oneblkread > count) + oneblkread = count; + + if ((offset == 0) && (oneblkread == p_bd->sector_size)) { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) buffer)+read_bytes, ((char *) tmp_bh->b_data), (s32) oneblkread); + } else { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) buffer)+read_bytes, ((char *) tmp_bh->b_data)+offset, (s32) oneblkread); + } + count -= oneblkread; + read_bytes += oneblkread; + fid->rwoffset += oneblkread; + } + brelse(tmp_bh); + +err_out: + /* set the size of read bytes */ + if (rcount != NULL) + *rcount = read_bytes; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsReadFile */ + +/* ffsWriteFile : write data into a opened file */ +s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +{ + s32 modified = FALSE, offset, sec_offset, clu_offset; + s32 num_clusters, num_alloc, num_alloced = (s32) ~0; + u32 clu, last_clu; + sector_t LogSector, sector = 0; + u64 oneblkwrite, write_bytes; + CHAIN_T new_clu; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct buffer_head *tmp_bh = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + + if (count == 0) { + if (wcount != NULL) + *wcount = 0; + return FFS_SUCCESS; + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + if (fid->size == 0) + num_clusters = 0; + else + num_clusters = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + + write_bytes = 0; + + while (count > 0) { + clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + clu = last_clu = fid->start_clu; + + if (fid->flags == 0x03) { + if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { + last_clu += clu_offset - 1; + + if (clu_offset == num_clusters) + clu = CLUSTER_32(~0); + else + clu += clu_offset; + } + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu = fid->hint_last_clu; + } + + while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { + last_clu = clu; + /* clu = FAT_read(sb, clu); */ + if (FAT_read(sb, clu, &clu) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + + if (clu == CLUSTER_32(~0)) { + num_alloc = (s32)((count-1) >> p_fs->cluster_size_bits) + 1; + new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1; + new_clu.size = 0; + new_clu.flags = fid->flags; + + /* (1) allocate a chain of clusters */ + num_alloced = p_fs->fs_func->alloc_cluster(sb, num_alloc, &new_clu); + if (num_alloced == 0) + break; + else if (num_alloced < 0) + return FFS_MEDIAERR; + + /* (2) append to the FAT chain */ + if (last_clu == CLUSTER_32(~0)) { + if (new_clu.flags == 0x01) + fid->flags = 0x01; + fid->start_clu = new_clu.dir; + modified = TRUE; + } else { + if (new_clu.flags != fid->flags) { + exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters); + fid->flags = 0x01; + modified = TRUE; + } + if (new_clu.flags == 0x01) + FAT_write(sb, last_clu, new_clu.dir); + } + + num_clusters += num_alloced; + clu = new_clu.dir; + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = clu; + + offset = (s32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */ + sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + offset &= p_bd->sector_size_mask; /* byte offset in sector */ + + LogSector = START_SECTOR(clu) + sec_offset; + + oneblkwrite = (u64)(p_bd->sector_size - offset); + if (oneblkwrite > count) + oneblkwrite = count; + + if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) { + if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) tmp_bh->b_data), ((char *) buffer)+write_bytes, (s32) oneblkwrite); + if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) { + brelse(tmp_bh); + goto err_out; + } + } else { + if ((offset > 0) || ((fid->rwoffset+oneblkwrite) < fid->size)) { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + } else { + if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS) + goto err_out; + } + + memcpy(((char *) tmp_bh->b_data)+offset, ((char *) buffer)+write_bytes, (s32) oneblkwrite); + if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) { + brelse(tmp_bh); + goto err_out; + } + } + + count -= oneblkwrite; + write_bytes += oneblkwrite; + fid->rwoffset += oneblkwrite; + + fid->attr |= ATTR_ARCHIVE; + + if (fid->size < fid->rwoffset) { + fid->size = fid->rwoffset; + modified = TRUE; + } + } + + brelse(tmp_bh); + + /* (3) update the direcoty entry */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + goto err_out; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + goto err_out; + ep2 = ep; + } + + p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); + p_fs->fs_func->set_entry_attr(ep, fid->attr); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + + if (modified) { + if (p_fs->fs_func->get_entry_flag(ep2) != fid->flags) + p_fs->fs_func->set_entry_flag(ep2, fid->flags); + + if (p_fs->fs_func->get_entry_size(ep2) != fid->size) + p_fs->fs_func->set_entry_size(ep2, fid->size); + + if (p_fs->fs_func->get_entry_clu0(ep2) != fid->start_clu) + p_fs->fs_func->set_entry_clu0(ep2, fid->start_clu); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + } + + if (p_fs->vol_type == EXFAT) { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + +err_out: + /* set the size of written bytes */ + if (wcount != NULL) + *wcount = write_bytes; + + if (num_alloced == 0) + return FFS_FULL; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsWriteFile */ + +/* ffsTruncateFile : resize the file length */ +s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +{ + s32 num_clusters; + u32 last_clu = CLUSTER_32(0); + sector_t sector = 0; + CHAIN_T clu; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + ENTRY_SET_CACHE_T *es = NULL; + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->size != old_size) { + printk(KERN_ERR "[EXFAT] truncate : can't skip it because of " + "size-mismatch(old:%lld->fid:%lld).\n" + ,old_size, fid->size); + } + + if (old_size <= new_size) + return FFS_SUCCESS; + + fs_set_vol_flags(sb, VOL_DIRTY); + + clu.dir = fid->start_clu; + clu.size = (s32)((old_size-1) >> p_fs->cluster_size_bits) + 1; + clu.flags = fid->flags; + + if (new_size > 0) { + num_clusters = (s32)((new_size-1) >> p_fs->cluster_size_bits) + 1; + + if (clu.flags == 0x03) { + clu.dir += num_clusters; + } else { + while (num_clusters > 0) { + last_clu = clu.dir; + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + num_clusters--; + } + } + + clu.size -= num_clusters; + } + + fid->size = new_size; + fid->attr |= ATTR_ARCHIVE; + if (new_size == 0) { + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->start_clu = CLUSTER_32(~0); + } + + /* (1) update the directory entry */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); + p_fs->fs_func->set_entry_attr(ep, fid->attr); + + p_fs->fs_func->set_entry_size(ep2, new_size); + if (new_size == 0) { + p_fs->fs_func->set_entry_flag(ep2, 0x01); + p_fs->fs_func->set_entry_clu0(ep2, CLUSTER_32(0)); + } + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + /* (2) cut off from the FAT chain */ + if (last_clu != CLUSTER_32(0)) { + if (fid->flags == 0x01) + FAT_write(sb, last_clu, CLUSTER_32(~0)); + } + + /* (3) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu, 0); + + /* hint information */ + fid->hint_last_off = -1; + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsTruncateFile */ + +static void update_parent_info(FILE_ID_T *fid, struct inode *parent_inode) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); + FILE_ID_T *parent_fid = &(EXFAT_I(parent_inode)->fid); + + if (unlikely((parent_fid->flags != fid->dir.flags) + || (parent_fid->size != (fid->dir.size<cluster_size_bits)) + || (parent_fid->start_clu != fid->dir.dir))) { + + fid->dir.dir = parent_fid->start_clu; + fid->dir.flags = parent_fid->flags; + fid->dir.size = ((parent_fid->size + (p_fs->cluster_size-1)) + >> p_fs->cluster_size_bits); + } +} + +/* ffsMoveFile : move(rename) a old file into a new file */ +s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +{ + s32 ret; + s32 dentry; + CHAIN_T olddir, newdir; + CHAIN_T *p_dir = NULL; + UNI_NAME_T uni_name; + DENTRY_T *ep; + struct super_block *sb = old_parent_inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + u8 *new_path = (u8 *) new_dentry->d_name.name; + struct inode *new_inode = new_dentry->d_inode; + int num_entries; + FILE_ID_T *new_fid = NULL; + s32 new_entry = 0; + + /* check the validity of pointer parameters */ + if ((new_path == NULL) || (*new_path == '\0')) + return FFS_ERROR; + + update_parent_info(fid, old_parent_inode); + + olddir.dir = fid->dir.dir; + olddir.size = fid->dir.size; + olddir.flags = fid->dir.flags; + + dentry = fid->entry; + + /* check if the old file is "." or ".." */ + if (p_fs->vol_type != EXFAT) { + if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) + return FFS_PERMISSIONERR; + } + + ep = get_entry_in_dir(sb, &olddir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + + if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) + return FFS_PERMISSIONERR; + + /* check whether new dir is existing directory and empty */ + if (new_inode) { + u32 entry_type; + + ret = FFS_MEDIAERR; + new_fid = &EXFAT_I(new_inode)->fid; + + update_parent_info(new_fid, new_parent_inode); + + p_dir = &(new_fid->dir); + new_entry = new_fid->entry; + ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); + if (!ep) + goto out; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if (entry_type == TYPE_DIR) { + CHAIN_T new_clu; + new_clu.dir = new_fid->start_clu; + new_clu.size = (s32)((new_fid->size-1) >> p_fs->cluster_size_bits) + 1; + new_clu.flags = new_fid->flags; + + if (!is_dir_empty(sb, &new_clu)) + return FFS_FILEEXIST; + } + } + + /* check the validity of directory name in the given new pathname */ + ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + if (olddir.dir == newdir.dir) + ret = rename_file(new_parent_inode, &olddir, dentry, &uni_name, fid); + else + ret = move_file(new_parent_inode, &olddir, dentry, &newdir, &uni_name, fid); + + if ((ret == FFS_SUCCESS) && new_inode) { + /* delete entries of new_dir */ + ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); + if (!ep) + goto out; + + num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, new_entry, ep); + if (num_entries < 0) + goto out; + p_fs->fs_func->delete_dir_entry(sb, p_dir, new_entry, 0, num_entries+1); + } +out: +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsMoveFile */ + +/* ffsRemoveFile : remove a file */ +s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid) +{ + s32 dentry; + CHAIN_T dir, clu_to_free; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + dir.dir = fid->dir.dir; + dir.size = fid->dir.size; + dir.flags = fid->dir.flags; + + dentry = fid->entry; + + ep = get_entry_in_dir(sb, &dir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + + if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) + return FFS_PERMISSIONERR; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* (1) update the directory entry */ + remove_file(inode, &dir, dentry); + + clu_to_free.dir = fid->start_clu; + clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + clu_to_free.flags = fid->flags; + + /* (2) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu_to_free, 0); + + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsRemoveFile */ + +/* ffsSetAttr : set the attribute of a given file */ +s32 ffsSetAttr(struct inode *inode, u32 attr) +{ + u32 type; + sector_t sector = 0; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + ENTRY_SET_CACHE_T *es = NULL; + + if (fid->attr == attr) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + /* get the directory entry of given file */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + } + + type = p_fs->fs_func->get_entry_type(ep); + + if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) || + ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) { + s32 err; + if (p_fs->dev_ejected) + err = FFS_MEDIAERR; + else + err = FFS_ERROR; + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + return err; + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* set the file attribute */ + fid->attr = attr; + p_fs->fs_func->set_entry_attr(ep, attr); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSetAttr */ + +/* ffsGetStat : get the information of a given file */ +s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info) +{ + sector_t sector = 0; + s32 count; + CHAIN_T dir; + UNI_NAME_T uni_name; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + ENTRY_SET_CACHE_T *es = NULL; + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + + DPRINTK("ffsGetStat entered\n"); + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + info->Attr = ATTR_SUBDIR; + memset((char *) &info->CreateTimestamp, 0, sizeof(DATE_TIME_T)); + memset((char *) &info->ModifyTimestamp, 0, sizeof(DATE_TIME_T)); + memset((char *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + strcpy(info->ShortName, "."); + strcpy(info->Name, "."); + + dir.dir = p_fs->root_dir; + dir.flags = 0x01; + + if (p_fs->root_dir == CLUSTER_32(0)) /* FAT16 root_dir */ + info->Size = p_fs->dentries_in_root << DENTRY_SIZE_BITS; + else + info->Size = count_num_clusters(sb, &dir) << p_fs->cluster_size_bits; + + count = count_dos_name_entries(sb, &dir, TYPE_DIR); + if (count < 0) + return FFS_MEDIAERR; + info->NumSubdirs = count; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + /* get the directory entry of given file or directory */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_2_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + buf_lock(sb, sector); + } + + /* set FILE_INFO structure using the acquired DENTRY_T */ + info->Attr = p_fs->fs_func->get_entry_attr(ep); + + p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE); + info->CreateTimestamp.Year = tm.year; + info->CreateTimestamp.Month = tm.mon; + info->CreateTimestamp.Day = tm.day; + info->CreateTimestamp.Hour = tm.hour; + info->CreateTimestamp.Minute = tm.min; + info->CreateTimestamp.Second = tm.sec; + info->CreateTimestamp.MilliSecond = 0; + + p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY); + info->ModifyTimestamp.Year = tm.year; + info->ModifyTimestamp.Month = tm.mon; + info->ModifyTimestamp.Day = tm.day; + info->ModifyTimestamp.Hour = tm.hour; + info->ModifyTimestamp.Minute = tm.min; + info->ModifyTimestamp.Second = tm.sec; + info->ModifyTimestamp.MilliSecond = 0; + + memset((char *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + + *(uni_name.name) = 0x0; + /* XXX this is very bad for exfat cuz name is already included in es. + API should be revised */ + p_fs->fs_func->get_uni_name_from_ext_entry(sb, &(fid->dir), fid->entry, uni_name.name); + if (*(uni_name.name) == 0x0 && p_fs->vol_type != EXFAT) + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1); + nls_uniname_to_cstring(sb, info->Name, &uni_name); + + if (p_fs->vol_type == EXFAT) { + info->NumSubdirs = 2; + } else { + buf_unlock(sb, sector); + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0); + nls_uniname_to_cstring(sb, info->ShortName, &uni_name); + info->NumSubdirs = 0; + } + + info->Size = p_fs->fs_func->get_entry_size(ep2); + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + + if (is_dir) { + dir.dir = fid->start_clu; + dir.flags = 0x01; + + if (info->Size == 0) + info->Size = (u64) count_num_clusters(sb, &dir) << p_fs->cluster_size_bits; + + count = count_dos_name_entries(sb, &dir, TYPE_DIR); + if (count < 0) + return FFS_MEDIAERR; + info->NumSubdirs += count; + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + DPRINTK("ffsGetStat exited successfully\n"); + return FFS_SUCCESS; +} /* end of ffsGetStat */ + +/* ffsSetStat : set the information of a given file */ +s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info) +{ + sector_t sector = 0; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* get the directory entry of given file or directory */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + /* for other than exfat */ + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + + p_fs->fs_func->set_entry_attr(ep, info->Attr); + + /* set FILE_INFO structure using the acquired DENTRY_T */ + tm.sec = info->CreateTimestamp.Second; + tm.min = info->CreateTimestamp.Minute; + tm.hour = info->CreateTimestamp.Hour; + tm.day = info->CreateTimestamp.Day; + tm.mon = info->CreateTimestamp.Month; + tm.year = info->CreateTimestamp.Year; + p_fs->fs_func->set_entry_time(ep, &tm, TM_CREATE); + + tm.sec = info->ModifyTimestamp.Second; + tm.min = info->ModifyTimestamp.Minute; + tm.hour = info->ModifyTimestamp.Hour; + tm.day = info->ModifyTimestamp.Day; + tm.mon = info->ModifyTimestamp.Month; + tm.year = info->ModifyTimestamp.Year; + p_fs->fs_func->set_entry_time(ep, &tm, TM_MODIFY); + + + p_fs->fs_func->set_entry_size(ep2, info->Size); + + if (p_fs->vol_type != EXFAT) { + buf_modify(sb, sector); + } else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSetStat */ + +s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +{ + s32 num_clusters, num_alloced, modified = FALSE; + u32 last_clu; + sector_t sector = 0; + CHAIN_T new_clu; + DENTRY_T *ep; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; + + if (EXFAT_I(inode)->mmu_private == 0) + num_clusters = 0; + else + num_clusters = (s32)((EXFAT_I(inode)->mmu_private-1) >> p_fs->cluster_size_bits) + 1; + + *clu = last_clu = fid->start_clu; + + if (fid->flags == 0x03) { + if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { + last_clu += clu_offset - 1; + + if (clu_offset == num_clusters) + *clu = CLUSTER_32(~0); + else + *clu += clu_offset; + } + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + *clu = fid->hint_last_clu; + } + + while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { + last_clu = *clu; + if (FAT_read(sb, *clu, clu) == -1) + return FFS_MEDIAERR; + clu_offset--; + } + } + + if (*clu == CLUSTER_32(~0)) { + fs_set_vol_flags(sb, VOL_DIRTY); + + new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1; + new_clu.size = 0; + new_clu.flags = fid->flags; + + /* (1) allocate a cluster */ + num_alloced = p_fs->fs_func->alloc_cluster(sb, 1, &new_clu); + if (num_alloced < 0) + return FFS_MEDIAERR; + else if (num_alloced == 0) + return FFS_FULL; + + /* (2) append to the FAT chain */ + if (last_clu == CLUSTER_32(~0)) { + if (new_clu.flags == 0x01) + fid->flags = 0x01; + fid->start_clu = new_clu.dir; + modified = TRUE; + } else { + if (new_clu.flags != fid->flags) { + exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters); + fid->flags = 0x01; + modified = TRUE; + } + if (new_clu.flags == 0x01) + FAT_write(sb, last_clu, new_clu.dir); + } + + num_clusters += num_alloced; + *clu = new_clu.dir; + + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + /* get stream entry */ + ep++; + } + + /* (3) update directory entry */ + if (modified) { + if (p_fs->vol_type != EXFAT) { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + } + + if (p_fs->fs_func->get_entry_flag(ep) != fid->flags) + p_fs->fs_func->set_entry_flag(ep, fid->flags); + + if (p_fs->fs_func->get_entry_clu0(ep) != fid->start_clu) + p_fs->fs_func->set_entry_clu0(ep, fid->start_clu); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + } + + if (p_fs->vol_type == EXFAT) { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + /* add number of new blocks to inode */ + inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = *clu; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsMapCluster */ + +/*----------------------------------------------------------------------*/ +/* Directory Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* ffsCreateDir : create(make) a directory */ +s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +{ + s32 ret/*, dentry*/; + CHAIN_T dir; + UNI_NAME_T uni_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + DPRINTK("ffsCreateDir entered\n"); + + /* check the validity of directory name in the given old pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + ret = create_dir(inode, &dir, &uni_name, fid); + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsCreateDir */ + +/* ffsReadDir : read a directory entry from the opened directory */ +s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +{ + int i, dentry, clu_offset; + s32 dentries_per_clu, dentries_per_clu_bits = 0; + u32 type; + sector_t sector; + CHAIN_T dir, clu; + UNI_NAME_T uni_name; + TIMESTAMP_T tm; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_DIR) + return FFS_PERMISSIONERR; + + if (fid->entry == -1) { + dir.dir = p_fs->root_dir; + dir.flags = 0x01; + } else { + dir.dir = fid->start_clu; + dir.size = (s32)(fid->size >> p_fs->cluster_size_bits); + dir.flags = fid->flags; + } + + dentry = (s32) fid->rwoffset; + + if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + + if (dentry == dentries_per_clu) { + clu.dir = CLUSTER_32(~0); + } else { + clu.dir = dir.dir; + clu.size = dir.size; + clu.flags = dir.flags; + } + } else { + dentries_per_clu = p_fs->dentries_per_clu; + dentries_per_clu_bits = ilog2(dentries_per_clu); + + clu_offset = dentry >> dentries_per_clu_bits; + clu.dir = dir.dir; + clu.size = dir.size; + clu.flags = dir.flags; + + if (clu.flags == 0x03) { + clu.dir += clu_offset; + clu.size -= clu_offset; + } else { + /* hint_information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu.dir = fid->hint_last_clu; + } + + while (clu_offset > 0) { + /* clu.dir = FAT_read(sb, clu.dir); */ + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + } + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */ + i = dentry % dentries_per_clu; + else + i = dentry & (dentries_per_clu-1); + + for ( ; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, §or); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) + break; + + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + buf_lock(sb, sector); + dir_entry->Attr = p_fs->fs_func->get_entry_attr(ep); + + p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE); + dir_entry->CreateTimestamp.Year = tm.year; + dir_entry->CreateTimestamp.Month = tm.mon; + dir_entry->CreateTimestamp.Day = tm.day; + dir_entry->CreateTimestamp.Hour = tm.hour; + dir_entry->CreateTimestamp.Minute = tm.min; + dir_entry->CreateTimestamp.Second = tm.sec; + dir_entry->CreateTimestamp.MilliSecond = 0; + + p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY); + dir_entry->ModifyTimestamp.Year = tm.year; + dir_entry->ModifyTimestamp.Month = tm.mon; + dir_entry->ModifyTimestamp.Day = tm.day; + dir_entry->ModifyTimestamp.Hour = tm.hour; + dir_entry->ModifyTimestamp.Minute = tm.min; + dir_entry->ModifyTimestamp.Second = tm.sec; + dir_entry->ModifyTimestamp.MilliSecond = 0; + + memset((char *) &dir_entry->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + + *(uni_name.name) = 0x0; + p_fs->fs_func->get_uni_name_from_ext_entry(sb, &dir, dentry, uni_name.name); + if (*(uni_name.name) == 0x0 && p_fs->vol_type != EXFAT) + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1); + nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name); + buf_unlock(sb, sector); + + if (p_fs->vol_type == EXFAT) { + ep = get_entry_in_dir(sb, &clu, i+1, NULL); + if (!ep) + return FFS_MEDIAERR; + } else { + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0); + nls_uniname_to_cstring(sb, dir_entry->ShortName, &uni_name); + } + + dir_entry->Size = p_fs->fs_func->get_entry_size(ep); + + /* hint information */ + if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + } else { + fid->hint_last_off = dentry >> dentries_per_clu_bits; + fid->hint_last_clu = clu.dir; + } + + fid->rwoffset = (s64) ++dentry; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; + } + + if (dir.dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + /* clu.dir = FAT_read(sb, clu.dir); */ + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + } + } + + *(dir_entry->Name) = '\0'; + + fid->rwoffset = (s64) ++dentry; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsReadDir */ + +/* ffsRemoveDir : remove a directory */ +s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid) +{ + s32 dentry; + CHAIN_T dir, clu_to_free; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + dir.dir = fid->dir.dir; + dir.size = fid->dir.size; + dir.flags = fid->dir.flags; + + dentry = fid->entry; + + /* check if the file is "." or ".." */ + if (p_fs->vol_type != EXFAT) { + if ((dir.dir != p_fs->root_dir) && (dentry < 2)) + return FFS_PERMISSIONERR; + } + + clu_to_free.dir = fid->start_clu; + clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + clu_to_free.flags = fid->flags; + + if (!is_dir_empty(sb, &clu_to_free)) + return FFS_FILEEXIST; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* (1) update the directory entry */ + remove_file(inode, &dir, dentry); + + /* (2) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu_to_free, 1); + + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT)? 0x03: 0x01; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsRemoveDir */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +/* + * File System Management Functions + */ + +s32 fs_init(void) +{ + /* critical check for system requirement on size of DENTRY_T structure */ + if (sizeof(DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + return FFS_SUCCESS; +} /* end of fs_init */ + +s32 fs_shutdown(void) +{ + return FFS_SUCCESS; +} /* end of fs_shutdown */ + +void fs_set_vol_flags(struct super_block *sb, u32 new_flag) +{ + PBR_SECTOR_T *p_pbr; + BPBEX_T *p_bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->vol_flag == new_flag) + return; + + p_fs->vol_flag = new_flag; + + if (p_fs->vol_type == EXFAT) { + if (p_fs->pbr_bh == NULL) { + if (sector_read(sb, p_fs->PBR_sector, &(p_fs->pbr_bh), 1) != FFS_SUCCESS) + return; + } + + p_pbr = (PBR_SECTOR_T *) p_fs->pbr_bh->b_data; + p_bpb = (BPBEX_T *) p_pbr->bpb; + SET16(p_bpb->vol_flags, (u16) new_flag); + + /* XXX duyoung + what can we do here? (cuz fs_set_vol_flags() is void) */ + if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh))) + sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1); + else + sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0); + } +} /* end of fs_set_vol_flags */ + +void fs_sync(struct super_block *sb, s32 do_sync) +{ + if (do_sync) + bdev_sync(sb); +} /* end of fs_sync */ + +void fs_error(struct super_block *sb) +{ + struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; + + if (opts->errors == EXFAT_ERRORS_PANIC) + panic("[EXFAT] Filesystem panic from previous error\n"); + else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & MS_RDONLY)) { + sb->s_flags |= MS_RDONLY; + printk(KERN_ERR "[EXFAT] Filesystem has been set read-only\n"); + } +} + +/* + * Cluster Management Functions + */ + +s32 clear_cluster(struct super_block *sb, u32 clu) +{ + sector_t s, n; + s32 ret = FFS_SUCCESS; + struct buffer_head *tmp_bh = NULL; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */ + s = p_fs->root_start_sector; + n = p_fs->data_start_sector; + } else { + s = START_SECTOR(clu); + n = s + p_fs->sectors_per_clu; + } + + for (; s < n; s++) { + ret = sector_read(sb, s, &tmp_bh, 0); + if (ret != FFS_SUCCESS) + return ret; + + memset((char *) tmp_bh->b_data, 0x0, p_bd->sector_size); + ret = sector_write(sb, s, tmp_bh, 0); + if (ret != FFS_SUCCESS) + break; + } + + brelse(tmp_bh); + return ret; +} /* end of clear_cluster */ + +s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain) +{ + int i, num_clusters = 0; + u32 new_clu, last_clu = CLUSTER_32(~0), read_clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + new_clu = p_chain->dir; + if (new_clu == CLUSTER_32(~0)) + new_clu = p_fs->clu_srch_ptr; + else if (new_clu >= p_fs->num_clusters) + new_clu = 2; + + __set_sb_dirty(sb); + + p_chain->dir = CLUSTER_32(~0); + + for (i = 2; i < p_fs->num_clusters; i++) { + if (FAT_read(sb, new_clu, &read_clu) != 0) + return -1; + + if (read_clu == CLUSTER_32(0)) { + if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) + return -1; + num_clusters++; + + if (p_chain->dir == CLUSTER_32(~0)) + p_chain->dir = new_clu; + else { + if (FAT_write(sb, last_clu, new_clu) < 0) + return -1; + } + + last_clu = new_clu; + + if ((--num_alloc) == 0) { + p_fs->clu_srch_ptr = new_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + return num_clusters; + } + } + if ((++new_clu) >= p_fs->num_clusters) + new_clu = 2; + } + + p_fs->clu_srch_ptr = new_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + return num_clusters; +} /* end of fat_alloc_cluster */ + +s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain) +{ + s32 num_clusters = 0; + u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + hint_clu = p_chain->dir; + if (hint_clu == CLUSTER_32(~0)) { + hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr-2); + if (hint_clu == CLUSTER_32(~0)) + return 0; + } else if (hint_clu >= p_fs->num_clusters) { + hint_clu = 2; + p_chain->flags = 0x01; + } + + __set_sb_dirty(sb); + + p_chain->dir = CLUSTER_32(~0); + + while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUSTER_32(~0)) { + if (new_clu != hint_clu) { + if (p_chain->flags == 0x03) { + exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters); + p_chain->flags = 0x01; + } + } + + if (set_alloc_bitmap(sb, new_clu-2) != FFS_SUCCESS) + return -1; + + num_clusters++; + + if (p_chain->flags == 0x01) { + if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) + return -1; + } + + if (p_chain->dir == CLUSTER_32(~0)) { + p_chain->dir = new_clu; + } else { + if (p_chain->flags == 0x01) { + if (FAT_write(sb, last_clu, new_clu) < 0) + return -1; + } + } + last_clu = new_clu; + + if ((--num_alloc) == 0) { + p_fs->clu_srch_ptr = hint_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return num_clusters; + } + + hint_clu = new_clu + 1; + if (hint_clu >= p_fs->num_clusters) { + hint_clu = 2; + + if (p_chain->flags == 0x03) { + exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters); + p_chain->flags = 0x01; + } + } + } + + p_fs->clu_srch_ptr = hint_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return num_clusters; +} /* end of exfat_alloc_cluster */ + +void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse) +{ + s32 num_clusters = 0; + u32 clu, prev; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + int i; + sector_t sector; + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return; + __set_sb_dirty(sb); + clu = p_chain->dir; + + if (p_chain->size <= 0) + return; + + do { + if (p_fs->dev_ejected) + break; + + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + prev = clu; + if (FAT_read(sb, clu, &clu) == -1) + break; + + if (FAT_write(sb, prev, CLUSTER_32(0)) < 0) + break; + num_clusters++; + + } while (clu != CLUSTER_32(~0)); + + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters -= num_clusters; +} /* end of fat_free_cluster */ + +void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse) +{ + s32 num_clusters = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + int i; + sector_t sector; + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return; + + if (p_chain->size <= 0) { + printk(KERN_ERR "[EXFAT] free_cluster : skip free-req clu:%u, " + "because of zero-size truncation\n" + ,p_chain->dir); + return; + } + + __set_sb_dirty(sb); + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + do { + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) + break; + clu++; + + num_clusters++; + } while (num_clusters < p_chain->size); + } else { + do { + if (p_fs->dev_ejected) + break; + + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) + break; + + if (FAT_read(sb, clu, &clu) == -1) + break; + num_clusters++; + } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); + } + + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters -= num_clusters; +} /* end of exfat_free_cluster */ + +u32 find_last_cluster(struct super_block *sb, CHAIN_T *p_chain) +{ + u32 clu, next; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + clu += p_chain->size - 1; + } else { + while ((FAT_read(sb, clu, &next) == 0) && (next != CLUSTER_32(~0))) { + if (p_fs->dev_ejected) + break; + clu = next; + } + } + + return clu; +} /* end of find_last_cluster */ + +s32 count_num_clusters(struct super_block *sb, CHAIN_T *p_chain) +{ + int i, count = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return 0; + + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + count = p_chain->size; + } else { + for (i = 2; i < p_fs->num_clusters; i++) { + count++; + if (FAT_read(sb, clu, &clu) != 0) + return 0; + if (clu == CLUSTER_32(~0)) + break; + } + } + + return count; +} /* end of count_num_clusters */ + +s32 fat_count_used_clusters(struct super_block *sb) +{ + int i, count = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = 2; i < p_fs->num_clusters; i++) { + if (FAT_read(sb, i, &clu) != 0) + break; + if (clu != CLUSTER_32(0)) + count++; + } + + return count; +} /* end of fat_count_used_clusters */ + +s32 exfat_count_used_clusters(struct super_block *sb) +{ + int i, map_i, map_b, count = 0; + u8 k; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + map_i = map_b = 0; + + for (i = 2; i < p_fs->num_clusters; i += 8) { + k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); + count += used_bit[k]; + + if ((++map_b) >= p_bd->sector_size) { + map_i++; + map_b = 0; + } + } + + return count; +} /* end of exfat_count_used_clusters */ + +void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len) +{ + if (len == 0) + return; + + while (len > 1) { + if (FAT_write(sb, chain, chain+1) < 0) + break; + chain++; + len--; + } + FAT_write(sb, chain, CLUSTER_32(~0)); +} /* end of exfat_chain_cont_cluster */ + +/* + * Allocation Bitmap Management Functions + */ + +s32 load_alloc_bitmap(struct super_block *sb) +{ + int i, j, ret; + u32 map_size; + u32 type; + sector_t sector; + CHAIN_T clu; + BMAP_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu.dir = p_fs->root_dir; + clu.flags = 0x01; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < p_fs->dentries_per_clu; i++) { + ep = (BMAP_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if (type != TYPE_BITMAP) + continue; + + if (ep->flags == 0x0) { + p_fs->map_clu = GET32_A(ep->start_clu); + map_size = (u32) GET64_A(ep->size); + + p_fs->map_sectors = ((map_size-1) >> p_bd->sector_size_bits) + 1; + + p_fs->vol_amap = (struct buffer_head **) kmalloc(sizeof(struct buffer_head *) * p_fs->map_sectors, GFP_KERNEL); + if (p_fs->vol_amap == NULL) + return FFS_MEMORYERR; + + sector = START_SECTOR(p_fs->map_clu); + + for (j = 0; j < p_fs->map_sectors; j++) { + p_fs->vol_amap[j] = NULL; + ret = sector_read(sb, sector+j, &(p_fs->vol_amap[j]), 1); + if (ret != FFS_SUCCESS) { + /* release all buffers and free vol_amap */ + i = 0; + while (i < j) + brelse(p_fs->vol_amap[i++]); + + if (p_fs->vol_amap) + kfree(p_fs->vol_amap); + p_fs->vol_amap = NULL; + return ret; + } + } + + p_fs->pbr_bh = NULL; + return FFS_SUCCESS; + } + } + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + + return FFS_FORMATERR; +} /* end of load_alloc_bitmap */ + +void free_alloc_bitmap(struct super_block *sb) +{ + int i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + brelse(p_fs->pbr_bh); + + for (i = 0; i < p_fs->map_sectors; i++) + __brelse(p_fs->vol_amap[i]); + + if (p_fs->vol_amap) + kfree(p_fs->vol_amap); + p_fs->vol_amap = NULL; +} /* end of free_alloc_bitmap */ + +s32 set_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, b; + sector_t sector; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + i = clu >> (p_bd->sector_size_bits + 3); + b = clu & ((p_bd->sector_size << 3) - 1); + + sector = START_SECTOR(p_fs->map_clu) + i; + + exfat_bitmap_set((u8 *) p_fs->vol_amap[i]->b_data, b); + + return sector_write(sb, sector, p_fs->vol_amap[i], 0); +} /* end of set_alloc_bitmap */ + +s32 clr_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, b; + sector_t sector; +#ifdef CONFIG_EXFAT_DISCARD + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_mount_options *opts = &sbi->options; + int ret; +#endif /* CONFIG_EXFAT_DISCARD */ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + i = clu >> (p_bd->sector_size_bits + 3); + b = clu & ((p_bd->sector_size << 3) - 1); + + sector = START_SECTOR(p_fs->map_clu) + i; + + exfat_bitmap_clear((u8 *) p_fs->vol_amap[i]->b_data, b); + + return sector_write(sb, sector, p_fs->vol_amap[i], 0); + +#ifdef CONFIG_EXFAT_DISCARD + if (opts->discard) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits)); +#else + ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits), GFP_NOFS, 0); +#endif + if (ret == -EOPNOTSUPP) { + printk(KERN_WARNING "discard not supported by device, disabling"); + opts->discard = 0; + } + } +#endif /* CONFIG_EXFAT_DISCARD */ +} /* end of clr_alloc_bitmap */ + +u32 test_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, map_i, map_b; + u32 clu_base, clu_free; + u8 k, clu_mask; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu_base = (clu & ~(0x7)) + 2; + clu_mask = (1 << (clu - clu_base + 2)) - 1; + + map_i = clu >> (p_bd->sector_size_bits + 3); + map_b = (clu >> 3) & p_bd->sector_size_mask; + + for (i = 2; i < p_fs->num_clusters; i += 8) { + k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); + if (clu_mask > 0) { + k |= clu_mask; + clu_mask = 0; + } + if (k < 0xFF) { + clu_free = clu_base + free_bit[k]; + if (clu_free < p_fs->num_clusters) + return clu_free; + } + clu_base += 8; + + if (((++map_b) >= p_bd->sector_size) || (clu_base >= p_fs->num_clusters)) { + if ((++map_i) >= p_fs->map_sectors) { + clu_base = 2; + map_i = 0; + } + map_b = 0; + } + } + + return CLUSTER_32(~0); +} /* end of test_alloc_bitmap */ + +void sync_alloc_bitmap(struct super_block *sb) +{ + int i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->vol_amap == NULL) + return; + + for (i = 0; i < p_fs->map_sectors; i++) + sync_dirty_buffer(p_fs->vol_amap[i]); +} /* end of sync_alloc_bitmap */ + +/* + * Upcase table Management Functions + */ +s32 __load_upcase_table(struct super_block *sb, sector_t sector, u32 num_sectors, u32 utbl_checksum) +{ + int i, ret = FFS_ERROR; + u32 j; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + struct buffer_head *tmp_bh = NULL; + sector_t end_sector = num_sectors + sector; + + u8 skip = FALSE; + u32 index = 0; + u16 uni = 0; + u16 **upcase_table; + + u32 checksum = 0; + + upcase_table = p_fs->vol_utbl = (u16 **) kmalloc(UTBL_COL_COUNT * sizeof(u16 *), GFP_KERNEL); + if (upcase_table == NULL) + return FFS_MEMORYERR; + memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); + + while (sector < end_sector) { + ret = sector_read(sb, sector, &tmp_bh, 1); + if (ret != FFS_SUCCESS) { + DPRINTK("sector read (0x%llX)fail\n", (unsigned long long)sector); + goto error; + } + sector++; + + for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) { + uni = GET16(((u8 *) tmp_bh->b_data)+i); + + checksum = ((checksum & 1) ? 0x80000000 : 0) + (checksum >> 1) + *(((u8 *) tmp_bh->b_data)+i); + checksum = ((checksum & 1) ? 0x80000000 : 0) + (checksum >> 1) + *(((u8 *) tmp_bh->b_data)+(i+1)); + + if (skip) { + DPRINTK("skip from 0x%X ", index); + index += uni; + DPRINTK("to 0x%X (amount of 0x%X)\n", index, uni); + skip = FALSE; + } else if (uni == index) + index++; + else if (uni == 0xFFFF) + skip = TRUE; + else { /* uni != index , uni != 0xFFFF */ + u16 col_index = get_col_index(index); + + if (upcase_table[col_index] == NULL) { + DPRINTK("alloc = 0x%X\n", col_index); + upcase_table[col_index] = (u16 *) kmalloc(UTBL_ROW_COUNT * sizeof(u16), GFP_KERNEL); + if (upcase_table[col_index] == NULL) { + ret = FFS_MEMORYERR; + goto error; + } + + for (j = 0; j < UTBL_ROW_COUNT; j++) + upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; + } + + upcase_table[col_index][get_row_index(index)] = uni; + index++; + } + } + } + if (index >= 0xFFFF && utbl_checksum == checksum) { + if (tmp_bh) + brelse(tmp_bh); + return FFS_SUCCESS; + } + ret = FFS_ERROR; +error: + if (tmp_bh) + brelse(tmp_bh); + free_upcase_table(sb); + return ret; +} + +s32 __load_default_upcase_table(struct super_block *sb) +{ + int i, ret = FFS_ERROR; + u32 j; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + u8 skip = FALSE; + u32 index = 0; + u16 uni = 0; + u16 **upcase_table; + + upcase_table = p_fs->vol_utbl = (u16 **) kmalloc(UTBL_COL_COUNT * sizeof(u16 *), GFP_KERNEL); + if (upcase_table == NULL) + return FFS_MEMORYERR; + memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); + + for (i = 0; index <= 0xFFFF && i < NUM_UPCASE*2; i += 2) { + uni = GET16(uni_upcase + i); + if (skip) { + DPRINTK("skip from 0x%X ", index); + index += uni; + DPRINTK("to 0x%X (amount of 0x%X)\n", index, uni); + skip = FALSE; + } else if (uni == index) + index++; + else if (uni == 0xFFFF) + skip = TRUE; + else { /* uni != index , uni != 0xFFFF */ + u16 col_index = get_col_index(index); + + if (upcase_table[col_index] == NULL) { + DPRINTK("alloc = 0x%X\n", col_index); + upcase_table[col_index] = (u16 *) kmalloc(UTBL_ROW_COUNT * sizeof(u16), GFP_KERNEL); + if (upcase_table[col_index] == NULL) { + ret = FFS_MEMORYERR; + goto error; + } + + for (j = 0; j < UTBL_ROW_COUNT; j++) + upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; + } + + upcase_table[col_index][get_row_index(index)] = uni; + index++; + } + } + + if (index >= 0xFFFF) + return FFS_SUCCESS; + +error: + /* FATAL error: default upcase table has error */ + free_upcase_table(sb); + return ret; +} + +s32 load_upcase_table(struct super_block *sb) +{ + int i; + u32 tbl_clu, tbl_size; + sector_t sector; + u32 type, num_sectors; + CHAIN_T clu; + CASE_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu.dir = p_fs->root_dir; + clu.flags = 0x01; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + while (clu.dir != CLUSTER_32(~0)) { + for (i = 0; i < p_fs->dentries_per_clu; i++) { + ep = (CASE_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if (type != TYPE_UPCASE) + continue; + + tbl_clu = GET32_A(ep->start_clu); + tbl_size = (u32) GET64_A(ep->size); + + sector = START_SECTOR(tbl_clu); + num_sectors = ((tbl_size-1) >> p_bd->sector_size_bits) + 1; + if (__load_upcase_table(sb, sector, num_sectors, GET32_A(ep->checksum)) != FFS_SUCCESS) + break; + else + return FFS_SUCCESS; + } + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + /* load default upcase table */ + return __load_default_upcase_table(sb); +} /* end of load_upcase_table */ + +void free_upcase_table(struct super_block *sb) +{ + u32 i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + u16 **upcase_table; + + upcase_table = p_fs->vol_utbl; + for (i = 0; i < UTBL_COL_COUNT; i++) { + if (upcase_table[i]) + kfree(upcase_table[i]); + } + + if (p_fs->vol_utbl) + kfree(p_fs->vol_utbl); + p_fs->vol_utbl = NULL; +} /* end of free_upcase_table */ + +/* + * Directory Entry Management Functions + */ + +u32 fat_get_entry_type(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + if (*(ep->name) == 0x0) + return TYPE_UNUSED; + + else if (*(ep->name) == 0xE5) + return TYPE_DELETED; + + else if (ep->attr == ATTR_EXTEND) + return TYPE_EXTEND; + + else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_VOLUME) + return TYPE_VOLUME; + + else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_SUBDIR) + return TYPE_DIR; + + return TYPE_FILE; +} /* end of fat_get_entry_type */ + +u32 exfat_get_entry_type(DENTRY_T *p_entry) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + if (ep->type == 0x0) { + return TYPE_UNUSED; + } else if (ep->type < 0x80) { + return TYPE_DELETED; + } else if (ep->type == 0x80) { + return TYPE_INVALID; + } else if (ep->type < 0xA0) { + if (ep->type == 0x81) { + return TYPE_BITMAP; + } else if (ep->type == 0x82) { + return TYPE_UPCASE; + } else if (ep->type == 0x83) { + return TYPE_VOLUME; + } else if (ep->type == 0x85) { + if (GET16_A(ep->attr) & ATTR_SUBDIR) + return TYPE_DIR; + else + return TYPE_FILE; + } + return TYPE_CRITICAL_PRI; + } else if (ep->type < 0xC0) { + if (ep->type == 0xA0) + return TYPE_GUID; + else if (ep->type == 0xA1) + return TYPE_PADDING; + else if (ep->type == 0xA2) + return TYPE_ACLTAB; + return TYPE_BENIGN_PRI; + } else if (ep->type < 0xE0) { + if (ep->type == 0xC0) + return TYPE_STREAM; + else if (ep->type == 0xC1) + return TYPE_EXTEND; + else if (ep->type == 0xC2) + return TYPE_ACL; + return TYPE_CRITICAL_SEC; + } + + return TYPE_BENIGN_SEC; +} /* end of exfat_get_entry_type */ + +void fat_set_entry_type(DENTRY_T *p_entry, u32 type) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + if (type == TYPE_UNUSED) + *(ep->name) = 0x0; + + else if (type == TYPE_DELETED) + *(ep->name) = 0xE5; + + else if (type == TYPE_EXTEND) + ep->attr = ATTR_EXTEND; + + else if (type == TYPE_DIR) + ep->attr = ATTR_SUBDIR; + + else if (type == TYPE_FILE) + ep->attr = ATTR_ARCHIVE; + + else if (type == TYPE_SYMLINK) + ep->attr = ATTR_ARCHIVE | ATTR_SYMLINK; +} /* end of fat_set_entry_type */ + +void exfat_set_entry_type(DENTRY_T *p_entry, u32 type) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + if (type == TYPE_UNUSED) { + ep->type = 0x0; + } else if (type == TYPE_DELETED) { + ep->type &= ~0x80; + } else if (type == TYPE_STREAM) { + ep->type = 0xC0; + } else if (type == TYPE_EXTEND) { + ep->type = 0xC1; + } else if (type == TYPE_BITMAP) { + ep->type = 0x81; + } else if (type == TYPE_UPCASE) { + ep->type = 0x82; + } else if (type == TYPE_VOLUME) { + ep->type = 0x83; + } else if (type == TYPE_DIR) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_SUBDIR); + } else if (type == TYPE_FILE) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_ARCHIVE); + } else if (type == TYPE_SYMLINK) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK); + } +} /* end of exfat_set_entry_type */ + +u32 fat_get_entry_attr(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return (u32) ep->attr; +} /* end of fat_get_entry_attr */ + +u32 exfat_get_entry_attr(DENTRY_T *p_entry) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + return (u32) GET16_A(ep->attr); +} /* end of exfat_get_entry_attr */ + +void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + ep->attr = (u8) attr; +} /* end of fat_set_entry_attr */ + +void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + SET16_A(ep->attr, (u16) attr); +} /* end of exfat_set_entry_attr */ + +u8 fat_get_entry_flag(DENTRY_T *p_entry) +{ + return 0x01; +} /* end of fat_get_entry_flag */ + +u8 exfat_get_entry_flag(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return ep->flags; +} /* end of exfat_get_entry_flag */ + +void fat_set_entry_flag(DENTRY_T *p_entry, u8 flags) +{ +} /* end of fat_set_entry_flag */ + +void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flags) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + ep->flags = flags; +} /* end of exfat_set_entry_flag */ + +u32 fat_get_entry_clu0(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return ((u32) GET16_A(ep->start_clu_hi) << 16) | GET16_A(ep->start_clu_lo); +} /* end of fat_get_entry_clu0 */ + +u32 exfat_get_entry_clu0(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return GET32_A(ep->start_clu); +} /* end of exfat_get_entry_clu0 */ + +void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); + SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); +} /* end of fat_set_entry_clu0 */ + +void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + SET32_A(ep->start_clu, start_clu); +} /* end of exfat_set_entry_clu0 */ + +u64 fat_get_entry_size(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return (u64) GET32_A(ep->size); +} /* end of fat_get_entry_size */ + +u64 exfat_get_entry_size(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return GET64_A(ep->valid_size); +} /* end of exfat_get_entry_size */ + +void fat_set_entry_size(DENTRY_T *p_entry, u64 size) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + SET32_A(ep->size, (u32) size); +} /* end of fat_set_entry_size */ + +void exfat_set_entry_size(DENTRY_T *p_entry, u64 size) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + SET64_A(ep->valid_size, size); + SET64_A(ep->size, size); +} /* end of exfat_set_entry_size */ + +void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t = 0x00, d = 0x21; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + switch (mode) { + case TM_CREATE: + t = GET16_A(ep->create_time); + d = GET16_A(ep->create_date); + break; + case TM_MODIFY: + t = GET16_A(ep->modify_time); + d = GET16_A(ep->modify_date); + break; + } + + tp->sec = (t & 0x001F) << 1; + tp->min = (t >> 5) & 0x003F; + tp->hour = (t >> 11); + tp->day = (d & 0x001F); + tp->mon = (d >> 5) & 0x000F; + tp->year = (d >> 9); +} /* end of fat_get_entry_time */ + +void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t = 0x00, d = 0x21; + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + switch (mode) { + case TM_CREATE: + t = GET16_A(ep->create_time); + d = GET16_A(ep->create_date); + break; + case TM_MODIFY: + t = GET16_A(ep->modify_time); + d = GET16_A(ep->modify_date); + break; + case TM_ACCESS: + t = GET16_A(ep->access_time); + d = GET16_A(ep->access_date); + break; + } + + tp->sec = (t & 0x001F) << 1; + tp->min = (t >> 5) & 0x003F; + tp->hour = (t >> 11); + tp->day = (d & 0x001F); + tp->mon = (d >> 5) & 0x000F; + tp->year = (d >> 9); +} /* end of exfat_get_entry_time */ + +void fat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t, d; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); + d = (tp->year << 9) | (tp->mon << 5) | tp->day; + + switch (mode) { + case TM_CREATE: + SET16_A(ep->create_time, t); + SET16_A(ep->create_date, d); + break; + case TM_MODIFY: + SET16_A(ep->modify_time, t); + SET16_A(ep->modify_date, d); + break; + } +} /* end of fat_set_entry_time */ + +void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t, d; + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); + d = (tp->year << 9) | (tp->mon << 5) | tp->day; + + switch (mode) { + case TM_CREATE: + SET16_A(ep->create_time, t); + SET16_A(ep->create_date, d); + break; + case TM_MODIFY: + SET16_A(ep->modify_time, t); + SET16_A(ep->modify_date, d); + break; + case TM_ACCESS: + SET16_A(ep->access_time, t); + SET16_A(ep->access_date, d); + break; + } +} /* end of exfat_set_entry_time */ + +s32 fat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size) +{ + sector_t sector; + DOS_DENTRY_T *dos_ep; + + dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!dos_ep) + return FFS_MEDIAERR; + + init_dos_entry(dos_ep, type, start_clu); + buf_modify(sb, sector); + + return FFS_SUCCESS; +} /* end of fat_init_dir_entry */ + +s32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size) +{ + sector_t sector; + u8 flags; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + + flags = (type == TYPE_FILE) ? 0x01 : 0x03; + + /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */ + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return FFS_MEDIAERR; + + strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, §or); + if (!strm_ep) + return FFS_MEDIAERR; + + init_file_entry(file_ep, type); + buf_modify(sb, sector); + + init_strm_entry(strm_ep, flags, start_clu, size); + buf_modify(sb, sector); + + return FFS_SUCCESS; +} /* end of exfat_init_dir_entry */ + +s32 fat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i; + sector_t sector; + u8 chksum; + u16 *uniname = p_uniname->name; + DOS_DENTRY_T *dos_ep; + EXT_DENTRY_T *ext_ep; + + dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!dos_ep) + return FFS_MEDIAERR; + + dos_ep->lcase = p_dosname->name_case; + memcpy(dos_ep->name, p_dosname->name, DOS_NAME_LENGTH); + buf_modify(sb, sector); + + if ((--num_entries) > 0) { + chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0); + + for (i = 1; i < num_entries; i++) { + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ext_ep) + return FFS_MEDIAERR; + + init_ext_entry(ext_ep, i, chksum, uniname); + buf_modify(sb, sector); + uniname += 13; + } + + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ext_ep) + return FFS_MEDIAERR; + + init_ext_entry(ext_ep, i+0x40, chksum, uniname); + buf_modify(sb, sector); + } + + return FFS_SUCCESS; +} /* end of fat_init_ext_entry */ + +s32 exfat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i; + sector_t sector; + u16 *uniname = p_uniname->name; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + NAME_DENTRY_T *name_ep; + + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return FFS_MEDIAERR; + + file_ep->num_ext = (u8)(num_entries - 1); + buf_modify(sb, sector); + + strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, §or); + if (!strm_ep) + return FFS_MEDIAERR; + + strm_ep->name_len = p_uniname->name_len; + SET16_A(strm_ep->name_hash, p_uniname->name_hash); + buf_modify(sb, sector); + + for (i = 2; i < num_entries; i++) { + name_ep = (NAME_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+i, §or); + if (!name_ep) + return FFS_MEDIAERR; + + init_name_entry(name_ep, uniname); + buf_modify(sb, sector); + uniname += 15; + } + + update_dir_checksum(sb, p_dir, entry); + + return FFS_SUCCESS; +} /* end of exfat_init_ext_entry */ + +void init_dos_entry(DOS_DENTRY_T *ep, u32 type, u32 start_clu) +{ + TIMESTAMP_T tm, *tp; + + fat_set_entry_type((DENTRY_T *) ep, type); + SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); + SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); + SET32_A(ep->size, 0); + + tp = tm_current(&tm); + fat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); + fat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); + SET16_A(ep->access_date, 0); + ep->create_time_ms = 0; +} /* end of init_dos_entry */ + +void init_ext_entry(EXT_DENTRY_T *ep, s32 order, u8 chksum, u16 *uniname) +{ + int i; + u8 end = FALSE; + + fat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND); + ep->order = (u8) order; + ep->sysid = 0; + ep->checksum = chksum; + SET16_A(ep->start_clu, 0); + + for (i = 0; i < 10; i += 2) { + if (!end) { + SET16(ep->unicode_0_4+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16(ep->unicode_0_4+i, 0xFFFF); + } + } + + for (i = 0; i < 12; i += 2) { + if (!end) { + SET16_A(ep->unicode_5_10+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16_A(ep->unicode_5_10+i, 0xFFFF); + } + } + + for (i = 0; i < 4; i += 2) { + if (!end) { + SET16_A(ep->unicode_11_12+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16_A(ep->unicode_11_12+i, 0xFFFF); + } + } +} /* end of init_ext_entry */ + +void init_file_entry(FILE_DENTRY_T *ep, u32 type) +{ + TIMESTAMP_T tm, *tp; + + exfat_set_entry_type((DENTRY_T *) ep, type); + + tp = tm_current(&tm); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS); + ep->create_time_ms = 0; + ep->modify_time_ms = 0; + ep->access_time_ms = 0; +} /* end of init_file_entry */ + +void init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size) +{ + exfat_set_entry_type((DENTRY_T *) ep, TYPE_STREAM); + ep->flags = flags; + SET32_A(ep->start_clu, start_clu); + SET64_A(ep->valid_size, size); + SET64_A(ep->size, size); +} /* end of init_strm_entry */ + +void init_name_entry(NAME_DENTRY_T *ep, u16 *uniname) +{ + int i; + + exfat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND); + ep->flags = 0x0; + + for (i = 0; i < 30; i++, i++) { + SET16_A(ep->unicode_0_14+i, *uniname); + if (*uniname == 0x0) + break; + uniname++; + } +} /* end of init_name_entry */ + +void fat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries) +{ + int i; + sector_t sector; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = num_entries-1; i >= order; i--) { + ep = get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ep) + return; + + p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); + buf_modify(sb, sector); + } +} /* end of fat_delete_dir_entry */ + +void exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries) +{ + int i; + sector_t sector; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = order; i < num_entries; i++) { + ep = get_entry_in_dir(sb, p_dir, entry+i, §or); + if (!ep) + return; + + p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); + buf_modify(sb, sector); + } +} /* end of exfat_delete_dir_entry */ + +void update_dir_checksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry) +{ + int i, num_entries; + sector_t sector; + u16 chksum; + FILE_DENTRY_T *file_ep; + DENTRY_T *ep; + + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return; + + buf_lock(sb, sector); + + num_entries = (s32) file_ep->num_ext + 1; + chksum = calc_checksum_2byte((void *) file_ep, DENTRY_SIZE, 0, CS_DIR_ENTRY); + + for (i = 1; i < num_entries; i++) { + ep = get_entry_in_dir(sb, p_dir, entry+i, NULL); + if (!ep) { + buf_unlock(sb, sector); + return; + } + + chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, CS_DEFAULT); + } + + SET16_A(file_ep->checksum, chksum); + buf_modify(sb, sector); + buf_unlock(sb, sector); +} /* end of update_dir_checksum */ + +void update_dir_checksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es) +{ + DENTRY_T *ep; + u16 chksum = 0; + s32 chksum_type = CS_DIR_ENTRY, i; + + ep = (DENTRY_T *)&(es->__buf); + for (i = 0; i < es->num_entries; i++) { + DPRINTK("update_dir_checksum_with_entry_set ep %p\n", ep); + chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type); + ep++; + chksum_type = CS_DEFAULT; + } + + ep = (DENTRY_T *)&(es->__buf); + SET16_A(((FILE_DENTRY_T *)ep)->checksum, chksum); + write_whole_entry_set(sb, es); +} + +static s32 _walk_fat_chain(struct super_block *sb, CHAIN_T *p_dir, s32 byte_offset, u32 *clu) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + s32 clu_offset; + u32 cur_clu; + + clu_offset = byte_offset >> p_fs->cluster_size_bits; + cur_clu = p_dir->dir; + + if (p_dir->flags == 0x03) { + cur_clu += clu_offset; + } else { + while (clu_offset > 0) { + if (FAT_read(sb, cur_clu, &cur_clu) == -1) + return FFS_MEDIAERR; + clu_offset--; + } + } + + if (clu) + *clu = cur_clu; + return FFS_SUCCESS; +} +s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector, s32 *offset) +{ + s32 off, ret; + u32 clu = 0; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + off = entry << DENTRY_SIZE_BITS; + + if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + *offset = off & p_bd->sector_size_mask; + *sector = off >> p_bd->sector_size_bits; + *sector += p_fs->root_start_sector; + } else { + ret = _walk_fat_chain(sb, p_dir, off, &clu); + if (ret != FFS_SUCCESS) + return ret; + + off &= p_fs->cluster_size - 1; /* byte offset in cluster */ + + *offset = off & p_bd->sector_size_mask; /* byte offset in sector */ + *sector = off >> p_bd->sector_size_bits; /* sector offset in cluster */ + *sector += START_SECTOR(clu); + } + return FFS_SUCCESS; +} /* end of find_location */ + +DENTRY_T *get_entry_with_sector(struct super_block *sb, sector_t sector, s32 offset) +{ + u8 *buf; + + buf = buf_getblk(sb, sector); + + if (buf == NULL) + return NULL; + + return (DENTRY_T *)(buf + offset); +} /* end of get_entry_with_sector */ + +DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector) +{ + s32 off; + sector_t sec; + u8 *buf; + + if (find_location(sb, p_dir, entry, &sec, &off) != FFS_SUCCESS) + return NULL; + + buf = buf_getblk(sb, sec); + + if (buf == NULL) + return NULL; + + if (sector != NULL) + *sector = sec; + return (DENTRY_T *)(buf + off); +} /* end of get_entry_in_dir */ + + +/* returns a set of dentries for a file or dir. + * Note that this is a copy (dump) of dentries so that user should call write_entry_set() + * to apply changes made in this entry set to the real device. + * in: + * sb+p_dir+entry: indicates a file/dir + * type: specifies how many dentries should be included. + * out: + * file_ep: will point the first dentry(= file dentry) on success + * return: + * pointer of entry set on success, + * NULL on failure. + */ + +#define ES_MODE_STARTED 0 +#define ES_MODE_GET_FILE_ENTRY 1 +#define ES_MODE_GET_STRM_ENTRY 2 +#define ES_MODE_GET_NAME_ENTRY 3 +#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4 +ENTRY_SET_CACHE_T *get_entry_set_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep) +{ + s32 off, ret, byte_offset; + u32 clu = 0; + sector_t sec; + u32 entry_type; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + ENTRY_SET_CACHE_T *es = NULL; + DENTRY_T *ep, *pos; + u8 *buf; + u8 num_entries; + s32 mode = ES_MODE_STARTED; + + DPRINTK("get_entry_set_in_dir entered\n"); + DPRINTK("p_dir dir %u flags %x size %d\n", p_dir->dir, p_dir->flags, p_dir->size); + + byte_offset = entry << DENTRY_SIZE_BITS; + ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); + if (ret != FFS_SUCCESS) + return NULL; + + + byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */ + + off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */ + sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + sec += START_SECTOR(clu); + + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + + + ep = (DENTRY_T *)(buf + off); + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type != TYPE_FILE) + && (entry_type != TYPE_DIR)) + goto err_out; + + if (type == ES_ALL_ENTRIES) + num_entries = ((FILE_DENTRY_T *)ep)->num_ext+1; + else + num_entries = type; + + DPRINTK("trying to kmalloc %zx bytes for %d entries\n", offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T), num_entries); + es = kmalloc(offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T), GFP_KERNEL); + if (es == NULL) + goto err_out; + + es->num_entries = num_entries; + es->sector = sec; + es->offset = off; + es->alloc_flag = p_dir->flags; + + pos = (DENTRY_T *) &(es->__buf); + + while(num_entries) { + /* instead of copying whole sector, we will check every entry. + * this will provide minimum stablity and consistancy. + */ + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) + goto err_out; + + switch (mode) { + case ES_MODE_STARTED: + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) + mode = ES_MODE_GET_FILE_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_FILE_ENTRY: + if (entry_type == TYPE_STREAM) + mode = ES_MODE_GET_STRM_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_STRM_ENTRY: + if (entry_type == TYPE_EXTEND) + mode = ES_MODE_GET_NAME_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_NAME_ENTRY: + if (entry_type == TYPE_EXTEND) + break; + else if (entry_type == TYPE_STREAM) + goto err_out; + else if (entry_type & TYPE_CRITICAL_SEC) + mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_CRITICAL_SEC_ENTRY: + if ((entry_type == TYPE_EXTEND) || (entry_type == TYPE_STREAM)) + goto err_out; + else if ((entry_type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC) + goto err_out; + break; + } + + memcpy(pos, ep, sizeof(DENTRY_T)); + + if (--num_entries == 0) + break; + + if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < (off & p_bd->sector_size_mask)) { + /* get the next sector */ + if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { + if (es->alloc_flag == 0x03) { + clu++; + } else { + if (FAT_read(sb, clu, &clu) == -1) + goto err_out; + } + sec = START_SECTOR(clu); + } else { + sec++; + } + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + off = 0; + ep = (DENTRY_T *)(buf); + } else { + ep++; + off += DENTRY_SIZE; + } + pos++; + } + + if (file_ep) + *file_ep = (DENTRY_T *)&(es->__buf); + + DPRINTK("es sec %llu offset %d flags %d, num_entries %u buf ptr %p\n", + (unsigned long long)es->sector, es->offset, es->alloc_flag, + es->num_entries, &(es->__buf)); + DPRINTK("get_entry_set_in_dir exited %p\n", es); + return es; +err_out: + DPRINTK("get_entry_set_in_dir exited NULL (es %p)\n", es); + if (es) + kfree(es); + return NULL; +} + +void release_entry_set(ENTRY_SET_CACHE_T *es) +{ + DPRINTK("release_entry_set %p\n", es); + if (es) + kfree(es); +} + + +static s32 __write_partial_entries_in_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es, sector_t sec, s32 off, u32 count) +{ + s32 num_entries, buf_off = (off - es->offset); + u32 remaining_byte_in_sector, copy_entries; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + u32 clu; + u8 *buf, *esbuf = (u8 *)&(es->__buf); + + DPRINTK("__write_partial_entries_in_entry_set entered\n"); + DPRINTK("es %p sec %llu off %d count %d\n", es, (unsigned long long)sec, off, count); + num_entries = count; + + while (num_entries) { + /* white per sector base */ + remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; + copy_entries = MIN(remaining_byte_in_sector >> DENTRY_SIZE_BITS , num_entries); + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + DPRINTK("es->buf %p buf_off %u\n", esbuf, buf_off); + DPRINTK("copying %d entries from %p to sector %llu\n", copy_entries, (esbuf + buf_off), (unsigned long long)sec); + memcpy(buf + off, esbuf + buf_off, copy_entries << DENTRY_SIZE_BITS); + buf_modify(sb, sec); + num_entries -= copy_entries; + + if (num_entries) { + /* get next sector */ + if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { + clu = GET_CLUSTER_FROM_SECTOR(sec); + if (es->alloc_flag == 0x03) { + clu++; + } else { + if (FAT_read(sb, clu, &clu) == -1) + goto err_out; + } + sec = START_SECTOR(clu); + } else { + sec++; + } + off = 0; + buf_off += copy_entries << DENTRY_SIZE_BITS; + } + } + + DPRINTK("__write_partial_entries_in_entry_set exited successfully\n"); + return FFS_SUCCESS; +err_out: + DPRINTK("__write_partial_entries_in_entry_set failed\n"); + return FFS_ERROR; +} + +/* write back all entries in entry set */ +s32 write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es) +{ + return __write_partial_entries_in_entry_set(sb, es, es->sector, es->offset, es->num_entries); +} + +/* write back some entries in entry set */ +s32 write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es, DENTRY_T *ep, u32 count) +{ + s32 ret, byte_offset, off; + u32 clu=0; + sector_t sec; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + CHAIN_T dir; + + /* vaidity check */ + if (ep + count > ((DENTRY_T *)&(es->__buf)) + es->num_entries) + return FFS_ERROR; + + dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector); + dir.flags = es->alloc_flag; + dir.size = 0xffffffff; /* XXX */ + + byte_offset = (es->sector - START_SECTOR(dir.dir)) << p_bd->sector_size_bits; + byte_offset += ((void **)ep - &(es->__buf)) + es->offset; + + ret =_walk_fat_chain(sb, &dir, byte_offset, &clu); + if (ret != FFS_SUCCESS) + return ret; + byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */ + off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */ + sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + sec += START_SECTOR(clu); + return __write_partial_entries_in_entry_set(sb, es, sec, off, count); +} + +/* search EMPTY CONTINUOUS "num_entries" entries */ +s32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, s32 num_entries) +{ + int i, dentry, num_empty = 0; + s32 dentries_per_clu; + u32 type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + if (p_fs->hint_uentry.dir == p_dir->dir) { + if (p_fs->hint_uentry.entry == -1) + return -1; + + clu.dir = p_fs->hint_uentry.clu.dir; + clu.size = p_fs->hint_uentry.clu.size; + clu.flags = p_fs->hint_uentry.clu.flags; + + dentry = p_fs->hint_uentry.entry; + } else { + p_fs->hint_uentry.entry = -1; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + dentry = 0; + } + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + i = dentry % dentries_per_clu; + else + i = dentry & (dentries_per_clu-1); + + for (; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -1; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) { + num_empty++; + if (p_fs->hint_uentry.entry == -1) { + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = dentry; + + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = clu.size; + p_fs->hint_uentry.clu.flags = clu.flags; + } + } else if (type == TYPE_DELETED) { + num_empty++; + } else { + num_empty = 0; + } + + if (num_empty >= num_entries) { + p_fs->hint_uentry.dir = CLUSTER_32(~0); + p_fs->hint_uentry.entry = -1; + + if (p_fs->vol_type == EXFAT) + return dentry - (num_entries-1); + else + return dentry; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -1; + } + } + + return -1; +} /* end of search_deleted_or_unused_entry */ + +s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries) +{ + s32 ret, dentry; + u32 last_clu; + sector_t sector; + u64 size = 0; + CHAIN_T clu; + DENTRY_T *ep = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + return search_deleted_or_unused_entry(sb, p_dir, num_entries); + + while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) { + if (p_fs->dev_ejected) + break; + + if (p_fs->vol_type == EXFAT) { + if (p_dir->dir != p_fs->root_dir) + size = i_size_read(inode); + } + + last_clu = find_last_cluster(sb, p_dir); + clu.dir = last_clu + 1; + clu.size = 0; + clu.flags = p_dir->flags; + + /* (1) allocate a cluster */ + ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu); + if (ret < 1) + return -1; + + if (clear_cluster(sb, clu.dir) != FFS_SUCCESS) + return -1; + + /* (2) append to the FAT chain */ + if (clu.flags != p_dir->flags) { + exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); + p_dir->flags = 0x01; + p_fs->hint_uentry.clu.flags = 0x01; + } + if (clu.flags == 0x01) + if (FAT_write(sb, last_clu, clu.dir) < 0) + return -1; + + if (p_fs->hint_uentry.entry == -1) { + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = 0; + p_fs->hint_uentry.clu.flags = clu.flags; + } + p_fs->hint_uentry.clu.size++; + p_dir->size++; + + /* (3) update the directory entry */ + if (p_fs->vol_type == EXFAT) { + if (p_dir->dir != p_fs->root_dir) { + size += p_fs->cluster_size; + + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry+1, §or); + if (!ep) + return -1; + p_fs->fs_func->set_entry_size(ep, size); + p_fs->fs_func->set_entry_flag(ep, p_dir->flags); + buf_modify(sb, sector); + + update_dir_checksum(sb, &(fid->dir), fid->entry); + } + } + + i_size_write(inode, i_size_read(inode)+p_fs->cluster_size); + EXFAT_I(inode)->mmu_private += p_fs->cluster_size; + EXFAT_I(inode)->fid.size += p_fs->cluster_size; + EXFAT_I(inode)->fid.flags = p_dir->flags; + inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); + } + + return dentry; +} /* end of find_empty_entry */ + +/* return values of fat_find_dir_entry() + >= 0 : return dir entiry position with the name in dir + -1 : (root dir, ".") it is the root dir itself + -2 : entry with the name does not exist */ +s32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type) +{ + int i, dentry = 0, lossy = FALSE, len; + s32 order = 0, is_feasible_entry = TRUE, has_ext_entry = FALSE; + s32 dentries_per_clu; + u32 entry_type; + u16 entry_uniname[14], *uniname = NULL, unichar; + CHAIN_T clu; + DENTRY_T *ep; + DOS_DENTRY_T *dos_ep; + EXT_DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == p_fs->root_dir) { + if ((!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_CUR_DIR_NAME)) || + (!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_PAR_DIR_NAME))) + return -1; // special case, root directory itself + } + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -2; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { + if ((type == TYPE_ALL) || (type == entry_type)) { + if (is_feasible_entry && has_ext_entry) + return dentry; + + dos_ep = (DOS_DENTRY_T *) ep; + if ((!lossy) && (!nls_dosname_cmp(sb, p_dosname->name, dos_ep->name))) + return dentry; + } + is_feasible_entry = TRUE; + has_ext_entry = FALSE; + } else if (entry_type == TYPE_EXTEND) { + if (is_feasible_entry) { + ext_ep = (EXT_DENTRY_T *) ep; + if (ext_ep->order > 0x40) { + order = (s32)(ext_ep->order - 0x40); + uniname = p_uniname->name + 13 * (order-1); + } else { + order = (s32) ext_ep->order; + uniname -= 13; + } + + len = extract_uni_name_from_ext_entry(ext_ep, entry_uniname, order); + + unichar = *(uniname+len); + *(uniname+len) = 0x0; + + if (nls_uniname_cmp(sb, uniname, entry_uniname)) + is_feasible_entry = FALSE; + + *(uniname+len) = unichar; + } + has_ext_entry = TRUE; + } else if (entry_type == TYPE_UNUSED) { + return -2; + } else { + is_feasible_entry = TRUE; + has_ext_entry = FALSE; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -2; + } + + return -2; +} /* end of fat_find_dir_entry */ + +/* return values of exfat_find_dir_entry() + >= 0 : return dir entiry position with the name in dir + -1 : (root dir, ".") it is the root dir itself + -2 : entry with the name does not exist */ +s32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type) +{ + int i = 0, dentry = 0, num_ext_entries = 0, len, step; + s32 order = 0, is_feasible_entry = FALSE; + s32 dentries_per_clu, num_empty = 0; + u32 entry_type; + u16 entry_uniname[16], *uniname = NULL, unichar; + CHAIN_T clu; + DENTRY_T *ep; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + NAME_DENTRY_T *name_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == p_fs->root_dir) { + if ((!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_CUR_DIR_NAME)) || + (!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_PAR_DIR_NAME))) + return -1; // special case, root directory itself + } + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = -1; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + while (i < dentries_per_clu) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -2; + + entry_type = p_fs->fs_func->get_entry_type(ep); + step = 1; + + if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) { + is_feasible_entry = FALSE; + + if (p_fs->hint_uentry.entry == -1) { + num_empty++; + + if (num_empty == 1) { + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = clu.size; + p_fs->hint_uentry.clu.flags = clu.flags; + } + if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) + p_fs->hint_uentry.entry = dentry - (num_empty-1); + } + + if (entry_type == TYPE_UNUSED) + return -2; + } else { + num_empty = 0; + + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { + file_ep = (FILE_DENTRY_T *) ep; + if ((type == TYPE_ALL) || (type == entry_type)) { + num_ext_entries = file_ep->num_ext; + is_feasible_entry = TRUE; + } else { + is_feasible_entry = FALSE; + step = file_ep->num_ext + 1; + } + } else if (entry_type == TYPE_STREAM) { + if (is_feasible_entry) { + strm_ep = (STRM_DENTRY_T *) ep; + if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) && + p_uniname->name_len == strm_ep->name_len) { + order = 1; + } else { + is_feasible_entry = FALSE; + step = num_ext_entries; + } + } + } else if (entry_type == TYPE_EXTEND) { + if (is_feasible_entry) { + name_ep = (NAME_DENTRY_T *) ep; + + if ((++order) == 2) + uniname = p_uniname->name; + else + uniname += 15; + + len = extract_uni_name_from_name_entry(name_ep, entry_uniname, order); + + unichar = *(uniname+len); + *(uniname+len) = 0x0; + + if (nls_uniname_cmp(sb, uniname, entry_uniname)) { + is_feasible_entry = FALSE; + step = num_ext_entries - order + 1; + } else if (order == num_ext_entries) { + p_fs->hint_uentry.dir = CLUSTER_32(~0); + p_fs->hint_uentry.entry = -1; + return dentry - (num_ext_entries); + } + + *(uniname+len) = unichar; + } + } else { + is_feasible_entry = FALSE; + } + } + + i += step; + dentry += step; + } + + i -= dentries_per_clu; + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -2; + } + } + + return -2; +} /* end of exfat_find_dir_entry */ + +/* returns -1 on error */ +s32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry) +{ + s32 count = 0; + u8 chksum; + DOS_DENTRY_T *dos_ep = (DOS_DENTRY_T *) p_entry; + EXT_DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0); + + for (entry--; entry >= 0; entry--) { + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ext_ep) + return -1; + + if ((p_fs->fs_func->get_entry_type((DENTRY_T *) ext_ep) == TYPE_EXTEND) && + (ext_ep->checksum == chksum)) { + count++; + if (ext_ep->order > 0x40) + return count; + } else { + return count; + } + } + + return count; +} /* end of fat_count_ext_entries */ + +/* returns -1 on error */ +s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry) +{ + int i, count = 0; + u32 type; + FILE_DENTRY_T *file_ep = (FILE_DENTRY_T *) p_entry; + DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) { + ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ext_ep) + return -1; + + type = p_fs->fs_func->get_entry_type(ext_ep); + if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) + count++; + else + return count; + } + + return count; +} /* end of exfat_count_ext_entries */ + +/* returns -1 on error */ +s32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type) +{ + int i, count = 0; + s32 dentries_per_clu; + u32 entry_type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -1; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if (entry_type == TYPE_UNUSED) + return count; + if (!(type & TYPE_CRITICAL_PRI) && !(type & TYPE_BENIGN_PRI)) + continue; + + if ((type == TYPE_ALL) || (type == entry_type)) + count++; + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -1; + } + } + + return count; +} /* end of count_dos_name_entries */ + +bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir) +{ + int i, count = 0; + s32 dentries_per_clu; + u32 type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + break; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) + return TRUE; + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + return FALSE; + } else { + if (p_fs->vol_type == EXFAT) + return FALSE; + if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2)) + return FALSE; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + break; + } + } + + return TRUE; +} /* end of is_dir_empty */ + +/* + * Name Conversion Functions + */ + +/* input : dir, uni_name + output : num_of_entry, dos_name(format : aaaaaa~1.bbb) */ +s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 *entries, DOS_NAME_T *p_dosname) +{ + s32 ret, num_entries, lossy = FALSE; + char **r; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + num_entries = p_fs->fs_func->calc_num_entries(p_uniname); + if (num_entries == 0) + return FFS_INVALIDPATH; + + if (p_fs->vol_type != EXFAT) { + nls_uniname_to_dosname(sb, p_dosname, p_uniname, &lossy); + + if (lossy) { + ret = fat_generate_dos_name(sb, p_dir, p_dosname); + if (ret) + return ret; + } else { + for (r = reserved_names; *r; r++) { + if (!strncmp((void *) p_dosname->name, *r, 8)) + return FFS_INVALIDPATH; + } + + if (p_dosname->name_case != 0xFF) + num_entries = 1; + } + + if (num_entries > 1) + p_dosname->name_case = 0x0; + } + + *entries = num_entries; + + return FFS_SUCCESS; +} /* end of get_num_entries_and_dos_name */ + +void get_uni_name_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode) +{ + DOS_NAME_T dos_name; + + if (mode == 0x0) + dos_name.name_case = 0x0; + else + dos_name.name_case = ep->lcase; + + memcpy(dos_name.name, ep->name, DOS_NAME_LENGTH); + nls_dosname_to_uniname(sb, p_uniname, &dos_name); +} /* end of get_uni_name_from_dos_entry */ + +void fat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname) +{ + int i; + EXT_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (entry--, i = 1; entry >= 0; entry--, i++) { + ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ep) + return; + + if (p_fs->fs_func->get_entry_type((DENTRY_T *) ep) == TYPE_EXTEND) { + extract_uni_name_from_ext_entry(ep, uniname, i); + if (ep->order > 0x40) + return; + } else { + return; + } + + uniname += 13; + } +} /* end of fat_get_uni_name_from_ext_entry */ + +void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname) +{ + int i; + DENTRY_T *ep; + ENTRY_SET_CACHE_T *es; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); + if (es == NULL || es->num_entries < 3) { + if (es) + release_entry_set(es); + return; + } + + ep += 2; + + /* + * First entry : file entry + * Second entry : stream-extension entry + * Third entry : first file-name entry + * So, the index of first file-name dentry should start from 2. + */ + for (i = 2; i < es->num_entries; i++, ep++) { + if (p_fs->fs_func->get_entry_type(ep) == TYPE_EXTEND) + extract_uni_name_from_name_entry((NAME_DENTRY_T *)ep, uniname, i); + else + goto out; + uniname += 15; + } + +out: + release_entry_set(es); +} /* end of exfat_get_uni_name_from_ext_entry */ + +s32 extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 order) +{ + int i, len = 0; + + for (i = 0; i < 10; i += 2) { + *uniname = GET16(ep->unicode_0_4+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + if (order < 20) { + for (i = 0; i < 12; i += 2) { + *uniname = GET16_A(ep->unicode_5_10+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + } else { + for (i = 0; i < 8; i += 2) { + *uniname = GET16_A(ep->unicode_5_10+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + *uniname = 0x0; /* uniname[MAX_NAME_LENGTH-1] */ + return len; + } + + for (i = 0; i < 4; i += 2) { + *uniname = GET16_A(ep->unicode_11_12+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + *uniname = 0x0; + return len; + +} /* end of extract_uni_name_from_ext_entry */ + +s32 extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order) +{ + int i, len = 0; + + for (i = 0; i < 30; i += 2) { + *uniname = GET16_A(ep->unicode_0_14+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + *uniname = 0x0; + return len; + +} /* end of extract_uni_name_from_name_entry */ + +s32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname) +{ + int i, j, count = 0, count_begin = FALSE; + s32 dentries_per_clu; + u32 type; + u8 bmap[128/* 1 ~ 1023 */]; + CHAIN_T clu; + DOS_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + memset(bmap, 0, sizeof bmap); + exfat_bitmap_set(bmap, 0); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + count = 0; + count_begin = FALSE; + + for (j = 0; j < 8; j++) { + if (ep->name[j] == ' ') + break; + + if (ep->name[j] == '~') { + count_begin = TRUE; + } else if (count_begin) { + if ((ep->name[j] >= '0') && (ep->name[j] <= '9')) { + count = count * 10 + (ep->name[j] - '0'); + } else { + count = 0; + count_begin = FALSE; + } + } + } + + if ((count > 0) && (count < 1024)) + exfat_bitmap_set(bmap, count); + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + + count = 0; + for (i = 0; i < 128; i++) { + if (bmap[i] != 0xFF) { + for (j = 0; j < 8; j++) { + if (exfat_bitmap_test(&(bmap[i]), j) == 0) { + count = (i << 3) + j; + break; + } + } + if (count != 0) + break; + } + } + + if ((count == 0) || (count >= 1024)) + return FFS_FILEEXIST; + else + fat_attach_count_to_dos_name(p_dosname->name, count); + + /* Now dos_name has DOS~????.EXT */ + return FFS_SUCCESS; +} /* end of generate_dos_name */ + +void fat_attach_count_to_dos_name(u8 *dosname, s32 count) +{ + int i, j, length; + char str_count[6]; + + snprintf(str_count, sizeof str_count, "~%d", count); + length = strlen(str_count); + + i = j = 0; + while (j <= (8 - length)) { + i = j; + if (dosname[j] == ' ') + break; + if (dosname[j] & 0x80) + j += 2; + else + j++; + } + + for (j = 0; j < length; i++, j++) + dosname[i] = (u8) str_count[j]; + + if (i == 7) + dosname[7] = ' '; + +} /* end of attach_count_to_dos_name */ + +s32 fat_calc_num_entries(UNI_NAME_T *p_uniname) +{ + s32 len; + + len = p_uniname->name_len; + if (len == 0) + return 0; + + /* 1 dos name entry + extended entries */ + return (len-1) / 13 + 2; + +} /* end of calc_num_enties */ + +s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname) +{ + s32 len; + + len = p_uniname->name_len; + if (len == 0) + return 0; + + /* 1 file entry + 1 stream entry + name entries */ + return (len-1) / 15 + 3; + +} /* end of exfat_calc_num_enties */ + +u8 calc_checksum_1byte(void *data, s32 len, u8 chksum) +{ + int i; + u8 *c = (u8 *) data; + + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c; + + return chksum; +} /* end of calc_checksum_1byte */ + +u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type) +{ + int i; + u8 *c = (u8 *) data; + + switch (type) { + case CS_DIR_ENTRY: + for (i = 0; i < len; i++, c++) { + if ((i == 2) || (i == 3)) + continue; + chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c; + } + break; + default + : + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c; + } + + return chksum; +} /* end of calc_checksum_2byte */ + +u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type) +{ + int i; + u8 *c = (u8 *) data; + + switch (type) { + case CS_PBR_SECTOR: + for (i = 0; i < len; i++, c++) { + if ((i == 106) || (i == 107) || (i == 112)) + continue; + chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (u32) *c; + } + break; + default + : + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (u32) *c; + } + + return chksum; +} /* end of calc_checksum_4byte */ + +/* + * Name Resolution Functions + */ + +/* return values of resolve_path() + > 0 : return the length of the path + < 0 : return error */ +s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname) +{ + s32 lossy = FALSE; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + if (strlen(path) >= (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) + return FFS_INVALIDPATH; + + strcpy(name_buf, path); + + nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); + if (lossy) + return FFS_INVALIDPATH; + + fid->size = i_size_read(inode); + + p_dir->dir = fid->start_clu; + p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits); + p_dir->flags = fid->flags; + + return FFS_SUCCESS; +} + +/* + * File Operation Functions + */ +static FS_FUNC_T fat_fs_func = { + .alloc_cluster = fat_alloc_cluster, + .free_cluster = fat_free_cluster, + .count_used_clusters = fat_count_used_clusters, + + .init_dir_entry = fat_init_dir_entry, + .init_ext_entry = fat_init_ext_entry, + .find_dir_entry = fat_find_dir_entry, + .delete_dir_entry = fat_delete_dir_entry, + .get_uni_name_from_ext_entry = fat_get_uni_name_from_ext_entry, + .count_ext_entries = fat_count_ext_entries, + .calc_num_entries = fat_calc_num_entries, + + .get_entry_type = fat_get_entry_type, + .set_entry_type = fat_set_entry_type, + .get_entry_attr = fat_get_entry_attr, + .set_entry_attr = fat_set_entry_attr, + .get_entry_flag = fat_get_entry_flag, + .set_entry_flag = fat_set_entry_flag, + .get_entry_clu0 = fat_get_entry_clu0, + .set_entry_clu0 = fat_set_entry_clu0, + .get_entry_size = fat_get_entry_size, + .set_entry_size = fat_set_entry_size, + .get_entry_time = fat_get_entry_time, + .set_entry_time = fat_set_entry_time, +}; + + +s32 fat16_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + s32 num_reserved, num_root_sectors; + BPB16_T *p_bpb = (BPB16_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + num_root_sectors = GET16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS; + num_root_sectors = ((num_root_sectors-1) >> p_bd->sector_size_bits) + 1; + + p_fs->sectors_per_clu = p_bpb->sectors_per_clu; + p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET16(p_bpb->num_fat_sectors); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors; + p_fs->data_start_sector = p_fs->root_start_sector + num_root_sectors; + + p_fs->num_sectors = GET16(p_bpb->num_sectors); + if (p_fs->num_sectors == 0) + p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); + + num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; + p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >> p_fs->sectors_per_clu_bits) + 2; + /* because the cluster index starts with 2 */ + + if (p_fs->num_clusters < FAT12_THRESHOLD) + p_fs->vol_type = FAT12; + else + p_fs->vol_type = FAT16; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = 0; + p_fs->dentries_in_root = GET16(p_bpb->num_root_entries); + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = VOL_CLEAN; + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &fat_fs_func; + + return FFS_SUCCESS; +} /* end of fat16_mount */ + +s32 fat32_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + s32 num_reserved; + BPB32_T *p_bpb = (BPB32_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + p_fs->sectors_per_clu = p_bpb->sectors_per_clu; + p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET32(p_bpb->num_fat32_sectors); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors; + p_fs->data_start_sector = p_fs->root_start_sector; + + p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); + num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; + + p_fs->num_clusters = ((p_fs->num_sectors-num_reserved) >> p_fs->sectors_per_clu_bits) + 2; + /* because the cluster index starts with 2 */ + + p_fs->vol_type = FAT32; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = GET32(p_bpb->root_cluster); + p_fs->dentries_in_root = 0; + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = VOL_CLEAN; + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &fat_fs_func; + + return FFS_SUCCESS; +} /* end of fat32_mount */ + +static FS_FUNC_T exfat_fs_func = { + .alloc_cluster = exfat_alloc_cluster, + .free_cluster = exfat_free_cluster, + .count_used_clusters = exfat_count_used_clusters, + + .init_dir_entry = exfat_init_dir_entry, + .init_ext_entry = exfat_init_ext_entry, + .find_dir_entry = exfat_find_dir_entry, + .delete_dir_entry = exfat_delete_dir_entry, + .get_uni_name_from_ext_entry = exfat_get_uni_name_from_ext_entry, + .count_ext_entries = exfat_count_ext_entries, + .calc_num_entries = exfat_calc_num_entries, + + .get_entry_type = exfat_get_entry_type, + .set_entry_type = exfat_set_entry_type, + .get_entry_attr = exfat_get_entry_attr, + .set_entry_attr = exfat_set_entry_attr, + .get_entry_flag = exfat_get_entry_flag, + .set_entry_flag = exfat_set_entry_flag, + .get_entry_clu0 = exfat_get_entry_clu0, + .set_entry_clu0 = exfat_set_entry_clu0, + .get_entry_size = exfat_get_entry_size, + .set_entry_size = exfat_set_entry_size, + .get_entry_time = exfat_get_entry_time, + .set_entry_time = exfat_set_entry_time, +}; + +s32 exfat_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + BPBEX_T *p_bpb = (BPBEX_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits; + p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits; + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET32(p_bpb->fat_length); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset); + p_fs->data_start_sector = p_fs->root_start_sector; + + p_fs->num_sectors = GET64(p_bpb->vol_length); + p_fs->num_clusters = GET32(p_bpb->clu_count) + 2; + /* because the cluster index starts with 2 */ + + p_fs->vol_type = EXFAT; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = GET32(p_bpb->root_cluster); + p_fs->dentries_in_root = 0; + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = (u32) GET16(p_bpb->vol_flags); + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &exfat_fs_func; + + return FFS_SUCCESS; +} /* end of exfat_mount */ + +s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + u64 size; + CHAIN_T clu; + DOS_NAME_T dos_name, dot_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name); + if (ret) + return ret; + + /* find_empty_entry must be called before alloc_cluster */ + dentry = find_empty_entry(inode, p_dir, num_entries); + if (dentry < 0) + return FFS_FULL; + + clu.dir = CLUSTER_32(~0); + clu.size = 0; + clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + + /* (1) allocate a cluster */ + ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu); + if (ret < 0) + return FFS_MEDIAERR; + else if (ret == 0) + return FFS_FULL; + + ret = clear_cluster(sb, clu.dir); + if (ret != FFS_SUCCESS) + return ret; + + if (p_fs->vol_type == EXFAT) { + size = p_fs->cluster_size; + } else { + size = 0; + + /* initialize the . and .. entry + Information for . points to itself + Information for .. points to parent dir */ + + dot_name.name_case = 0x0; + memcpy(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH); + + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 0, TYPE_DIR, clu.dir, 0); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, &clu, 0, 1, NULL, &dot_name); + if (ret != FFS_SUCCESS) + return ret; + + memcpy(dot_name.name, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH); + + if (p_dir->dir == p_fs->root_dir) + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, CLUSTER_32(0), 0); + else + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, p_dir->dir, 0); + + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, &clu, 1, 1, NULL, &dot_name); + if (ret != FFS_SUCCESS) + return ret; + } + + /* (2) update the directory entry */ + /* make sub-dir entry in parent directory */ + ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, size); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + fid->dir.dir = p_dir->dir; + fid->dir.size = p_dir->size; + fid->dir.flags = p_dir->flags; + fid->entry = dentry; + + fid->attr = ATTR_SUBDIR; + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->size = size; + fid->start_clu = clu.dir; + + fid->type = TYPE_DIR; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + return FFS_SUCCESS; +} /* end of create_dir */ + +s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + DOS_NAME_T dos_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name); + if (ret) + return ret; + + /* find_empty_entry must be called before alloc_cluster() */ + dentry = find_empty_entry(inode, p_dir, num_entries); + if (dentry < 0) + return FFS_FULL; + + /* (1) update the directory entry */ + /* fill the dos name directory entry information of the created file. + the first cluster is not determined yet. (0) */ + ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, CLUSTER_32(0), 0); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + fid->dir.dir = p_dir->dir; + fid->dir.size = p_dir->size; + fid->dir.flags = p_dir->flags; + fid->entry = dentry; + + fid->attr = ATTR_ARCHIVE | mode; + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + + fid->type = TYPE_FILE; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + return FFS_SUCCESS; +} /* end of create_file */ + +void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry) +{ + s32 num_entries; + sector_t sector; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ep = get_entry_in_dir(sb, p_dir, entry, §or); + if (!ep) + return; + + buf_lock(sb, sector); + + /* buf_lock() before call count_ext_entries() */ + num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, entry, ep); + if (num_entries < 0) { + buf_unlock(sb, sector); + return; + } + num_entries++; + + buf_unlock(sb, sector); + + /* (1) update the directory entry */ + p_fs->fs_func->delete_dir_entry(sb, p_dir, entry, 0, num_entries); +} /* end of remove_file */ + +s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 oldentry, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, newentry = -1, num_old_entries, num_new_entries; + sector_t sector_old, sector_new; + DOS_NAME_T dos_name; + DENTRY_T *epold, *epnew; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + epold = get_entry_in_dir(sb, p_dir, oldentry, §or_old); + if (!epold) + return FFS_MEDIAERR; + + buf_lock(sb, sector_old); + + /* buf_lock() before call count_ext_entries() */ + num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, oldentry, epold); + if (num_old_entries < 0) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + num_old_entries++; + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_new_entries, &dos_name); + if (ret) { + buf_unlock(sb, sector_old); + return ret; + } + + if (num_old_entries < num_new_entries) { + newentry = find_empty_entry(inode, p_dir, num_new_entries); + if (newentry < 0) { + buf_unlock(sb, sector_old); + return FFS_FULL; + } + + epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); + if (!epnew) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epold, DENTRY_SIZE); + if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_new); + buf_unlock(sb, sector_old); + + if (p_fs->vol_type == EXFAT) { + epold = get_entry_in_dir(sb, p_dir, oldentry+1, §or_old); + buf_lock(sb, sector_old); + epnew = get_entry_in_dir(sb, p_dir, newentry+1, §or_new); + + if (!epold || !epnew) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epold, DENTRY_SIZE); + buf_modify(sb, sector_new); + buf_unlock(sb, sector_old); + } + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, newentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, 0, num_old_entries); + fid->entry = newentry; + } else { + if (p_fs->fs_func->get_entry_type(epold) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epold, p_fs->fs_func->get_entry_attr(epold) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_old); + buf_unlock(sb, sector_old); + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, oldentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, num_new_entries, num_old_entries); + } + + return FFS_SUCCESS; +} /* end of rename_file */ + +s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, newentry, num_new_entries, num_old_entries; + sector_t sector_mov, sector_new; + CHAIN_T clu; + DOS_NAME_T dos_name; + DENTRY_T *epmov, *epnew; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + epmov = get_entry_in_dir(sb, p_olddir, oldentry, §or_mov); + if (!epmov) + return FFS_MEDIAERR; + + /* check if the source and target directory is the same */ + if (p_fs->fs_func->get_entry_type(epmov) == TYPE_DIR && + p_fs->fs_func->get_entry_clu0(epmov) == p_newdir->dir) + return FFS_INVALIDPATH; + + buf_lock(sb, sector_mov); + + /* buf_lock() before call count_ext_entries() */ + num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_olddir, oldentry, epmov); + if (num_old_entries < 0) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + num_old_entries++; + + ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, &num_new_entries, &dos_name); + if (ret) { + buf_unlock(sb, sector_mov); + return ret; + } + + newentry = find_empty_entry(inode, p_newdir, num_new_entries); + if (newentry < 0) { + buf_unlock(sb, sector_mov); + return FFS_FULL; + } + + epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); + if (!epnew) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epmov, DENTRY_SIZE); + if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_new); + buf_unlock(sb, sector_mov); + + if (p_fs->vol_type == EXFAT) { + epmov = get_entry_in_dir(sb, p_olddir, oldentry+1, §or_mov); + buf_lock(sb, sector_mov); + epnew = get_entry_in_dir(sb, p_newdir, newentry+1, §or_new); + if (!epmov || !epnew) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epmov, DENTRY_SIZE); + buf_modify(sb, sector_new); + buf_unlock(sb, sector_mov); + } else if (p_fs->fs_func->get_entry_type(epnew) == TYPE_DIR) { + /* change ".." pointer to new parent dir */ + clu.dir = p_fs->fs_func->get_entry_clu0(epnew); + clu.flags = 0x01; + + epnew = get_entry_in_dir(sb, &clu, 1, §or_new); + if (!epnew) + return FFS_MEDIAERR; + + if (p_newdir->dir == p_fs->root_dir) + p_fs->fs_func->set_entry_clu0(epnew, CLUSTER_32(0)); + else + p_fs->fs_func->set_entry_clu0(epnew, p_newdir->dir); + buf_modify(sb, sector_new); + } + + ret = p_fs->fs_func->init_ext_entry(sb, p_newdir, newentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries); + + fid->dir.dir = p_newdir->dir; + fid->dir.size = p_newdir->size; + fid->dir.flags = p_newdir->flags; + + fid->entry = newentry; + + return FFS_SUCCESS; +} /* end of move_file */ + +/* + * Sector Read/Write Functions + */ + +s32 sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 read) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((sec >= (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] sector_read: out of range error! (sec = %llu)\n", (unsigned long long)sec); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_read(sb, sec, bh, 1, read); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of sector_read */ + +s32 sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 sync) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (sec >= (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] sector_write: out of range error! (sec = %llu)\n", (unsigned long long)sec); + fs_error(sb); + return ret; + } + + if (bh == NULL) { + printk("[EXFAT] sector_write: bh is NULL!\n"); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_write(sb, sec, bh, 1, sync); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of sector_write */ + +s32 multi_sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 num_secs, s32 read) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] multi_sector_read: out of range error! (sec = %llu, num_secs = %d)\n", + (unsigned long long)sec, num_secs); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_read(sb, sec, bh, num_secs, read); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of multi_sector_read */ + +s32 multi_sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 num_secs, s32 sync) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] multi_sector_write: out of range error! (sec = %llu, num_secs = %d)\n", + (unsigned long long)sec, num_secs); + fs_error(sb); + return ret; + } + if (bh == NULL) { + printk("[EXFAT] multi_sector_write: bh is NULL!\n"); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_write(sb, sec, bh, num_secs, sync); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of multi_sector_write */ diff --git a/code/driver/source/fs/exfat/exfat_core.h b/code/driver/source/fs/exfat/exfat_core.h new file mode 100755 index 000000000..52d05c700 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_core.h @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_core.h */ +/* PURPOSE : Header File for exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_H +#define _EXFAT_H + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_cache.h" + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + /* For Debugging Purpose */ + /* IOCTL code 'f' used by + * - file systems typically #0~0x1F + * - embedded terminal devices #128~ + * - exts for debugging purpose #99 + * number 100 and 101 is availble now but has possible conflicts + */ +#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) +#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) + +#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 +#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02 +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + /*----------------------------------------------------------------------*/ + /* Constant & Macro Definitions */ + /*----------------------------------------------------------------------*/ + +#define DENTRY_SIZE 32 /* dir entry size */ +#define DENTRY_SIZE_BITS 5 + +/* PBR entries */ +#define PBR_SIGNATURE 0xAA55 +#define EXT_SIGNATURE 0xAA550000 +#define VOL_LABEL "NO NAME " /* size should be 11 */ +#define OEM_NAME "MSWIN4.1" /* size should be 8 */ +#define STR_FAT12 "FAT12 " /* size should be 8 */ +#define STR_FAT16 "FAT16 " /* size should be 8 */ +#define STR_FAT32 "FAT32 " /* size should be 8 */ +#define STR_EXFAT "EXFAT " /* size should be 8 */ +#define VOL_CLEAN 0x0000 +#define VOL_DIRTY 0x0002 + +/* max number of clusters */ +#define FAT12_THRESHOLD 4087 /* 2^12 - 1 + 2 (clu 0 & 1) */ +#define FAT16_THRESHOLD 65527 /* 2^16 - 1 + 2 */ +#define FAT32_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ +#define EXFAT_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ + +/* file types */ +#define TYPE_UNUSED 0x0000 +#define TYPE_DELETED 0x0001 +#define TYPE_INVALID 0x0002 +#define TYPE_CRITICAL_PRI 0x0100 +#define TYPE_BITMAP 0x0101 +#define TYPE_UPCASE 0x0102 +#define TYPE_VOLUME 0x0103 +#define TYPE_DIR 0x0104 +#define TYPE_FILE 0x011F +#define TYPE_SYMLINK 0x015F +#define TYPE_CRITICAL_SEC 0x0200 +#define TYPE_STREAM 0x0201 +#define TYPE_EXTEND 0x0202 +#define TYPE_ACL 0x0203 +#define TYPE_BENIGN_PRI 0x0400 +#define TYPE_GUID 0x0401 +#define TYPE_PADDING 0x0402 +#define TYPE_ACLTAB 0x0403 +#define TYPE_BENIGN_SEC 0x0800 +#define TYPE_ALL 0x0FFF + +/* time modes */ +#define TM_CREATE 0 +#define TM_MODIFY 1 +#define TM_ACCESS 2 + +/* checksum types */ +#define CS_DIR_ENTRY 0 +#define CS_PBR_SECTOR 1 +#define CS_DEFAULT 2 + +#define CLUSTER_16(x) ((u16)(x)) +#define CLUSTER_32(x) ((u32)(x)) + +#define FALSE 0 +#define TRUE 1 + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define START_SECTOR(x) \ + ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) + p_fs->data_start_sector) + +#define IS_LAST_SECTOR_IN_CLUSTER(sec) \ + ((((sec) - p_fs->data_start_sector + 1) & ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0) + +#define GET_CLUSTER_FROM_SECTOR(sec) \ + ((u32)((((sec) - p_fs->data_start_sector) >> p_fs->sectors_per_clu_bits) + 2)) + +#define GET16(p_src) \ + (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8)) +#define GET32(p_src) \ + (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \ + (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24)) +#define GET64(p_src) \ + (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \ + (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \ + (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \ + (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56)) + + +#define SET16(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u16)(src)) >> 8); \ + } while (0) +#define SET32(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u32)(src)) >> 8); \ + (p_dst)[2] = (u8)(((u32)(src)) >> 16); \ + (p_dst)[3] = (u8)(((u32)(src)) >> 24); \ + } while (0) +#define SET64(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u64)(src)) >> 8); \ + (p_dst)[2] = (u8)(((u64)(src)) >> 16); \ + (p_dst)[3] = (u8)(((u64)(src)) >> 24); \ + (p_dst)[4] = (u8)(((u64)(src)) >> 32); \ + (p_dst)[5] = (u8)(((u64)(src)) >> 40); \ + (p_dst)[6] = (u8)(((u64)(src)) >> 48); \ + (p_dst)[7] = (u8)(((u64)(src)) >> 56); \ + } while (0) + +#ifdef __LITTLE_ENDIAN +#define GET16_A(p_src) (*((u16 *)(p_src))) +#define GET32_A(p_src) (*((u32 *)(p_src))) +#define GET64_A(p_src) (*((u64 *)(p_src))) +#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src)) +#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src)) +#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src)) +#else /* BIG_ENDIAN */ +#define GET16_A(p_src) GET16(p_src) +#define GET32_A(p_src) GET32(p_src) +#define GET64_A(p_src) GET64(p_src) +#define SET16_A(p_dst, src) SET16(p_dst, src) +#define SET32_A(p_dst, src) SET32(p_dst, src) +#define SET64_A(p_dst, src) SET64(p_dst, src) +#endif + +/* Upcase tabel mecro */ +#define HIGH_INDEX_BIT (8) +#define HIGH_INDEX_MASK (0xFF00) +#define LOW_INDEX_BIT (16-HIGH_INDEX_BIT) +#define UTBL_ROW_COUNT (1<> LOW_INDEX_BIT; +} +static inline u16 get_row_index(u16 i) +{ + return i & ~HIGH_INDEX_MASK; +} +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +/* MS_DOS FAT partition boot record (512 bytes) */ +typedef struct { + u8 jmp_boot[3]; + u8 oem_name[8]; + u8 bpb[109]; + u8 boot_code[390]; + u8 signature[2]; +} PBR_SECTOR_T; + +/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */ +typedef struct { + u8 sector_size[2]; + u8 sectors_per_clu; + u8 num_reserved[2]; + u8 num_fats; + u8 num_root_entries[2]; + u8 num_sectors[2]; + u8 media_type; + u8 num_fat_sectors[2]; + u8 sectors_in_track[2]; + u8 num_heads[2]; + u8 num_hid_sectors[4]; + u8 num_huge_sectors[4]; + + u8 phy_drv_no; + u8 reserved; + u8 ext_signature; + u8 vol_serial[4]; + u8 vol_label[11]; + u8 vol_type[8]; +} BPB16_T; + +/* MS-DOS FAT32 BIOS parameter block (79 bytes) */ +typedef struct { + u8 sector_size[2]; + u8 sectors_per_clu; + u8 num_reserved[2]; + u8 num_fats; + u8 num_root_entries[2]; + u8 num_sectors[2]; + u8 media_type; + u8 num_fat_sectors[2]; + u8 sectors_in_track[2]; + u8 num_heads[2]; + u8 num_hid_sectors[4]; + u8 num_huge_sectors[4]; + u8 num_fat32_sectors[4]; + u8 ext_flags[2]; + u8 fs_version[2]; + u8 root_cluster[4]; + u8 fsinfo_sector[2]; + u8 backup_sector[2]; + u8 reserved[12]; + + u8 phy_drv_no; + u8 ext_reserved; + u8 ext_signature; + u8 vol_serial[4]; + u8 vol_label[11]; + u8 vol_type[8]; +} BPB32_T; + +/* MS-DOS EXFAT BIOS parameter block (109 bytes) */ +typedef struct { + u8 reserved1[53]; + u8 vol_offset[8]; + u8 vol_length[8]; + u8 fat_offset[4]; + u8 fat_length[4]; + u8 clu_offset[4]; + u8 clu_count[4]; + u8 root_cluster[4]; + u8 vol_serial[4]; + u8 fs_version[2]; + u8 vol_flags[2]; + u8 sector_size_bits; + u8 sectors_per_clu_bits; + u8 num_fats; + u8 phy_drv_no; + u8 perc_in_use; + u8 reserved2[7]; +} BPBEX_T; + +/* MS-DOS FAT file system information sector (512 bytes) */ +typedef struct { + u8 signature1[4]; + u8 reserved1[480]; + u8 signature2[4]; + u8 free_cluster[4]; + u8 next_cluster[4]; + u8 reserved2[14]; + u8 signature3[2]; +} FSI_SECTOR_T; + +/* MS-DOS FAT directory entry (32 bytes) */ +typedef struct { + u8 dummy[32]; +} DENTRY_T; + +typedef struct { + u8 name[DOS_NAME_LENGTH]; + u8 attr; + u8 lcase; + u8 create_time_ms; + u8 create_time[2]; + u8 create_date[2]; + u8 access_date[2]; + u8 start_clu_hi[2]; + u8 modify_time[2]; + u8 modify_date[2]; + u8 start_clu_lo[2]; + u8 size[4]; +} DOS_DENTRY_T; + +/* MS-DOS FAT extended directory entry (32 bytes) */ +typedef struct { + u8 order; + u8 unicode_0_4[10]; + u8 attr; + u8 sysid; + u8 checksum; + u8 unicode_5_10[12]; + u8 start_clu[2]; + u8 unicode_11_12[4]; +} EXT_DENTRY_T; + +/* MS-DOS EXFAT file directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 num_ext; + u8 checksum[2]; + u8 attr[2]; + u8 reserved1[2]; + u8 create_time[2]; + u8 create_date[2]; + u8 modify_time[2]; + u8 modify_date[2]; + u8 access_time[2]; + u8 access_date[2]; + u8 create_time_ms; + u8 modify_time_ms; + u8 access_time_ms; + u8 reserved2[9]; +} FILE_DENTRY_T; + +/* MS-DOS EXFAT stream extension directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 reserved1; + u8 name_len; + u8 name_hash[2]; + u8 reserved2[2]; + u8 valid_size[8]; + u8 reserved3[4]; + u8 start_clu[4]; + u8 size[8]; +} STRM_DENTRY_T; + +/* MS-DOS EXFAT file name directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 unicode_0_14[30]; +} NAME_DENTRY_T; + +/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 reserved[18]; + u8 start_clu[4]; + u8 size[8]; +} BMAP_DENTRY_T; + +/* MS-DOS EXFAT up-case table directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 reserved1[3]; + u8 checksum[4]; + u8 reserved2[12]; + u8 start_clu[4]; + u8 size[8]; +} CASE_DENTRY_T; + +/* MS-DOS EXFAT volume label directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 label_len; + u8 unicode_0_10[22]; + u8 reserved[8]; +} VOLM_DENTRY_T; + +/* unused entry hint information */ +typedef struct { + u32 dir; + s32 entry; + CHAIN_T clu; +} UENTRY_T; + +typedef struct { + s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); + void (*free_cluster)(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); + s32 (*count_used_clusters)(struct super_block *sb); + + s32 (*init_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size); + s32 (*init_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); + s32 (*find_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); + void (*delete_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 offset, s32 num_entries); + void (*get_uni_name_from_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); + s32 (*count_ext_entries)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); + s32 (*calc_num_entries)(UNI_NAME_T *p_uniname); + + u32 (*get_entry_type)(DENTRY_T *p_entry); + void (*set_entry_type)(DENTRY_T *p_entry, u32 type); + u32 (*get_entry_attr)(DENTRY_T *p_entry); + void (*set_entry_attr)(DENTRY_T *p_entry, u32 attr); + u8 (*get_entry_flag)(DENTRY_T *p_entry); + void (*set_entry_flag)(DENTRY_T *p_entry, u8 flag); + u32 (*get_entry_clu0)(DENTRY_T *p_entry); + void (*set_entry_clu0)(DENTRY_T *p_entry, u32 clu0); + u64 (*get_entry_size)(DENTRY_T *p_entry); + void (*set_entry_size)(DENTRY_T *p_entry, u64 size); + void (*get_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); + void (*set_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +} FS_FUNC_T; + +typedef struct __FS_INFO_T { + u32 drv; /* drive ID */ + u32 vol_type; /* volume FAT type */ + u32 vol_id; /* volume serial number */ + + u64 num_sectors; /* num of sectors in volume */ + u32 num_clusters; /* num of clusters in volume */ + u32 cluster_size; /* cluster size in bytes */ + u32 cluster_size_bits; + u32 sectors_per_clu; /* cluster size in sectors */ + u32 sectors_per_clu_bits; + + u32 PBR_sector; /* PBR sector */ + u32 FAT1_start_sector; /* FAT1 start sector */ + u32 FAT2_start_sector; /* FAT2 start sector */ + u32 root_start_sector; /* root dir start sector */ + u32 data_start_sector; /* data area start sector */ + u32 num_FAT_sectors; /* num of FAT sectors */ + + u32 root_dir; /* root dir cluster */ + u32 dentries_in_root; /* num of dentries in root dir */ + u32 dentries_per_clu; /* num of dentries per cluster */ + + u32 vol_flag; /* volume dirty flag */ + struct buffer_head *pbr_bh; /* PBR sector */ + + u32 map_clu; /* allocation bitmap start cluster */ + u32 map_sectors; /* num of allocation bitmap sectors */ + struct buffer_head **vol_amap; /* allocation bitmap */ + + u16 **vol_utbl; /* upcase table */ + + u32 clu_srch_ptr; /* cluster search pointer */ + u32 used_clusters; /* number of used clusters */ + UENTRY_T hint_uentry; /* unused entry hint information */ + + u32 dev_ejected; /* block device operation error flag */ + + FS_FUNC_T *fs_func; + struct semaphore v_sem; + + /* FAT cache */ + BUF_CACHE_T FAT_cache_array[FAT_CACHE_SIZE]; + BUF_CACHE_T FAT_cache_lru_list; + BUF_CACHE_T FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; + + /* buf cache */ + BUF_CACHE_T buf_cache_array[BUF_CACHE_SIZE]; + BUF_CACHE_T buf_cache_lru_list; + BUF_CACHE_T buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; +} FS_INFO_T; + +#define ES_2_ENTRIES 2 +#define ES_3_ENTRIES 3 +#define ES_ALL_ENTRIES 0 + +typedef struct { + sector_t sector; /* sector number that contains file_entry */ + s32 offset; /* byte offset in the sector */ + s32 alloc_flag; /* flag in stream entry. 01 for cluster chain, 03 for contig. clusteres. */ + u32 num_entries; + + /* __buf should be the last member */ + void *__buf; +} ENTRY_SET_CACHE_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* file system initialization & shutdown functions */ +s32 ffsInit(void); +s32 ffsShutdown(void); + +/* volume management functions */ +s32 ffsMountVol(struct super_block *sb); +s32 ffsUmountVol(struct super_block *sb); +s32 ffsCheckVol(struct super_block *sb); +s32 ffsGetVolInfo(struct super_block *sb, VOL_INFO_T *info); +s32 ffsSyncVol(struct super_block *sb, s32 do_sync); + +/* file management functions */ +s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); +s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); +s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); +s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); +s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); +s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); +s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid); +s32 ffsSetAttr(struct inode *inode, u32 attr); +s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info); +s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info); +s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); + +/* directory management functions */ +s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); +s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_ent); +s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid); + +/*----------------------------------------------------------------------*/ +/* External Function Declarations (NOT TO UPPER LAYER) */ +/*----------------------------------------------------------------------*/ + +/* fs management functions */ +s32 fs_init(void); +s32 fs_shutdown(void); +void fs_set_vol_flags(struct super_block *sb, u32 new_flag); +void fs_sync(struct super_block *sb, s32 do_sync); +void fs_error(struct super_block *sb); + +/* cluster management functions */ +s32 clear_cluster(struct super_block *sb, u32 clu); +s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); +s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); +void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); +void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); +u32 find_last_cluster(struct super_block *sb, CHAIN_T *p_chain); +s32 count_num_clusters(struct super_block *sb, CHAIN_T *dir); +s32 fat_count_used_clusters(struct super_block *sb); +s32 exfat_count_used_clusters(struct super_block *sb); +void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len); + +/* allocation bitmap management functions */ +s32 load_alloc_bitmap(struct super_block *sb); +void free_alloc_bitmap(struct super_block *sb); +s32 set_alloc_bitmap(struct super_block *sb, u32 clu); +s32 clr_alloc_bitmap(struct super_block *sb, u32 clu); +u32 test_alloc_bitmap(struct super_block *sb, u32 clu); +void sync_alloc_bitmap(struct super_block *sb); + +/* upcase table management functions */ +s32 load_upcase_table(struct super_block *sb); +void free_upcase_table(struct super_block *sb); + +/* dir entry management functions */ +u32 fat_get_entry_type(DENTRY_T *p_entry); +u32 exfat_get_entry_type(DENTRY_T *p_entry); +void fat_set_entry_type(DENTRY_T *p_entry, u32 type); +void exfat_set_entry_type(DENTRY_T *p_entry, u32 type); +u32 fat_get_entry_attr(DENTRY_T *p_entry); +u32 exfat_get_entry_attr(DENTRY_T *p_entry); +void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr); +void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr); +u8 fat_get_entry_flag(DENTRY_T *p_entry); +u8 exfat_get_entry_flag(DENTRY_T *p_entry); +void fat_set_entry_flag(DENTRY_T *p_entry, u8 flag); +void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flag); +u32 fat_get_entry_clu0(DENTRY_T *p_entry); +u32 exfat_get_entry_clu0(DENTRY_T *p_entry); +void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu); +void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu); +u64 fat_get_entry_size(DENTRY_T *p_entry); +u64 exfat_get_entry_size(DENTRY_T *p_entry); +void fat_set_entry_size(DENTRY_T *p_entry, u64 size); +void exfat_set_entry_size(DENTRY_T *p_entry, u64 size); +void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void fat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +s32 fat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, u32 start_clu, u64 size); +s32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, u32 start_clu, u64 size); +s32 fat_init_ext_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +s32 exfat_init_ext_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +void init_dos_entry(DOS_DENTRY_T *ep, u32 type, u32 start_clu); +void init_ext_entry(EXT_DENTRY_T *ep, s32 order, u8 chksum, u16 *uniname); +void init_file_entry(FILE_DENTRY_T *ep, u32 type); +void init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size); +void init_name_entry(NAME_DENTRY_T *ep, u16 *uniname); +void fat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries); +void exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries); + +s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector, s32 *offset); +DENTRY_T *get_entry_with_sector(struct super_block *sb, sector_t sector, s32 offset); +DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector); +ENTRY_SET_CACHE_T *get_entry_set_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep); +void release_entry_set(ENTRY_SET_CACHE_T *es); +s32 write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es); +s32 write_partial_entries_in_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es, DENTRY_T *ep, u32 count); +s32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, s32 num_entries); +s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries); +s32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); +s32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); +s32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); +s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); +s32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type); +void update_dir_checksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry); +void update_dir_checksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es); +bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir); + +/* name conversion functions */ +s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 *entries, DOS_NAME_T *p_dosname); +void get_uni_name_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode); +void fat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); +void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); +s32 extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 order); +s32 extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order); +s32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname); +void fat_attach_count_to_dos_name(u8 *dosname, s32 count); +s32 fat_calc_num_entries(UNI_NAME_T *p_uniname); +s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname); +u8 calc_checksum_1byte(void *data, s32 len, u8 chksum); +u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); +u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type); + +/* name resolution functions */ +s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname); +s32 resolve_name(u8 *name, u8 **arg); + +/* file operation functions */ +s32 fat16_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 fat32_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 exfat_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid); +void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry); +s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 old_entry, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); + +/* sector read/write functions */ +s32 sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 read); +s32 sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 sync); +s32 multi_sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 num_secs, s32 read); +s32 multi_sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 num_secs, s32 sync); + +#endif /* _EXFAT_H */ diff --git a/code/driver/source/fs/exfat/exfat_data.c b/code/driver/source/fs/exfat/exfat_data.c new file mode 100755 index 000000000..65da07aff --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_data.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_data.c */ +/* PURPOSE : exFAT Configuable Data Definitions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*======================================================================*/ +/* */ +/* GLOBAL VARIABLE DEFINITIONS */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* File Manager */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Buffer Manager */ +/*----------------------------------------------------------------------*/ + +/* FAT cache */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(f_sem); +#else +DEFINE_SEMAPHORE(f_sem); +#endif +BUF_CACHE_T FAT_cache_array[FAT_CACHE_SIZE]; +BUF_CACHE_T FAT_cache_lru_list; +BUF_CACHE_T FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; + +/* buf cache */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(b_sem); +#else +DEFINE_SEMAPHORE(b_sem); +#endif +BUF_CACHE_T buf_cache_array[BUF_CACHE_SIZE]; +BUF_CACHE_T buf_cache_lru_list; +BUF_CACHE_T buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; diff --git a/code/driver/source/fs/exfat/exfat_data.h b/code/driver/source/fs/exfat/exfat_data.h new file mode 100755 index 000000000..53b0e3939 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_data.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_data.h */ +/* PURPOSE : Header File for exFAT Configuable Constants */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_DATA_H +#define _EXFAT_DATA_H + +#include "exfat_config.h" + +/*======================================================================*/ +/* */ +/* FFS CONFIGURATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/* max number of root directory entries in FAT12/16 */ +/* (should be an exponential value of 2) */ +#define MAX_DENTRY 512 + +/* cache size (in number of sectors) */ +/* (should be an exponential value of 2) */ +#define FAT_CACHE_SIZE 128 +#define FAT_CACHE_HASH_SIZE 64 +#define BUF_CACHE_SIZE 256 +#define BUF_CACHE_HASH_SIZE 64 + +#endif /* _EXFAT_DATA_H */ diff --git a/code/driver/source/fs/exfat/exfat_nls.c b/code/driver/source/fs/exfat/exfat_nls.c new file mode 100755 index 000000000..a48b3d05a --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_nls.c @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_nls.c */ +/* PURPOSE : exFAT NLS Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" + +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +#include + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +static u16 bad_dos_chars[] = { + /* + , ; = [ ] */ + 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D, + 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D, + 0 +}; + +static u16 bad_uni_chars[] = { + /* " * / : < > ? \ | */ + 0x0022, 0x002A, 0x002F, 0x003A, + 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, + 0 +}; + +/*----------------------------------------------------------------------*/ +/* Local Function Declarations */ +/*----------------------------------------------------------------------*/ + +static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy); +static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy); + +/*======================================================================*/ +/* Global Function Definitions */ +/*======================================================================*/ + +u16 nls_upper(struct super_block *sb, u16 a) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (EXFAT_SB(sb)->options.casesensitive) + return a; + if (p_fs->vol_utbl != NULL && (p_fs->vol_utbl)[get_col_index(a)] != NULL) + return (p_fs->vol_utbl)[get_col_index(a)][get_row_index(a)]; + else + return a; +} + +u16 *nls_wstrchr(u16 *str, u16 wchar) +{ + while (*str) { + if (*(str++) == wchar) + return str; + } + + return 0; +} + +s32 nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b) +{ + return strncmp((void *) a, (void *) b, DOS_NAME_LENGTH); +} /* end of nls_dosname_cmp */ + +s32 nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b) +{ + int i; + + for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { + if (nls_upper(sb, *a) != nls_upper(sb, *b)) + return 1; + if (*a == 0x0) + return 0; + } + return 0; +} /* end of nls_uniname_cmp */ + +void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, s32 *p_lossy) +{ + int i, j, len, lossy = FALSE; + u8 buf[MAX_CHARSET_SIZE]; + u8 lower = 0, upper = 0; + u8 *dosname = p_dosname->name; + u16 *uniname = p_uniname->name; + u16 *p, *last_period; + struct nls_table *nls = EXFAT_SB(sb)->nls_disk; + + for (i = 0; i < DOS_NAME_LENGTH; i++) + *(dosname+i) = ' '; + + if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_CUR_DIR_NAME)) { + *(dosname) = '.'; + p_dosname->name_case = 0x0; + if (p_lossy != NULL) + *p_lossy = FALSE; + return; + } + + if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_PAR_DIR_NAME)) { + *(dosname) = '.'; + *(dosname+1) = '.'; + p_dosname->name_case = 0x0; + if (p_lossy != NULL) + *p_lossy = FALSE; + return; + } + + /* search for the last embedded period */ + last_period = NULL; + for (p = uniname; *p; p++) { + if (*p == (u16) '.') + last_period = p; + } + + i = 0; + while (i < DOS_NAME_LENGTH) { + if (i == 8) { + if (last_period == NULL) + break; + + if (uniname <= last_period) { + if (uniname < last_period) + lossy = TRUE; + uniname = last_period + 1; + } + } + + if (*uniname == (u16) '\0') { + break; + } else if (*uniname == (u16) ' ') { + lossy = TRUE; + } else if (*uniname == (u16) '.') { + if (uniname < last_period) + lossy = TRUE; + else + i = 8; + } else if (nls_wstrchr(bad_dos_chars, *uniname)) { + lossy = TRUE; + *(dosname+i) = '_'; + i++; + } else { + len = convert_uni_to_ch(nls, buf, *uniname, &lossy); + + if (len > 1) { + if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) + break; + + if ((i < 8) && ((i+len) > 8)) { + i = 8; + continue; + } + + lower = 0xFF; + + for (j = 0; j < len; j++, i++) + *(dosname+i) = *(buf+j); + } else { /* len == 1 */ + if ((*buf >= 'a') && (*buf <= 'z')) { + *(dosname+i) = *buf - ('a' - 'A'); + + if (i < 8) + lower |= 0x08; + else + lower |= 0x10; + } else if ((*buf >= 'A') && (*buf <= 'Z')) { + *(dosname+i) = *buf; + + if (i < 8) + upper |= 0x08; + else + upper |= 0x10; + } else { + *(dosname+i) = *buf; + } + i++; + } + } + + uniname++; + } + + if (*dosname == 0xE5) + *dosname = 0x05; + + if (*uniname != 0x0) + lossy = TRUE; + + if (upper & lower) + p_dosname->name_case = 0xFF; + else + p_dosname->name_case = lower; + + if (p_lossy != NULL) + *p_lossy = lossy; +} /* end of nls_uniname_to_dosname */ + +void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i = 0, j, n = 0; + u8 buf[DOS_NAME_LENGTH+2]; + u8 *dosname = p_dosname->name; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_disk; + + if (*dosname == 0x05) { + *buf = 0xE5; + i++; + n++; + } + + for (; i < 8; i++, n++) { + if (*(dosname+i) == ' ') + break; + + if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x08)) + *(buf+n) = *(dosname+i) + ('a' - 'A'); + else + *(buf+n) = *(dosname+i); + } + if (*(dosname+8) != ' ') { + *(buf+n) = '.'; + n++; + } + + for (i = 8; i < DOS_NAME_LENGTH; i++, n++) { + if (*(dosname+i) == ' ') + break; + + if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x10)) + *(buf+n) = *(dosname+i) + ('a' - 'A'); + else + *(buf+n) = *(dosname+i); + } + *(buf+n) = '\0'; + + i = j = 0; + while (j < (MAX_NAME_LENGTH-1)) { + if (*(buf+i) == '\0') + break; + + i += convert_ch_to_uni(nls, uniname, (buf+i), NULL); + + uniname++; + j++; + } + + *uniname = (u16) '\0'; +} /* end of nls_dosname_to_uniname */ + +void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, UNI_NAME_T *p_uniname) +{ + int i, j, len; + u8 buf[MAX_CHARSET_SIZE]; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + if (nls == NULL) { + len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, p_cstring, MAX_NAME_LENGTH); + p_cstring[len] = 0; + return; + } + + i = 0; + while (i < (MAX_NAME_LENGTH-1)) { + if (*uniname == (u16) '\0') + break; + + len = convert_uni_to_ch(nls, buf, *uniname, NULL); + + if (len > 1) { + for (j = 0; j < len; j++) + *p_cstring++ = (char) *(buf+j); + } else { /* len == 1 */ + *p_cstring++ = (char) *buf; + } + + uniname++; + i++; + } + + *p_cstring = '\0'; +} /* end of nls_uniname_to_cstring */ + +void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 *p_lossy) +{ + int i, j, lossy = FALSE; + u8 *end_of_name; + u8 upname[MAX_NAME_LENGTH * 2]; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + + /* strip all trailing spaces */ + end_of_name = p_cstring + strlen((char *) p_cstring); + + while (*(--end_of_name) == ' ') { + if (end_of_name < p_cstring) + break; + } + *(++end_of_name) = '\0'; + + if (strcmp((char *) p_cstring, ".") && strcmp((char *) p_cstring, "..")) { + + /* strip all trailing periods */ + while (*(--end_of_name) == '.') { + if (end_of_name < p_cstring) + break; + } + *(++end_of_name) = '\0'; + } + + if (*p_cstring == '\0') + lossy = TRUE; + + if (nls == NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,101) + i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, uniname); +#else + i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, uniname, MAX_NAME_LENGTH); +#endif + for (j = 0; j < i; j++) + SET16_A(upname + j * 2, nls_upper(sb, uniname[j])); + uniname[i] = '\0'; + } + else { + i = j = 0; + while (j < (MAX_NAME_LENGTH-1)) { + if (*(p_cstring+i) == '\0') + break; + + i += convert_ch_to_uni(nls, uniname, (u8 *)(p_cstring+i), &lossy); + + if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname)) + lossy = TRUE; + + SET16_A(upname + j * 2, nls_upper(sb, *uniname)); + + uniname++; + j++; + } + + if (*(p_cstring+i) != '\0') + lossy = TRUE; + *uniname = (u16) '\0'; + } + + p_uniname->name_len = j; + p_uniname->name_hash = calc_checksum_2byte((void *) upname, j<<1, 0, CS_DEFAULT); + + if (p_lossy != NULL) + *p_lossy = lossy; +} /* end of nls_cstring_to_uniname */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy) +{ + int len; + + *uni = 0x0; + + if (ch[0] < 0x80) { + *uni = (u16) ch[0]; + return 1; + } + + len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni); + if (len < 0) { + /* conversion failed */ + printk("%s: fail to use nls\n", __func__); + if (lossy != NULL) + *lossy = TRUE; + *uni = (u16) '_'; + if (!strcmp(nls->charset, "utf8")) + return 1; + else + return 2; + } + + return len; +} /* end of convert_ch_to_uni */ + +static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy) +{ + int len; + + ch[0] = 0x0; + + if (uni < 0x0080) { + ch[0] = (u8) uni; + return 1; + } + + len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE); + if (len < 0) { + /* conversion failed */ + printk("%s: fail to use nls\n", __func__); + if (lossy != NULL) + *lossy = TRUE; + ch[0] = '_'; + return 1; + } + + return len; + +} /* end of convert_uni_to_ch */ diff --git a/code/driver/source/fs/exfat/exfat_nls.h b/code/driver/source/fs/exfat/exfat_nls.h new file mode 100755 index 000000000..bc516d762 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_nls.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_nls.h */ +/* PURPOSE : Header File for exFAT NLS Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_NLS_H +#define _EXFAT_NLS_H + +#include +#include + +#include "exfat_config.h" +#include "exfat_api.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define NUM_UPCASE 2918 + +#define DOS_CUR_DIR_NAME ". " +#define DOS_PAR_DIR_NAME ".. " + +#ifdef __LITTLE_ENDIAN +#define UNI_CUR_DIR_NAME ".\0" +#define UNI_PAR_DIR_NAME ".\0.\0" +#else +#define UNI_CUR_DIR_NAME "\0." +#define UNI_PAR_DIR_NAME "\0.\0." +#endif + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +/* DOS name stucture */ +typedef struct { + u8 name[DOS_NAME_LENGTH]; + u8 name_case; +} DOS_NAME_T; + +/* unicode name stucture */ +typedef struct { + u16 name[MAX_NAME_LENGTH]; + u16 name_hash; + u8 name_len; +} UNI_NAME_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* NLS management function */ +u16 nls_upper(struct super_block *sb, u16 a); +s32 nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b); +s32 nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); +void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, s32 *p_lossy); +void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, UNI_NAME_T *p_uniname); +void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 *p_lossy); + +#endif /* _EXFAT_NLS_H */ diff --git a/code/driver/source/fs/exfat/exfat_oal.c b/code/driver/source/fs/exfat/exfat_oal.c new file mode 100755 index 000000000..743544244 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_oal.c @@ -0,0 +1,196 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_oal.c */ +/* PURPOSE : exFAT OS Adaptation Layer */ +/* (Semaphore Functions & Real-Time Clock Functions) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include + +#include "exfat_config.h" +#include "exfat_api.h" +#include "exfat_oal.h" + +/*======================================================================*/ +/* */ +/* SEMAPHORE FUNCTIONS */ +/* */ +/*======================================================================*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(z_sem); +#else +DEFINE_SEMAPHORE(z_sem); +#endif + +s32 sm_init(struct semaphore *sm) +{ + sema_init(sm, 1); + return 0; +} /* end of sm_init */ + +s32 sm_P(struct semaphore *sm) +{ + down(sm); + return 0; +} /* end of sm_P */ + +void sm_V(struct semaphore *sm) +{ + up(sm); +} /* end of sm_V */ + + +/*======================================================================*/ +/* */ +/* REAL-TIME CLOCK FUNCTIONS */ +/* */ +/*======================================================================*/ + +extern struct timezone sys_tz; + +/* + * The epoch of FAT timestamp is 1980. + * : bits : value + * date: 0 - 4: day (1 - 31) + * date: 5 - 8: month (1 - 12) + * date: 9 - 15: year (0 - 127) from 1980 + * time: 0 - 4: sec (0 - 29) 2sec counts + * time: 5 - 10: min (0 - 59) + * time: 11 - 15: hour (0 - 23) + */ +#define UNIX_SECS_1980 315532800L + +#if BITS_PER_LONG == 64 +#define UNIX_SECS_2108 4354819200L +#endif +/* days between 1.1.70 and 1.1.80 (2 leap days) */ +#define DAYS_DELTA_DECADE (365 * 10 + 2) +/* 120 (2100 - 1980) isn't leap year */ +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while (0) + +/* Linear day numbers of the respective 1sts in non-leap years. */ +static time_t accum_days_in_year[] = { + /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ + 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, +}; + +TIMESTAMP_T *tm_current(TIMESTAMP_T *tp) +{ + struct timespec ts; + time_t second, day, leap_day, month, year; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) + ts = CURRENT_TIME_SEC; +#else + ktime_get_real_ts(&ts); +#endif + + second = ts.tv_sec; + second -= sys_tz.tz_minuteswest * SECS_PER_MIN; + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (second < UNIX_SECS_1980) { + tp->sec = 0; + tp->min = 0; + tp->hour = 0; + tp->day = 1; + tp->mon = 1; + tp->year = 0; + return tp; + } +#if BITS_PER_LONG == 64 + if (second >= UNIX_SECS_2108) { + tp->sec = 59; + tp->min = 59; + tp->hour = 23; + tp->day = 31; + tp->mon = 12; + tp->year = 127; + return tp; + } +#endif + + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; + year = day / 365; + + MAKE_LEAP_YEAR(leap_day, year); + if (year * 365 + leap_day > day) + year--; + + MAKE_LEAP_YEAR(leap_day, year); + + day -= year * 365 + leap_day; + + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { + month = 2; + } else { + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) + day--; + for (month = 1; month < 12; month++) { + if (accum_days_in_year[month + 1] > day) + break; + } + } + day -= accum_days_in_year[month]; + + tp->sec = second % SECS_PER_MIN; + tp->min = (second / SECS_PER_MIN) % 60; + tp->hour = (second / SECS_PER_HOUR) % 24; + tp->day = day + 1; + tp->mon = month; + tp->year = year; + + return tp; +} /* end of tm_current */ diff --git a/code/driver/source/fs/exfat/exfat_oal.h b/code/driver/source/fs/exfat/exfat_oal.h new file mode 100755 index 000000000..b6dd7897a --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_oal.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_oal.h */ +/* PURPOSE : Header File for exFAT OS Adaptation Layer */ +/* (Semaphore Functions & Real-Time Clock Functions) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_OAL_H +#define _EXFAT_OAL_H + +#include +#include "exfat_config.h" +#include + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Non-Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct { + u16 sec; /* 0 ~ 59 */ + u16 min; /* 0 ~ 59 */ + u16 hour; /* 0 ~ 23 */ + u16 day; /* 1 ~ 31 */ + u16 mon; /* 1 ~ 12 */ + u16 year; /* 0 ~ 127 (since 1980) */ +} TIMESTAMP_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 sm_init(struct semaphore *sm); +s32 sm_P(struct semaphore *sm); +void sm_V(struct semaphore *sm); + +TIMESTAMP_T *tm_current(TIMESTAMP_T *tm); + +#endif /* _EXFAT_OAL_H */ diff --git a/code/driver/source/fs/exfat/exfat_super.c b/code/driver/source/fs/exfat/exfat_super.c new file mode 100755 index 000000000..148d29d66 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_super.c @@ -0,0 +1,2753 @@ +/* Some of the source code in this file came from "linux/fs/fat/file.c","linux/fs/fat/inode.c" and "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/file.c + * + * Written 1992,1993 by Werner Almesberger + * + * regular file handling primitives for fat-based filesystems + */ + +/* + * linux/fs/fat/inode.c + * + * Written 1992,1993 by Werner Almesberger + * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner + * Rewritten for the constant inumbers support by Al Viro + * + * Fixes: + * + * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 + */ + +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_version.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_core.h" + +#include "exfat_super.h" + +static struct kmem_cache *exfat_inode_cachep; + +static int exfat_default_codepage = CONFIG_EXFAT_DEFAULT_CODEPAGE; +static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; + +extern struct timezone sys_tz; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) +#define current_time(x) (CURRENT_TIME_SEC) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) +#define USE_NEW_IVERSION_API +#define INC_IVERSION(x) (inode_inc_iversion(x)) +#define GET_IVERSION(x) (inode_peek_iversion_raw(x)) +#define SET_IVERSION(x,y) (inode_set_iversion(x, y)) +#else +#define INC_IVERSION(x) (x->i_version++) +#define GET_IVERSION(x) (x->i_version) +#define SET_IVERSION(x,y) (x->i_version = y) +#endif + +#define CHECK_ERR(x) BUG_ON(x) + +#define UNIX_SECS_1980 315532800L + +#if BITS_PER_LONG == 64 +#define UNIX_SECS_2108 4354819200L +#endif +/* days between 1.1.70 and 1.1.80 (2 leap days) */ +#define DAYS_DELTA_DECADE (365 * 10 + 2) +/* 120 (2100 - 1980) isn't leap year */ +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while (0) + +/* Linear day numbers of the respective 1sts in non-leap years. */ +static time_t accum_days_in_year[] = { + /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ + 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, +}; + +static void _exfat_truncate(struct inode *inode, loff_t old_size); + +/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ +void exfat_time_fat2unix(struct exfat_sb_info *sbi, struct timespec64 *ts,DATE_TIME_T *tp) +{ + time_t year = tp->Year; + time_t ld; + + MAKE_LEAP_YEAR(ld, year); + + if (IS_LEAP_YEAR(year) && (tp->Month) > 2) + ld++; + +#if 0 + ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN + + tp->Hour * SECS_PER_HOUR + + (year * 365 + ld + accum_days_in_year[(tp->Month)] + (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY + + sys_tz.tz_minuteswest * SECS_PER_MIN; +#else + ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN + + tp->Hour * SECS_PER_HOUR + + (year * 365 + ld + accum_days_in_year[(tp->Month)] + (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY; + + if (!sbi->options.tz_set) + ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN; + else + ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN; +#endif + ts->tv_nsec = 0; +} + +/* Convert linear UNIX date to a FAT time/date pair. */ +void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec64 *ts, + DATE_TIME_T *tp) +{ + time_t second = ts->tv_sec; + time_t day, month, year; + time_t ld; + +#if 0 + second -= sys_tz.tz_minuteswest * SECS_PER_MIN; +#else + if (sbi->options.tz_set) + second += sbi->options.time_offset * SECS_PER_MIN; + else + second -= sys_tz.tz_minuteswest * SECS_PER_MIN; +#endif + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (second < UNIX_SECS_1980) { + tp->Second = 0; + tp->Minute = 0; + tp->Hour = 0; + tp->Day = 1; + tp->Month = 1; + tp->Year = 0; + return; + } +#if (BITS_PER_LONG == 64) + if (second >= UNIX_SECS_2108) { + tp->Second = 59; + tp->Minute = 59; + tp->Hour = 23; + tp->Day = 31; + tp->Month = 12; + tp->Year = 127; + return; + } +#endif + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; + year = day / 365; + MAKE_LEAP_YEAR(ld, year); + if (year * 365 + ld > day) + year--; + + MAKE_LEAP_YEAR(ld, year); + day -= year * 365 + ld; + + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { + month = 2; + } else { + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) + day--; + for (month = 1; month < 12; month++) { + if (accum_days_in_year[month + 1] > day) + break; + } + } + day -= accum_days_in_year[month]; + + tp->Second = second % SECS_PER_MIN; + tp->Minute = (second / SECS_PER_MIN) % 60; + tp->Hour = (second / SECS_PER_HOUR) % 24; + tp->Day = day + 1; + tp->Month = month; + tp->Year = year; +} + +static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static int exfat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +#else +static long exfat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static int exfat_sync_inode(struct inode *inode); +static struct inode *exfat_build_inode(struct super_block *sb, FILE_ID_T *fid, loff_t i_pos); +static void exfat_detach(struct inode *inode); +static void exfat_attach(struct inode *inode, loff_t i_pos); +static inline unsigned long exfat_hash(loff_t i_pos); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) +static int exfat_write_inode(struct inode *inode, int wait); +#else +static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); +#endif +static void exfat_write_super(struct super_block *sb); + +static void __lock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + lock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_lock(&sbi->s_lock); +#endif +} + +static void __unlock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + unlock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_unlock(&sbi->s_lock); +#endif +} + +static int __is_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + return sb->s_dirt; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + return sbi->s_dirt; +#endif +} + +static void __set_sb_clean(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 0; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 0; +#endif +} + +static int __exfat_revalidate(struct dentry *dentry) +{ + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_revalidate(struct dentry *dentry, unsigned int flags) +#else +static int exfat_revalidate(struct dentry *dentry, struct nameidata *nd) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + if (flags & LOOKUP_RCU) + return -ECHILD; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; +#endif + + if (dentry->d_inode) + return 1; + return __exfat_revalidate(dentry); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags) +#else +static int exfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + if (flags & LOOKUP_RCU) + return -ECHILD; +#else + unsigned int flags; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; +#endif + + flags = nd ? nd->flags : 0; +#endif + + if (dentry->d_inode) + return 1; + + if (!flags) + return 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; +#else + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } +#endif + + return __exfat_revalidate(dentry); +} + +static unsigned int __exfat_striptail_len(unsigned int len, const char *name) +{ + while (len && name[len - 1] == '.') + len--; + return len; +} + +static unsigned int exfat_striptail_len(const struct qstr *qstr) +{ + return __exfat_striptail_len(qstr->len, qstr->name); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_d_hash(struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_d_hash(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) + qstr->hash = full_name_hash(dentry, qstr->name, exfat_striptail_len(qstr)); +#else + qstr->hash = full_name_hash(qstr->name, exfat_striptail_len(qstr)); +#endif + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_d_hashi(struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_d_hashi(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif +{ + struct super_block *sb = dentry->d_sb; + const unsigned char *name; + unsigned int len; + unsigned long hash; + + name = qstr->name; + len = exfat_striptail_len(qstr); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) + hash = init_name_hash(dentry); +#else + hash = init_name_hash(); +#endif + while (len--) + hash = partial_name_hash(nls_upper(sb, *name++), hash); + qstr->hash = end_name_hash(hash); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) +static int exfat_cmpi(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_cmpi(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_cmpi(struct dentry *parent, struct qstr *a, struct qstr *b) +#else +static int exfat_cmpi(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) + struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io; +#else + struct nls_table *t = EXFAT_SB(parent->d_sb)->nls_io; +#endif + unsigned int alen, blen; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + alen = exfat_striptail_len(a); + blen = exfat_striptail_len(b); +#else + alen = exfat_striptail_len(name); + blen = __exfat_striptail_len(len, str); +#endif + if (alen == blen) { + if (t == NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (strncasecmp(a->name, b->name, alen) == 0) +#else + if (strncasecmp(name->name, str, alen) == 0) +#endif + return 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + } else if (nls_strnicmp(t, a->name, b->name, alen) == 0) +#else + } else if (nls_strnicmp(t, name->name, str, alen) == 0) +#endif + return 0; + } + return 1; +} +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) +static int exfat_cmp(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_cmp(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_cmp(struct dentry *parent, struct qstr *a, + struct qstr *b) +#else +static int exfat_cmp(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif +{ + unsigned int alen, blen; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + alen = exfat_striptail_len(a); + blen = exfat_striptail_len(b); +#else + alen = exfat_striptail_len(name); + blen = __exfat_striptail_len(len, str); +#endif + if (alen == blen) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (strncmp(a->name, b->name, alen) == 0) +#else + if (strncmp(name->name, str, alen) == 0) +#endif + return 0; + } + return 1; +} + +static const struct dentry_operations exfat_ci_dentry_ops = { + .d_revalidate = exfat_revalidate_ci, + .d_hash = exfat_d_hashi, + .d_compare = exfat_cmpi, +}; + +static const struct dentry_operations exfat_dentry_ops = { + .d_revalidate = exfat_revalidate, + .d_hash = exfat_d_hash, + .d_compare = exfat_cmp, +}; + +/*======================================================================*/ +/* Directory Entry Operations */ +/*======================================================================*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_readdir(struct file *filp, struct dir_context *ctx) +#else +static int exfat_readdir(struct file *filp, void *dirent, filldir_t filldir) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) + struct inode *inode = file_inode(filp); +#else + struct inode *inode = filp->f_path.dentry->d_inode; +#endif + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + DIR_ENTRY_T de; + unsigned long inum; + loff_t cpos; + int err = 0; + + __lock_super(sb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + cpos = ctx->pos; +#else + cpos = filp->f_pos; +#endif + /* Fake . and .. for the root directory. */ + if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { + while (cpos < 2) { + if (inode->i_ino == EXFAT_ROOT_INO) + inum = EXFAT_ROOT_INO; + else if (cpos == 0) + inum = inode->i_ino; + else /* (cpos == 1) */ + inum = parent_ino(filp->f_path.dentry); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + if (!dir_emit_dots(filp, ctx)) +#else + if (filldir(dirent, "..", cpos+1, cpos, inum, DT_DIR) < 0) +#endif + goto out; + cpos++; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos++; +#else + filp->f_pos++; +#endif + } + if (cpos == 2) + cpos = 0; + } + if (cpos & (DENTRY_SIZE - 1)) { + err = -ENOENT; + goto out; + } + +get_new: + EXFAT_I(inode)->fid.size = i_size_read(inode); + EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; + + err = FsReadDir(inode, &de); + if (err) { + /* at least we tried to read a sector + * move cpos to next sector position (should be aligned) + */ + if (err == FFS_MEDIAERR) { + cpos += 1 << p_bd->sector_size_bits; + cpos &= ~((1 << p_bd->sector_size_bits)-1); + } + + err = -EIO; + goto end_of_dir; + } + + cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; + + if (!de.Name[0]) + goto end_of_dir; + + if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) { + inum = inode->i_ino; + } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) { + inum = parent_ino(filp->f_path.dentry); + } else { + loff_t i_pos = ((loff_t) EXFAT_I(inode)->fid.start_clu << 32) | + ((EXFAT_I(inode)->fid.rwoffset-1) & 0xffffffff); + + struct inode *tmp = exfat_iget(sb, i_pos); + if (tmp) { + inum = tmp->i_ino; + iput(tmp); + } else { + inum = iunique(sb, EXFAT_ROOT_INO); + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + if (!dir_emit(ctx, de.Name, strlen(de.Name), inum, + (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) +#else + if (filldir(dirent, de.Name, strlen(de.Name), cpos-1, inum, + (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG) < 0) +#endif + goto out; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif + goto get_new; + +end_of_dir: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif +out: + __unlock_super(sb); + return err; +} + +static int exfat_ioctl_volume_id(struct inode *dir) +{ + struct super_block *sb = dir->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + + return p_fs->vol_id; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static int exfat_generic_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +#else +static long exfat_generic_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +#endif +{ +#if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) + #if !(LINUX_VERSION_CODE < KERNEL_VERSION(3,18,3)) + struct inode *inode = filp->f_path.dentry->d_inode; + #else + struct inode *inode = filp->f_dentry->d_inode; + #endif +#endif +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + unsigned int flags; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + switch (cmd) { + case EXFAT_IOCTL_GET_VOLUME_ID: + return exfat_ioctl_volume_id(inode); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + case EXFAT_IOC_GET_DEBUGFLAGS: { + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + flags = sbi->debug_flags; + return put_user(flags, (int __user *)arg); + } + case EXFAT_IOC_SET_DEBUGFLAGS: { + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(flags, (int __user *) arg)) + return -EFAULT; + + __lock_super(sb); + sbi->debug_flags = flags; + __unlock_super(sb); + + return 0; + } +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + default: + return -ENOTTY; /* Inappropriate ioctl for device */ + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) +static int exfat_file_fsync(struct file *filp, struct dentry *dentry, + int datasync) +#else +static int exfat_file_fsync(struct file *filp, int datasync) +#endif +{ + struct inode *inode = filp->f_mapping->host; + struct super_block *sb = inode->i_sb; + int res, err; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + res = simple_fsync(filp, dentry, datasync); +#else + res = generic_file_fsync(filp, datasync); +#endif + err = FsSyncVol(sb, 1); + + return res ? res : err; +} +#endif + +const struct file_operations exfat_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + .iterate = exfat_readdir, +#else + .readdir = exfat_readdir, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .ioctl = exfat_generic_ioctl, + .fsync = exfat_file_fsync, +#else + .unlocked_ioctl = exfat_generic_ioctl, + .fsync = generic_file_fsync, +#endif +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + struct nameidata *nd) +#else +static int exfat_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + FILE_ID_T fid; + loff_t i_pos; + int err; + + __lock_super(sb); + + DPRINTK("exfat_create entered\n"); + + err = FsCreateFile(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else if (err == FFS_NAMETOOLONG) + err = -ENAMETOOLONG; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + INC_IVERSION(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unnecessary. */ + + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_create exited\n"); + return err; +} + +static int exfat_find(struct inode *dir, struct qstr *qname, + FILE_ID_T *fid) +{ + int err; + + if (qname->len == 0) + return -ENOENT; + + err = FsLookupFile(dir, (u8 *) qname->name, fid); + if (err) + return -ENOENT; + + return 0; +} + +static int exfat_d_anon_disconn(struct dentry *dentry) +{ + return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +#else +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct dentry *alias; + int err; + FILE_ID_T fid; + loff_t i_pos; + u64 ret; + mode_t i_mode; + + __lock_super(sb); + DPRINTK("exfat_lookup entered\n"); + err = exfat_find(dir, &dentry->d_name, &fid); + if (err) { + if (err == -ENOENT) { + inode = NULL; + goto out; + } + goto error; + } + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto error; + } + + i_mode = inode->i_mode; + if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) { + EXFAT_I(inode)->target = kmalloc(i_size_read(inode)+1, GFP_KERNEL); + if (!EXFAT_I(inode)->target) { + err = -ENOMEM; + goto error; + } + FsReadFile(dir, &fid, EXFAT_I(inode)->target, i_size_read(inode), &ret); + *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; + } + + alias = d_find_alias(inode); + if (alias && !exfat_d_anon_disconn(alias)) { + CHECK_ERR(d_unhashed(alias)); + if (!S_ISDIR(i_mode)) + d_move(alias, dentry); + iput(inode); + __unlock_super(sb); + DPRINTK("exfat_lookup exited 1\n"); + return alias; + } else { + dput(alias); + } +out: + __unlock_super(sb); + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + dentry->d_op = sb->s_root->d_op; + dentry = d_splice_alias(inode, dentry); + if (dentry) { + dentry->d_op = sb->s_root->d_op; + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + } +#else + dentry = d_splice_alias(inode, dentry); + if (dentry) + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); +#endif + DPRINTK("exfat_lookup exited 2\n"); + return dentry; + +error: + __unlock_super(sb); + DPRINTK("exfat_lookup exited 3\n"); + return ERR_PTR(err); +} + +static int exfat_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = dir->i_sb; + int err; + + __lock_super(sb); + + DPRINTK("exfat_unlink entered\n"); + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsRemoveFile(dir, &(EXFAT_I(inode)->fid)); + if (err) { + if (err == FFS_PERMISSIONERR) + err = -EPERM; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = current_time(inode); + exfat_detach(inode); + remove_inode_hash(inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_unlink exited\n"); + return err; +} + +static int exfat_symlink(struct inode *dir, struct dentry *dentry, const char *target) +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + FILE_ID_T fid; + loff_t i_pos; + int err; + u64 len = (u64) strlen(target); + u64 ret; + + __lock_super(sb); + + DPRINTK("exfat_symlink entered\n"); + + err = FsCreateFile(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + + err = FsWriteFile(dir, &fid, (char *) target, len, &ret); + + if (err) { + FsRemoveFile(dir, &fid); + + if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + + INC_IVERSION(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + INC_IVERSION(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + EXFAT_I(inode)->target = kmalloc(len+1, GFP_KERNEL); + if (!EXFAT_I(inode)->target) { + err = -ENOMEM; + goto out; + } + memcpy(EXFAT_I(inode)->target, target, len+1); + + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_symlink exited\n"); + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +#else +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + FILE_ID_T fid; + loff_t i_pos; + int err; + + __lock_super(sb); + + DPRINTK("exfat_mkdir entered\n"); + + err = FsCreateDir(dir, (u8 *) dentry->d_name.name, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else if (err == FFS_NAMETOOLONG) + err = -ENAMETOOLONG; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + inc_nlink(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + INC_IVERSION(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_mkdir exited\n"); + return err; +} + +static int exfat_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = dir->i_sb; + int err; + + __lock_super(sb); + + DPRINTK("exfat_rmdir entered\n"); + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsRemoveDir(dir, &(EXFAT_I(inode)->fid)); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -ENOTEMPTY; + else if (err == FFS_NOTFOUND) + err = -ENOENT; + else if (err == FFS_DIRBUSY) + err = -EBUSY; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + drop_nlink(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = current_time(inode); + exfat_detach(inode); + remove_inode_hash(inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_rmdir exited\n"); + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) +static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +#else +static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +#endif +{ + struct inode *old_inode, *new_inode; + struct super_block *sb = old_dir->i_sb; + loff_t i_pos; + int err; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + if (flags) + return -EINVAL; +#endif + + __lock_super(sb); + + DPRINTK("exfat_rename entered\n"); + + old_inode = old_dentry->d_inode; + new_inode = new_dentry->d_inode; + + EXFAT_I(old_inode)->fid.size = i_size_read(old_inode); + + err = FsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, new_dentry); + if (err) { + if (err == FFS_PERMISSIONERR) + err = -EPERM; + else if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_NOTFOUND) + err = -ENOENT; + else if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + INC_IVERSION(new_dir); + new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = current_time(new_dir); + if (IS_DIRSYNC(new_dir)) + (void) exfat_sync_inode(new_dir); + else + mark_inode_dirty(new_dir); + + i_pos = ((loff_t) EXFAT_I(old_inode)->fid.dir.dir << 32) | + (EXFAT_I(old_inode)->fid.entry & 0xffffffff); + + exfat_detach(old_inode); + exfat_attach(old_inode, i_pos); + if (IS_DIRSYNC(new_dir)) + (void) exfat_sync_inode(old_inode); + else + mark_inode_dirty(old_inode); + + if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { + drop_nlink(old_dir); + if (!new_inode) + inc_nlink(new_dir); + } + INC_IVERSION(old_dir); + old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); + if (IS_DIRSYNC(old_dir)) + (void) exfat_sync_inode(old_dir); + else + mark_inode_dirty(old_dir); + + if (new_inode) { + exfat_detach(new_inode); + drop_nlink(new_inode); + if (S_ISDIR(new_inode->i_mode)) + drop_nlink(new_inode); + new_inode->i_ctime = current_time(new_inode); + } + +out: + __unlock_super(sb); + DPRINTK("exfat_rename exited\n"); + return err; +} + +static int exfat_cont_expand(struct inode *inode, loff_t size) +{ + struct address_space *mapping = inode->i_mapping; + loff_t start = i_size_read(inode), count = size - i_size_read(inode); + int err, err2; + + err = generic_cont_expand_simple(inode, size); + if (err != 0) + return err; + + inode->i_ctime = inode->i_mtime = current_time(inode); + mark_inode_dirty(inode); + + if (IS_SYNC(inode)) { + err = filemap_fdatawrite_range(mapping, start, start + count - 1); + err2 = sync_mapping_buffers(mapping); + err = (err) ? (err) : (err2); + err2 = write_inode_now(inode, 1); + err = (err) ? (err) : (err2); + if (!err) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + err = wait_on_page_writeback_range(mapping, + start >> PAGE_CACHE_SHIFT, + (start + count - 1) >> PAGE_CACHE_SHIFT); +#else + err = filemap_fdatawait_range(mapping, start, start + count - 1); +#endif + } + return err; +} + +static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) +{ + mode_t allow_utime = sbi->options.allow_utime; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + if (!uid_eq(current_fsuid(), inode->i_uid)) +#else + if (current_fsuid() != inode->i_uid) +#endif + { + if (in_group_p(inode->i_gid)) + allow_utime >>= 3; + if (allow_utime & MAY_WRITE) + return 1; + } + + /* use a default check */ + return 0; +} + +static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, + struct inode *inode, umode_t *mode_ptr) +{ + mode_t i_mode, mask, perm; + + i_mode = inode->i_mode; + + if (S_ISREG(i_mode) || S_ISLNK(i_mode)) + mask = sbi->options.fs_fmask; + else + mask = sbi->options.fs_dmask; + + perm = *mode_ptr & ~(S_IFMT | mask); + + /* Of the r and x bits, all (subject to umask) must be present.*/ + if ((perm & (S_IRUGO | S_IXUGO)) != (i_mode & (S_IRUGO|S_IXUGO))) + return -EPERM; + + if (exfat_mode_can_hold_ro(inode)) { + /* Of the w bits, either all (subject to umask) or none must be present. */ + if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) + return -EPERM; + } else { + /* If exfat_mode_can_hold_ro(inode) is false, can't change w bits. */ + if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) + return -EPERM; + } + + *mode_ptr &= S_IFMT | perm; + + return 0; +} + +static int exfat_setattr(struct dentry *dentry, struct iattr *attr) +{ + + struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); + struct inode *inode = dentry->d_inode; + unsigned int ia_valid; + int error; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + loff_t old_size; +#endif + + DPRINTK("exfat_setattr entered\n"); + + if ((attr->ia_valid & ATTR_SIZE) + && (attr->ia_size > i_size_read(inode))) { + error = exfat_cont_expand(inode, attr->ia_size); + if (error || attr->ia_valid == ATTR_SIZE) + return error; + attr->ia_valid &= ~ATTR_SIZE; + } + + ia_valid = attr->ia_valid; + + if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) + && exfat_allow_set_time(sbi, inode)) { + attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + error = setattr_prepare(dentry, attr); +#else + error = inode_change_ok(inode, attr); +#endif + attr->ia_valid = ia_valid; + if (error) + return error; + + if (((attr->ia_valid & ATTR_UID) && +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) || + ((attr->ia_valid & ATTR_GID) && + (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) || +#else + (attr->ia_uid != sbi->options.fs_uid)) || + ((attr->ia_valid & ATTR_GID) && + (attr->ia_gid != sbi->options.fs_gid)) || +#endif + ((attr->ia_valid & ATTR_MODE) && + (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | S_IRWXUGO)))) { + return -EPERM; + } + + /* + * We don't return -EPERM here. Yes, strange, but this is too + * old behavior. + */ + if (attr->ia_valid & ATTR_MODE) { + if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) + attr->ia_valid &= ~ATTR_MODE; + } + + EXFAT_I(inode)->fid.size = i_size_read(inode); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + if (attr->ia_valid) + error = inode_setattr(inode, attr); +#else + if (attr->ia_valid & ATTR_SIZE) { + old_size = i_size_read(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_write(&EXFAT_I(inode)->truncate_lock); + truncate_setsize(inode, attr->ia_size); + _exfat_truncate(inode, old_size); + up_write(&EXFAT_I(inode)->truncate_lock); +#else + truncate_setsize(inode, attr->ia_size); + _exfat_truncate(inode, old_size); +#endif + } + setattr_copy(inode, attr); + mark_inode_dirty(inode); +#endif + + DPRINTK("exfat_setattr exited\n"); + return error; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +static int exfat_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + struct inode *inode = path->dentry->d_inode; +#else +static int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; +#endif + + DPRINTK("exfat_getattr entered\n"); + + generic_fillattr(inode, stat); + stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; + + DPRINTK("exfat_getattr exited\n"); + return 0; +} + +const struct inode_operations exfat_dir_inode_operations = { + .create = exfat_create, + .lookup = exfat_lookup, + .unlink = exfat_unlink, + .symlink = exfat_symlink, + .mkdir = exfat_mkdir, + .rmdir = exfat_rmdir, + .rename = exfat_rename, + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; + +/*======================================================================*/ +/* File Operations */ +/*======================================================================*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0) +static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + if (ei->target != NULL) { + char *cookie = ei->target; + if (cookie != NULL) { + return (char *)(ei->target); + } + } + return NULL; +} +#elif LINUX_VERSION_CODE > KERNEL_VERSION(4,1,0) +static const char *exfat_follow_link(struct dentry *dentry, void **cookie) +{ + struct exfat_inode_info *ei = EXFAT_I(dentry->d_inode); + return *cookie = (char *)(ei->target); +} +#else +static void *exfat_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct exfat_inode_info *ei = EXFAT_I(dentry->d_inode); + nd_set_link(nd, (char *)(ei->target)); + return NULL; +} +#endif + +const struct inode_operations exfat_symlink_inode_operations = { + #if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) + .readlink = generic_readlink, + #endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) + .follow_link = exfat_follow_link, + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0) + .get_link = exfat_get_link, + #endif +}; + +static int exfat_file_release(struct inode *inode, struct file *filp) +{ + struct super_block *sb = inode->i_sb; + + EXFAT_I(inode)->fid.size = i_size_read(inode); + FsSyncVol(sb, 0); + return 0; +} + +const struct file_operations exfat_file_operations = { + .llseek = generic_file_llseek, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) + .read = new_sync_read, + .write = new_sync_write, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, +#endif + .mmap = generic_file_mmap, + .release = exfat_file_release, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .ioctl = exfat_generic_ioctl, + .fsync = exfat_file_fsync, +#else + .unlocked_ioctl = exfat_generic_ioctl, + .fsync = generic_file_fsync, +#endif + .splice_read = generic_file_splice_read, +}; + +static void _exfat_truncate(struct inode *inode, loff_t old_size) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + int err; + + __lock_super(sb); + + /* + * This protects against truncating a file bigger than it was then + * trying to write into the hole. + */ + if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) + EXFAT_I(inode)->mmu_private = i_size_read(inode); + + if (EXFAT_I(inode)->fid.start_clu == 0) + goto out; + + err = FsTruncateFile(inode, old_size, i_size_read(inode)); + if (err) + goto out; + + inode->i_ctime = inode->i_mtime = current_time(inode); + if (IS_DIRSYNC(inode)) + (void) exfat_sync_inode(inode); + else + mark_inode_dirty(inode); + + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; +out: + __unlock_super(sb); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) +static void exfat_truncate(struct inode *inode) +{ + _exfat_truncate(inode, i_size_read(inode)); +} +#endif + +const struct inode_operations exfat_file_inode_operations = { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) + .truncate = exfat_truncate, +#endif + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; + +/*======================================================================*/ +/* Address Space Operations */ +/*======================================================================*/ + +static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, + unsigned long *mapped_blocks, int *create) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + BD_INFO_T *p_bd = &(sbi->bd_info); + const unsigned long blocksize = sb->s_blocksize; + const unsigned char blocksize_bits = sb->s_blocksize_bits; + sector_t last_block; + int err, clu_offset, sec_offset; + unsigned int cluster; + + *phys = 0; + *mapped_blocks = 0; + + if ((p_fs->vol_type == FAT12) || (p_fs->vol_type == FAT16)) { + if (inode->i_ino == EXFAT_ROOT_INO) { + if (sector < (p_fs->dentries_in_root >> (p_bd->sector_size_bits-DENTRY_SIZE_BITS))) { + *phys = sector + p_fs->root_start_sector; + *mapped_blocks = 1; + } + return 0; + } + } + + last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; + if (sector >= last_block) { + if (*create == 0) + return 0; + } else { + *create = 0; + } + + clu_offset = sector >> p_fs->sectors_per_clu_bits; /* cluster offset */ + sec_offset = sector & (p_fs->sectors_per_clu - 1); /* sector offset in cluster */ + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsMapCluster(inode, clu_offset, &cluster); + + if (err) { + if (err == FFS_FULL) + return -ENOSPC; + else + return -EIO; + } else if (cluster != CLUSTER_32(~0)) { + *phys = START_SECTOR(cluster) + sec_offset; + *mapped_blocks = p_fs->sectors_per_clu - sec_offset; + } + + return 0; +} + +static int exfat_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + struct super_block *sb = inode->i_sb; + unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; + int err; + unsigned long mapped_blocks; + sector_t phys; + + __lock_super(sb); + + err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); + if (err) { + __unlock_super(sb); + return err; + } + + if (phys) { + max_blocks = min(mapped_blocks, max_blocks); + if (create) { + EXFAT_I(inode)->mmu_private += max_blocks << sb->s_blocksize_bits; + set_buffer_new(bh_result); + } + map_bh(bh_result, sb, phys); + } + + bh_result->b_size = max_blocks << sb->s_blocksize_bits; + __unlock_super(sb); + + return 0; +} + +static int exfat_readpage(struct file *file, struct page *page) +{ + int ret; + ret = mpage_readpage(page, exfat_get_block); + return ret; +} + +static int exfat_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + int ret; + ret = mpage_readpages(mapping, pages, nr_pages, exfat_get_block); + return ret; +} + +static int exfat_writepage(struct page *page, struct writeback_control *wbc) +{ + int ret; + ret = block_write_full_page(page, exfat_get_block, wbc); + return ret; +} + +static int exfat_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + int ret; + ret = mpage_writepages(mapping, wbc, exfat_get_block); + return ret; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) +static void exfat_write_failed(struct address_space *mapping, loff_t to) +{ + struct inode *inode = mapping->host; + if (to > i_size_read(inode)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0) + truncate_pagecache(inode, i_size_read(inode)); +#else + truncate_pagecache(inode, to, i_size_read(inode)); +#endif + EXFAT_I(inode)->fid.size = i_size_read(inode); + _exfat_truncate(inode, i_size_read(inode)); + } +} +#endif + +static int exfat_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + int ret; + *pagep = NULL; + ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + exfat_get_block, + &EXFAT_I(mapping->host)->mmu_private); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (ret < 0) + exfat_write_failed(mapping, pos+len); +#endif + return ret; +} + +static int exfat_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pagep, void *fsdata) +{ + struct inode *inode = mapping->host; + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + int err; + + err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (err < len) + exfat_write_failed(mapping, pos+len); +#endif + + if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { + inode->i_mtime = inode->i_ctime = current_time(inode); + fid->attr |= ATTR_ARCHIVE; + mark_inode_dirty(inode); + } + return err; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifdef CONFIG_AIO_OPTIMIZATION +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#else +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) +static ssize_t exfat_direct_IO(struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#else /* >= 4.7.x */ +static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +#endif +{ + struct inode *inode = iocb->ki_filp->f_mapping->host; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + struct address_space *mapping = iocb->ki_filp->f_mapping; +#endif + ssize_t ret; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) + int rw; + + rw = iov_iter_rw(iter); +#endif + + if (rw == WRITE) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifdef CONFIG_AIO_OPTIMIZATION + if (EXFAT_I(inode)->mmu_private < + (offset + iov_iter_count(iter))) +#else + if (EXFAT_I(inode)->mmu_private < (offset + iov_length(iov, nr_segs))) +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) + if (EXFAT_I(inode)->mmu_private < (offset + iov_iter_count(iter))) +#else + if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter)) +#endif + return 0; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) + ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) + ret = blockdev_direct_IO(iocb, inode, iter, + offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#ifdef CONFIG_AIO_OPTIMIZATION + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, exfat_get_block); +#else + ret = blockdev_direct_IO(rw, iocb, inode, iov, + offset, nr_segs, exfat_get_block); +#endif +#else + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, exfat_get_block, NULL); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) + if ((ret < 0) && (rw & WRITE)) + exfat_write_failed(mapping, iov_iter_count(iter)); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + if ((ret < 0) && (rw & WRITE)) + exfat_write_failed(mapping, offset+iov_iter_count(iter)); +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if ((ret < 0) && (rw & WRITE)) +#ifdef CONFIG_AIO_OPTIMIZATION + exfat_write_failed(mapping, offset+iov_iter_count(iter)); +#else + exfat_write_failed(mapping, offset+iov_length(iov, nr_segs)); +#endif +#endif + return ret; +} + +static sector_t _exfat_bmap(struct address_space *mapping, sector_t block) +{ + sector_t blocknr; + + /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_read(&EXFAT_I(mapping->host)->truncate_lock); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->truncate_lock); +#else + down_read(&EXFAT_I(mapping->host)->i_alloc_sem); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->i_alloc_sem); +#endif + + return blocknr; +} + +const struct address_space_operations exfat_aops = { + .readpage = exfat_readpage, + .readpages = exfat_readpages, + .writepage = exfat_writepage, + .writepages = exfat_writepages, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) + .sync_page = block_sync_page, +#endif + .write_begin = exfat_write_begin, + .write_end = exfat_write_end, + .direct_IO = exfat_direct_IO, + .bmap = _exfat_bmap +}; + +/*======================================================================*/ +/* Super Operations */ +/*======================================================================*/ + +static inline unsigned long exfat_hash(loff_t i_pos) +{ + return hash_32(i_pos, EXFAT_HASH_BITS); +} + +static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *info; + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + struct inode *inode = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) + struct hlist_node *node; + + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, node, head, i_hash_fat) { +#else + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, head, i_hash_fat) { +#endif + CHECK_ERR(info->vfs_inode.i_sb != sb); + + if (i_pos != info->i_pos) + continue; + inode = igrab(&info->vfs_inode); + if (inode) + break; + } + spin_unlock(&sbi->inode_hash_lock); + return inode; +} + +static void exfat_attach(struct inode *inode, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + + spin_lock(&sbi->inode_hash_lock); + EXFAT_I(inode)->i_pos = i_pos; + hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); + spin_unlock(&sbi->inode_hash_lock); +} + +static void exfat_detach(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + spin_lock(&sbi->inode_hash_lock); + hlist_del_init(&EXFAT_I(inode)->i_hash_fat); + EXFAT_I(inode)->i_pos = 0; + spin_unlock(&sbi->inode_hash_lock); +} + +/* doesn't deal with root inode */ +static int exfat_fill_inode(struct inode *inode, FILE_ID_T *fid) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + DIR_ENTRY_T info; + + memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(FILE_ID_T)); + + FsReadStat(inode, &info); + + EXFAT_I(inode)->i_pos = 0; + EXFAT_I(inode)->target = NULL; + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + INC_IVERSION(inode); + inode->i_generation = get_seconds(); + + if (info.Attr & ATTR_SUBDIR) { /* directory */ + inode->i_generation &= ~1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,00) + set_nlink(inode, info.NumSubdirs); +#else + inode->i_nlink = info.NumSubdirs; +#endif + } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ + inode->i_generation |= 1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_symlink_inode_operations; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); + } else { /* regular file */ + inode->i_generation |= 1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_file_inode_operations; + inode->i_fop = &exfat_file_operations; + inode->i_mapping->a_ops = &exfat_aops; + inode->i_mapping->nrpages = 0; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); + } + exfat_save_attr(inode, info.Attr); + + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; + + + + exfat_time_fat2unix(sbi, &inode->i_mtime, &info.ModifyTimestamp); + exfat_time_fat2unix(sbi, &inode->i_ctime, &info.CreateTimestamp); + exfat_time_fat2unix(sbi, &inode->i_atime, &info.AccessTimestamp); + + return 0; +} + +static struct inode *exfat_build_inode(struct super_block *sb, + FILE_ID_T *fid, loff_t i_pos) { + struct inode *inode; + int err; + + inode = exfat_iget(sb, i_pos); + if (inode) + goto out; + inode = new_inode(sb); + if (!inode) { + inode = ERR_PTR(-ENOMEM); + goto out; + } + inode->i_ino = iunique(sb, EXFAT_ROOT_INO); + SET_IVERSION(inode, 1); + err = exfat_fill_inode(inode, fid); + if (err) { + iput(inode); + inode = ERR_PTR(err); + goto out; + } + exfat_attach(inode, i_pos); + insert_inode_hash(inode); +out: + return inode; +} + +static int exfat_sync_inode(struct inode *inode) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + return exfat_write_inode(inode, 0); +#else + return exfat_write_inode(inode, NULL); +#endif +} + +static struct inode *exfat_alloc_inode(struct super_block *sb) +{ + struct exfat_inode_info *ei; + + ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); + if (!ei) + return NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + init_rwsem(&ei->truncate_lock); +#endif + + return &ei->vfs_inode; +} + +static void exfat_destroy_inode(struct inode *inode) +{ + if (EXFAT_I(inode)->target) + kfree(EXFAT_I(inode)->target); + EXFAT_I(inode)->target = NULL; + + kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) +static int exfat_write_inode(struct inode *inode, int wait) +#else +static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) +#endif +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + DIR_ENTRY_T info; + + if (inode->i_ino == EXFAT_ROOT_INO) + return 0; + + info.Attr = exfat_make_attr(inode); + info.Size = i_size_read(inode); + + exfat_time_unix2fat(sbi, &inode->i_mtime, &info.ModifyTimestamp); + exfat_time_unix2fat(sbi, &inode->i_ctime, &info.CreateTimestamp); + exfat_time_unix2fat(sbi, &inode->i_atime, &info.AccessTimestamp); + + FsWriteStat(inode, &info); + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static void exfat_delete_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); +} + +static void exfat_clear_inode(struct inode *inode) +{ + exfat_detach(inode); + remove_inode_hash(inode); +} +#else +static void exfat_evict_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + + if (!inode->i_nlink) + i_size_write(inode, 0); + invalidate_inode_buffers(inode); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) + end_writeback(inode); +#else + clear_inode(inode); +#endif + exfat_detach(inode); + + remove_inode_hash(inode); +} +#endif + +static void exfat_free_super(struct exfat_sb_info *sbi) +{ + if (sbi->nls_disk) + unload_nls(sbi->nls_disk); + if (sbi->nls_io) + unload_nls(sbi->nls_io); + if (sbi->options.iocharset != exfat_default_iocharset) + kfree(sbi->options.iocharset); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + /* mutex_init is in exfat_fill_super function. only for 3.7+ */ + mutex_destroy(&sbi->s_lock); +#endif + kfree(sbi); +} + +static void exfat_put_super(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + if (__is_sb_dirty(sb)) + exfat_write_super(sb); + + FsUmountVol(sb); + + sb->s_fs_info = NULL; + exfat_free_super(sbi); +} + +static void exfat_write_super(struct super_block *sb) +{ + __lock_super(sb); + + __set_sb_clean(sb); + + if (!(sb->s_flags & MS_RDONLY)) + FsSyncVol(sb, 1); + + __unlock_super(sb); +} + +static int exfat_sync_fs(struct super_block *sb, int wait) +{ + int err = 0; + + if (__is_sb_dirty(sb)) { + __lock_super(sb); + __set_sb_clean(sb); + err = FsSyncVol(sb, 1); + __unlock_super(sb); + } + + return err; +} + +static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *sb = dentry->d_sb; + u64 id = huge_encode_dev(sb->s_bdev->bd_dev); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + VOL_INFO_T info; + + if (p_fs->used_clusters == (u32) ~0) { + if (FFS_MEDIAERR == FsGetVolInfo(sb, &info)) + return -EIO; + + } else { + info.FatType = p_fs->vol_type; + info.ClusterSize = p_fs->cluster_size; + info.NumClusters = p_fs->num_clusters - 2; + info.UsedClusters = p_fs->used_clusters; + info.FreeClusters = info.NumClusters - info.UsedClusters; + + if (p_fs->dev_ejected) + printk("[EXFAT] statfs on device is ejected\n"); + } + + buf->f_type = sb->s_magic; + buf->f_bsize = info.ClusterSize; + buf->f_blocks = info.NumClusters; + buf->f_bfree = info.FreeClusters; + buf->f_bavail = info.FreeClusters; + buf->f_fsid.val[0] = (u32)id; + buf->f_fsid.val[1] = (u32)(id >> 32); + buf->f_namelen = 260; + + return 0; +} + +static int exfat_remount(struct super_block *sb, int *flags, char *data) +{ + *flags |= MS_NODIRATIME; + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_show_options(struct seq_file *m, struct dentry *root) +{ + struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); +#else +static int exfat_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct exfat_sb_info *sbi = EXFAT_SB(mnt->mnt_sb); +#endif + struct exfat_mount_options *opts = &sbi->options; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + if (__kuid_val(opts->fs_uid)) + seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid)); + if (__kgid_val(opts->fs_gid)) + seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); +#else + if (opts->fs_uid != 0) + seq_printf(m, ",uid=%u", opts->fs_uid); + if (opts->fs_gid != 0) + seq_printf(m, ",gid=%u", opts->fs_gid); +#endif + seq_printf(m, ",fmask=%04o", opts->fs_fmask); + seq_printf(m, ",dmask=%04o", opts->fs_dmask); + if (opts->allow_utime) + seq_printf(m, ",allow_utime=%04o", opts->allow_utime); + if (sbi->nls_disk) + seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); + if (sbi->nls_io) + seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); + seq_printf(m, ",namecase=%u", opts->casesensitive); + if (opts->tz_set) { + if (opts->time_offset) + seq_printf(m, ",time_offset=%d", opts->time_offset); + else + seq_puts(m, ",tz=UTC"); + } + if (opts->errors == EXFAT_ERRORS_CONT) + seq_puts(m, ",errors=continue"); + else if (opts->errors == EXFAT_ERRORS_PANIC) + seq_puts(m, ",errors=panic"); + else + seq_puts(m, ",errors=remount-ro"); +#ifdef CONFIG_EXFAT_DISCARD + if (opts->discard) + seq_printf(m, ",discard"); +#endif + return 0; +} + +const struct super_operations exfat_sops = { + .alloc_inode = exfat_alloc_inode, + .destroy_inode = exfat_destroy_inode, + .write_inode = exfat_write_inode, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .delete_inode = exfat_delete_inode, + .clear_inode = exfat_clear_inode, +#else + .evict_inode = exfat_evict_inode, +#endif + .put_super = exfat_put_super, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + .write_super = exfat_write_super, +#endif + .sync_fs = exfat_sync_fs, + .statfs = exfat_statfs, + .remount_fs = exfat_remount, + .show_options = exfat_show_options, +}; + +/*======================================================================*/ +/* Export Operations */ +/*======================================================================*/ + +static struct inode *exfat_nfs_get_inode(struct super_block *sb, + u64 ino, u32 generation) +{ + struct inode *inode = NULL; + if (ino < EXFAT_ROOT_INO) + return inode; + inode = ilookup(sb, ino); + + if (inode && generation && (inode->i_generation != generation)) { + iput(inode); + inode = NULL; + } + + return inode; +} + +static struct dentry *exfat_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, + exfat_nfs_get_inode); +} + +static struct dentry *exfat_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_parent(sb, fid, fh_len, fh_type, + exfat_nfs_get_inode); +} + +const struct export_operations exfat_export_ops = { + .fh_to_dentry = exfat_fh_to_dentry, + .fh_to_parent = exfat_fh_to_parent, +}; + +/*======================================================================*/ +/* Super Block Read Operations */ +/*======================================================================*/ + +enum { + Opt_uid, + Opt_gid, + Opt_umask, + Opt_dmask, + Opt_fmask, + Opt_allow_utime, + Opt_codepage, + Opt_charset, + Opt_namecase, + Opt_tz_utc, + Opt_time_offset, + Opt_debug, + Opt_err_cont, + Opt_err_panic, + Opt_err_ro, + Opt_utf8_hack, + Opt_err, +#ifdef CONFIG_EXFAT_DISCARD + Opt_discard, +#endif /* EXFAT_CONFIG_DISCARD */ +}; + +static const match_table_t exfat_tokens = { + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_umask, "umask=%o"}, + {Opt_dmask, "dmask=%o"}, + {Opt_fmask, "fmask=%o"}, + {Opt_allow_utime, "allow_utime=%o"}, + {Opt_codepage, "codepage=%u"}, + {Opt_charset, "iocharset=%s"}, + {Opt_namecase, "namecase=%u"}, + {Opt_tz_utc, "tz=UTC"}, + {Opt_time_offset, "time_offset=%d"}, + {Opt_debug, "debug"}, + {Opt_err_cont, "errors=continue"}, + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, + {Opt_utf8_hack, "utf8"}, +#ifdef CONFIG_EXFAT_DISCARD + {Opt_discard, "discard"}, +#endif /* CONFIG_EXFAT_DISCARD */ + {Opt_err, NULL} +}; + +static int parse_options(char *options, int silent, int *debug, + struct exfat_mount_options *opts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + char *iocharset; + + opts->fs_uid = current_uid(); + opts->fs_gid = current_gid(); + opts->fs_fmask = opts->fs_dmask = current->fs->umask; + opts->allow_utime = (unsigned short) -1; + opts->codepage = exfat_default_codepage; + opts->iocharset = exfat_default_iocharset; + opts->casesensitive = 0; + opts->tz_set = 0; + opts->errors = EXFAT_ERRORS_RO; +#ifdef CONFIG_EXFAT_DISCARD + opts->discard = 0; +#endif + *debug = 0; + + if (!options) + goto out; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, exfat_tokens, args); + switch (token) { + case Opt_uid: + if (match_int(&args[0], &option)) + return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_uid = KUIDT_INIT(option); +#else + opts->fs_uid = option; +#endif + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_gid = KGIDT_INIT(option); +#else + opts->fs_gid = option; +#endif + break; + case Opt_umask: + case Opt_dmask: + case Opt_fmask: + if (match_octal(&args[0], &option)) + return 0; + if (token != Opt_dmask) + opts->fs_fmask = option; + if (token != Opt_fmask) + opts->fs_dmask = option; + break; + case Opt_allow_utime: + if (match_octal(&args[0], &option)) + return 0; + opts->allow_utime = option & (S_IWGRP | S_IWOTH); + break; + case Opt_codepage: + if (match_int(&args[0], &option)) + return 0; + opts->codepage = option; + break; + case Opt_charset: + if (opts->iocharset != exfat_default_iocharset) + kfree(opts->iocharset); + iocharset = match_strdup(&args[0]); + if (!iocharset) + return -ENOMEM; + opts->iocharset = iocharset; + break; + case Opt_namecase: + if (match_int(&args[0], &option)) + return 0; + opts->casesensitive = option; + break; + case Opt_time_offset: + if (match_int(&args[0], &option)) + return -EINVAL; + if (option < -12 * 60 || option > 12 * 60) + return -EINVAL; + opts->tz_set = 1; + opts->time_offset = option; + break; + case Opt_tz_utc: + opts->tz_set = 1; + opts->time_offset = 0; + break; + case Opt_err_cont: + opts->errors = EXFAT_ERRORS_CONT; + break; + case Opt_err_panic: + opts->errors = EXFAT_ERRORS_PANIC; + break; + case Opt_err_ro: + opts->errors = EXFAT_ERRORS_RO; + break; + case Opt_debug: + *debug = 1; + break; +#ifdef CONFIG_EXFAT_DISCARD + case Opt_discard: + opts->discard = 1; + break; +#endif /* CONFIG_EXFAT_DISCARD */ + case Opt_utf8_hack: + break; + default: + if (!silent) + printk(KERN_ERR "[EXFAT] Unrecognized mount option %s or missing value\n", p); + return -EINVAL; + } + } + +out: + if (opts->allow_utime == (unsigned short) -1) + opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); + + return 0; +} + +static void exfat_hash_init(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + int i; + + spin_lock_init(&sbi->inode_hash_lock); + for (i = 0; i < EXFAT_HASH_SIZE; i++) + INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); +} + +static int exfat_read_root(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + DIR_ENTRY_T info; + + EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; + EXFAT_I(inode)->fid.dir.flags = 0x01; + EXFAT_I(inode)->fid.entry = -1; + EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; + EXFAT_I(inode)->fid.flags = 0x01; + EXFAT_I(inode)->fid.type = TYPE_DIR; + EXFAT_I(inode)->fid.rwoffset = 0; + EXFAT_I(inode)->fid.hint_last_off = -1; + + EXFAT_I(inode)->target = NULL; + + FsReadStat(inode, &info); + + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + INC_IVERSION(inode); + inode->i_generation = 0; + inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + + i_size_write(inode, info.Size); + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; + EXFAT_I(inode)->i_pos = ((loff_t) p_fs->root_dir << 32) | 0xffffffff; + EXFAT_I(inode)->mmu_private = i_size_read(inode); + + exfat_save_attr(inode, ATTR_SUBDIR); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,00) + set_nlink(inode, info.NumSubdirs + 2); +#else + inode->i_nlink = info.NumSubdirs + 2; +#endif + + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) +static void setup_dops(struct super_block *sb) +{ + if (EXFAT_SB(sb)->options.casesensitive == 0) + sb->s_d_op = &exfat_ci_dentry_ops; + else + sb->s_d_op = &exfat_dentry_ops; +} +#endif + +static int exfat_fill_super(struct super_block *sb, void *data, int silent) +{ + struct inode *root_inode = NULL; + struct exfat_sb_info *sbi; + int debug, ret; + long error; + char buf[50]; + + /* + * GFP_KERNEL is ok here, because while we do hold the + * supeblock lock, memory pressure can't call back into + * the filesystem, since we're only just about to mount + * it and have no inodes etc active! + */ + sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + mutex_init(&sbi->s_lock); +#endif + sb->s_fs_info = sbi; + sb->s_flags |= MS_NODIRATIME; + sb->s_magic = EXFAT_SUPER_MAGIC; + sb->s_op = &exfat_sops; + sb->s_export_op = &exfat_export_ops; + + error = parse_options(data, silent, &debug, &sbi->options); + if (error) + goto out_fail; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) + setup_dops(sb); +#endif + + error = -EIO; + sb_min_blocksize(sb, 512); + sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */ + + ret = FsMountVol(sb); + if (ret) { + if (!silent) + printk(KERN_ERR "[EXFAT] FsMountVol failed\n"); + + goto out_fail; + } + + /* set up enough so that it can read an inode */ + exfat_hash_init(sb); + + /* + * The low byte of FAT's first entry must have same value with + * media-field. But in real world, too many devices is + * writing wrong value. So, removed that validity check. + * + * if (FAT_FIRST_ENT(sb, media) != first) + */ + + /* codepage is not meaningful in exfat */ + if (sbi->fs_info.vol_type != EXFAT) { + error = -EINVAL; + sprintf(buf, "cp%d", sbi->options.codepage); + sbi->nls_disk = load_nls(buf); + if (!sbi->nls_disk) { + printk(KERN_ERR "[EXFAT] Codepage %s not found\n", buf); + goto out_fail2; + } + } + + sbi->nls_io = load_nls(sbi->options.iocharset); + + error = -ENOMEM; + root_inode = new_inode(sb); + if (!root_inode) + goto out_fail2; + root_inode->i_ino = EXFAT_ROOT_INO; + SET_IVERSION(root_inode, 1); + + error = exfat_read_root(root_inode); + if (error < 0) + goto out_fail2; + error = -ENOMEM; + exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); + insert_inode_hash(root_inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + sb->s_root = d_make_root(root_inode); +#else + sb->s_root = d_alloc_root(root_inode); +#endif + if (!sb->s_root) { + printk(KERN_ERR "[EXFAT] Getting the root inode failed\n"); + goto out_fail2; + } + + return 0; + +out_fail2: + FsUmountVol(sb); +out_fail: + if (root_inode) + iput(root_inode); + sb->s_fs_info = NULL; + exfat_free_super(sbi); + return error; +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +static int exfat_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, exfat_fill_super, mnt); +} +#else +static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) { + return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); +} +#endif + +static void init_once(void *foo) +{ + struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; + + INIT_HLIST_NODE(&ei->i_hash_fat); + inode_init_once(&ei->vfs_inode); +} + +static int __init exfat_init_inodecache(void) +{ + exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", + sizeof(struct exfat_inode_info), + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), + init_once); + if (exfat_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + +static void __exit exfat_destroy_inodecache(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); +#endif + kmem_cache_destroy(exfat_inode_cachep); +} + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG +static void exfat_debug_kill_sb(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct block_device *bdev = sb->s_bdev; + + long flags; + + if (sbi) { + flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) { + /* invalidate_bdev drops all device cache include dirty. + we use this to simulate device removal */ + FsReleaseCache(sb); + invalidate_bdev(bdev); + } + } + + kill_block_super(sb); +} +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + +static struct file_system_type exfat_fs_type = { + .owner = THIS_MODULE, +#if defined(CONFIG_MACH_LGE) || defined(CONFIG_HTC_BATT_CORE) + .name = "texfat", +#else + .name = "exfat", +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + .get_sb = exfat_get_sb, +#else + .mount = exfat_fs_mount, +#endif +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + .kill_sb = exfat_debug_kill_sb, +#else + .kill_sb = kill_block_super, +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + .fs_flags = FS_REQUIRES_DEV, +}; + +static int __init init_exfat(void) +{ + int err; + + err = FsInit(); + if (err) { + if (err == FFS_MEMORYERR) + return -ENOMEM; + else + return -EIO; + } + + printk(KERN_INFO "exFAT: Version %s\n", EXFAT_VERSION); + + err = exfat_init_inodecache(); + if (err) + goto out; + + err = register_filesystem(&exfat_fs_type); + if (err) + goto out; + + return 0; +out: + FsShutdown(); + return err; +} + +static void __exit exit_exfat(void) +{ + exfat_destroy_inodecache(); + unregister_filesystem(&exfat_fs_type); + FsShutdown(); +} + +module_init(init_exfat); +module_exit(exit_exfat); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("exFAT Filesystem Driver"); +#ifdef MODULE_ALIAS_FS +#if defined(CONFIG_MACH_LGE) || defined(CONFIG_HTC_BATT_CORE) +MODULE_ALIAS_FS("texfat"); +#else +MODULE_ALIAS_FS("exfat"); +#endif +#endif diff --git a/code/driver/source/fs/exfat/exfat_super.h b/code/driver/source/fs/exfat/exfat_super.h new file mode 100755 index 000000000..46a26ba04 --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_super.h @@ -0,0 +1,173 @@ +/* Some of the source code in this file came from "linux/fs/fat/fat.h". */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _EXFAT_LINUX_H +#define _EXFAT_LINUX_H + +#include +#include +#include +#include +#include +#include + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_core.h" + +#define EXFAT_ERRORS_CONT 1 /* ignore error and continue */ +#define EXFAT_ERRORS_PANIC 2 /* panic on error */ +#define EXFAT_ERRORS_RO 3 /* remount r/o on error */ + +/* ioctl command */ +#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) + +struct exfat_mount_options { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + kuid_t fs_uid; + kgid_t fs_gid; +#else + uid_t fs_uid; + gid_t fs_gid; +#endif + unsigned short fs_fmask; + unsigned short fs_dmask; + unsigned short allow_utime; /* permission for setting the [am]time */ + unsigned short codepage; /* codepage for shortname conversions */ + int time_offset; /* Offset of timestamps from UTC (in minutes) */ + char *iocharset; /* charset for filename input/display */ + unsigned char casesensitive; + unsigned char errors; /* on error: continue, panic, remount-ro */ +#ifdef CONFIG_EXFAT_DISCARD + unsigned char discard; /* flag on if -o dicard specified and device support discard() */ +#endif /* CONFIG_EXFAT_DISCARD */ + unsigned tz_set:1; /* Filesystem timestamps' offset set */ +}; + +#define EXFAT_HASH_BITS 8 +#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS) + +/* + * EXFAT file system in-core superblock data + */ +struct exfat_sb_info { + FS_INFO_T fs_info; + BD_INFO_T bd_info; + + struct exfat_mount_options options; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + int s_dirt; + struct mutex s_lock; +#endif + struct nls_table *nls_disk; /* Codepage used on disk */ + struct nls_table *nls_io; /* Charset used for input and display */ + + struct inode *fat_inode; + + spinlock_t inode_hash_lock; + struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + long debug_flags; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ +}; + +/* + * EXFAT file system inode data in memory + */ +struct exfat_inode_info { + FILE_ID_T fid; + char *target; + /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ + loff_t mmu_private; /* physically allocated size */ + loff_t i_pos; /* on-disk position of directory entry or 0 */ + struct hlist_node i_hash_fat; /* hash by i_location */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + struct rw_semaphore truncate_lock; +#endif + struct inode vfs_inode; + struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ +}; + +#define EXFAT_SB(sb) ((struct exfat_sb_info *)((sb)->s_fs_info)) + +static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) +{ + return container_of(inode, struct exfat_inode_info, vfs_inode); +} + +/* + * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to + * save ATTR_RO instead of ->i_mode. + * + * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only + * bit, it's just used as flag for app. + */ +static inline int exfat_mode_can_hold_ro(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + if (S_ISDIR(inode->i_mode)) + return 0; + + if ((~sbi->options.fs_fmask) & S_IWUGO) + return 1; + return 0; +} + +/* Convert attribute bits and a mask to the UNIX mode. */ +static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, + u32 attr, mode_t mode) +{ + if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) + mode &= ~S_IWUGO; + + if (attr & ATTR_SUBDIR) + return (mode & ~sbi->options.fs_dmask) | S_IFDIR; + else if (attr & ATTR_SYMLINK) + return (mode & ~sbi->options.fs_dmask) | S_IFLNK; + else + return (mode & ~sbi->options.fs_fmask) | S_IFREG; +} + +/* Return the FAT attribute byte for this inode */ +static inline u32 exfat_make_attr(struct inode *inode) +{ + if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO)) + return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; + else + return EXFAT_I(inode)->fid.attr; +} + +static inline void exfat_save_attr(struct inode *inode, u32 attr) +{ + if (exfat_mode_can_hold_ro(inode)) + EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; + else + EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); +} + +#endif /* _EXFAT_LINUX_H */ diff --git a/code/driver/source/fs/exfat/exfat_upcase.c b/code/driver/source/fs/exfat/exfat_upcase.c new file mode 100755 index 000000000..3807f37ca --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_upcase.c @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_upcase.c */ +/* PURPOSE : exFAT Up-case Table */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" + +#include "exfat_nls.h" + +const u8 uni_upcase[NUM_UPCASE<<1] = { + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, + 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, + 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, + 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, + 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, + 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, + 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, + 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, + 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, + 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, + 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, + 0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, + 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, + 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, + 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, + 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, + 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, + 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, + 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, + 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00, + 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00, + 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, + 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00, + 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, + 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, + 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00, + 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00, + 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, + 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, + 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00, + 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01, + 0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01, + 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01, 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01, + 0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01, 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01, + 0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01, + 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01, 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01, + 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01, 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01, + 0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01, + 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01, 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01, + 0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01, 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01, + 0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01, + 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01, 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01, + 0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01, 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01, + 0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01, + 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01, 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01, + 0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01, 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01, + 0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01, + 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01, 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01, + 0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01, 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01, + 0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01, + 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01, 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01, + 0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01, 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01, + 0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01, + 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01, 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01, + 0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01, 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01, + 0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01, + 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01, 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01, + 0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01, 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01, + 0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01, + 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01, 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01, + 0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01, 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01, + 0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01, + 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02, + 0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02, 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02, + 0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02, + 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02, 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02, + 0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02, 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02, + 0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02, + 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02, 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02, + 0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02, 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02, + 0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02, + 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02, 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02, + 0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01, 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01, + 0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02, + 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01, 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, + 0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C, 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01, + 0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02, + 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02, 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02, + 0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02, + 0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02, + 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02, 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, + 0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02, 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02, + 0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02, + 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02, 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02, + 0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02, 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02, + 0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02, + 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02, 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02, + 0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02, 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02, + 0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02, + 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02, 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02, + 0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02, 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02, + 0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02, + 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02, 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02, + 0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02, 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03, + 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03, 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03, + 0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03, 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03, + 0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03, + 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03, 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03, + 0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03, 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03, + 0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03, + 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03, 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03, + 0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03, 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03, + 0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03, + 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03, 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03, + 0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03, 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03, + 0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03, + 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03, 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03, + 0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03, 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03, + 0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03, + 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03, 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03, + 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03, 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03, + 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, + 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, + 0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, + 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, + 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, + 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, + 0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, + 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03, + 0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03, 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03, + 0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03, + 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03, 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03, 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03, + 0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03, + 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03, 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, + 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, + 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, + 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, + 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, + 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, + 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, + 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, + 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, + 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, + 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, + 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, + 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, + 0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04, 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04, + 0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04, + 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04, 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04, + 0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04, 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04, + 0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04, + 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04, 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04, + 0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04, 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04, + 0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04, + 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04, 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04, + 0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04, 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04, + 0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04, + 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04, + 0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04, 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04, + 0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04, + 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04, 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04, + 0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04, 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04, + 0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04, + 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04, + 0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04, 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04, + 0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04, + 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05, 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05, + 0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05, + 0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05, + 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05, 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05, + 0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05, 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05, + 0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05, + 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, + 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, + 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, + 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, + 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05, + 0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05, + 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, + 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, + 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, + 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, + 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF, + 0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D, + 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D, 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D, + 0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D, 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D, + 0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D, + 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D, 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D, + 0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D, 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D, + 0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D, + 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D, 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D, + 0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D, 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D, + 0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D, + 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D, 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D, + 0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D, 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D, + 0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D, + 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D, 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D, + 0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D, 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D, + 0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D, + 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D, 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, + 0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E, 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E, + 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E, 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E, + 0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E, + 0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E, + 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E, 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E, + 0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E, 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E, + 0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E, + 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E, 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E, + 0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E, 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E, + 0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E, + 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E, 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E, + 0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E, 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E, + 0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E, + 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E, + 0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E, 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E, + 0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E, + 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E, 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E, + 0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E, 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E, + 0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E, + 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E, 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E, + 0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E, 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E, + 0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E, + 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E, 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E, + 0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E, 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E, + 0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E, + 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E, 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E, + 0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E, 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E, + 0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E, + 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E, + 0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E, 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E, + 0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, + 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, + 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, + 0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, + 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, + 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, + 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, + 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, + 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, + 0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, + 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F, 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F, + 0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F, 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F, + 0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, + 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, + 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, + 0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, + 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, + 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, + 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, + 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, + 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, + 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, + 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F, + 0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, + 0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F, + 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F, + 0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F, + 0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, + 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F, + 0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, + 0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F, + 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, + 0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20, + 0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20, + 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20, 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20, + 0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20, + 0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20, + 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20, 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20, + 0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20, + 0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20, + 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20, 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20, + 0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20, 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20, + 0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20, + 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20, 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20, + 0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20, 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20, + 0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20, + 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20, 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20, + 0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20, 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20, + 0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20, + 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20, + 0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20, 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20, + 0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20, + 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20, 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20, + 0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20, 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20, + 0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20, + 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20, 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20, + 0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20, 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20, + 0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20, + 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20, 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20, + 0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20, 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20, + 0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20, + 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20, 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20, + 0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20, 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20, + 0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20, + 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20, 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21, + 0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21, 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21, + 0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21, + 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21, 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21, + 0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21, + 0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21, + 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21, 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21, + 0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21, 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21, + 0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21, + 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21, 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21, + 0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21, 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21, + 0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21, + 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, + 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, + 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, + 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, + 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21, + 0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24, + 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24, 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24, + 0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24, 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24, + 0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C, + 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C, 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C, + 0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C, 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C, + 0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C, + 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C, 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C, + 0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C, 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C, + 0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C, + 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C, 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C, + 0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C, 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C, + 0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C, + 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C, 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C, + 0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C, 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C, + 0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C, + 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C, 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C, + 0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C, 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C, + 0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C, + 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C, 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C, + 0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C, 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C, + 0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C, + 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C, 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C, + 0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C, 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C, + 0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C, + 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C, 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C, + 0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C, 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C, + 0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C, + 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C, 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C, + 0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C, 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10, + 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, + 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, + 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, + 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, + 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF, + 0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF, 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF, + 0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF, + 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF, 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF, + 0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF, 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF, + 0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF, + 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF, 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF, + 0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF, 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF, + 0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF, + 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF, 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF, + 0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF, 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF, + 0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF, + 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF, + 0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF, 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF, + 0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF, + 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF, 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, + 0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF, 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF, + 0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF, + 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF, + 0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF, + 0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF, + 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF, + 0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, + 0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, + 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF +}; diff --git a/code/driver/source/fs/exfat/exfat_version.h b/code/driver/source/fs/exfat/exfat_version.h new file mode 100755 index 000000000..a93fa46be --- /dev/null +++ b/code/driver/source/fs/exfat/exfat_version.h @@ -0,0 +1,19 @@ +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_version.h */ +/* PURPOSE : exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY */ +/* */ +/* - 2012.02.10 : Release Version 1.1.0 */ +/* - 2012.04.02 : P1 : Change Module License to Samsung Proprietary */ +/* - 2012.06.07 : P2 : Fixed incorrect filename problem */ +/* */ +/************************************************************************/ + +#define EXFAT_VERSION "1.2.9" diff --git a/code/lib/external/Makefile b/code/lib/external/Makefile index 0ced0a06a..3e9cdcd2a 100755 --- a/code/lib/external/Makefile +++ b/code/lib/external/Makefile @@ -6,7 +6,7 @@ INSTALL_DIR =${EXTLIB}/__install #MAKEFILE_LIST = freetype libnl openssl # openssl for tee MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo) -MAKEFILE_LIST = openssl libnl +MAKEFILE_LIST = openssl libnl exfat-utils XML2 := libxml2-2.9.3 @@ -19,6 +19,7 @@ FFMPEG := ffmpeg-3.0 LIBNL := libnl-3.2.27 OPENSSL := openssl-1.0.2d CURL := curl-7.45.0 +EXFAT_UTILS := exfat-utils-1.2.7 unexport CC unexport CPP @@ -164,6 +165,17 @@ endif @rm -rf ${INSTALL_DIR}/lib/pkgconfig @echo $(NVT_CURL_SSL) > ${CURL}/.nvt_finish +exfat-utils: init + @echo ">>>>>>>>>>>>>>>>>>> $@ compiling >>>>>>>>>>>>>>>>>>>" + @if [ ! -f ${EXFAT_UTILS}/.nvt_finish ]; then \ + $(call check_exist, ${EXFAT_UTILS}); \ + cd ${EXFAT_UTILS}; ./configure --host=${NVT_HOST} --prefix=${EXTERNAL}/${INSTALL_DIR}; make; \ + fi + @mkdir -p ${EXTERNAL}/${INSTALL_DIR}/sbin/; + @cd ${EXFAT_UTILS}; cp -f ./mkfs/mkexfatfs ${ROOTFS_DIR}/rootfs/sbin/; + @${CROSS_COMPILE}strip ${ROOTFS_DIR}/rootfs/sbin/mkexfatfs; + @touch ${EXFAT_UTILS}/.nvt_finish + install: @echo ">>>>>>>>>>>>>>>>>>> $@ >>>>>>>>>>>>>>>>>>>" @if [ -x ${INSTALL_DIR}/include ]; then \ @@ -181,4 +193,4 @@ install: clean: @echo ">>>>>>>>>>>>>>>>>>> Remove >>>>>>>>>>>>>>>>>>>" @rm -rf ${INSTALL_DIR} - @rm -rf ${XML2} ${AXTLS} ${FUSE} ${FREETYPE} ${FFMPEG} ${LIBNL} ${SQLITE3} ${OPENSSL} ${CURL} ${UNWIND} ${LIBP11} + @rm -rf ${XML2} ${AXTLS} ${FUSE} ${FREETYPE} ${FFMPEG} ${LIBNL} ${SQLITE3} ${OPENSSL} ${CURL} ${UNWIND} ${LIBP11} ${EXFAT_UTILS} diff --git a/configs/Linux/cfg_565_HUNTING_EVB_LINUX_4G_S550/make_post.sh b/configs/Linux/cfg_565_HUNTING_EVB_LINUX_4G_S550/make_post.sh index 5ef61d24f..6d69af810 100755 --- a/configs/Linux/cfg_565_HUNTING_EVB_LINUX_4G_S550/make_post.sh +++ b/configs/Linux/cfg_565_HUNTING_EVB_LINUX_4G_S550/make_post.sh @@ -102,6 +102,7 @@ MV_KO_LIST=(\ /lib/modules/$KERVER/kernel/drivers/usb/serial/option.ko \ /lib/modules/$KERVER/kernel/drivers/usb/class/cdc-wdm.ko \ /lib/modules/$KERVER/kernel/drivers/net/usb/qmi_wwan.ko \ +/lib/modules/$KERVER/extra/fs/exfat/exfat.ko \ ) diff --git a/rtos/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c b/rtos/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c index e96ff6893..fdb3192a5 100644 --- a/rtos/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c +++ b/rtos/code/application/source/cardv/SrcCode/System/SysStrg_Exe.c @@ -343,8 +343,8 @@ void System_OnStrgInit_FS(void) GxStrg_SetConfigEx(0, FILE_CFG_MAX_OPEN_FILE, 10); #endif // support exFAT -// GxStrg_SetConfigEx(0, FILE_CFG_SUPPORT_EXFAT, TRUE); - GxStrg_SetConfigEx(0, FILE_CFG_SUPPORT_EXFAT, FALSE); + GxStrg_SetConfigEx(0, FILE_CFG_SUPPORT_EXFAT, TRUE); + // GxStrg_SetConfigEx(0, FILE_CFG_SUPPORT_EXFAT, FALSE); // mount path strncpy(mount_path, "/mnt/sd", sizeof(mount_path) - 1); mount_path[sizeof(mount_path) - 1] = '\0'; From 0d75e82d10e7070123a8eb89ec397a36e2d781d1 Mon Sep 17 00:00:00 2001 From: payton Date: Thu, 23 Nov 2023 15:48:05 +0800 Subject: [PATCH 3/5] =?UTF-8?q?1.exfat=E5=B7=A5=E5=85=B7=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/.gitignore | 4 +++- code/lib/external/exfat-utils-1.2.7.tar.bz2 | Bin 0 -> 116939 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100755 code/lib/external/exfat-utils-1.2.7.tar.bz2 diff --git a/code/.gitignore b/code/.gitignore index f3e741557..ccbdffa53 100644 --- a/code/.gitignore +++ b/code/.gitignore @@ -1,6 +1,8 @@ **/*.o **/*.nvt_finish -lib/external +lib/external/openssl-1.0.2d +lib/external/libnl-3.2.27 +lib/external/exfat-utils-1.2.7 lib/source/lvgl/liblvgl.a lib/source/lvgl/liblvgl.so lib/source/nvtlibc/libnvtlibc.a diff --git a/code/lib/external/exfat-utils-1.2.7.tar.bz2 b/code/lib/external/exfat-utils-1.2.7.tar.bz2 new file mode 100755 index 0000000000000000000000000000000000000000..4e7994180e1da623170530f2d6e07e8b769f661c GIT binary patch literal 116939 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 Gg8$$jG{SBG literal 0 HcmV?d00001 From 0c835f714dc9a259c57c55f14d833d417ad1cdf2 Mon Sep 17 00:00:00 2001 From: payton Date: Fri, 24 Nov 2023 10:11:05 +0800 Subject: [PATCH 4/5] =?UTF-8?q?1.=E4=BF=AE=E5=A4=8D=E6=8F=92=E5=85=A5usb?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../source/cardv/SrcCode/System/SysUsb_Exe.c | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/code/application/source/cardv/SrcCode/System/SysUsb_Exe.c b/code/application/source/cardv/SrcCode/System/SysUsb_Exe.c index f34c55fd9..c17b7b835 100755 --- a/code/application/source/cardv/SrcCode/System/SysUsb_Exe.c +++ b/code/application/source/cardv/SrcCode/System/SysUsb_Exe.c @@ -72,6 +72,7 @@ static BOOL System_WaitUsbDev(void) break; vos_util_delay_ms(10); + cnt++; } while(cnt < timeout); if(exit_code == 0) @@ -103,6 +104,22 @@ static BOOL System_check_usb_host(void) } } +static BOOL System_check_usb_dev(void) +{ + char command[26] = "lsmod | grep nvt_usb2dev"; + FILE *fp = popen(command, "r"); + char result[256]; + fgets(result, sizeof(result), fp); + pclose(fp); + if (result[0] == '\0') { + printf("nvt_usb2dev module is not loaded.\n"); + return FALSE; + } else { + printf("nvt_usb2dev module is loaded.\n"); + return TRUE; + } +} + static BOOL System_InsmodUsb(BOOL isHost) { char** usb_drivers = NULL; @@ -178,13 +195,13 @@ static BOOL System_RmmodUsb(BOOL isHost) if(isHost){ - if(is_usb_host_driver_inserted == FALSE) + if(System_check_usb_host() == FALSE) return TRUE; usb_drivers = usb_host_drivers; } else{ - if(is_usb_dev_driver_inserted == FALSE) + if(System_check_usb_dev() == FALSE) return TRUE; usb_drivers = usb_dev_drivers; From d377144dc936636990ab2671518931bef1d47efd Mon Sep 17 00:00:00 2001 From: payton Date: Fri, 24 Nov 2023 10:12:47 +0800 Subject: [PATCH 5/5] =?UTF-8?q?1.=E4=B8=AD=E9=97=B4=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/.gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/.gitignore b/code/.gitignore index ccbdffa53..388accd27 100644 --- a/code/.gitignore +++ b/code/.gitignore @@ -3,7 +3,9 @@ lib/external/openssl-1.0.2d lib/external/libnl-3.2.27 lib/external/exfat-utils-1.2.7 +lib/external/__install lib/source/lvgl/liblvgl.a lib/source/lvgl/liblvgl.so lib/source/nvtlibc/libnvtlibc.a -lib/source/nvtlibc/libnvtlibc.so \ No newline at end of file +lib/source/nvtlibc/libnvtlibc.so +driver/source/fs/exfat/.exfat_api.o.d \ No newline at end of file