view ffstools/tiffs-mkfs/input.c @ 921:74d284add54d

fc-fsio: guard against bogus readdir results from the target If the FFS being operated on contains SE K2x0 extended filenames, readdir will return strings that are bad for printing. We need to guard against this possibility, and also against possible other bogosity that could be sent by other alien firmwares.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 31 Dec 2022 22:55:23 +0000
parents 12ae93940467
children
line wrap: on
line source

#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "struct.h"
#include "globals.h"

void
read_dir_level(dto, srcpath, depth)
	struct tree_object *dto;
	char *srcpath;
{
	DIR *rdd;
	struct dirent *dirent;
	char hostpath_child[MAXPATHLEN];
	struct stat hst;
	struct tree_object *cto;
	unsigned nchildren;

	dto->is_dir = 1;
	rdd = opendir(srcpath);
	if (!rdd) {
		perror(srcpath);
		exit(1);
	}
	nchildren = 0;
	while (dirent = readdir(rdd)) {
		if (dirent->d_name[0] == '.')
			continue;
		if (strlen(dirent->d_name) > MAX_FN_COMPONENT) {
			fprintf(stderr,
		"error: \"%s\" in %s exceeds the FFS component name limit\n",
				dirent->d_name, srcpath);
			exit(1);
		}
		if (nchildren >= MAX_DIR_ENTRIES) {
			fprintf(stderr, "error: %s has too many children\n",
				srcpath);
			exit(1);
		}
		cto = malloc(sizeof(struct tree_object));
		if (!cto) {
			perror("malloc of struct tree_object");
			exit(1);
		}
		strcpy(cto->name, dirent->d_name);
		dto->u.d.children[nchildren++] = cto;
		if (strlen(srcpath) + strlen(dirent->d_name) + 2 >
		    sizeof hostpath_child) {
			fprintf(stderr,
				"error: host side pathname buffer overflow\n");
			exit(1);
		}
		sprintf(hostpath_child, "%s/%s", srcpath, dirent->d_name);
		if (lstat(hostpath_child, &hst) < 0) {
			perror(hostpath_child);
			exit(1);
		}
		switch (hst.st_mode & S_IFMT) {
		case S_IFREG:
			cto->is_dir = 0;
			strcpy(cto->u.f.host_pathname, hostpath_child);
			break;
		case S_IFDIR:
			if (depth >= MAX_DIR_NEST-1) {
				fprintf(stderr,
				"error: directory nesting too deep at %s\n",
					hostpath_child);
				exit(1);
			}
			read_dir_level(cto, hostpath_child, depth + 1);
			break;
		default:
			fprintf(stderr,
			"error: %s is neither a regular file nor a directory\n",
				hostpath_child);
			exit(1);
		}
	}
	closedir(rdd);
	dto->u.d.nchildren = nchildren;
}

static int
compare_func(p1, p2)
	struct tree_object **p1, **p2;
{
	return strcmp((*p1)->name, (*p2)->name);
}

void
sort_dir_level(dto)
	struct tree_object *dto;
{
	unsigned n;
	struct tree_object *cto;

	if (dto->u.d.nchildren > 1)
		qsort(dto->u.d.children, dto->u.d.nchildren,
			sizeof(struct tree_object *), compare_func);
	for (n = 0; n < dto->u.d.nchildren; n++) {
		cto = dto->u.d.children[n];
		if (cto->is_dir)
			sort_dir_level(cto);
	}
}