#include "precompile.h" #include #include #include #ifdef _WIN32 #include #include #include #else #include #include #include #include #include #include #include #endif #include "array.h" #include "fileutil.h" #include "strutil.h" #include "memutil.h" #include "dbgutil.h" #include #define TAG TOOLKIT_TAG("fileutil") TOOLKIT_API BOOL ExistsDirA(LPCSTR lpDirPath) { DWORD dwRet = GetFileAttributesA(lpDirPath); return (dwRet != INVALID_FILE_ATTRIBUTES) && (dwRet & FILE_ATTRIBUTE_DIRECTORY); } TOOLKIT_API BOOL ExistsFileA(LPCSTR lpFilePath) { DWORD dwRet = GetFileAttributesA(lpFilePath); return (dwRet != INVALID_FILE_ATTRIBUTES) && !(dwRet & FILE_ATTRIBUTE_DIRECTORY); } TOOLKIT_API DWORD ReadFileSize(LPCSTR pszFile) { DWORD fileSize = (DWORD)-1; #ifndef _MSC_VER struct stat statbuf; memset(&statbuf, 0, sizeof(statbuf)); if (stat(pszFile, &statbuf) >= 0) { fileSize = statbuf.st_size; } #else HANDLE hFile; hFile = CreateFile(pszFile, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { fileSize = GetFileSize(hFile, NULL); CloseHandle(hFile); } #endif return fileSize; } TOOLKIT_API BOOL CreateDirA(LPCSTR lpDirPath, BOOL bRecursive) { char* slashPos = NULL; char* backSlashPos = NULL; size_t len = strlen(lpDirPath); if (len <= 2 || len >= MAX_PATH-2) { return FALSE; } else { if (!bRecursive) { if (ExistsDirA(lpDirPath)) return TRUE; return CreateDirectoryA(lpDirPath, NULL); } else { CHAR tmp[MAX_PATH], * p; CHAR* q = NULL; q = p = &tmp[0]; strncpy(tmp, lpDirPath, MAX_PATH); tmp[MAX_PATH - 1] = 0; if (tmp[len - 1] != BACK_SLASH && tmp[len - 1] != SLASH) { tmp[len++] = SPLIT_SLASH; tmp[len] = 0; } #ifdef _WIN32 do { slashPos = strchr(p, SLASH); backSlashPos = strchr(p, BACK_SLASH); if (slashPos != NULL && backSlashPos != NULL) { p = slashPos < backSlashPos ? slashPos : backSlashPos; } else if (slashPos != NULL) { p = slashPos; } else { p = backSlashPos; } if (!p) { break; } *p = 0; if (!ExistsDirA(tmp)) { if (!CreateDirectoryA(tmp, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) return FALSE; } *p = SPLIT_SLASH; p++; } while (1); #else while ((p = strchr(p, SPLIT_SLASH)) != NULL) { if(p != q) {//linux compatibility. *p = 0; if (!ExistsDirA(tmp)) { if (!CreateDirectoryA(tmp, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) return FALSE; } *p = SPLIT_SLASH; } p++; q = p; } #endif } } return TRUE; } TOOLKIT_API BOOL CreateDirRecursiveA(LPCSTR lpDirPath) { return CreateDirA(lpDirPath, TRUE); } TOOLKIT_API BOOL CreateParentDirA(LPCSTR lpPath, BOOL bRecursive) { CHAR pdir[MAX_PATH]; const CHAR *p; p = strrchr(lpPath, '\\'); if (!p) { p = strrchr(lpPath, '/'); } if (!p) { return FALSE; } strncpy(pdir, lpPath, p-lpPath); pdir[p-lpPath] = 0; return CreateDirA(pdir, bRecursive); } TOOLKIT_API BOOL ClearDirRecursiveA(LPCSTR lpDirPath) { array_header_t *arr; BOOL bRet = TRUE; TOOLKIT_ASSERT(lpDirPath); arr = fileutil_get_sub_files_a(lpDirPath); if (arr) { int i; for (i = 0; i < arr->nelts; ++i) { char *tmp = ARRAY_IDX(arr, i, char*); bRet &= DeleteFileA(tmp); } toolkit_array_free2(arr); } arr = fileutil_get_sub_dirs_a(lpDirPath); if (arr) { int i; for (i = 0; i < arr->nelts; ++i) { char *tmp = ARRAY_IDX(arr, i, char*); bRet &= ClearDirRecursiveA(tmp); } toolkit_array_free2(arr); } return bRet; } TOOLKIT_API BOOL RemoveFileA(LPCSTR pszFile) { if(ExistsFileA(pszFile)) { // remove readonly attribute DWORD dwRet = GetFileAttributesA(pszFile); if (dwRet & FILE_ATTRIBUTE_READONLY) { dwRet &= (~FILE_ATTRIBUTE_READONLY); SetFileAttributesA(pszFile, dwRet); } // delete it return DeleteFileA(pszFile); } return FALSE; } // 移除文件只读属性 TOOLKIT_API BOOL RemoveFileReadOnlyAttributeA(LPCSTR pszFile) { if(ExistsFileA(pszFile)) { // remove readonly attribute DWORD dwRet = GetFileAttributesA(pszFile); if (dwRet & FILE_ATTRIBUTE_READONLY) { dwRet &= (~FILE_ATTRIBUTE_READONLY); SetFileAttributesA(pszFile, dwRet); } return TRUE; } return FALSE; } // 递归拷贝所有文件及子文件夹 TOOLKIT_API BOOL CopyDirA(LPCSTR pszSourceDir, LPCSTR pszDestDir) { array_header_t *arr; BOOL bRet = TRUE; if (!ExistsDirA(pszSourceDir)) return FALSE; if (!ExistsDirA(pszDestDir)) { if (!CreateDirRecursiveA(pszDestDir)) return FALSE; } arr = fileutil_get_sub_files_a(pszSourceDir); if (arr) { int i; for (i = 0; i < arr->nelts; ++i) { char szDestFile[256] = {0}; char *file = ARRAY_IDX(arr, i, char*); strcpy(szDestFile, pszDestDir); if (szDestFile[strlen(szDestFile)-1] != '\\' && szDestFile[strlen(szDestFile) - 1] != '/') strcat(szDestFile, MB_SPLIT_SLASH_STR); strcat(szDestFile, strrchr(file, SPLIT_SLASH)+1); bRet &= CopyFileA(file, szDestFile, FALSE); } toolkit_array_free2(arr); } arr = fileutil_get_sub_dirs_a(pszSourceDir); if (arr) { int i; for (i = 0; i < arr->nelts; ++i) { char szDestSubDir[256] = {0}; char *dir = ARRAY_IDX(arr, i, char*); strcpy(szDestSubDir, pszDestDir); if (szDestSubDir[strlen(szDestSubDir)-1] != '\\' && szDestSubDir[strlen(szDestSubDir) - 1] != '/') strcat(szDestSubDir, MB_SPLIT_SLASH_STR); strcat(szDestSubDir, strrchr(dir, SPLIT_SLASH)+1); bRet &= CopyDirA(dir, szDestSubDir); } toolkit_array_free2(arr); } return bRet; } TOOLKIT_API BOOL RemoveDirRecursiveA(LPCSTR lpDirPath) { #ifdef _WIN32 int nRet = 0; char szDir[256] = {0}; SHFILEOPSTRUCT fo; memset(&fo, 0, sizeof(fo)); memcpy(szDir, lpDirPath, strlen(lpDirPath)); fo.wFunc = FO_DELETE; fo.pFrom = szDir; fo.fFlags = FOF_NO_UI; nRet = SHFileOperationA(&fo); return nRet ==0 ? TRUE: FALSE; #else array_header_t* arr; BOOL bRet = TRUE; TOOLKIT_ASSERT(lpDirPath); arr = fileutil_get_sub_files_a(lpDirPath); if (arr) { int i; for (i = 0; i < arr->nelts; ++i) { char* tmp = ARRAY_IDX(arr, i, char*); bRet &= DeleteFileA(tmp); } toolkit_array_free2(arr); } arr = fileutil_get_sub_dirs_a(lpDirPath); if (arr) { int i; for (i = 0; i < arr->nelts; ++i) { char* tmp = ARRAY_IDX(arr, i, char*); bRet &= RemoveDirRecursiveA(tmp); } toolkit_array_free2(arr); } if (bRet) { bRet = RemoveDirectoryA(lpDirPath); } return bRet; #endif } TOOLKIT_API HANDLE ExtCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { if (!lpFileName) return INVALID_HANDLE_VALUE; if (lpFileName[0] != '\\') CreateParentDirA(lpFileName, TRUE); return CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } TOOLKIT_API int fileutil_copy_file(const char* dest_file_path, const char* src_file_path) { if (CopyFileA(src_file_path, dest_file_path, FALSE)) { return 0; } return -1; } TOOLKIT_API void fileutil_delete_file(const char* filename) { #ifdef _WIN32 DeleteFileA(filename); #else unlink(filename); #endif //_WIN32 } /* * isfile: only fetch file type elem or not. * limitation: max elem count to satsfy. */ static array_header_t *fileutil_get_sub_a(const char *path, int isfile, int limitation) { #if 1 array_header_t* arr = NULL; char tmp[MAX_PATH]; int npath; if (!path) return NULL; npath = strlen(path); if (npath < 2) return NULL; strcpy(tmp, path); if (tmp[npath - 1] != '\\' && tmp[npath - 1] != '/') { tmp[npath++] = SPLIT_SLASH; tmp[npath] = 0; } tmp[npath++] = '*'; tmp[npath] = 0; arr = array_make(3, sizeof(char*)); { WIN32_FIND_DATAA fd; HANDLE hFind = FindFirstFileA(tmp, &fd); if (hFind != INVALID_HANDLE_VALUE) { tmp[--npath] = 0; do { int isdir = !!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); if (isdir) { if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0) { continue; } } /*[if require file while is not dir] or [not require file but is dir]*/ if (isfile ^ isdir) { char* v = malloc(sizeof(char) * (npath + strlen(fd.cFileName) + 1)); strcpy(v, tmp); strcat(v, fd.cFileName); ARRAY_PUSH(arr, char*) = v; } } while (FindNextFileA(hFind, &fd) && arr->nelts < limitation); FindClose(hFind); } } #else array_header_t* arr = NULL; char tmp[MAX_PATH]; char tmp2[MAX_PATH]; DIR* d = NULL; struct dirent* dp = NULL; struct stat st; int npath; if (!path) return NULL; npath = strlen(path); if (npath < 1) return NULL; strcpy(tmp, path); if (tmp[npath - 1] == '/') { tmp[npath - 1] = '\0'; } if (stat(tmp, &st) < 0 || !S_ISDIR(st.st_mode)) { return NULL; } if (!(d = opendir(tmp))) { return NULL; } if (tmp[npath - 1] != '/') { tmp[npath++] = '/'; tmp[npath] = 0; } arr = array_make(3, sizeof(char*)); while ((dp = readdir(d)) != NULL && arr->nelts < limitation) { if((!strncmp(dp->d_name, ".", 1)) || (!strncmp(dp->d_name, "..", 2))) { continue; } snprintf(tmp2, sizeof(tmp2) - 1, "%s%s", tmp, dp->d_name); stat(tmp2, &st); int isdir = !!(S_ISDIR(st.st_mode)); if (isfile ^ isdir) { char* v = malloc(sizeof(char) * (npath + strlen(dp->d_name) + 1)); strcpy(v, tmp); strcat(v, dp->d_name); ARRAY_PUSH(arr, char*) = v; } } closedir(d); #endif //1 return arr; } TOOLKIT_API array_header_t *fileutil_get_sub_files_a(const char *path) { return fileutil_get_sub_a(path, 1, INT_MAX); } TOOLKIT_API array_header_t *fileutil_get_sub_dirs_a(const char *path) { return fileutil_get_sub_a(path, 0, INT_MAX); } TOOLKIT_API array_header_t *fileutil_get_sub_files2_a(const char *path, int limitation) { return fileutil_get_sub_a(path, 1, limitation); } TOOLKIT_API array_header_t *fileutil_get_sub_dirs2_a(const char *path, int limitation) { return fileutil_get_sub_a(path, 0, limitation); } TOOLKIT_API FILE *fileutil_transaction_fopen(const char *filename, const char *mode) { DWORD dwAttr; char t[MAX_PATH]; int write_flag; if (!filename || !mode) { errno = EINVAL; return NULL; } write_flag = (int)strchr(mode, 'w'); strcpy(t, filename); strcat(t, ".bak"); dwAttr = GetFileAttributesA(filename); if (dwAttr != INVALID_FILE_ATTRIBUTES && dwAttr & FILE_ATTRIBUTE_DIRECTORY) { errno = EIO; return NULL; } if (dwAttr != INVALID_FILE_ATTRIBUTES) { if (!(dwAttr & FILE_ATTRIBUTE_READONLY)) { BOOL bRet = DeleteFileA(filename); if (bRet) { if (!write_flag) { if (ExistsFileA(t)) { bRet = CopyFileA(t, filename, FALSE); if (bRet) bRet = SetFileAttributesA(filename, FILE_ATTRIBUTE_NORMAL); } } } if (!bRet) { errno = EIO; return NULL; } } else { if (write_flag) { BOOL bRet = TRUE; if (ExistsFileA(t)) { bRet = SetFileAttributesA(t, dwAttr & ~FILE_ATTRIBUTE_READONLY); } if (bRet) { bRet = CopyFileA(filename, t, FALSE); } if (!bRet) { errno = EIO; return NULL; } } } } else { if (!write_flag) { BOOL bRet = TRUE; if (ExistsFileA(t)) { bRet = CopyFileA(t, filename, FALSE); } else { bRet = FALSE; } if (!bRet) { errno = EIO; return NULL; } } } return fopen(filename, mode); } TOOLKIT_API int fileutil_transaction_fclose(const char *filename, FILE *fp) { int rc = fclose(fp); if (!rc && filename) { DWORD dwAttr = GetFileAttributesA(filename); if (dwAttr != INVALID_FILE_ATTRIBUTES) { if (!(dwAttr & FILE_ATTRIBUTE_READONLY)) SetFileAttributesA(filename, dwAttr | FILE_ATTRIBUTE_READONLY); } } return rc; } #ifndef _WIN32 void _splitpath(const char* path, char* drive, char* dir, char* fname, char* ext) { char resolved_path[4096]; char* p; char* q; char* last_slash = NULL; char* dot = NULL; size_t len, sub_len; if (drive) { *drive = '\0'; } if (path == NULL) { if (dir) { *dir = '\0'; } if (fname) { *fname = '\0'; } if (ext) { *ext = '\0'; } return; } if (realpath(path, resolved_path) == NULL) { WLog_ERR(TAG, "realpath failed: %s", strerror(errno)); strcpy(resolved_path, path); } else { //WLog_DBG(TAG, "resolved_path: %s", resolved_path); } len = strlen(resolved_path); if (resolved_path[0] == '/') { p = strchr(resolved_path + 1, '/'); if (p != NULL) { *p = '\0'; } if (drive) { strcpy(drive, resolved_path); } if (p != NULL) { *p = '/'; } else { p = resolved_path + len; } } else { p = resolved_path; } q = p; for (last_slash = NULL; p && *p != '\0'; ++p) { if (*p == '/') { last_slash = p + 1; if (dot) { dot = NULL; } } else if(*p == '.') { dot = p; } } if (last_slash) { if (dir) { sub_len = last_slash - q; strncpy(dir, q, sub_len); *(dir + sub_len) = '\0'; } q = last_slash; } else if(dir){ *dir = '\0'; } if (dot) { if (fname) { sub_len = dot - q; strncpy(fname, q, sub_len); *(fname + sub_len) = '\0'; } if (ext) { sub_len = p - dot; strncpy(ext, dot, sub_len); *(ext + sub_len) = '\0'; } } else { if (fname) { sub_len = p - q; strncpy(fname, q, sub_len); *(fname + sub_len) = '\0'; } if (ext) { *ext = '\0'; } } } #endif //NOT _WIN32