ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/uboot/fs/tffs/dirent.c b/marvell/uboot/fs/tffs/dirent.c
new file mode 100755
index 0000000..07c5ca9
--- /dev/null
+++ b/marvell/uboot/fs/tffs/dirent.c
@@ -0,0 +1,656 @@
+/*
+ * dirent.c
+ *
+ * Include functions implementing directory entry.
+ * implementation file.
+ *
+ * Copyright (C) knightray@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include "dirent.h"
+#include "debug.h"
+#include "fat.h"
+#include "common.h"
+#include "dir.h"
+
+#ifndef DBG_DIRENT
+#undef DBG
+#define DBG nulldbg
+#endif
+
+/* Private routins declaration. */
+
+static int32
+_get_dirent(
+ IN tdir_t * pdir,
+ OUT dir_entry_t * pdirent
+);
+
+static void
+_parse_file_name(
+ IN tdir_t * pdir,
+ IN dir_entry_t * pdirent,
+ OUT tdir_entry_t * pdir_entry
+);
+
+static BOOL
+_get_long_file_name(
+ IN dir_entry_t * pdirent,
+ OUT byte * long_name
+);
+
+static BOOL
+_convert_short_fname(
+ IN ubyte * dir_name,
+ OUT byte * d_name
+);
+
+static BOOL
+_convert_to_short_fname(
+ IN byte * fname,
+ OUT ubyte * short_fname
+);
+
+static ubyte
+_get_check_sum(
+ IN ubyte * fname
+);
+
+/*----------------------------------------------------------------------------------------------------*/
+
+int32
+dirent_find(
+ IN tdir_t * pdir,
+ IN byte * dirname,
+ OUT tdir_entry_t * pdir_entry)
+{
+ int32 ret;
+
+ pdir->cur_clus = pdir->start_clus;
+ pdir->cur_sec = 0;
+ pdir->cur_dir_entry = 0;
+ if (dir_read_sector(pdir) != DIR_OK)
+ return ERR_DIRENTRY_NOT_FOUND;
+
+ ASSERT(pdir_entry->pdirent == NULL);
+ ret = DIRENTRY_OK;
+
+ while(1) {
+ dir_entry_t dirent;
+
+ if ((ret = _get_dirent(pdir, &dirent)) == DIRENTRY_OK) {
+
+ if (dirent.dir_name[0] == 0x00) {
+ ret = ERR_DIRENTRY_NOT_FOUND;
+ break;
+ }
+ else if (dirent.dir_name[0] == 0xE5) {
+ //FixMe do with 0x5
+ continue;
+ }
+
+ Memset(pdir_entry->long_name, 0, LONG_NAME_LEN);
+ Memset(pdir_entry->short_name, 0, SHORT_NAME_LEN);
+ _parse_file_name(pdir, &dirent, pdir_entry);
+
+ if (!Strcmp(pdir_entry->long_name, dirname)) {
+ break;
+ }
+ }
+ else if (ret == ERR_DIRENTRY_NOMORE_ENTRY){
+ ret = ERR_DIRENTRY_NOT_FOUND;
+ break;
+ }
+ else {
+ ret = ERR_DIRENTRY_DEVICE_FAIL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+BOOL
+dirent_is_empty(
+ IN tdir_t * pdir)
+{
+ BOOL ret;
+ tdir_entry_t * pdir_entry;
+
+ pdir->cur_clus = pdir->start_clus;
+ pdir->cur_sec = 0;
+ pdir->cur_dir_entry = 0;
+ if (dir_read_sector(pdir) != DIR_OK)
+ return ERR_DIRENTRY_NOT_FOUND;
+
+ pdir_entry = dirent_malloc();
+ ASSERT(pdir_entry->pdirent == NULL);
+ ret = TRUE;
+
+ while(1) {
+ dir_entry_t dirent;
+
+ if ((ret = _get_dirent(pdir, &dirent)) == DIRENTRY_OK) {
+
+ if (dirent.dir_name[0] == 0x00) {
+ break;
+ }
+ else if (dirent.dir_name[0] == 0xE5) {
+ //FixMe do with 0x5
+ continue;
+ }
+
+ Memset(pdir_entry->long_name, 0, LONG_NAME_LEN);
+ Memset(pdir_entry->short_name, 0, SHORT_NAME_LEN);
+ _parse_file_name(pdir, &dirent, pdir_entry);
+
+ if (!Strcmp(pdir_entry->long_name, ".") || !Strcmp(pdir_entry->long_name, "..")) {
+ continue;
+ }
+ else {
+ ret = FALSE;
+ break;
+ }
+ }
+ else if (ret == ERR_DIRENTRY_NOMORE_ENTRY){
+ break;
+ }
+ else {
+ ERR("%s(): get next direntry failed. ret = %d\n", __FUNCTION__, ret);
+ ret = FALSE;
+ break;
+ }
+ }
+
+ dirent_release(pdir_entry);
+ return ret;
+}
+
+/* Marvell fixed: when a new cluster is being allocated to a directory
+ the contents of all dirent's should be 0 */
+static void
+dirent_clear_new_cluster(tdir_t *pdir)
+{
+ Memset(pdir->secbuf, 0, pdir->ptffs->pbs->byts_per_sec);
+ for (pdir->cur_sec = 0;
+ pdir->cur_sec < pdir->ptffs->pbs->sec_per_clus;
+ pdir->cur_sec++)
+ if (dir_write_sector(pdir) != DIR_OK)
+ break;
+ pdir->cur_sec = 0;
+ pdir->cur_dir_entry = 0;
+ /* Leave secbuf as is, so no need to read it again */
+}
+
+/* Marvell fixed: when a new entry is appended at the end of a directory,
+all the entries should be allocated in the same sector, as they are later
+accessed in the sector buffer. This function:
+- checks if the required number of entries (dirent_num) is available;
+- otherwise, pads the current sector with E5 (deleted) entries,
+ and lets the search continue into the following sector. */
+static int32 dirent_space_check_extend(tdir_t *pdir, int32 dirent_num)
+{
+ int32 nent = pdir->ptffs->pbs->byts_per_sec / sizeof(dir_entry_t);
+ dir_entry_t *pde = (dir_entry_t *)pdir->secbuf;
+ int32 i, n0, ne5;
+ for (i = n0 = ne5 = 0; i < nent; i++) {
+ unsigned char c = pde[i].dir_name[0];
+ if (n0)
+ ASSERT(c == 0);
+ if (c == 0)
+ n0++;
+ else if (c == 0xE5)
+ ne5++;
+ else
+ n0 = ne5 = 0;
+ if ((n0 + ne5) == dirent_num) {
+ pdir->cur_dir_entry = i + 1 - dirent_num;
+ return DIRENTRY_OK;
+ }
+ }
+
+ /* not found the free entry sequence in this sector */
+ if (n0) {
+ /* replace 0 entries with E5 as dir continues to next sector */
+ for (i = nent - n0; i < nent; i++)
+ pde[i].dir_name[0] = 0xE5;
+ if (dir_write_sector(pdir) != DIR_OK)
+ return ERR_DIRENTRY_DEVICE_FAIL;
+ }
+ pdir->cur_dir_entry = nent; /* sector ended */
+ return ERR_DIRENTRY_NOMORE_ENTRY;
+}
+
+int32
+dirent_find_free_entry(
+ IN tdir_t * pdir,
+ IN tdir_entry_t * pdir_entry)
+{
+ int32 ret;
+ tffs_t * ptffs = pdir->ptffs;
+
+ ret = DIRENTRY_OK;
+
+ while(1) {
+ dir_entry_t dirent;
+
+ if ((ret = _get_dirent(pdir, &dirent)) == DIRENTRY_OK) {
+ /* Marvell fixed: revised search for free entries */
+ if (dirent_space_check_extend(pdir, pdir_entry->dirent_num) == DIRENTRY_OK)
+ break; /* enough free entries in this sector */
+ }
+ else if (ret == ERR_DIRENTRY_NOMORE_ENTRY) {
+ uint32 new_clus;
+
+ if (dir_write_sector(pdir) != DIR_OK) {
+ ret = ERR_DIRENTRY_DEVICE_FAIL;
+ break;
+ }
+ if ((ret = fat_malloc_clus(ptffs->pfat, pdir->cur_clus, &new_clus)) == FAT_OK) {
+ pdir->cur_clus = new_clus;
+ pdir->cur_sec = 0;
+ pdir->cur_dir_entry = 0;
+ /* Marvell fixed: zero the new cluster */
+ dirent_clear_new_cluster(pdir);
+ }
+ else {
+ ret = ERR_DIRENTRY_NOMORE_ENTRY;
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int32
+dirent_get_next(
+ IN tdir_t * pdir,
+ OUT tdir_entry_t * pdir_entry)
+{
+ int32 ret;
+
+ ret = DIRENTRY_OK;
+
+ while(1) {
+ dir_entry_t dirent;
+
+ //print_sector(pdir->secbuf, 1);
+ DBG("%s():pdir->cur_clus = %d, pdir->cur_dir_entry = %d\n", __FUNCTION__, pdir->cur_clus, pdir->cur_dir_entry);
+ if ((ret = _get_dirent(pdir, &dirent)) == DIRENTRY_OK) {
+
+ if (dirent.dir_name[0] == 0x00) {
+ ret = ERR_DIRENTRY_NOMORE_ENTRY;
+ break;
+ }
+ else if (dirent.dir_name[0] == 0xE5) {
+ //FixMe do with 0x5
+ continue;
+ }
+
+ Memset(pdir_entry->long_name, 0, LONG_NAME_LEN);
+ Memset(pdir_entry->short_name, 0, SHORT_NAME_LEN);
+ _parse_file_name(pdir, &dirent, pdir_entry);
+
+ break;
+ }
+ else {
+ break;
+ }
+ }
+ return ret;
+}
+
+void
+dirent_release(
+ IN tdir_entry_t * pdir_entry)
+{
+ Free(pdir_entry->pdirent);
+ Free(pdir_entry);
+}
+
+tdir_entry_t *
+dirent_malloc()
+{
+ tdir_entry_t * pdir_entry;
+
+ pdir_entry = (tdir_entry_t *)Malloc(sizeof(tdir_entry_t));
+ Memset(pdir_entry, 0, sizeof(tdir_entry_t));
+ return pdir_entry;
+}
+
+BOOL
+dirent_init(
+ IN byte * fname,
+ IN ubyte dir_attr,
+ IN byte use_long_name,
+ OUT tdir_entry_t * pdir_entry)
+{
+ long_dir_entry_t * plfent;
+ dir_entry_t * pdirent;
+ uint32 lfent_num;
+ int32 lfent_i;
+ byte * pfname;
+
+ if (Strlen(fname) > LONG_NAME_LEN ||
+ (!use_long_name && Strlen(fname) > SHORT_NAME_LEN))
+ return FALSE;
+
+ if (use_long_name) {
+ lfent_num = Strlen(fname) / 13 + 2;
+ }
+ else {
+ lfent_num = 1;
+ }
+
+ pfname = fname;
+
+ plfent = (long_dir_entry_t *)Malloc(sizeof(long_dir_entry_t) * lfent_num);
+ Memset(plfent, 0, sizeof(long_dir_entry_t) * lfent_num);
+ pdirent = (dir_entry_t *)(&plfent[lfent_num - 1]);
+
+ _convert_to_short_fname(fname, pdirent->dir_name);
+ DBG("%s(): %s=>%s\n", __FUNCTION__, fname, pdirent->dir_name);
+ pdirent->dir_attr = dir_attr;
+ pdirent->dir_ntres = 0;
+ pdirent->dir_crt_time_tenth = dirent_get_cur_time_tenth();
+ pdirent->dir_crt_time = dirent_get_cur_time();
+ pdirent->dir_crt_date = dirent_get_cur_date();
+ pdirent->dir_lst_acc_date = pdirent->dir_crt_date;
+ pdirent->dir_wrt_time = pdirent->dir_crt_time;
+ pdirent->dir_wrt_date = pdirent->dir_crt_date;
+ pdirent->dir_fst_clus_hi = 0;
+ pdirent->dir_fst_clus_lo = 0;
+ pdirent->dir_file_size = 0;
+
+ if (use_long_name) {
+ for (lfent_i = lfent_num - 2; lfent_i >= 0; lfent_i--) {
+ ubyte fname_line[13];
+
+ Memset(fname_line, 0xFF, 13);
+ Memcpy(fname_line, pfname, min(fname + Strlen(fname) - pfname + 1, 13));
+
+ if (lfent_i == 0) {
+ plfent[lfent_i].ldir_ord = (lfent_num - 1 - lfent_i) | LAST_LONG_ENTRY;
+ }
+ else {
+ plfent[lfent_i].ldir_ord = lfent_num - 1 - lfent_i;
+ }
+ copy_to_unicode(fname_line, 5, plfent[lfent_i].ldir_name1);
+ copy_to_unicode(fname_line + 5, 6, plfent[lfent_i].ldir_name2);
+ copy_to_unicode(fname_line + 11, 2, plfent[lfent_i].ldir_name3);
+ pfname += 13;
+
+ plfent[lfent_i].ldir_attr = ATTR_LONG_NAME;
+ plfent[lfent_i].ldir_type = 0;
+ plfent[lfent_i].ldir_chksum = _get_check_sum(pdirent->dir_name);
+ plfent[lfent_i].ldir_fst_clus_lo = 0;
+ }
+ }
+
+ pdir_entry->pdirent = (dir_entry_t *)plfent;
+ pdir_entry->dirent_num = lfent_num;
+ Strcpy(pdir_entry->long_name, fname);
+ _convert_short_fname(pdirent->dir_name, pdir_entry->short_name);
+
+ return TRUE;
+}
+
+uint16
+dirent_get_cur_time()
+{
+ tffs_sys_time_t curtm;
+ uint16 ret;
+
+ Getcurtime(&curtm);
+
+ ret = 0;
+ ret |= (curtm.tm_sec >> 2) & 0x1F;
+ ret |= (curtm.tm_min << 5) & 0x7E0;
+ ret |= (curtm.tm_hour << 11) & 0xF800;
+
+ return ret;
+}
+
+uint16
+dirent_get_cur_date()
+{
+ tffs_sys_time_t curtm;
+ uint16 ret;
+
+ Getcurtime(&curtm);
+
+ ret = 0;
+ ret |= (curtm.tm_mday) & 0x1F;
+ ret |= ((curtm.tm_mon + 1) << 5) & 0x1E0;
+ ret |= ((curtm.tm_year - 80) << 9) & 0xFE00;
+
+ return ret;
+}
+
+ubyte
+dirent_get_cur_time_tenth()
+{
+ tffs_sys_time_t curtm;
+ uint16 ret;
+
+ Getcurtime(&curtm);
+
+ ret = (curtm.tm_sec & 1) == 0 ? 0 : 100;
+ return ret;
+}
+
+/*----------------------------------------------------------------------------------------------------*/
+
+static int32
+_get_dirent(
+ IN tdir_t * pdir,
+ OUT dir_entry_t * pdirent)
+{
+ int32 ret;
+
+ ret = DIRENTRY_OK;
+
+ if (pdir->cur_dir_entry <
+ (pdir->ptffs->pbs->byts_per_sec / sizeof(dir_entry_t))) {
+ Memcpy(pdirent, (dir_entry_t *)pdir->secbuf + pdir->cur_dir_entry, sizeof(dir_entry_t));
+ pdir->cur_dir_entry++;
+ }
+ else {
+ if (fat_get_next_sec(pdir->ptffs->pfat, &pdir->cur_clus, &pdir->cur_sec)) {
+ pdir->cur_dir_entry = 0;
+ if ((ret = dir_read_sector(pdir)) == DIR_OK) {
+ Memcpy(pdirent, (dir_entry_t *)pdir->secbuf + pdir->cur_dir_entry, sizeof(dir_entry_t));
+ pdir->cur_dir_entry++;
+ }
+ else {
+ ret = ERR_DIRENTRY_DEVICE_FAIL;
+ }
+ }
+ else {
+ ret = ERR_DIRENTRY_NOMORE_ENTRY;
+ }
+ }
+
+ return ret;
+}
+
+static void
+_parse_file_name(
+ IN tdir_t * pdir,
+ IN dir_entry_t * pdirent,
+ OUT tdir_entry_t * pdir_entry)
+{
+ int32 lf_entry_num;
+
+ /*
+ * Marvell fixed: pdir_entry->pdirent is allocated below, while
+ * the function is called in a loop, e.g. in dirent_find(), so
+ * the previously allocated memory should be released to prevent
+ * a memory leak: with a lot of files in the working dir, searches
+ * exhausted the heap and following allocations failed.
+ */
+ if (pdir_entry->pdirent) {
+ /* This is 0 after dirent_init() unless object re-used */
+ Free(pdir_entry->pdirent);
+ pdir_entry->pdirent = NULL;
+ }
+ lf_entry_num = 0;
+ /* Marvell fixed: was "& ATTR_LONG_NAME", however one of the bits
+ is ATTR_VOLUME_ID, which alone indicates a volume id, short */
+ if (pdirent->dir_attr == ATTR_LONG_NAME) {
+ uint32 lf_i;
+ dir_entry_t dirent;
+
+ lf_entry_num = pdirent->dir_name[0] & ~(LAST_LONG_ENTRY);
+ pdir_entry->pdirent = (dir_entry_t *)Malloc((lf_entry_num + 1) * sizeof(dir_entry_t));
+
+ _get_long_file_name(pdirent, pdir_entry->long_name + (lf_entry_num - 1) * 13);
+ Memcpy(pdir_entry->pdirent, pdirent, sizeof(dir_entry_t));
+
+ for (lf_i = 1; lf_i < lf_entry_num; lf_i++) {
+ _get_dirent(pdir, &dirent);
+ Memcpy(pdir_entry->pdirent + lf_i, &dirent, sizeof(dir_entry_t));
+ _get_long_file_name(&dirent, pdir_entry->long_name + (lf_entry_num - lf_i - 1) * 13);
+ }
+
+ _get_dirent(pdir, &dirent);
+ Memcpy(pdir_entry->pdirent + lf_i, &dirent, sizeof(dir_entry_t));
+ }
+ else {
+ pdir_entry->pdirent = (dir_entry_t *)Malloc(sizeof(dir_entry_t));
+
+ _convert_short_fname(pdirent->dir_name, pdir_entry->long_name);
+ Memcpy(pdir_entry->pdirent, pdirent, sizeof(dir_entry_t));
+ }
+
+ _convert_short_fname(pdirent->dir_name, pdir_entry->short_name);
+ pdir_entry->dirent_num = lf_entry_num + 1;
+}
+
+static ubyte
+_get_check_sum(
+ IN ubyte * fname)
+{
+ int16 fname_len;
+ ubyte sum;
+
+ sum = 0;
+ for (fname_len = 11; fname_len != 0; fname_len--) {
+ sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *fname++;
+ }
+ return sum;
+}
+
+static BOOL
+_convert_to_short_fname(
+ IN byte * fname,
+ OUT ubyte * short_fname)
+{
+ byte * pfname;
+ byte * pcur;
+ uint16 sf_i;
+ static uint16 num_tail = 0;
+
+ for (sf_i = 0; sf_i < 11; sf_i++)
+ short_fname[sf_i] = ' ';
+
+ if (!Strcmp(fname, ".") || !Strcmp(fname, "..")) {
+ /* Marvell fixed: names should not be 0-terminated */
+ Memcpy((byte *)short_fname, fname, Strlen(fname));
+ return TRUE;
+ }
+
+ pfname = dup_string(fname);
+ pcur = pfname;
+ sf_i = 0;
+
+ trip_blanks(pfname);
+
+ while (sf_i < 8) {
+ if (*pcur == '\0' || *pcur == '.') {
+ break;
+ }
+ short_fname[sf_i++] = Toupper(*pcur++);
+ }
+
+ if (*pcur == '.') {
+ pcur++;
+ }
+ else {
+ if (*pcur != '\0') {
+ byte str_tail[8];
+
+ while(*pcur && *pcur != '.')
+ pcur++;
+
+ if (*pcur == '.')
+ pcur++;
+
+ Sprintf(str_tail, "~%d", num_tail++);
+ Memcpy(short_fname + (8 - Strlen(str_tail)), str_tail, Strlen(str_tail));
+
+ if (*pcur == '\0')
+ goto _release;
+ }
+ }
+
+ sf_i = 8;
+
+ while (sf_i < 11) {
+ if (*pcur == '\0')
+ break;
+ short_fname[sf_i++] = Toupper(*pcur++);
+ }
+
+_release:
+ Free(pfname);
+ return TRUE;
+}
+
+static BOOL
+_get_long_file_name(
+ IN dir_entry_t * pdirent,
+ OUT byte * long_name)
+{
+ long_dir_entry_t * pldirent;
+
+ pldirent = (long_dir_entry_t *)pdirent;
+
+ copy_from_unicode(pldirent->ldir_name1, 5, long_name);
+ copy_from_unicode(pldirent->ldir_name2, 6, long_name + 5);
+ copy_from_unicode(pldirent->ldir_name3, 2, long_name + 11);
+ return TRUE;
+}
+
+static BOOL
+_convert_short_fname(
+ IN ubyte * dir_name,
+ OUT byte * d_name)
+{
+ uint32 i;
+
+ Memset(d_name, 0, 11);
+ for (i = 0; i < 8; i++) {
+ if (dir_name[i] == ' ')
+ break;
+ d_name[i] = dir_name[i];
+ }
+
+ if (dir_name[8] != ' ') {
+ uint32 j;
+
+ d_name[i++] = '.';
+ for (j = 0; j < 3; j++) {
+ if (dir_name[8 + j] == ' ')
+ break;
+ d_name[i + j] = dir_name[8 + j];
+ }
+ }
+ return TRUE;
+}
+