sp_pst.c 16 KB

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