sp_pst.c 16 KB

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