static grub_err_t grub_cpio_open (grub_file_t file, const char *name_in) { struct grub_cpio_data *data; grub_disk_addr_t ofs; char *fn; char *name = grub_strdup (name_in + 1); int symlinknest = 0; if (!name) return grub_errno; canonicalize (name); grub_dl_ref (my_mod); data = grub_cpio_mount (file->device->disk); if (!data) { grub_free (name); return grub_errno; } data->hofs = 0; while (1) { grub_uint32_t mode; int restart; if (grub_cpio_find_file (data, &fn, NULL, &ofs, &mode)) goto fail; if (!ofs) { grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name_in); break; } if (handle_symlink (data, fn, &name, mode, &restart)) { grub_free (fn); goto fail; } if (restart) { ofs = 0; if (++symlinknest == 8) { grub_error (GRUB_ERR_SYMLINK_LOOP, N_("too deep nesting of symlinks")); goto fail; } goto no_match; } if (grub_strcmp (name, fn) != 0) goto no_match; file->data = data; file->size = data->size; grub_free (fn); grub_free (name); return GRUB_ERR_NONE; no_match: grub_free (fn); data->hofs = ofs; } fail: #ifdef MODE_USTAR grub_free (data->linkname); #endif grub_free (data); grub_free (name); grub_dl_unref (my_mod); return grub_errno; }
static grub_err_t grub_cpio_dir (grub_device_t device, const char *path_in, int (*hook) (const char *filename, const struct grub_dirhook_info *info)) { struct grub_cpio_data *data; grub_disk_addr_t ofs; char *prev, *name, *path, *ptr; grub_size_t len; int symlinknest = 0; path = grub_strdup (path_in + 1); if (!path) return grub_errno; canonicalize (path); for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--) *ptr = 0; grub_dl_ref (my_mod); prev = 0; data = grub_cpio_mount (device->disk); if (!data) { grub_free (path); return grub_errno; } len = grub_strlen (path); data->hofs = 0; while (1) { grub_int32_t mtime; grub_uint32_t mode; grub_err_t err; if (grub_cpio_find_file (data, &name, &mtime, &ofs, &mode)) goto fail; if (!ofs) break; if (grub_memcmp (path, name, len) == 0 && (name[len] == 0 || name[len] == '/' || len == 0)) { char *p, *n; n = name + len; while (*n == '/') n++; p = grub_strchr (n, '/'); if (p) *p = 0; if (((!prev) || (grub_strcmp (prev, name) != 0)) && *n != 0) { struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = (p != NULL) || ((mode & ATTR_TYPE) == ATTR_DIR); info.mtime = mtime; info.mtimeset = 1; if (hook (n, &info)) { grub_free (name); goto fail; } grub_free (prev); prev = name; } else { int restart = 0; err = handle_symlink (data, name, &path, mode, &restart); grub_free (name); if (err) goto fail; if (restart) { len = grub_strlen (path); if (++symlinknest == 8) { grub_error (GRUB_ERR_SYMLINK_LOOP, N_("too deep nesting of symlinks")); goto fail; } ofs = 0; } } } else grub_free (name); data->hofs = ofs; } fail: grub_free (path); grub_free (prev); #ifdef MODE_USTAR grub_free (data->linkname); #endif grub_free (data); grub_dl_unref (my_mod); return grub_errno; }
grub_err_t grub_archelp_open (struct grub_archelp_data *data, struct grub_archelp_ops *arcops, const char *name_in) { char *fn; char *name = grub_strdup (name_in + 1); int symlinknest = 0; if (!name) return grub_errno; canonicalize (name); while (1) { grub_uint32_t mode; grub_int32_t mtime; int restart; if (arcops->find_file (data, &fn, &mtime, &mode)) goto fail; if (mode == GRUB_ARCHELP_ATTR_END) { grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name_in); break; } canonicalize (fn); if (handle_symlink (data, arcops, fn, &name, mode, &restart)) { grub_free (fn); goto fail; } if (restart) { arcops->rewind (data); if (++symlinknest == 8) { grub_error (GRUB_ERR_SYMLINK_LOOP, N_("too deep nesting of symlinks")); goto fail; } goto no_match; } if (grub_strcmp (name, fn) != 0) goto no_match; grub_free (fn); grub_free (name); return GRUB_ERR_NONE; no_match: grub_free (fn); } fail: grub_free (name); return grub_errno; }
static int hash_dir(const char *dirname) { struct bucket_info *bi, *nextbi; struct entry_info *ei, *nextei; struct dirent *de; struct stat st; unsigned char idmask[MAX_COLLISIONS / 8]; int i, n, nextid, buflen, ret = -1; const char *pathsep; char *buf; DIR *d; if (access(dirname, R_OK|W_OK|X_OK) != 0) { fprintf(stderr, "ERROR: Access denied '%s'\n", dirname); return -1; } buflen = strlen(dirname); pathsep = (buflen && dirname[buflen-1] == '/') ? "" : "/"; buflen += NAME_MAX + 2; buf = malloc(buflen); if (buf == NULL) goto err; if (do_verbose) printf("Doing %s\n", dirname); d = opendir(dirname); if (!d) goto err; while ((de = readdir(d)) != NULL) { if (snprintf(buf, buflen, "%s%s%s", dirname, pathsep, de->d_name) >= buflen) continue; if (lstat(buf, &st) < 0) continue; if (S_ISLNK(st.st_mode) && handle_symlink(de->d_name, buf) == 0) continue; handle_certificate(de->d_name, buf); } closedir(d); for (i = 0; i < countof(hash_table); i++) { for (bi = hash_table[i]; bi; bi = nextbi) { nextbi = bi->next; DEBUG("Type %d, hash %08x, num entries %d:\n", bi->type, bi->hash, bi->num_needed); nextid = 0; memset(idmask, 0, (bi->num_needed+7)/8); for (ei = bi->first_entry; ei; ei = ei->next) if (ei->old_id < bi->num_needed) bit_set(idmask, ei->old_id); for (ei = bi->first_entry; ei; ei = nextei) { nextei = ei->next; DEBUG("\t(old_id %d, need_symlink %d) Cert %s\n", ei->old_id, ei->need_symlink, ei->filename); if (ei->old_id < bi->num_needed) { /* Link exists, and is used as-is */ snprintf(buf, buflen, "%08x.%s%d", bi->hash, symlink_extensions[bi->type], ei->old_id); if (do_verbose) printf("link %s -> %s\n", ei->filename, buf); } else if (ei->need_symlink) { /* New link needed (it may replace something) */ while (bit_isset(idmask, nextid)) nextid++; snprintf(buf, buflen, "%s%s%n%08x.%s%d", dirname, pathsep, &n, bi->hash, symlink_extensions[bi->type], nextid); if (do_verbose) printf("link %s -> %s\n", ei->filename, &buf[n]); unlink(buf); symlink(ei->filename, buf); } else if (do_remove_links) { /* Link to be deleted */ snprintf(buf, buflen, "%s%s%n%08x.%s%d", dirname, pathsep, &n, bi->hash, symlink_extensions[bi->type], ei->old_id); if (do_verbose) printf("unlink %s\n", &buf[n]); unlink(buf); } free(ei->filename); free(ei); } free(bi); } hash_table[i] = NULL; } ret = 0; err: free(buf); return ret; }
grub_err_t grub_archelp_dir (struct grub_archelp_data *data, struct grub_archelp_ops *arcops, const char *path_in, grub_fs_dir_hook_t hook, void *hook_data) { char *prev, *name, *path, *ptr; grub_size_t len; int symlinknest = 0; path = grub_strdup (path_in + 1); if (!path) return grub_errno; canonicalize (path); for (ptr = path + grub_strlen (path) - 1; ptr >= path && *ptr == '/'; ptr--) *ptr = 0; prev = 0; len = grub_strlen (path); while (1) { grub_int32_t mtime; grub_uint32_t mode; grub_err_t err; if (arcops->find_file (data, &name, &mtime, &mode)) goto fail; if (mode == GRUB_ARCHELP_ATTR_END) break; canonicalize (name); if (grub_memcmp (path, name, len) == 0 && (name[len] == 0 || name[len] == '/' || len == 0)) { char *p, *n; n = name + len; while (*n == '/') n++; p = grub_strchr (n, '/'); if (p) *p = 0; if (((!prev) || (grub_strcmp (prev, name) != 0)) && *n != 0) { struct grub_dirhook_info info; grub_memset (&info, 0, sizeof (info)); info.dir = (p != NULL) || ((mode & GRUB_ARCHELP_ATTR_TYPE) == GRUB_ARCHELP_ATTR_DIR); info.symlink = (p != NULL) || ((mode & GRUB_ARCHELP_ATTR_TYPE) == GRUB_ARCHELP_ATTR_LNK); if (!(mode & GRUB_ARCHELP_ATTR_NOTIME)) { info.mtime = mtime; info.mtimeset = 1; } if (hook (n, &info, hook_data)) { grub_free (name); goto fail; } grub_free (prev); prev = name; } else { int restart = 0; err = handle_symlink (data, arcops, name, &path, mode, &restart); grub_free (name); if (err) goto fail; if (restart) { len = grub_strlen (path); if (++symlinknest == 8) { grub_error (GRUB_ERR_SYMLINK_LOOP, N_("too deep nesting of symlinks")); goto fail; } arcops->rewind (data); } } } else grub_free (name); } fail: grub_free (path); grub_free (prev); return grub_errno; }