ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/lte-telephony/apps/NVM_Proxy/source/NVMFileOps.c b/marvell/lte-telephony/apps/NVM_Proxy/source/NVMFileOps.c
new file mode 100644
index 0000000..a12f27f
--- /dev/null
+++ b/marvell/lte-telephony/apps/NVM_Proxy/source/NVMFileOps.c
@@ -0,0 +1,950 @@
+/******************************************************************************
+*(C) Copyright 2011 Marvell International Ltd.
+* All Rights Reserved
+******************************************************************************/
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <sys/stat.h>
+#include <libgen.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <unistd.h>
+#include "NVMFileOps.h"
+#include "NVMServer_defs.h"
+#include "pxa_dbg.h"
+#include "nvm_shared.h"
+#include "nvm_copy.h"
+
+#define NVM_TMP_EXT_LEN 4 /*=strlen(.tmp) but in compile time*/
+
+#define NVM_FILE_NAME_MAX_LENGTH_LONG 128
+
+#define NVM_FLAG_IS_COMM 0x1
+#define NVM_FLAG_IS_DIR 0x2
+#define NVM_FLAG_IS_READONLY 0x4
+
+pthread_mutex_t lock;
+#ifdef NVMS_SYNC_THREAD_ENA
+pthread_mutex_t syncLock;
+pthread_t syncTaskRef;
+sem_t syncSem;
+#endif
+char rootDir[80];
+
+//#undef DBGMSG
+//#define DBGMSG(...) /* */
+
+#ifndef BIONIC
+/* There is well known problem with huge file operation time
+ * occurred on low-memory.
+ * The problem may occur on BIONIC also but is critical on
+ * non-BIONIC low-memory devices using JFFS file system.
+ * Hige latency could cause failure. Let's detect TimeOut and
+ * print message into kmsg-buffer; in case of N timeouts
+ * try to call panic.
+ * Mostly critical are sync/fflush commands...
+ */
+#define NVMS_GUARD_TIMER
+#endif
+
+#ifndef NVMS_GUARD_TIMER
+static void NVMS_GuardTimerInit(void) {}
+static void NVMS_GuardTimerStart(int nn) {}
+static void NVMS_GuardTimerStop(void) {}
+#else
+static int NVMS_GuardErrMsg_fd = -1;
+static int NVMS_Guard;
+static int NVMS_GuardOpTrack;
+
+#define NVMS_GUARD_SEC 4
+#define NVMS_GUARD_NUM_TO_PANIC 5 /* equal 5*4=16sec */
+/* Enable NVMS_GUARD_PANIC only if NVMS knows to stop guard-timer or
+ * abort file-operation (and stop-timer) on cp-assert
+ * CP-logging is extreemly long on JFFS, guard may be started just before
+ * cp-assert and could abort (by panic) the logging.
+*/
+//#define NVMS_GUARD_PANIC
+
+
+static void NVMS_GuardTimerStart(int nn);
+
+void lockFile(void) { pthread_mutex_lock(&lock); }
+void unlockFile(void) { pthread_mutex_unlock(&lock); }
+
+FileItem* getItemByFd(int fd, List list)
+{
+ FileItem* Item;
+ Iterator it;
+ unsigned int cnt=0;
+
+ for (it = Begin(list); it != End(list); it = GetNext(it))
+ {
+ Item = it->data;
+ cnt++;
+ if (Item->fd == fd)
+ {
+ DBGMSG("getItemByFd %d=%d\r\n",fd, cnt);
+ return Item;
+ }
+ }
+
+ return NULL;
+}
+
+static void NVMS_GuardTimerHandler(int signum, struct siginfo *pInfo, void *p)
+{
+ (void)signum; // unused
+ (void)pInfo; // unused
+ (void)p; //unused
+#ifdef NVMS_GUARD_PANIC
+ FILE *fd;
+#endif
+ if (!NVMS_Guard)
+ return; //already deleted
+ if (NVMS_GuardErrMsg_fd >= 0) {
+ char buf[80];
+ int len;
+ len = sprintf(buf, "[NVMS] file opTrackNo_%d TimeOut (%d*%dsec)\n",
+ NVMS_GuardOpTrack, NVMS_Guard, NVMS_GUARD_SEC);
+ write(NVMS_GuardErrMsg_fd, buf, len);
+ }
+ if (NVMS_Guard >= NVMS_GUARD_NUM_TO_PANIC) {
+#ifdef NVMS_GUARD_PANIC
+ pxa_dbg("NVMS_GUARD_PANIC!!!\n");
+ fd = fopen("/dev/ramdump_ctl", "w");
+ fprintf(fd, "p_NVMS_GUARD_TIMER") ;
+ fclose(fd);
+#else
+ // do not restart timer; stop printing
+ NVMS_Guard = 0;
+#endif
+ } else {
+ //Re-start the timer
+ NVMS_GuardTimerStart(NVMS_GuardOpTrack);
+ }
+}
+
+static void NVMS_GuardTimerInit(void)
+{
+ /* set up the handler */
+ struct sigaction act;
+ act.sa_sigaction = NVMS_GuardTimerHandler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ NVMS_Guard = 0;
+ NVMS_GuardOpTrack = 0;
+ sigaction(SIGALRM, &act, NULL);
+ /* kmsg must be opened on init but not on failure */
+ NVMS_GuardErrMsg_fd = open("/dev/kmsg", O_WRONLY | O_SYNC);
+}
+
+static void NVMS_GuardTimerStart(int nn)
+{
+ int rc;
+ struct itimerval interval_timer;
+ interval_timer.it_interval.tv_usec = 0;
+ interval_timer.it_interval.tv_sec = 0;
+ interval_timer.it_value.tv_usec = 0;
+ interval_timer.it_value.tv_sec = NVMS_GUARD_SEC;
+ rc = setitimer(ITIMER_REAL, &interval_timer, NULL);
+ if (!rc) {
+ NVMS_Guard++;
+ NVMS_GuardOpTrack = nn;
+ }
+}
+
+static void NVMS_GuardTimerStop(void)
+{
+ struct itimerval interval_timer;
+ if (!NVMS_Guard)
+ return; //timer is not running.
+ NVMS_Guard = 0;
+ memset(&interval_timer, 0, sizeof(interval_timer));
+ setitimer(ITIMER_REAL, &interval_timer, NULL);
+}
+#endif//NVMS_GUARD_TIMER
+
+
+static int nvm_dir_fsync(const char* dirName)
+{
+ int ret = -1;
+ if (dirName != NULL)
+ {
+ int fid;
+ FILE* fd;
+ fd = fopen(dirName, "rb");
+ if (fd == NULL)
+ {
+ ERRMSG("ERR: DIR fopen(%s) fail:%s", dirName, strerror(errno));
+ }
+ else
+ {
+ fid = fileno(fd);
+ ret = fsync(fid);
+ if (ret != 0)
+ {
+ ERRMSG("ERR: DIR fsync(%d) fail:%s", fid, strerror(errno));
+ }
+ fclose(fd);
+ }
+ }
+ return(ret);
+}
+
+static int is_tmpfile_required(const char * file_name __attribute__ ((unused)), const char * szAttrib)
+{
+ return ((szAttrib[0] == 'w') || (szAttrib[0] == 'a') ||
+ (szAttrib[1] == '+') || (szAttrib[2] == '+'));
+}
+
+static void removeTmpfile(const char* dirname)
+{
+ DIR* dirstream;
+ struct dirent* ent;
+ char* pos;
+ int len, offsTMP;
+
+ DBGMSG("scan for tmp file");
+ dirstream = opendir(dirname);
+ if (dirstream == NULL)
+ {
+ ERRMSG("failed to open dir %s", dirname);
+ return;
+ }
+
+ while ((ent = readdir(dirstream)))
+ {
+ if (ent->d_type != DT_REG)
+ continue; //not a regular file
+
+ len = strlen(ent->d_name);
+ if (len <= NVM_TMP_EXT_LEN)
+ continue; //name too short to be "*.tmp"
+
+ offsTMP = len - NVM_TMP_EXT_LEN;
+ if (strcmp(ent->d_name + offsTMP, ".tmp"))
+ continue; //not "*.tmp"
+
+ unlink(ent->d_name);
+ DBGMSG("unlink tmp file [%s]", ent->d_name);
+ }
+ /* TMP remove is not critical. Do not flush/sync for it */
+ closedir(dirstream);
+}
+
+#ifdef NVMS_SYNC_THREAD_ENA
+extern "C" void* syncTask(void* param)
+{
+#error NVMS sync thread is obsolet
+ return 0;
+}
+#endif
+
+
+void NVMFileOps(const char* dir, bool async __attribute__ ((unused)))
+{
+ pthread_mutex_init(&lock, NULL);
+ rootDir[0] = '\0';
+ strncat(rootDir, dir, sizeof(rootDir) - 1);
+ chdir(rootDir);
+ removeTmpfile(rootDir);
+ NVMS_GuardTimerInit();
+}
+
+NVM_STATUS_T FileDelete(const char* szFileName)
+{
+ if (unlink(szFileName) == 0)
+ {
+ DBGMSG("unlink(%s) done\n", szFileName);
+ return NVM_STATUS_SUCCESS;
+ }
+ else
+ {
+ ERRMSG("unlink %s failed:%s\n", szFileName, strerror(errno));
+ return NVM_STATUS_FAILURE; //todo how we handle this?- just output error message
+ }
+}
+
+int FileFindEntry(DIR** dirstream, const char* szFileName,
+ NVM_FILE_INFO* pFindResults, unsigned *fStatus)
+{
+ struct dirent* ent;
+ struct stat fs;
+ int ret, file_date, file_time;
+ struct tm gm_time;
+ char *pdir, *pbase, *fileName;
+ char dir[NVM_FILE_NAME_MAX_LENGTH_LONG];
+ char base[NVM_FILE_NAME_MAX_LENGTH_LONG];
+ char path[NVM_FILE_NAME_MAX_LENGTH_LONG];
+ int nameOffs;
+
+ dir[0] = '\0';
+ strncat(dir, szFileName, NVM_FILE_NAME_MAX_LENGTH_LONG - 1);
+ base[0] = '\0';
+ strncat(base, szFileName, NVM_FILE_NAME_MAX_LENGTH_LONG - 1);
+ pdir = dirname(dir);
+ pbase = basename(base);
+
+ if (!*dirstream)
+ {
+ *dirstream = opendir(pdir);
+ if (!*dirstream)
+ {
+ DBGMSG("failed to open dir %s", pdir);
+ return -1;
+ }
+ }
+ snprintf(path, NVM_FILE_NAME_MAX_LENGTH_LONG, "%s/", pdir);
+ nameOffs = strlen(path);
+
+ while ((ent = readdir(*dirstream)))
+ {
+ if (strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".") == 0)
+ continue;
+
+ //DBGMSG("%s: ent->d_name[%s], ent->d_type[%d]", __FUNCTION__, ent->d_name, ent->d_type);
+ //DBGMSG("%s: path[%s], pdir[%s], pbase[%s]", __FUNCTION__, path, pdir, pbase);
+ //DBGMSG("%s: pFindResults->plr_date[0x%lx]", __FUNCTION__, pFindResults->plr_date);
+ /* current request from cp NVM, ignore cp NVM directory file */
+ if ( (pFindResults->plr_date == 0xCFCFCFCF) && (ent->d_type == DT_DIR))
+ continue;
+
+ /* Found */
+ if (fnmatch(pbase, ent->d_name, 0) == 0)
+ {
+ strncat(path + nameOffs, ent->d_name, NVM_FILE_NAME_MAX_LENGTH_LONG - nameOffs - 1);
+ ret = stat(path, &fs);
+ if (!ret)
+ {
+ memset(pFindResults, 0, sizeof(NVM_FILE_INFO));
+ strncat(pFindResults->file_name, ent->d_name, sizeof(pFindResults->file_name) - 1);
+ break; /* OK, entry is valid; otherwise continue as non-statable entries might exist, e.g. softlink with bad target */
+ }
+ else
+ {
+ ret = errno;
+ ERRMSG("Failed to get file info[%s]: %s\n", ent->d_name, strerror(ret));
+ path[nameOffs] = '\0'; //reset file name
+ }
+ }
+ }
+
+ if (ent)
+ {
+ DBGMSG("readdir() return [%s]\n", ent->d_name);
+ gmtime_r((const time_t *)&(fs.st_mtime), &gm_time);
+ file_date = gm_time.tm_mday << (12 + 4);
+ file_date += (gm_time.tm_mon + 1) << 12;
+ file_date += gm_time.tm_year + 1900;
+ file_time = gm_time.tm_hour << (6 + 6);
+ file_time += gm_time.tm_min << 6;
+ file_time += gm_time.tm_sec;
+ pFindResults->size = fs.st_size;
+ pFindResults->date = file_date;
+ pFindResults->time = file_time;
+ *fStatus = S_ISDIR(fs.st_mode) ? NVM_DIR_MASK | NVM_FILE_MASK
+ : NVM_FILE_MASK;
+ return 0;
+ }
+ return -1;
+}
+
+NVM_STATUS_T FileFindFirst(int ClientID, const char* szFileName,
+ NVM_FILE_INFO* pFindResults, unsigned *fStatus, int *searchHandle, List list)
+{
+ DIR* dirstream = NULL;
+ int ret;
+ FileItem* item;
+
+ DBGMSG("Find First [%s]\n", szFileName);
+
+ ret = FileFindEntry(&dirstream, szFileName, pFindResults, fStatus);
+ if (!ret)
+ {
+ item = (FileItem*)malloc(sizeof(*item));
+ if (!item)
+ {
+ ERRMSG("failed to add file list for FindNext.\n");
+ closedir(dirstream);
+ *searchHandle = -1;
+ return NVM_STATUS_FAILURE;
+ }
+ strcpy(item->fName, szFileName);
+ item->fd = dirfd(dirstream);
+ item->handle = dirstream;
+ item->flag = NVM_FLAG_IS_DIR;
+ if (ClientID == NVM_CLIENT_COMM)
+ item->flag |= NVM_FLAG_IS_COMM;
+
+ lockFile();
+ Append(list, item);
+ unlockFile();
+
+ *searchHandle = item->fd;
+ if (ClientID == NVM_CLIENT_ACAT)
+ usleep(10000); //Prevents CPU starvation caused by ACAT APPS
+ free(item);
+ return NVM_STATUS_SUCCESS;
+ }
+ else
+ {
+ DBGMSG("failed to FileFindFirst a matching file");
+ if (dirstream)
+ closedir(dirstream);
+ *searchHandle = -1;
+ return NVM_STATUS_FAILURE;
+ }
+}
+
+NVM_STATUS_T FileFindNext(NVM_FILE_INFO* pFindResults,
+ unsigned* fStatus, int searchHandle, List list)
+{
+ DIR* dirstream;
+ int ret;
+ char path[NVM_FILE_NAME_MAX_LENGTH_LONG];
+ FileItem* item;
+
+ lockFile();
+ item = getItemByFd(searchHandle, list);
+ if (item == NULL || !item->fName[0] || item->handle == NULL)
+ {
+ unlockFile();
+ ERRMSG("Invalid dir item\n");
+ return NVM_STATUS_FAILURE;
+ }
+ dirstream = (DIR*)item->handle;
+ path[0] = '\0';
+ strncat(path, item->fName, NVM_FILE_NAME_MAX_LENGTH_LONG - 1);
+ DBGMSG("Find Next [%s]\n", item->fName);
+ unlockFile();
+
+ ret = FileFindEntry(&dirstream, path, pFindResults, fStatus);
+ if (!ret)
+ return NVM_STATUS_SUCCESS;
+ else
+ {
+ DBGMSG("failed to FileFindNext a matching file"); //=OK, end of dir-list
+ return NVM_STATUS_FAILURE;
+ }
+}
+
+
+NVM_STATUS_T FileFindClose(int searchHandle, List list)
+{
+ NVM_STATUS_T rc = NVM_STATUS_SUCCESS;
+ FileItem* item;
+ DIR* dirstream;
+
+ lockFile();
+// item = removeItemByFd(searchHandle, list);
+ item = getItemByFd(searchHandle, list);
+// unlockFile();
+ if (item != NULL)
+ {
+ DBGMSG("FileFindClose [%s]", item->fName);
+ dirstream = (DIR*)item->handle;
+ if (dirstream == NULL)
+ rc = NVM_STATUS_FAILURE;
+ else
+ closedir(dirstream);
+ if (!item->fName[0])
+ rc = NVM_STATUS_FAILURE;
+ item = removeItemByFd(searchHandle, list);
+ }
+ else
+ {
+ ERRMSG("cannot find dir handle %d", searchHandle);
+ }
+ unlockFile();
+ return rc;
+}
+
+NVM_STATUS_T GetFileSize(const char* szFileName,
+ unsigned* pdwSizeHigh, unsigned* pdwSizeLow)
+{
+ struct stat fs;
+ int ret;
+
+ ret = stat(szFileName, &fs);
+ if (ret != 0)
+ {
+ DBGMSG("failed to open the file [%s].\n", szFileName);
+ return NVM_STATUS_FAILURE;
+ }
+ *pdwSizeLow = fs.st_size;
+ *pdwSizeHigh = 0;
+ DBGMSG("%s size = %lld\n", szFileName, fs.st_size);
+ return NVM_STATUS_SUCCESS;
+}
+
+
+NVM_STATUS_T FileOpen(int ClientID, const char* szFileName,
+ const char* szAttrib, unsigned* hFile, List list)
+{
+ FILE* fp;
+ int ret;
+ FileItem* item;
+
+ item = (FileItem *)malloc(sizeof(*item));
+ if (!item)
+ {
+ ERRMSG("Cannot add file [%s] with attrib [%s] to file list\n", szFileName, szAttrib);
+ return NVM_STATUS_FAILURE;
+ }
+ item->fName[0] = 0; // no one cares about file name in read only mode
+ item->flag = 0;
+ if (is_tmpfile_required(szFileName, szAttrib))
+ { //open for Write
+ if (strlen(szFileName) > NAME_MAX)
+ {
+ ERRMSG("file [%s] length too long!!!\n", szFileName);
+ return NVM_STATUS_FAILURE;
+ }
+ strcpy(item->fName, szFileName);
+ NVMS_GuardTimerStart(1);
+ fp = FileOpenSafe(szFileName, szAttrib);
+ NVMS_GuardTimerStop();//1
+ }
+ else
+ { //open for Read
+ item->flag |= NVM_FLAG_IS_READONLY;
+ NVMS_GuardTimerStart(2);
+ fp = fopen(szFileName, szAttrib);
+ NVMS_GuardTimerStop();//2
+ }
+
+ if (!fp)
+ {
+ DBGMSG("Cannot open file [%s] with attrib [%s]\n", szFileName, szAttrib);
+ free(item);
+ return NVM_STATUS_FAILURE;
+ }
+
+ DBGMSG("FileOpen(%s with %s) returns %p\n", szFileName, szAttrib, fp);
+ item->fd = fileno(fp);
+ item->handle = fp;
+ if (ClientID == NVM_CLIENT_COMM)
+ item->flag |= NVM_FLAG_IS_COMM;
+ lockFile();
+ Append(list, item);
+ unlockFile();
+ *hFile = item->fd;
+ free(item);
+ return NVM_STATUS_SUCCESS;
+}
+
+NVM_STATUS_T FileWrite(unsigned hFile, const void* pBuffer, unsigned dwBufferLen,
+ short wItemSize, unsigned dwCount, unsigned* pdwActual, List list)
+{
+ UNUSEDPARAM(dwBufferLen)
+ FILE *fp;
+ NVM_STATUS_T ret = NVM_STATUS_SUCCESS;
+ FileItem* item;
+
+ *pdwActual = 0;
+ if ((wItemSize == 0) || (dwCount == 0))
+ return NVM_STATUS_FAILURE;
+
+ lockFile();
+ item = getItemByFd(hFile, list);
+ if (!item)
+ {
+ unlockFile();
+ return NVM_STATUS_FAILURE;
+ }
+ fp = (FILE*)item->handle;
+ unlockFile();
+ DBGMSG("FileWrite(%p, %d * %d)\n", fp, wItemSize, dwCount);
+ NVMS_GuardTimerStart(3);
+ *pdwActual = fwrite(pBuffer, wItemSize, dwCount, fp);
+ NVMS_GuardTimerStop();//3
+ if (ferror(fp))
+ {
+ ERRMSG("FileWrite: File write error %d, %s.[%p].\n", *pdwActual, strerror(errno), fp);
+ clearerr(fp);
+ ret = NVM_STATUS_FAILURE;
+ }
+ DBGMSG("FileWrite(%p, %d * %d) returns %d\n", fp, wItemSize, dwCount, *pdwActual);
+ return ret;
+}
+
+NVM_STATUS_T FileFlush(unsigned hFile, List list)
+{
+ FILE *fp;
+ FileItem* item;
+
+ lockFile();
+ item = getItemByFd(hFile, list);
+ if (!item)
+ {
+ unlockFile();
+ return NVM_STATUS_FAILURE;
+ }
+ fp = (FILE*)item->handle;
+ unlockFile();
+ int ret = fflush(fp);
+ DBGMSG("FileFlush(%p) returns %d\n", fp, ret);
+ return NVM_STATUS_SUCCESS;
+}
+
+NVM_STATUS_T FileSeek(unsigned hFile, long dwOffset, int dwOrigin, List list)
+{
+ FILE *fp;
+ FileItem* item;
+
+ lockFile();
+ item = getItemByFd(hFile, list);
+ if (!item)
+ {
+ unlockFile();
+ return NVM_STATUS_FAILURE;
+ }
+ fp = (FILE*)item->handle;
+ unlockFile();
+ int ret = fseek(fp, dwOffset, dwOrigin);
+ DBGMSG("FileSeek(%p at %d from %d) returns %d\n", fp, dwOffset, dwOrigin, ret);
+ if (ret == 0)
+ return NVM_STATUS_SUCCESS;
+ else
+ return NVM_STATUS_FAILURE;
+}
+
+NVM_STATUS_T FileRead(unsigned hFile, short wItemSize, unsigned dwCount,
+ unsigned* pdwActual, void* pBuffer, List list)
+{
+ FILE *fp;
+ FileItem* item;
+
+ lockFile();
+ item = getItemByFd(hFile, list);
+ if (!item)
+ {
+ unlockFile();
+ return NVM_STATUS_FAILURE;
+ }
+ fp = (FILE*)item->handle;
+ unlockFile();
+ if (feof(fp))
+ {
+ ERRMSG("FileRead: File pointer is at the end of the file!.[%p].\n", fp);
+ }
+ DBGMSG("FileRead(%p)\n", fp);
+
+ NVMS_GuardTimerStart(4);
+ *pdwActual = fread(pBuffer, wItemSize, dwCount, fp);
+ NVMS_GuardTimerStop();//4
+ if (ferror(fp))
+ {
+ ERRMSG("FileRead(%s) error", item->fName);
+ clearerr(fp);
+ }
+
+ DBGMSG("FileRead(%p %d * %d) returns %d\n", fp, wItemSize, dwCount, *pdwActual);
+
+ return NVM_STATUS_SUCCESS;
+}
+
+NVM_STATUS_T FileClose(int ClientID, unsigned hFile, List list)
+{
+ int ret = 0;
+ FileItem* item;
+ FILE* fp;
+
+ lockFile();
+ item = getItemByFd(hFile, list);
+// item = removeItemByFd(hFile, list);
+ if (!item)
+ {
+ unlockFile();
+ ERRMSG("FileClose: cannot find file handler [%u].\n", hFile);
+ return NVM_STATUS_FAILURE;
+ }
+ fp = (FILE*)item->handle;
+ if (item->flag & NVM_FLAG_IS_READONLY)
+ {
+ //No NVMS_GuardTimerStart() required since no problems seen
+ ret = fclose(fp);
+ }
+ else
+ {
+ NVMS_GuardTimerStart(6);
+ ERRMSG("FileClose: fflush fp[0x%lx].\n", fp);
+ fflush(fp);
+ ret = FileCloseSafe(item); //close with rename
+ NVMS_GuardTimerStop();//6
+ }
+ item = removeItemByFd(hFile, list);
+
+ unlockFile();
+ if (ClientID != NVM_CLIENT_ACAT)
+ {
+ if (ret == 0)
+ ret = NVM_STATUS_SUCCESS;
+ else
+ ret = NVM_STATUS_FS_ERROR;
+ }
+ else
+ {
+ usleep(10000); //Prevents CPU starvation caused by ACAT APPS
+ ret = NVM_STATUS_SUCCESS;
+ }
+ DBGMSG("FileClose returns %d\n", ret);
+ return (NVM_STATUS_T)ret;
+}
+
+NVM_STATUS_T FileCloseAll(int ClientID, List list)
+{
+ bool type, client = (NVM_CLIENT_COMM == ClientID);
+ size_t file_num = 0, dir_num = 0, remain;
+ int wr_cnt = 0;
+
+ FileItem* Item = NULL;
+ Iterator it;
+ Iterator it2;
+
+ lockFile();
+
+ for (it = Begin(list); it != End(list);)
+ {
+ Item = it->data;
+ if (Item->flag & NVM_FLAG_IS_DIR)
+ {
+ DBGMSG("close dir %s", Item->fName);
+ closedir((DIR*)Item->handle);
+ ++dir_num;
+ }
+ else
+ {
+ // close but not safe. TMP removed at the end
+ if (!(Item->flag & NVM_FLAG_IS_READONLY))
+ wr_cnt++;
+ fclose((FILE*)Item->handle);
+ ++file_num;
+ }
+ /* get next item before free current item */
+ it2 = GetNext(it);
+ Remove(list, it);
+ it = it2;
+ }
+ remain = GetLength(list);
+
+ unlockFile();
+ DBGMSG("FileCloseAll: closed %zu dirs, %zu files, %zu left", dir_num, file_num, remain);
+ if (wr_cnt)
+ removeTmpfile(rootDir);
+ return NVM_STATUS_SUCCESS;
+}
+
+NVM_STATUS_T FileRename(const char* szOldFileName, const char* szNewFileName)
+{
+ int ret;
+
+ ret = rename(szOldFileName, szNewFileName);
+ DBGMSG("rename(%s --> %s) returns %d\n", szOldFileName, szNewFileName, ret);
+ if (ret == 0)
+ return NVM_STATUS_SUCCESS;
+ else
+ {
+ ERRMSG("rename %s to %s failed\n", szOldFileName, szNewFileName);
+ return NVM_STATUS_FAILURE; //todo how we handle this??- just output error messages now.
+ }
+}
+
+NVM_STATUS_T GetFileStat(const char* szFileName, int* dwStat)
+{
+ struct stat fs;
+ int ret;
+
+ ret = stat(szFileName, &fs);
+ DBGMSG("stat(%s) returns %d\n", szFileName, ret);
+ if (ret == 0)
+ {
+ *dwStat = S_ISDIR(fs.st_mode)
+ ? NVM_DIR_MASK | NVM_FILE_MASK
+ : NVM_FILE_MASK;
+ return NVM_STATUS_SUCCESS;
+ }
+ else
+ return NVM_STATUS_FAILURE;
+}
+
+NVM_STATUS_T FileChangeMode(const char* szFileName, mode_t dwNewMode)
+{
+ int ret;
+
+ ret = chmod(szFileName, dwNewMode);
+ DBGMSG("%chmod(%s, %u) returns %d\n", szFileName, dwNewMode, ret);
+ if (ret == 0)
+ return NVM_STATUS_SUCCESS;
+ else
+ return NVM_STATUS_FAILURE;
+}
+
+NVM_STATUS_T GetAvailSpace(const char* szVol, unsigned* pdwSize)
+{
+ struct statfs fs;
+
+ /*FIXME PC tool sends Unicode16 for szVol, disable szVol param for now */
+ szVol = "/NVM/";
+ if (statfs(szVol, &fs) < 0)
+ {
+ *pdwSize = 0;
+ ERRMSG("failed to get filesystem info for %s", szVol);
+ return NVM_STATUS_FAILURE;
+ }
+
+ *pdwSize = fs.f_bavail * fs.f_bsize;
+ DBGMSG("GetAvailSpace returns %u\n", *pdwSize);
+
+ return NVM_STATUS_SUCCESS;
+}
+
+NVM_STATUS_T GetTotalSpace(unsigned long long* pdwSize)
+{
+ struct statfs fs;
+
+ if (statfs(rootDir, &fs) < 0)
+ {
+ *pdwSize = 0;
+ ERRMSG("failed to get filesystem info for %s", rootDir);
+ return NVM_STATUS_FAILURE;
+ }
+
+ *pdwSize = fs.f_blocks * fs.f_bsize;
+ DBGMSG("GetTotalSpace returns %llu\n", *pdwSize);
+
+ return NVM_STATUS_SUCCESS;
+}
+
+NVM_STATUS_T MkDir(const char* szDirName, mode_t dwMode)
+{
+ int ret;
+
+ ret = mkdir(szDirName, dwMode);
+ DBGMSG("mkdir(%s, %u) returns %d\n", szDirName, dwMode, ret);
+ if (ret == 0)
+ return NVM_STATUS_SUCCESS;
+ else
+ return NVM_STATUS_FAILURE;
+}
+
+NVM_STATUS_T RmDir(const char* szDirName)
+{
+ int ret;
+
+ ret = rmdir(szDirName);
+ DBGMSG("rmdir(%s) returns %d\n", szDirName, ret);
+ if (ret == 0)
+ return NVM_STATUS_SUCCESS;
+ else
+ return NVM_STATUS_FAILURE;
+}
+
+
+/* File opened for Write operation and not closed properly
+* (power reset, CP-assert) may have partial/incorrect data
+* Always write into TMP-copy and move to original only upon fclose.
+* => so the Original could be "not updated" but always last valid!
+* Refer FileOpenSafe, FileCloseSafe, removeTmpfile and FileCloseAll
+*/
+FILE* FileOpenSafe(const char* fName, const char* szAttrib)
+{
+ #define TMP_BUF_SIZE 1024
+ char * tmpfile_name = NULL;
+ FILE * fpTmp, *fpOrig = NULL;
+ char buf[TMP_BUF_SIZE];
+ int bRead, bWrite;
+
+ asprintf(&tmpfile_name, "%s.tmp", fName);
+ if (!tmpfile_name)
+ return NULL; //no memory error !
+
+ /* Try to copy from original to TMP */
+ fpOrig = fopen(fName, "rb");
+ if (fpOrig) {
+ fpTmp = fopen(tmpfile_name, "wb");
+ if (!fpTmp) {
+ fclose(fpOrig);
+ free(tmpfile_name);
+ return NULL; // error !
+ }
+ do {
+ bRead = fread(buf, 1, TMP_BUF_SIZE, fpOrig);
+ if (bRead == 0)
+ break;
+ bWrite = fwrite(buf, 1, bRead, fpTmp);
+ if (bWrite != bRead) {
+ fclose(fpOrig);
+ fclose(fpTmp);
+ free(tmpfile_name);
+ ERRMSG("ERR: fopen: %s \"%s\" COPY-to-TMP failed\n", fName, szAttrib);
+ return NULL;
+ }
+ } while (bRead == TMP_BUF_SIZE);
+ fclose(fpOrig);
+ fclose(fpTmp);
+ }
+
+ fpTmp = fopen(tmpfile_name, szAttrib);
+ free(tmpfile_name);
+ return fpTmp;
+}
+
+int FileCloseSafe(FileItem* item)
+{
+ int ret;
+ char * tmpfile_name = NULL;
+ FILE* fp = (FILE*)item->handle;
+
+ DBGMSG("%s: fp[0x%lx]\n", __FUNCTION__, fp);
+ /* fsync does not flushes meta-data
+ * This is done by nvm_dir_fsync()
+ */
+ ret = fsync(item->fd);
+ if (ret < 0)
+ {
+ ERRMSG("fsync %p failed:%s", item->handle, strerror(errno));
+ }
+ fclose(fp);
+ asprintf(&tmpfile_name, "%s.tmp", item->fName);
+ if (!tmpfile_name) {
+ ERRMSG("ERR: fclose: no memory, [%s] failed", tmpfile_name);
+ return -1;
+ }
+ if (rename(tmpfile_name, item->fName)) {
+ ERRMSG("ERR: fclose: rename %s > %s failed, errno %d, strerr %s\n", tmpfile_name, item->fName, errno, strerror(errno));
+ return -1;
+ }
+ nvm_dir_fsync(rootDir);
+ DBGMSG("%s: rootDir %s\n", __FUNCTION__, rootDir);
+ free(tmpfile_name);
+ return ret;
+}
+
+FileItem* removeItemByFd(int fd, List list)
+{
+ FileItem* Item = NULL;
+ Iterator it;
+
+ for (it = Begin(list); it != End(list); it = GetNext(it))
+ {
+ Item = it->data;
+ if (Item->fd == fd)
+ {
+ Remove(list, it);
+ DBGMSG("removeItemByFd %d\r\n",fd);
+ break;
+ }
+ }
+
+ return Item;
+}
+