// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 /* * Copyright (C), 2008-2021, OPPO Mobile Comm Corp., Ltd. * Created by Huang Jianan */ #include #include #include "erofs/err.h" #include "erofs/list.h" #include "erofs/print.h" #include "erofs/compress_hints.h" static LIST_HEAD(compress_hints_head); static void dump_regerror(int errcode, const char *s, const regex_t *preg) { char str[512]; regerror(errcode, preg, str, sizeof(str)); erofs_err("invalid regex %s (%s)\n", s, str); } static int erofs_insert_compress_hints(const char *s, unsigned int blks) { struct erofs_compress_hints *r; int ret; r = malloc(sizeof(struct erofs_compress_hints)); if (!r) return -ENOMEM; ret = regcomp(&r->reg, s, REG_EXTENDED|REG_NOSUB); if (ret) { dump_regerror(ret, s, &r->reg); goto err_out; } r->physical_clusterblks = blks; list_add_tail(&r->list, &compress_hints_head); erofs_info("compress hint %s (%u) is inserted", s, blks); return ret; err_out: free(r); return ret; } bool z_erofs_apply_compress_hints(struct erofs_inode *inode) { const char *s; struct erofs_compress_hints *r; unsigned int pclusterblks; if (inode->z_physical_clusterblks) return true; s = erofs_fspath(inode->i_srcpath); pclusterblks = cfg.c_pclusterblks_def; list_for_each_entry(r, &compress_hints_head, list) { int ret = regexec(&r->reg, s, (size_t)0, NULL, 0); if (!ret) { pclusterblks = r->physical_clusterblks; break; } if (ret != REG_NOMATCH) dump_regerror(ret, s, &r->reg); } inode->z_physical_clusterblks = pclusterblks; /* pclusterblks is 0 means this file shouldn't be compressed */ return !!pclusterblks; } void erofs_cleanup_compress_hints(void) { struct erofs_compress_hints *r, *n; list_for_each_entry_safe(r, n, &compress_hints_head, list) { list_del(&r->list); free(r); } } int erofs_load_compress_hints(void) { char buf[PATH_MAX + 100]; FILE *f; unsigned int line, max_pclustersize = 0; int ret = 0; if (!cfg.c_compress_hints_file) return 0; f = fopen(cfg.c_compress_hints_file, "r"); if (!f) return -errno; for (line = 1; fgets(buf, sizeof(buf), f); ++line) { unsigned int pclustersize; char *pattern; pclustersize = atoi(strtok(buf, "\t ")); pattern = strtok(NULL, "\n"); if (!pattern || *pattern == '\0') { erofs_err("cannot find a match pattern at line %u", line); ret = -EINVAL; goto out; } if (pclustersize % EROFS_BLKSIZ) { erofs_warn("invalid physical clustersize %u, " "use default pclusterblks %u", pclustersize, cfg.c_pclusterblks_def); continue; } erofs_insert_compress_hints(pattern, pclustersize / EROFS_BLKSIZ); if (pclustersize > max_pclustersize) max_pclustersize = pclustersize; } if (cfg.c_pclusterblks_max * EROFS_BLKSIZ < max_pclustersize) { cfg.c_pclusterblks_max = max_pclustersize / EROFS_BLKSIZ; erofs_warn("update max pclusterblks to %u", cfg.c_pclusterblks_max); } out: fclose(f); return ret; }