123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- #include "precompile.h"
- #include "sp_pst.h"
- #include "sp_def.h"
- #include "memutil.h"
- #include "fileutil.h"
- #include "strutil.h"
- #include "list.h"
- #include <winpr/string.h>
- #include <winpr/file.h>
- struct sp_pst_tree_t {
- sp_pst_elem_t *root;
- };
- struct sp_pst_elem_t {
- struct list_head entry;
- int type;
- char *key;
- void *value;
- int value_len;
- sp_pst_elem_t *parent;
- int file_offset;
- struct list_head child_list;
- };
- // file serialize order are first-order
- static const char *get_full_path(const char *base_dir, const char *ent, const char *cls, const char *obj, char *buf)
- {
- if (cls) {
- if (obj) {
- sprintf(buf, "%s" SPLIT_SLASH_STR "objects" SPLIT_SLASH_STR "%s" SPLIT_SLASH_STR "%s" SPLIT_SLASH_STR "%s.dat", base_dir, ent, cls, obj);
- }
- else {
- sprintf(buf, "%s" SPLIT_SLASH_STR "objects" SPLIT_SLASH_STR "%s" SPLIT_SLASH_STR "%s", base_dir, ent, cls);
- }
- }
- else {
- sprintf(buf, "%s" SPLIT_SLASH_STR "objects" SPLIT_SLASH_STR "%s", base_dir, ent);
- }
- return buf;
- }
- static int file_write_elem_single(FILE *fp, sp_pst_elem_t *elem)
- {
- int type = elem->type;
- int child_offset;
- int next_sibling_offset;
- int key_len = strlen(elem->key);
- void *key = elem->key;
- int value_len = elem->value_len;
- void *value = elem->value;
- size_t t, cnt;
- if (list_empty(&elem->child_list)) {
- child_offset = 0;
- } else {
- sp_pst_elem_t *child = list_first_entry(&elem->child_list, sp_pst_elem_t, entry);
- child_offset = child->file_offset;
- }
- if (elem->entry.next) {
- sp_pst_elem_t *next_sibling = sp_pst_elem_next_sibling(elem);
- next_sibling_offset = next_sibling ? next_sibling->file_offset : 0;
- } else {
- next_sibling_offset = 0;
- }
- // type | child_offset | next_sibling_offset | key | value
- cnt = sizeof(int);
- t = fwrite(&type, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- t = fwrite(&child_offset, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- t = fwrite(&next_sibling_offset, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- t = fwrite(&key_len, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- cnt = key_len;
- t = fwrite(key, 1, key_len, fp);
- if (t != cnt)
- goto on_error;
- cnt = sizeof(int);
- t = fwrite(&value_len, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- cnt = value_len;
- t = fwrite(value, 1, value_len, fp);
- if (t != cnt)
- goto on_error;
- return 0;
- on_error:
- return Error_IO;
- }
- // first-order write
- static int file_write_elem(FILE *fp, sp_pst_elem_t *elem)
- {
- int rc;
- rc = file_write_elem_single(fp, elem);
- if (rc == 0) {
- sp_pst_elem_t *pos;
- list_for_each_entry(pos, &elem->child_list, sp_pst_elem_t, entry) {
- rc = file_write_elem(fp, pos);
- if (rc != 0)
- break;
- }
- }
- return rc;
- }
- static int file_write(FILE *fp, sp_pst_tree_t *tree)
- {
- return file_write_elem(fp, tree->root);
- }
- // first-order fill
- static void fill_offset_elem(int *curr_offset, sp_pst_elem_t *elem)
- {
- sp_pst_elem_t *pos;
- int size = 5 * sizeof(int) + strlen(elem->key) + elem->value_len;
- elem->file_offset = *curr_offset;
- *curr_offset += size;
- list_for_each_entry(pos, &elem->child_list, sp_pst_elem_t, entry) {
- fill_offset_elem(curr_offset, pos);
- }
- }
- static int fill_offset(sp_pst_tree_t *tree)
- {
- int curr_offset = 0;
- fill_offset_elem(&curr_offset, tree->root);
- return curr_offset;
- }
- static int file_read_elem_single(FILE *fp, int offset, sp_pst_elem_t **p_elem, int *next_sibling_offset, int *first_child_offset)
- {
- int rc = 0;
- sp_pst_elem_t *elem = NULL;
- size_t t, cnt;
- int key_len;
- rc = fseek(fp, offset, SEEK_SET);
- if (rc != 0)
- goto on_error;
- elem = ZALLOC_T(sp_pst_elem_t);
-
- cnt = sizeof(int);
- t = fread(&elem->type, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- t = fread(first_child_offset, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- t = fread(next_sibling_offset, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- cnt = sizeof(int);
- t = fread(&key_len, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- if (key_len) {
- elem->key = malloc(key_len+1);
- cnt = key_len;
- t = fread(elem->key, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- }
- cnt = sizeof(int);
- t = fread(&elem->value_len, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- if (elem->value_len) {
- elem->value = malloc(elem->value_len);
- cnt = elem->value_len;
- t = fread(elem->value, 1, cnt, fp);
- if (t != cnt)
- goto on_error;
- }
- elem->file_offset = offset;
- INIT_LIST_HEAD(&elem->child_list);
- *p_elem = elem;
- return 0;
- on_error:
- if (elem) {
- if (elem->key)
- free(elem->key);
- if (elem->value)
- free(elem->value);
- free(elem);
- }
- return Error_IO;
- }
- static int file_read_elem(FILE *fp, sp_pst_elem_t *parent, int offset, sp_pst_elem_t **p_elem, int *next_sibling_offset)
- {
- int rc, first_child_offset;
- sp_pst_elem_t *elem;
- rc = file_read_elem_single(fp, offset, &elem, next_sibling_offset, &first_child_offset);
- if (rc != 0)
- return rc;
- list_add_tail(&elem->entry, &parent->child_list);
- elem->parent = parent;
- *p_elem = elem;
- if (first_child_offset != 0) {
- sp_pst_elem_t *child_elem = NULL;
- int child_next_sibling_offset;
- rc = file_read_elem(fp, elem, first_child_offset, &child_elem, &child_next_sibling_offset);
- if (rc == 0) {
- while (child_next_sibling_offset != 0) {
- sp_pst_elem_t *tmp;
- rc = file_read_elem(fp, elem, child_next_sibling_offset, &tmp, &child_next_sibling_offset);
- if (rc != 0) {
- sp_pst_elem_destroy(tmp);
- break;
- } else {
- child_elem = tmp;
- }
- }
- } else {
- sp_pst_elem_destroy(child_elem);
- }
- }
- return rc;
- }
- int sp_pst_tree_create(sp_pst_tree_t **p_tree)
- {
- sp_pst_tree_t *tree = MALLOC_T(sp_pst_tree_t);
- tree->root = NULL;
- *p_tree = tree;
- return 0;
- }
- void sp_pst_tree_destroy(sp_pst_tree_t *tree)
- {
- sp_pst_elem_t *root = tree->root;
- if (root) {
- sp_pst_elem_destroy(root);
- free(tree);
- }
- }
- sp_pst_elem_t *sp_pst_tree_get_root(sp_pst_tree_t *tree)
- {
- return tree->root;
- }
- int sp_pst_tree_set_root(sp_pst_tree_t *tree, sp_pst_elem_t *elem)
- {
- if (tree->root)
- return Error_AlreadyExist;
- tree->root = elem;
- return 0;
- }
- sp_pst_elem_t *sp_pst_elem_create(sp_pst_elem_t *parent, const char *key)
- {
- sp_pst_elem_t *elem = ZALLOC_T(sp_pst_elem_t);
- INIT_LIST_HEAD(&elem->child_list);
- elem->key = _strdup(key);
- elem->parent = parent;
- return elem;
- }
- void sp_pst_elem_destroy(sp_pst_elem_t *elem)
- {
- if (elem) {
- while (!list_empty(&elem->child_list)) {
- sp_pst_elem_t *child = list_first_entry(&elem->child_list, sp_pst_elem_t, entry);
- list_del(&child->entry);
- sp_pst_elem_destroy(child);
- }
- free(elem->key);
- free(elem->value);
- free(elem);
- }
- }
- int sp_pst_elem_set_value(sp_pst_elem_t *elem, int type, const void *value, int value_len)
- {
- if (elem->value) {
- free(elem->value);
- elem->value = NULL;
- elem->type = SP_PST_T_UNKNOWN;
- }
- elem->type = type;
- if (value_len == -1) {
- elem->value_len = value ? strlen(value) : 0;
- elem->value = _strdup(value);
- } else if (value_len == 0) {
- elem->value = NULL;
- elem->value_len = 0;
- } else {
- elem->value = malloc(value_len);
- elem->value_len = value_len;
- memcpy(elem->value, value, value_len); // {bug} added
- }
- return 0;
- }
- sp_pst_elem_t *sp_pst_elem_get_parent(sp_pst_elem_t *elem)
- {
- return elem->parent;
- }
- const char *sp_pst_elem_get_key(sp_pst_elem_t *elem)
- {
- return elem->key;
- }
- int sp_pst_elem_get_type(sp_pst_elem_t *elem)
- {
- return elem->type;
- }
- const void *sp_pst_elem_get_value(sp_pst_elem_t *elem)
- {
- return elem->value;
- }
- int sp_pst_elem_get_value_len(sp_pst_elem_t *elem)
- {
- return elem->value_len;
- }
- int sp_pst_elem_append_child(sp_pst_elem_t *elem, sp_pst_elem_t *new_elem)
- {
- if (elem && new_elem) {
- list_add_tail(&new_elem->entry, &elem->child_list);
- return 0;
- } else {
- return Error_Param;
- }
- }
- int sp_pst_elem_remove_child_by_key(sp_pst_elem_t *elem, const char *key)
- {
- sp_pst_elem_t *child = sp_pst_elem_find_child(elem, key);
- if (child) {
- list_del(&child->entry);
- sp_pst_elem_destroy(child);
- } else {
- return Error_NotExist;
- }
- return 0;
- }
- int sp_pst_elem_remove(sp_pst_elem_t *elem)
- {
- if (elem) {
- if (elem->entry.next && elem->entry.prev)
- list_del(&elem->entry);
- } else {
- return Error_Param;
- }
- return 0;
- }
- sp_pst_elem_t *sp_pst_elem_find_child(sp_pst_elem_t *elem, const char *key)
- {
- if (elem && key) {
- sp_pst_elem_t *pos;
- list_for_each_entry(pos, &elem->child_list, sp_pst_elem_t, entry) {
- if (_stricmp(pos->key, key) == 0)
- return pos;
- }
- }
- return NULL;
- }
- int sp_pst_elem_insert_before( sp_pst_elem_t *pos, sp_pst_elem_t *new_elem )
- {
- if (pos && new_elem) {
- __list_add(&new_elem->entry, pos->entry.prev, &pos->entry);
- } else {
- return Error_Param;
- }
- return 0;
- }
- int sp_pst_elem_insert_after(sp_pst_elem_t *pos, sp_pst_elem_t *new_elem)
- {
- if (pos && new_elem) {
- __list_add(&new_elem->entry, &pos->entry, pos->entry.next);
- } else {
- return Error_Param;
- }
- return 0;
- }
- sp_pst_elem_t *sp_pst_elem_first_child(sp_pst_elem_t *parent_elem)
- {
- if (!list_empty(&parent_elem->child_list))
- return list_first_entry(&parent_elem->child_list, sp_pst_elem_t, entry);
- return NULL;
- }
- sp_pst_elem_t *sp_pst_elem_last_child(sp_pst_elem_t *parent_elem)
- {
- if (!list_empty(&parent_elem->child_list))
- return list_last_entry(&parent_elem->child_list, sp_pst_elem_t, entry);
- return NULL;
- }
- sp_pst_elem_t *sp_pst_elem_next_sibling(sp_pst_elem_t *iter_elem)
- {
- sp_pst_elem_t *parent_elem = iter_elem->parent;
- struct list_head *next = iter_elem->entry.next;
- if (parent_elem->child_list.next != next) {
- return list_entry(next, sp_pst_elem_t, entry);
- }
- return NULL;
- }
- sp_pst_elem_t *sp_pst_elem_last_sibling(sp_pst_elem_t *iter_elem)
- {
- sp_pst_elem_t *parent_elem = iter_elem->parent;
- struct list_head *last = iter_elem->entry.prev;
- if (parent_elem->child_list.prev != last) {
- return list_entry(last, sp_pst_elem_t, entry);
- }
- return NULL;
- }
- int sp_pst_tree_load(const char *base_dir, const char *ent, const char *cls, const char *obj, sp_pst_tree_t **p_tree)
- {
- int rc = 0;
- char tmp[MAX_PATH];
- FILE *fp;
- get_full_path(base_dir, ent, cls, obj, tmp);
- fp = fileutil_transaction_fopen(tmp, "rb");
- if (fp) {
- int next_sibling_offset;
- sp_pst_elem_t *root = NULL;
- rc = file_read_elem(fp, NULL, 0, &root, &next_sibling_offset);
- if (rc != 0) {
- sp_pst_elem_destroy(root);
- } else {
- sp_pst_tree_create(p_tree);
- sp_pst_tree_set_root(*p_tree, root);
- }
- fileutil_transaction_fclose(tmp, fp);
- } else {
- if (!ExistsFileA(tmp)) {
- rc = Error_NotExist;
- } else {
- rc = Error_IO;
- }
- }
- return rc;
- }
- int sp_pst_tree_save(const char *base_dir, const char *ent, const char *cls, const char *obj, sp_pst_tree_t *tree)
- {
- int rc = 0;
- FILE *fp;
- char tmp[MAX_PATH];
- get_full_path(base_dir, ent, cls, obj, tmp);
- CreateParentDirA(tmp, TRUE);
- fp = fileutil_transaction_fopen(tmp, "wb");
- if (fp) {
- fill_offset(tree);
- rc = file_write(fp, tree);
- fileutil_transaction_fclose(tmp, fp);
- } else {
- rc = Error_IO;
- }
- return rc;
- }
- static void recover_persist_dir_files(const char *dir)
- {
- HANDLE hFind;
- char szFile[MAX_PATH];
- WIN32_FIND_DATAA fd;
- strcpy(szFile, dir);
- strcat(szFile, SPLIT_SLASH_STR "*");
- hFind = FindFirstFileA(szFile, &fd);
- if (hFind != INVALID_HANDLE_VALUE) {
- do {
- if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
- char t[MAX_PATH];
- strcpy(t, szFile);
- t[strlen(t)-1] = 0;
- strcat(t, fd.cFileName);
- DeleteFileA(t);
- }
- }
- } while (FindNextFileA(hFind, &fd));
- FindClose(hFind);
- }
- hFind = FindFirstFileA(szFile, &fd);
- if (hFind != INVALID_HANDLE_VALUE) {
- do {
- if (fd.dwFileAttributes & FILE_ATTRIBUTE_NORMAL & FILE_ATTRIBUTE_READONLY) {
- if (str_has_suffix(fd.cFileName, ".dat") == 0) {
- char t[MAX_PATH];
- strcpy(t, szFile);
- szFile[strlen(szFile)-1] = 0;
- strcat(t, fd.cFileName);
- strcat(t, ".bak");
- if (ExistsFileA(t))
- DeleteFileA(t);
- } else if (str_has_suffix(fd.cFileName, ".bak") == 0) {
- char t[MAX_PATH];
- DWORD dwType;
- strcpy(t, szFile);
- szFile[strlen(szFile)-1] = 0;
- strcat(t, fd.cFileName);
- t[strlen(t)-4] = 0;
- dwType = GetFileAttributesA(t);
- if (dwType & FILE_ATTRIBUTE_READONLY) {
- t[strlen(t)] = '.';
- SetFileAttributesA(t, dwType & ~FILE_ATTRIBUTE_READONLY);
- DeleteFileA(t);
- } else {
- char tt[MAX_PATH];
- strcpy(tt, t);
- strcat(tt, ".bak");
- CopyFileA(t, tt, FALSE);
- SetFileAttributesA(tt, fd.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
- DeleteFileA(tt);
- }
- }
- }
- } while (FindNextFileA(hFind, &fd));
- FindClose(hFind);
- }
- }
- void sp_pst_recover(const char *base_dir)
- {
- HANDLE hFind;
- char szObject[MAX_PATH];
- WIN32_FIND_DATAA fd;
- int rc = 0;
- sprintf(szObject, "%s" SPLIT_SLASH_STR "*", base_dir);
- hFind = FindFirstFileA(szObject, &fd);
- if (hFind != INVALID_HANDLE_VALUE) {
- do {
- if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
- strcmp(fd.cFileName, ".") &&
- strcmp(fd.cFileName, "..")) {
- HANDLE hChildFind;
- char szEntity[MAX_PATH];
- WIN32_FIND_DATAA fdChild;
- strcpy(szEntity, szObject);
- szEntity[strlen(szEntity)-1] = 0;
- strcat(szEntity, fd.cFileName);
- strcat(szEntity, SPLIT_SLASH_STR "*");
- hChildFind = FindFirstFileA(szEntity, &fdChild);
- if (hChildFind != INVALID_HANDLE_VALUE) {
- do {
- if (fdChild.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
- strcmp(fdChild.cFileName, ".") &&
- strcmp(fdChild.cFileName, "..")) {
- char szClass[MAX_PATH];
- strcpy(szClass, szEntity);
- szClass[strlen(szClass)-1] = 0;
- strcat(szClass, fdChild.cFileName);
- recover_persist_dir_files(szClass);
- }
- } while (FindNextFileA(hChildFind, &fdChild));
- FindClose(hChildFind);
- }
- }
- } while (FindNextFileA(hFind, &fd));
- FindClose(hFind);
- }
- }
- int sp_pst_get_object_count(const char *base_dir, const char *ent, const char *cls, int *p_cnt)
- {
- char tmp[MAX_PATH];
- HANDLE hFind;
- WIN32_FIND_DATAA fd;
- int rc = 0;
- int cnt = 0;
- get_full_path(base_dir, ent, cls, "*", tmp);
- hFind = FindFirstFileA(tmp, &fd);
- if (hFind != INVALID_HANDLE_VALUE) {
- do {
- if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- if (str_has_suffix(fd.cFileName, ".dat") == 0)
- cnt++;
- }
- } while (FindNextFileA(hFind, &fd));
- FindClose(hFind);
- } else {
- if (GetLastError() != ERROR_FILE_NOT_FOUND)
- rc = Error_IO;
- }
- *p_cnt = cnt;
- return rc;
- }
- array_header_t* sp_pst_get_object_keys(const char *base_dir, const char *ent, const char *cls)
- {
- array_header_t *arr = NULL;
- char tmp[MAX_PATH];
- HANDLE hFind;
- WIN32_FIND_DATAA fd;
- get_full_path(base_dir, ent, cls, "*", tmp);
- hFind = FindFirstFileA(tmp, &fd);
- if (hFind != INVALID_HANDLE_VALUE) {
- arr = array_make(-1, sizeof(char*));
- do {
- if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- if (str_has_suffix(fd.cFileName, ".dat") == 0) {
- size_t idx = strlen(fd.cFileName) - 4;
- int t = fd.cFileName[idx];
- fd.cFileName[idx] = '\0';
- ARRAY_PUSH(arr, char*) = _strdup(fd.cFileName);
- fd.cFileName[idx] = t;
- }
- }
- } while (FindNextFileA(hFind, &fd));
- FindClose(hFind);
- } else {
- if (GetLastError() != ERROR_FILE_NOT_FOUND)
- arr = array_make(-1, sizeof(char*));
- }
- return arr;
- }
- int sp_pst_delete_object(const char *base_dir, const char *ent, const char *cls, const char *obj)
- {
- char tmp[MAX_PATH];
- int rc = 0;
- get_full_path(base_dir, ent, cls, obj, tmp);
- if (ExistsFileA(tmp)) {
- BOOL bRet = DeleteFileA(tmp);
- if (!bRet)
- rc = Error_IO;
- } else {
- rc = Error_NotExist;
- }
- strcat(tmp, ".bak");
- DeleteFileA(tmp);
- return rc;
- }
- int sp_pst_delete_class_objects(const char *base_dir, const char *ent, const char *cls)
- {
- char tmp[MAX_PATH];
- get_full_path(base_dir, ent, cls, NULL, tmp);
- RemoveDirRecursiveA(tmp);
- return 0;
- }
|