改良版。参考:https://gitlab.freedesktop.org/xdg/shared-mime-info/issues/42

格式
Diff
提交日期
2020-03-11 12:28
Publication Period
Unlimited
  1. --- a/update-mime-database.c
  2. +++ b/update-mime-database.c
  3. @@ -1,3 +1,5 @@
  4. +#define _GNU_SOURCE
  5. +
  6. #include <config.h>
  7. #define N_(x) x
  8. @@ -37,6 +39,15 @@
  9. #define NOGLOBS "__NOGLOBS__"
  10. #define NOMAGIC "__NOMAGIC__"
  11. +#ifdef __linux__
  12. +# include <linux/version.h>
  13. +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
  14. +# include <linux/aio_abi.h>
  15. +# include <sys/syscall.h>
  16. +# include <sys/eventfd.h>
  17. +# endif
  18. +#endif
  19. +
  20. #ifndef PATH_SEPARATOR
  21. # ifdef _WIN32
  22. # define PATH_SEPARATOR ";"
  23. @@ -168,12 +179,31 @@
  24. /* Lists enabled log levels */
  25. static GLogLevelFlags enabled_log_levels = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING;
  26. +static GHashTable *rename_set = NULL;
  27. +
  28. /* Static prototypes */
  29. static Magic *magic_new(xmlNode *node, Type *type, GError **error);
  30. static Match *match_new(void);
  31. static TreeMagic *tree_magic_new(xmlNode *node, Type *type, GError **error);
  32. +#ifdef __LINUX__AIO_ABI_H
  33. +static int io_setup(unsigned nr_events, aio_context_t *ctx_idp){
  34. + return syscall(SYS_io_setup, nr_events, ctx_idp);
  35. +}
  36. +static int io_submit(aio_context_t ctx_id, long nr, struct iocb **iocbpp){
  37. + return syscall(SYS_io_submit, ctx_id, nr, iocbpp);
  38. +}
  39. +static int io_getevents(aio_context_t ctx_id, long min_nr, long nr,
  40. + struct io_event *events, struct timespec *timeout
  41. +){
  42. + return syscall(SYS_io_getevents, ctx_id, min_nr, nr, events, timeout);
  43. +}
  44. +static int io_destroy(aio_context_t ctx_id){
  45. + return syscall(SYS_io_destroy, ctx_id);
  46. +}
  47. +#endif
  48. +
  49. static void g_log_handler (const gchar *log_domain,
  50. GLogLevelFlags log_level,
  51. const gchar *message,
  52. @@ -986,38 +1016,237 @@
  53. return 0;
  54. }
  55. -/* Renames pathname by removing the .new extension */
  56. -static gboolean atomic_update(const gchar *pathname, GError **error)
  57. +static gboolean add_atomic_update(const gchar *pathname, GError **error)
  58. {
  59. - gboolean ret = FALSE;
  60. - gchar *new_name = NULL;
  61. int len;
  62. len = strlen(pathname);
  63. + g_return_val_if_fail(len > 4, FALSE);
  64. + g_return_val_if_fail(strcmp(pathname + len - 4, ".new") == 0, FALSE);
  65. +
  66. + gchar *dupname = g_strdup(pathname);
  67. + g_hash_table_add(rename_set, dupname);
  68. + return TRUE;
  69. +}
  70. +
  71. +static gboolean atomic_update_file(const gchar *pathname, GError **error){
  72. + gboolean ret = FALSE;
  73. + int len;
  74. + gchar *new_name = NULL;
  75. +
  76. + len = strlen(pathname);
  77. + g_return_val_if_fail(len > 4, FALSE);
  78. g_return_val_if_fail(strcmp(pathname + len - 4, ".new") == 0, FALSE);
  79. new_name = g_strndup(pathname, len - 4);
  80. - if (sync_file(pathname, error) == -1)
  81. - goto out;
  82. -
  83. #ifdef _WIN32
  84. /* we need to remove the old file first! */
  85. remove(new_name);
  86. #endif
  87. +
  88. if (rename(pathname, new_name) == -1)
  89. {
  90. int errsv = errno;
  91. - g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv),
  92. - "Failed to rename %s as %s: %s", pathname, new_name,
  93. - g_strerror(errsv));
  94. + g_set_error(error, G_FILE_ERROR,
  95. + g_file_error_from_errno(errsv),
  96. + "Failed to rename %s as %s: %s",
  97. + pathname, new_name, g_strerror(errsv));
  98. goto out;
  99. }
  100. ret = TRUE;
  101. out:
  102. g_free(new_name);
  103. +
  104. + return ret;
  105. +}
  106. +
  107. +#ifdef __LINUX__AIO_ABI_H
  108. +static gboolean linux_aio_wait(
  109. + aio_context_t aio_context, unsigned *aio_waiting, unsigned aio_max_cnt,
  110. + struct io_event *io_event_array, GError **error
  111. +){
  112. + int fin_cnt;
  113. + int i;
  114. +
  115. + fin_cnt = io_getevents(aio_context,
  116. + 1, aio_max_cnt, io_event_array, NULL);
  117. + if(fin_cnt < 0){
  118. + int errsv = errno;
  119. + if(errsv == EINTR){
  120. + return TRUE;
  121. + }
  122. + g_set_error(error, G_FILE_ERROR,
  123. + g_file_error_from_errno(errsv),
  124. + "io_getevents failed: %s", g_strerror(errsv));
  125. + return FALSE;
  126. + }
  127. +
  128. + // rename file if success
  129. + for(i = 0; i < fin_cnt; i++){
  130. + struct iocb *finished = (struct iocb *)io_event_array[i].obj;
  131. + gchar *pathname = (gchar *)finished->aio_data;
  132. +
  133. + close(finished->aio_fildes);
  134. + finished->aio_data = 0; // mark fd closed
  135. +
  136. + if(io_event_array[i].res){ // error
  137. + int errsv = errno;
  138. + if(errsv == EIO){
  139. + continue;
  140. + }
  141. + g_set_error(error, G_FILE_ERROR,
  142. + g_file_error_from_errno(errsv),
  143. + "io_getevents failed: %s", g_strerror(errsv));
  144. + return FALSE;
  145. + }
  146. +
  147. + if(!atomic_update_file(pathname, error)){
  148. + return FALSE;
  149. + }
  150. +
  151. + // remove finished element from list
  152. + g_hash_table_remove(rename_set, pathname);
  153. + }
  154. + *aio_waiting -= fin_cnt;
  155. +
  156. + return TRUE;
  157. +}
  158. +static gboolean finish_atomic_update_linux_aio(GError **error){
  159. + gboolean ret = TRUE;
  160. + guint fsync_cnt = g_hash_table_size(rename_set);
  161. + unsigned aio_max_cnt = fsync_cnt;
  162. + aio_context_t aio_context = 0;
  163. + struct iocb *iocb_array = NULL;
  164. + struct io_event *io_event_array = NULL;
  165. + guint aio_submited = 0;
  166. + unsigned aio_waiting = 0;
  167. + int evfd = -1;
  168. + GList *listp, *listh = NULL;
  169. + int i;
  170. +
  171. + if(!sync_enabled() || fsync_cnt <= 1){
  172. + goto noaio;
  173. + }
  174. +
  175. + while(io_setup(aio_max_cnt, &aio_context)){
  176. + if(errno == EAGAIN){
  177. + aio_max_cnt = (aio_max_cnt + 1) / 2;
  178. + if(aio_max_cnt <= 1){
  179. + goto noaio;
  180. + }
  181. + }else{
  182. + goto noaio;
  183. + }
  184. + }
  185. +
  186. + if((evfd = eventfd(0, 0)) < 0){
  187. + goto exit_aio;
  188. + }
  189. +
  190. + iocb_array = g_malloc0(sizeof(struct iocb) * fsync_cnt);
  191. + io_event_array
  192. + = g_malloc(sizeof(struct io_event) * aio_max_cnt);
  193. +
  194. + listh = g_hash_table_get_keys(rename_set);
  195. + for(listp = listh; listp; listp = listp->next){
  196. + gchar *pathname = listp->data;
  197. + struct iocb *iocbp;
  198. + int fd;
  199. +
  200. + while(aio_waiting >= aio_max_cnt){
  201. + if(!linux_aio_wait(aio_context, &aio_waiting,
  202. + aio_max_cnt, io_event_array, error)
  203. + ){
  204. + ret = FALSE;
  205. + goto exit_aio;
  206. + }
  207. + }
  208. +
  209. + // make aio request
  210. + if((fd = open(pathname, O_RDWR)) < 0){
  211. + continue;
  212. + }
  213. + iocbp = &iocb_array[aio_submited];
  214. + iocbp->aio_data = (__u64)pathname;
  215. + //iocbp->aio_rw_flags = 0;
  216. + iocbp->aio_lio_opcode = IOCB_CMD_FDSYNC;
  217. + //iocbp->aio_reqprio = 0;
  218. + iocbp->aio_fildes = fd;
  219. + //iocbp->aio_buf = 0;
  220. + //iocbp->aio_nbytes = 0;
  221. + //iocbp->aio_offset = 0;
  222. + //iocbp->aio_flags = 0;
  223. + iocbp->aio_resfd = evfd;
  224. +
  225. + if(io_submit(aio_context, (long)1, &iocbp) != 1){
  226. + close(fd);
  227. + continue;
  228. + }
  229. +
  230. + aio_waiting++;
  231. + aio_submited++;
  232. + }
  233. +
  234. + while(aio_waiting > 0){
  235. + if(!linux_aio_wait(aio_context, &aio_waiting,
  236. + aio_max_cnt, io_event_array, error)
  237. + ){
  238. + ret = FALSE;
  239. + goto exit_aio;
  240. + }
  241. + }
  242. +
  243. +exit_aio:
  244. + io_destroy(aio_context);
  245. + if(evfd >= 0){
  246. + close(evfd);
  247. + }
  248. + for(i = 0; i < aio_submited; i++){
  249. + struct iocb *iocbp = &iocb_array[i];
  250. + if(iocbp->aio_data != 0){
  251. + close(iocbp->aio_fildes);
  252. + }
  253. + }
  254. +
  255. +noaio:
  256. + g_list_free(listh);
  257. + g_free(iocb_array);
  258. + g_free(io_event_array);
  259. +
  260. + return ret;
  261. +}
  262. +#endif //__LINUX__AIO_ABI_H
  263. +
  264. +static gboolean finish_atomic_update(GError **error){
  265. + gboolean ret = FALSE;
  266. + GHashTableIter it;
  267. + gpointer k, v;
  268. +
  269. +#ifdef __LINUX__AIO_ABI_H
  270. + if(!finish_atomic_update_linux_aio(error)){
  271. + goto out;
  272. + }
  273. +#endif
  274. +
  275. + g_hash_table_iter_init(&it, rename_set);
  276. + while(g_hash_table_iter_next(&it, &k, &v)){
  277. + gchar *pathname = (gchar *)k;
  278. +
  279. + if(sync_file(pathname, error)){
  280. + goto out;
  281. + }
  282. +
  283. + if(!atomic_update_file(pathname, error)){
  284. + goto out;
  285. + }
  286. + }
  287. +
  288. + ret = TRUE;
  289. +out:
  290. + g_hash_table_remove_all(rename_set);
  291. return ret;
  292. }
  293. @@ -1048,7 +1277,7 @@
  294. if (!save_xml_file(type->output, filename, &local_error))
  295. fatal_gerror(local_error);
  296. - if (!atomic_update(filename, &local_error))
  297. + if (!add_atomic_update(filename, &local_error))
  298. fatal_gerror(local_error);
  299. g_free(filename);
  300. @@ -3731,6 +3960,8 @@
  301. g_free, NULL);
  302. generic_icon_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
  303. g_free, NULL);
  304. + rename_set = g_hash_table_new_full(g_str_hash, g_str_equal,
  305. + g_free, NULL);
  306. scan_source_dir(package_dir);
  307. g_free(package_dir);
  308. @@ -3756,7 +3987,7 @@
  309. write_out_glob(glob_list, globs);
  310. if (!fclose_gerror(globs, error))
  311. goto out;
  312. - if (!atomic_update(globs_path, error))
  313. + if (!add_atomic_update(globs_path, error))
  314. goto out;
  315. g_free(globs_path);
  316. @@ -3770,7 +4001,7 @@
  317. write_out_glob2 (glob_list, globs);
  318. if (!fclose_gerror(globs, error))
  319. goto out;
  320. - if (!atomic_update(globs_path, error))
  321. + if (!add_atomic_update(globs_path, error))
  322. goto out;
  323. g_free(globs_path);
  324. @@ -3797,7 +4028,7 @@
  325. }
  326. if (!fclose_gerror(stream, error))
  327. goto out;
  328. - if (!atomic_update(magic_path, error))
  329. + if (!add_atomic_update(magic_path, error))
  330. goto out;
  331. g_free(magic_path);
  332. }
  333. @@ -3813,7 +4044,7 @@
  334. write_namespaces(stream);
  335. if (!fclose_gerror(stream, error))
  336. goto out;
  337. - if (!atomic_update(ns_path, error))
  338. + if (!add_atomic_update(ns_path, error))
  339. goto out;
  340. g_free(ns_path);
  341. }
  342. @@ -3829,7 +4060,7 @@
  343. write_subclasses(stream);
  344. if (!fclose_gerror(stream, error))
  345. goto out;
  346. - if (!atomic_update(path, error))
  347. + if (!add_atomic_update(path, error))
  348. goto out;
  349. g_free(path);
  350. }
  351. @@ -3845,7 +4076,7 @@
  352. write_aliases(stream);
  353. if (!fclose_gerror(stream, error))
  354. goto out;
  355. - if (!atomic_update(path, error))
  356. + if (!add_atomic_update(path, error))
  357. goto out;
  358. g_free(path);
  359. }
  360. @@ -3861,7 +4092,7 @@
  361. write_types(stream);
  362. if (!fclose_gerror(stream, error))
  363. goto out;
  364. - if (!atomic_update(path, error))
  365. + if (!add_atomic_update(path, error))
  366. goto out;
  367. g_free(path);
  368. }
  369. @@ -3877,7 +4108,7 @@
  370. write_icons(generic_icon_hash, stream);
  371. if (!fclose_gerror(stream, error))
  372. goto out;
  373. - if (!atomic_update(icon_path, error))
  374. + if (!add_atomic_update(icon_path, error))
  375. goto out;
  376. g_free(icon_path);
  377. }
  378. @@ -3893,7 +4124,7 @@
  379. write_icons(icon_hash, stream);
  380. if (!fclose_gerror(stream, error))
  381. goto out;
  382. - if (!atomic_update(icon_path, error))
  383. + if (!add_atomic_update(icon_path, error))
  384. goto out;
  385. g_free(icon_path);
  386. }
  387. @@ -3918,7 +4149,7 @@
  388. }
  389. if (!fclose_gerror(stream, error))
  390. goto out;
  391. - if (!atomic_update(path, error))
  392. + if (!add_atomic_update(path, error))
  393. goto out;
  394. g_free(path);
  395. }
  396. @@ -3934,7 +4165,7 @@
  397. write_cache(stream);
  398. if (!fclose_gerror(stream, error))
  399. goto out;
  400. - if (!atomic_update(path, error))
  401. + if (!add_atomic_update(path, error))
  402. goto out;
  403. g_free(path);
  404. }
  405. @@ -3951,11 +4182,15 @@
  406. VERSION "\n");
  407. if (!fclose_gerror(stream, error))
  408. goto out;
  409. - if (!atomic_update(path, error))
  410. + if (!add_atomic_update(path, error))
  411. goto out;
  412. g_free(path);
  413. }
  414. + if (!finish_atomic_update(error)){
  415. + goto out;
  416. + }
  417. +
  418. g_ptr_array_foreach(magic_array, (GFunc)magic_free, NULL);
  419. g_ptr_array_free(magic_array, TRUE);
  420. g_ptr_array_foreach(tree_magic_array, (GFunc)tree_magic_free, NULL);
  421. @@ -3968,6 +4203,7 @@
  422. g_hash_table_destroy(alias_hash);
  423. g_hash_table_destroy(icon_hash);
  424. g_hash_table_destroy(generic_icon_hash);
  425. + g_hash_table_destroy(rename_set);
  426. check_in_path_xdg_data(mime_dir);
下载 可打印视图

网址

Embed with JavaScript

Embed with iframe

原始文本