sp_pst.c 16 KB

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