sp_pst.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. #include "precompile.h"
  2. #include "sp_pst.h"
  3. #include "sp_def.h"
  4. #include "memutil.h"
  5. #include "fileutil.h"
  6. #include "strutil.h"
  7. #include "list.h"
  8. struct sp_pst_tree_t {
  9. sp_pst_elem_t *root;
  10. };
  11. struct sp_pst_elem_t {
  12. struct list_head entry;
  13. int type;
  14. char *key;
  15. void *value;
  16. int value_len;
  17. sp_pst_elem_t *parent;
  18. int file_offset;
  19. struct list_head child_list;
  20. };
  21. // file serialize order are first-order
  22. static const char *get_full_path(const char *base_dir, const char *ent, const char *cls, const char *obj, char *buf)
  23. {
  24. if (cls) {
  25. if (obj) {
  26. sprintf(buf, "%s\\objects\\%s\\%s\\%s.dat", base_dir, ent, cls, obj);
  27. } else {
  28. sprintf(buf, "%s\\objects\\%s\\%s", base_dir, ent, cls);
  29. }
  30. } else {
  31. sprintf(buf, "%s\\objects\\%s", base_dir, ent);
  32. }
  33. return buf;
  34. }
  35. static int file_write_elem_single(FILE *fp, sp_pst_elem_t *elem)
  36. {
  37. int type = elem->type;
  38. int child_offset;
  39. int next_sibling_offset;
  40. int key_len = strlen(elem->key);
  41. void *key = elem->key;
  42. int value_len = elem->value_len;
  43. void *value = elem->value;
  44. size_t t, cnt;
  45. if (list_empty(&elem->child_list)) {
  46. child_offset = 0;
  47. } else {
  48. sp_pst_elem_t *child = list_first_entry(&elem->child_list, sp_pst_elem_t, entry);
  49. child_offset = child->file_offset;
  50. }
  51. if (elem->entry.next) {
  52. sp_pst_elem_t *next_sibling = sp_pst_elem_next_sibling(elem);
  53. next_sibling_offset = next_sibling ? next_sibling->file_offset : 0;
  54. } else {
  55. next_sibling_offset = 0;
  56. }
  57. // type | child_offset | next_sibling_offset | key | value
  58. cnt = sizeof(int);
  59. t = fwrite(&type, 1, cnt, fp);
  60. if (t != cnt)
  61. goto on_error;
  62. t = fwrite(&child_offset, 1, cnt, fp);
  63. if (t != cnt)
  64. goto on_error;
  65. t = fwrite(&next_sibling_offset, 1, cnt, fp);
  66. if (t != cnt)
  67. goto on_error;
  68. t = fwrite(&key_len, 1, cnt, fp);
  69. if (t != cnt)
  70. goto on_error;
  71. cnt = key_len;
  72. t = fwrite(key, 1, key_len, fp);
  73. if (t != cnt)
  74. goto on_error;
  75. cnt = sizeof(int);
  76. t = fwrite(&value_len, 1, cnt, fp);
  77. if (t != cnt)
  78. goto on_error;
  79. cnt = value_len;
  80. t = fwrite(value, 1, value_len, fp);
  81. if (t != cnt)
  82. goto on_error;
  83. return 0;
  84. on_error:
  85. return Error_IO;
  86. }
  87. // first-order write
  88. static int file_write_elem(FILE *fp, sp_pst_elem_t *elem)
  89. {
  90. int rc;
  91. rc = file_write_elem_single(fp, elem);
  92. if (rc == 0) {
  93. sp_pst_elem_t *pos;
  94. list_for_each_entry(pos, &elem->child_list, sp_pst_elem_t, entry) {
  95. rc = file_write_elem(fp, pos);
  96. if (rc != 0)
  97. break;
  98. }
  99. }
  100. return rc;
  101. }
  102. static int file_write(FILE *fp, sp_pst_tree_t *tree)
  103. {
  104. return file_write_elem(fp, tree->root);
  105. }
  106. // first-order fill
  107. static void fill_offset_elem(int *curr_offset, sp_pst_elem_t *elem)
  108. {
  109. sp_pst_elem_t *pos;
  110. int size = 5 * sizeof(int) + strlen(elem->key) + elem->value_len;
  111. elem->file_offset = *curr_offset;
  112. *curr_offset += size;
  113. list_for_each_entry(pos, &elem->child_list, sp_pst_elem_t, entry) {
  114. fill_offset_elem(curr_offset, pos);
  115. }
  116. }
  117. static int fill_offset(sp_pst_tree_t *tree)
  118. {
  119. int curr_offset = 0;
  120. fill_offset_elem(&curr_offset, tree->root);
  121. return curr_offset;
  122. }
  123. static int file_read_elem_single(FILE *fp, int offset, sp_pst_elem_t **p_elem, int *next_sibling_offset, int *first_child_offset)
  124. {
  125. int rc = 0;
  126. sp_pst_elem_t *elem = NULL;
  127. size_t t, cnt;
  128. int key_len;
  129. rc = fseek(fp, offset, SEEK_SET);
  130. if (rc != 0)
  131. goto on_error;
  132. elem = ZALLOC_T(sp_pst_elem_t);
  133. cnt = sizeof(int);
  134. t = fread(&elem->type, 1, cnt, fp);
  135. if (t != cnt)
  136. goto on_error;
  137. t = fread(first_child_offset, 1, cnt, fp);
  138. if (t != cnt)
  139. goto on_error;
  140. t = fread(next_sibling_offset, 1, cnt, fp);
  141. if (t != cnt)
  142. goto on_error;
  143. cnt = sizeof(int);
  144. t = fread(&key_len, 1, cnt, fp);
  145. if (t != cnt)
  146. goto on_error;
  147. if (key_len) {
  148. elem->key = malloc(key_len+1);
  149. cnt = key_len;
  150. t = fread(elem->key, 1, cnt, fp);
  151. if (t != cnt)
  152. goto on_error;
  153. }
  154. cnt = sizeof(int);
  155. t = fread(&elem->value_len, 1, cnt, fp);
  156. if (t != cnt)
  157. goto on_error;
  158. if (elem->value_len) {
  159. elem->value = malloc(elem->value_len);
  160. cnt = elem->value_len;
  161. t = fread(elem->value, 1, cnt, fp);
  162. if (t != cnt)
  163. goto on_error;
  164. }
  165. elem->file_offset = offset;
  166. INIT_LIST_HEAD(&elem->child_list);
  167. *p_elem = elem;
  168. return 0;
  169. on_error:
  170. if (elem) {
  171. if (elem->key)
  172. free(elem->key);
  173. if (elem->value)
  174. free(elem->value);
  175. free(elem);
  176. }
  177. return Error_IO;
  178. }
  179. static int file_read_elem(FILE *fp, sp_pst_elem_t *parent, int offset, sp_pst_elem_t **p_elem, int *next_sibling_offset)
  180. {
  181. int rc, first_child_offset;
  182. sp_pst_elem_t *elem;
  183. rc = file_read_elem_single(fp, offset, &elem, next_sibling_offset, &first_child_offset);
  184. if (rc != 0)
  185. return rc;
  186. list_add_tail(&elem->entry, &parent->child_list);
  187. elem->parent = parent;
  188. *p_elem = elem;
  189. if (first_child_offset != 0) {
  190. sp_pst_elem_t *child_elem = NULL;
  191. int child_next_sibling_offset;
  192. rc = file_read_elem(fp, elem, first_child_offset, &child_elem, &child_next_sibling_offset);
  193. if (rc == 0) {
  194. while (child_next_sibling_offset != 0) {
  195. sp_pst_elem_t *tmp;
  196. rc = file_read_elem(fp, elem, child_next_sibling_offset, &tmp, &child_next_sibling_offset);
  197. if (rc != 0) {
  198. sp_pst_elem_destroy(tmp);
  199. break;
  200. } else {
  201. child_elem = tmp;
  202. }
  203. }
  204. } else {
  205. sp_pst_elem_destroy(child_elem);
  206. }
  207. }
  208. return rc;
  209. }
  210. int sp_pst_tree_create(sp_pst_tree_t **p_tree)
  211. {
  212. sp_pst_tree_t *tree = MALLOC_T(sp_pst_tree_t);
  213. tree->root = NULL;
  214. *p_tree = tree;
  215. return 0;
  216. }
  217. void sp_pst_tree_destroy(sp_pst_tree_t *tree)
  218. {
  219. sp_pst_elem_t *root = tree->root;
  220. if (root) {
  221. sp_pst_elem_destroy(root);
  222. free(tree);
  223. }
  224. }
  225. sp_pst_elem_t *sp_pst_tree_get_root(sp_pst_tree_t *tree)
  226. {
  227. return tree->root;
  228. }
  229. int sp_pst_tree_set_root(sp_pst_tree_t *tree, sp_pst_elem_t *elem)
  230. {
  231. if (tree->root)
  232. return Error_AlreadyExist;
  233. tree->root = elem;
  234. return 0;
  235. }
  236. sp_pst_elem_t *sp_pst_elem_create(sp_pst_elem_t *parent, const char *key)
  237. {
  238. sp_pst_elem_t *elem = ZALLOC_T(sp_pst_elem_t);
  239. INIT_LIST_HEAD(&elem->child_list);
  240. elem->key = _strdup(key);
  241. elem->parent = parent;
  242. return elem;
  243. }
  244. void sp_pst_elem_destroy(sp_pst_elem_t *elem)
  245. {
  246. if (elem) {
  247. while (!list_empty(&elem->child_list)) {
  248. sp_pst_elem_t *child = list_first_entry(&elem->child_list, sp_pst_elem_t, entry);
  249. list_del(&child->entry);
  250. sp_pst_elem_destroy(child);
  251. }
  252. free(elem->key);
  253. free(elem->value);
  254. free(elem);
  255. }
  256. }
  257. int sp_pst_elem_set_value(sp_pst_elem_t *elem, int type, const void *value, int value_len)
  258. {
  259. if (elem->value) {
  260. free(elem->value);
  261. elem->value = NULL;
  262. elem->type = SP_PST_T_UNKNOWN;
  263. }
  264. elem->type = type;
  265. if (value_len == -1) {
  266. elem->value_len = value ? strlen(value) : 0;
  267. elem->value = _strdup(value);
  268. } else if (value_len == 0) {
  269. elem->value = NULL;
  270. elem->value_len = 0;
  271. } else {
  272. elem->value = malloc(value_len);
  273. elem->value_len = value_len;
  274. memcpy(elem->value, value, value_len); // {bug} added
  275. }
  276. return 0;
  277. }
  278. sp_pst_elem_t *sp_pst_elem_get_parent(sp_pst_elem_t *elem)
  279. {
  280. return elem->parent;
  281. }
  282. const char *sp_pst_elem_get_key(sp_pst_elem_t *elem)
  283. {
  284. return elem->key;
  285. }
  286. int sp_pst_elem_get_type(sp_pst_elem_t *elem)
  287. {
  288. return elem->type;
  289. }
  290. const void *sp_pst_elem_get_value(sp_pst_elem_t *elem)
  291. {
  292. return elem->value;
  293. }
  294. int sp_pst_elem_get_value_len(sp_pst_elem_t *elem)
  295. {
  296. return elem->value_len;
  297. }
  298. int sp_pst_elem_append_child(sp_pst_elem_t *elem, sp_pst_elem_t *new_elem)
  299. {
  300. if (elem && new_elem) {
  301. list_add_tail(&new_elem->entry, &elem->child_list);
  302. return 0;
  303. } else {
  304. return Error_Param;
  305. }
  306. }
  307. int sp_pst_elem_remove_child_by_key(sp_pst_elem_t *elem, const char *key)
  308. {
  309. sp_pst_elem_t *child = sp_pst_elem_find_child(elem, key);
  310. if (child) {
  311. list_del(&child->entry);
  312. sp_pst_elem_destroy(child);
  313. } else {
  314. return Error_NotExist;
  315. }
  316. return 0;
  317. }
  318. int sp_pst_elem_remove(sp_pst_elem_t *elem)
  319. {
  320. if (elem) {
  321. if (elem->entry.next && elem->entry.prev)
  322. list_del(&elem->entry);
  323. } else {
  324. return Error_Param;
  325. }
  326. return 0;
  327. }
  328. sp_pst_elem_t *sp_pst_elem_find_child(sp_pst_elem_t *elem, const char *key)
  329. {
  330. if (elem && key) {
  331. sp_pst_elem_t *pos;
  332. list_for_each_entry(pos, &elem->child_list, sp_pst_elem_t, entry) {
  333. if (_stricmp(pos->key, key) == 0)
  334. return pos;
  335. }
  336. }
  337. return NULL;
  338. }
  339. int sp_pst_elem_insert_before( sp_pst_elem_t *pos, sp_pst_elem_t *new_elem )
  340. {
  341. if (pos && new_elem) {
  342. __list_add(&new_elem->entry, pos->entry.prev, &pos->entry);
  343. } else {
  344. return Error_Param;
  345. }
  346. return 0;
  347. }
  348. int sp_pst_elem_insert_after(sp_pst_elem_t *pos, sp_pst_elem_t *new_elem)
  349. {
  350. if (pos && new_elem) {
  351. __list_add(&new_elem->entry, &pos->entry, pos->entry.next);
  352. } else {
  353. return Error_Param;
  354. }
  355. return 0;
  356. }
  357. sp_pst_elem_t *sp_pst_elem_first_child(sp_pst_elem_t *parent_elem)
  358. {
  359. if (!list_empty(&parent_elem->child_list))
  360. return list_first_entry(&parent_elem->child_list, sp_pst_elem_t, entry);
  361. return NULL;
  362. }
  363. sp_pst_elem_t *sp_pst_elem_last_child(sp_pst_elem_t *parent_elem)
  364. {
  365. if (!list_empty(&parent_elem->child_list))
  366. return list_last_entry(&parent_elem->child_list, sp_pst_elem_t, entry);
  367. return NULL;
  368. }
  369. sp_pst_elem_t *sp_pst_elem_next_sibling(sp_pst_elem_t *iter_elem)
  370. {
  371. sp_pst_elem_t *parent_elem = iter_elem->parent;
  372. struct list_head *next = iter_elem->entry.next;
  373. if (parent_elem->child_list.next != next) {
  374. return list_entry(next, sp_pst_elem_t, entry);
  375. }
  376. return NULL;
  377. }
  378. sp_pst_elem_t *sp_pst_elem_last_sibling(sp_pst_elem_t *iter_elem)
  379. {
  380. sp_pst_elem_t *parent_elem = iter_elem->parent;
  381. struct list_head *last = iter_elem->entry.prev;
  382. if (parent_elem->child_list.prev != last) {
  383. return list_entry(last, sp_pst_elem_t, entry);
  384. }
  385. return NULL;
  386. }
  387. int sp_pst_tree_load(const char *base_dir, const char *ent, const char *cls, const char *obj, sp_pst_tree_t **p_tree)
  388. {
  389. int rc = 0;
  390. char tmp[MAX_PATH];
  391. FILE *fp;
  392. get_full_path(base_dir, ent, cls, obj, tmp);
  393. fp = fileutil_transaction_fopen(tmp, "rb");
  394. if (fp) {
  395. int next_sibling_offset;
  396. sp_pst_elem_t *root = NULL;
  397. rc = file_read_elem(fp, NULL, 0, &root, &next_sibling_offset);
  398. if (rc != 0) {
  399. sp_pst_elem_destroy(root);
  400. } else {
  401. sp_pst_tree_create(p_tree);
  402. sp_pst_tree_set_root(*p_tree, root);
  403. }
  404. fileutil_transaction_fclose(tmp, fp);
  405. } else {
  406. if (!ExistsFileA(tmp)) {
  407. rc = Error_NotExist;
  408. } else {
  409. rc = Error_IO;
  410. }
  411. }
  412. return rc;
  413. }
  414. int sp_pst_tree_save(const char *base_dir, const char *ent, const char *cls, const char *obj, sp_pst_tree_t *tree)
  415. {
  416. int rc = 0;
  417. FILE *fp;
  418. char tmp[MAX_PATH];
  419. get_full_path(base_dir, ent, cls, obj, tmp);
  420. CreateParentDirA(tmp, TRUE);
  421. fp = fileutil_transaction_fopen(tmp, "wb");
  422. if (fp) {
  423. fill_offset(tree);
  424. rc = file_write(fp, tree);
  425. fileutil_transaction_fclose(tmp, fp);
  426. } else {
  427. rc = Error_IO;
  428. }
  429. return rc;
  430. }
  431. static void recover_persist_dir_files(const char *dir)
  432. {
  433. HANDLE hFind;
  434. char szFile[MAX_PATH];
  435. WIN32_FIND_DATAA fd;
  436. strcpy(szFile, dir);
  437. strcat(szFile, "\\*");
  438. hFind = FindFirstFileA(szFile, &fd);
  439. if (hFind != INVALID_HANDLE_VALUE) {
  440. do {
  441. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  442. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
  443. char t[MAX_PATH];
  444. strcpy(t, szFile);
  445. t[strlen(t)-1] = 0;
  446. strcat(t, fd.cFileName);
  447. DeleteFileA(t);
  448. }
  449. }
  450. } while (FindNextFileA(hFind, &fd));
  451. FindClose(hFind);
  452. }
  453. hFind = FindFirstFileA(szFile, &fd);
  454. if (hFind != INVALID_HANDLE_VALUE) {
  455. do {
  456. if (fd.dwFileAttributes & FILE_ATTRIBUTE_NORMAL & FILE_ATTRIBUTE_READONLY) {
  457. if (str_has_suffix(fd.cFileName, ".dat") == 0) {
  458. char t[MAX_PATH];
  459. strcpy(t, szFile);
  460. szFile[strlen(szFile)-1] = 0;
  461. strcat(t, fd.cFileName);
  462. strcat(t, ".bak");
  463. if (ExistsFileA(t))
  464. DeleteFileA(t);
  465. } else if (str_has_suffix(fd.cFileName, ".bak") == 0) {
  466. char t[MAX_PATH];
  467. DWORD dwType;
  468. strcpy(t, szFile);
  469. szFile[strlen(szFile)-1] = 0;
  470. strcat(t, fd.cFileName);
  471. t[strlen(t)-4] = 0;
  472. dwType = GetFileAttributesA(t);
  473. if (dwType & FILE_ATTRIBUTE_READONLY) {
  474. t[strlen(t)] = '.';
  475. SetFileAttributesA(t, dwType & ~FILE_ATTRIBUTE_READONLY);
  476. DeleteFileA(t);
  477. } else {
  478. char tt[MAX_PATH];
  479. strcpy(tt, t);
  480. strcat(tt, ".bak");
  481. CopyFileA(t, tt, FALSE);
  482. SetFileAttributesA(tt, fd.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
  483. DeleteFileA(tt);
  484. }
  485. }
  486. }
  487. } while (FindNextFileA(hFind, &fd));
  488. FindClose(hFind);
  489. }
  490. }
  491. void sp_pst_recover(const char *base_dir)
  492. {
  493. HANDLE hFind;
  494. char szObject[MAX_PATH];
  495. WIN32_FIND_DATAA fd;
  496. int rc = 0;
  497. sprintf(szObject, "%s\\*", base_dir);
  498. hFind = FindFirstFileA(szObject, &fd);
  499. if (hFind != INVALID_HANDLE_VALUE) {
  500. do {
  501. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
  502. strcmp(fd.cFileName, ".") &&
  503. strcmp(fd.cFileName, "..")) {
  504. HANDLE hChildFind;
  505. char szEntity[MAX_PATH];
  506. WIN32_FIND_DATAA fdChild;
  507. strcpy(szEntity, szObject);
  508. szEntity[strlen(szEntity)-1] = 0;
  509. strcat(szEntity, fd.cFileName);
  510. strcat(szEntity, "\\*");
  511. hChildFind = FindFirstFileA(szEntity, &fdChild);
  512. if (hChildFind != INVALID_HANDLE_VALUE) {
  513. do {
  514. if (fdChild.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
  515. strcmp(fdChild.cFileName, ".") &&
  516. strcmp(fdChild.cFileName, "..")) {
  517. char szClass[MAX_PATH];
  518. strcpy(szClass, szEntity);
  519. szClass[strlen(szClass)-1] = 0;
  520. strcat(szClass, fdChild.cFileName);
  521. recover_persist_dir_files(szClass);
  522. }
  523. } while (FindNextFileA(hChildFind, &fdChild));
  524. FindClose(hChildFind);
  525. }
  526. }
  527. } while (FindNextFileA(hFind, &fd));
  528. FindClose(hFind);
  529. }
  530. }
  531. int sp_pst_get_object_count(const char *base_dir, const char *ent, const char *cls, int *p_cnt)
  532. {
  533. char tmp[MAX_PATH];
  534. HANDLE hFind;
  535. WIN32_FIND_DATAA fd;
  536. int rc = 0;
  537. int cnt = 0;
  538. get_full_path(base_dir, ent, cls, "*", tmp);
  539. hFind = FindFirstFileA(tmp, &fd);
  540. if (hFind != INVALID_HANDLE_VALUE) {
  541. do {
  542. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  543. if (str_has_suffix(fd.cFileName, ".dat") == 0)
  544. cnt++;
  545. }
  546. } while (FindNextFileA(hFind, &fd));
  547. FindClose(hFind);
  548. } else {
  549. if (GetLastError() != ERROR_FILE_NOT_FOUND)
  550. rc = Error_IO;
  551. }
  552. *p_cnt = cnt;
  553. return rc;
  554. }
  555. array_header_t* sp_pst_get_object_keys(const char *base_dir, const char *ent, const char *cls)
  556. {
  557. array_header_t *arr = NULL;
  558. char tmp[MAX_PATH];
  559. HANDLE hFind;
  560. WIN32_FIND_DATAA fd;
  561. get_full_path(base_dir, ent, cls, "*", tmp);
  562. hFind = FindFirstFileA(tmp, &fd);
  563. if (hFind != INVALID_HANDLE_VALUE) {
  564. arr = array_make(-1, sizeof(char*));
  565. do {
  566. if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
  567. if (str_has_suffix(fd.cFileName, ".dat") == 0) {
  568. size_t idx = strlen(fd.cFileName) - 4;
  569. int t = fd.cFileName[idx];
  570. fd.cFileName[idx] = '\0';
  571. ARRAY_PUSH(arr, char*) = _strdup(fd.cFileName);
  572. fd.cFileName[idx] = t;
  573. }
  574. }
  575. } while (FindNextFileA(hFind, &fd));
  576. FindClose(hFind);
  577. } else {
  578. if (GetLastError() != ERROR_FILE_NOT_FOUND)
  579. arr = array_make(-1, sizeof(char*));
  580. }
  581. return arr;
  582. }
  583. int sp_pst_delete_object(const char *base_dir, const char *ent, const char *cls, const char *obj)
  584. {
  585. char tmp[MAX_PATH];
  586. int rc = 0;
  587. get_full_path(base_dir, ent, cls, obj, tmp);
  588. if (ExistsFileA(tmp)) {
  589. BOOL bRet = DeleteFileA(tmp);
  590. if (!bRet)
  591. rc = Error_IO;
  592. } else {
  593. rc = Error_NotExist;
  594. }
  595. strcat(tmp, ".bak");
  596. DeleteFileA(tmp);
  597. return rc;
  598. }
  599. int sp_pst_delete_class_objects(const char *base_dir, const char *ent, const char *cls)
  600. {
  601. char tmp[MAX_PATH];
  602. get_full_path(base_dir, ent, cls, NULL, tmp);
  603. RemoveDirRecursiveA(tmp);
  604. return 0;
  605. }