sp_pst.c 16 KB

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