From 2a5c9127ad298fd8ad11579f33c4d931d59c53dc Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Mon, 22 May 2023 20:40:43 -0400 Subject: opk/write: Fix path length handling, add virt path --- (limited to 'src/opk/write.c') diff --git a/src/opk/write.c b/src/opk/write.c index fa13dbf..c3a88c8 100644 --- a/src/opk/write.c +++ b/src/opk/write.c @@ -81,10 +81,9 @@ _opkg_opk_opk_write_compar(const struct dirent **a, const struct dirent **b) return strcmp((*a)->d_name, (*b)->d_name); } -/* path_len excludes '\0' */ static int _opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, - struct opkg_opk_dirent *dir) + struct opkg_opk_dirent *dir, size_t path_off) { int ret; char *child_path; @@ -110,25 +109,15 @@ _opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, ret = OPKG_OPK_OK; - child_path = strchr(opk->path, '\0'); - if (opk->path_len < 2) { - fprintf(stderr, "Error: File name \"%s\" too long", opk->path); - ret = OPKG_OPK_ERROR; - goto out0; - } - *child_path = '/'; - ++child_path; - *child_path = '\0'; - --opk->path_len; - - children_n = scandir(opk->path, &children, _opkg_opk_opk_write_filter, + child_path = opk->path_virt + path_off; + children_n = scandir(opk->path_real, &children, _opkg_opk_opk_write_filter, _opkg_opk_opk_write_compar); for (children_i = 0; children_i < children_n; ++children_i) { child.name = children[children_i]->d_name; child.parent = dir; for (name_i = 0; children[children_i]->d_name[name_i] != '\0'; ++name_i) { - if (name_i == opk->path_len) { + if (path_off + name_i + 1 == OPKG_OPK_USTAR_NAME_SIZE) { fprintf(stderr, "Error: File name \"%s\" too " "long", children[children_i]->d_name); @@ -139,9 +128,9 @@ _opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, children[children_i]->d_name[name_i]; } child_path[name_i] = '\0'; - if (lstat(opk->path, &st) != 0) { + if (lstat(opk->path_real, &st) != 0) { fprintf(stderr, _("Error: Failed to stat \"%s\"\n"), - opk->path); + opk->path_real); ret = OPKG_OPK_ERROR; goto out1; } @@ -151,6 +140,14 @@ _opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, gid = st.st_gid; gname = getgrgid(gid)->gr_name; if (S_ISDIR(st.st_mode)) { + if (path_off + name_i + 2 == OPKG_OPK_USTAR_NAME_SIZE) { + fprintf(stderr, "Error: File name \"%s\" too " + "long", child_path); + ret = OPKG_OPK_ERROR; + goto out1; + } + child_path[name_i] = '/'; + child_path[++name_i] = '\0'; if (opkg_opk_ustar_write_header(opk->inner_ustar, &child, st.st_mode & 0777, uid, uname, gid, gname, 0, 0, 0, @@ -161,13 +158,14 @@ _opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, ret = OPKG_OPK_ERROR; goto out1; } - if (_opkg_opk_opk_write_dir_read(opk, &child) != + if (_opkg_opk_opk_write_dir_read(opk, &child, + path_off + name_i) != OPKG_OPK_OK) { ret = OPKG_OPK_ERROR; goto out1; } } else if (S_ISLNK(st.st_mode)) { - link_len = readlink(opk->path, link, + link_len = readlink(opk->path_real, link, OPKG_OPK_USTAR_LINKNAME_SIZE); if (link_len < 0) { ret = OPKG_OPK_ERROR; @@ -236,10 +234,11 @@ _opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, ret = OPKG_OPK_ERROR; goto out1; } - fp = fopen(opk->path, "rb"); + fp = fopen(opk->path_real, "rb"); if (fp == NULL) { fprintf(stderr, _("Error: Failed to open file " - "\"%s\"\n"), opk->path); + "\"%s\"\n"), + opk->path_real); ret = OPKG_OPK_ERROR; goto out1; } @@ -273,7 +272,7 @@ _opkg_opk_opk_write_dir_read(struct opkg_opk_opk *opk, } } else { fprintf(stderr, _("Error: Unknown type of file \"%s\"\n" - ), opk->path); + ), opk->path_real); ret = OPKG_OPK_ERROR; goto out1; } @@ -334,12 +333,15 @@ _opkg_opk_opk_build_inner_archive(struct opkg_opk_opk *opk, dirent.name = "."; dirent.parent = NULL; if (archive_type == OPKG_OPK_OPK_ARCHIVE_TYPE_CONTROL_) { - strcpy(opk->path, opk->control_dir); + sprintf(opk->path_real, "%s/", opk->control_dir); + opk->path_virt = opk->path_real + opk->control_dir_len; } else { - strcpy(opk->path, opk->data_dir); + sprintf(opk->path_real, "%s/", opk->data_dir); + opk->path_virt = opk->path_real + opk->data_dir_len; } - if (stat(opk->path, &st) != 0) { - fprintf(stderr, _("Error: Failed to stat \"%s\"\n"), opk->path); + if (stat(opk->path_real, &st) != 0) { + fprintf(stderr, _("Error: Failed to stat \"%s\"\n"), + opk->path_real); goto err3; } uid = st.st_uid; @@ -353,7 +355,8 @@ _opkg_opk_opk_build_inner_archive(struct opkg_opk_opk *opk, stderr); goto err3; } - if (_opkg_opk_opk_write_dir_read(opk, &dirent) != OPKG_OPK_OK) { + if (_opkg_opk_opk_write_dir_read(opk, &dirent, 1 /* Skip '/' */) != + OPKG_OPK_OK) { goto err3; } @@ -426,8 +429,7 @@ opkg_opk_opk_write(struct opkg_opk_opk *opk, const char *file_name) struct opkg_opk_dirent dirent; char *buffer; size_t size; - size_t control_dir_len; - size_t data_dir_len; + size_t path_len; ret = OPKG_OPK_OK; @@ -487,14 +489,14 @@ opkg_opk_opk_write(struct opkg_opk_opk *opk, const char *file_name) } /* Allocate control and data file path buffer. */ - opk->path_len = control_dir_len = strlen(opk->control_dir); - data_dir_len = strlen(opk->data_dir); - if (data_dir_len > opk->path_len) { - opk->path_len = data_dir_len; - } - opk->path_len += 257; - opk->path = malloc(opk->path_len); - if (opk->path == NULL) { + if (opk->control_dir_len >= opk->data_dir_len) { + path_len = opk->control_dir_len; + } else { + path_len = opk->data_dir_len; + } + path_len += 1 /* '/' */ + OPKG_OPK_USTAR_NAME_SIZE; + opk->path_real = malloc(path_len); + if (opk->path_real == NULL) { ret = OPKG_OPK_ERROR; goto out3; } @@ -530,7 +532,7 @@ opkg_opk_opk_write(struct opkg_opk_opk *opk, const char *file_name) out5: free(opk->temp_file_name); out4: - free(opk->path); + free(opk->path_real); out3: opkg_opk_ustar_free(opk->outer_ustar); out2: -- cgit v0.9.1