예제 #1
0
static int
read_string(FILE *cfile)
{
	int i, c, bs;

	/*
	 * Read in characters until an un-escaped '"' is encountered. And
	 * then unvis the data that was read.
	 */
	bs = i = 0;
	memset(visbuf, 0, sizeof(visbuf));
	while ((c = get_char(cfile)) != EOF) {
		if (c == '"' && bs == 0)
			break;

		visbuf[i++] = c;
		if (bs)
			bs = 0;
		else if (c == '\\')
			bs = 1;

		if (i == sizeof(visbuf) - 1)
			break;
	}
	if (bs == 1)
		visbuf[--i] = '\0';
	i = strnunvis(tokbuf, visbuf, sizeof(tokbuf));

	if (c == EOF)
		parse_warn("eof in string constant");
	else if (i == -1 || i >= sizeof(tokbuf))
		parse_warn("string constant too long");

	tval = tokbuf;

	return (TOK_STRING);
}
예제 #2
0
파일: vis_test.c 프로젝트: NSGod/openbsd
int
main(int argc, char *argv[])
{

	char inp[UCHAR_MAX + 1];
	char out[4 * UCHAR_MAX + 1];
	int i, j, fail = 0;
	ssize_t owant, o, r;

	for (i = 0; i <= UCHAR_MAX; i++) {
		inp[i] = i;
	}
	strvisx(out, inp, UCHAR_MAX + 1, 0);
	printf("%s\n", out);

	for (i = 0; i < NTESTS; i++) {
		arc4random_buf(ibuf, sizeof(ibuf) - 1);
		ibuf[sizeof(ibuf) - 1] = '\0';
		title = 0;

		for (j = 0; j < sizeof(flags)/sizeof(flags[0]); j++) {
			owant = sizeof(ibuf);
			o = strnvis(obuf, ibuf, owant, flags[j]);
			if (o >= owant) {
				owant = o + 1;
				o = strnvis(obuf, ibuf, owant, flags[j]);
				if (o > owant) {
					dotitle(i, j);
					printf("HUGE overflow\n");
				}
				if (o < owant - 1) {
					dotitle(i, j);
					printf("over-estimate of overflow\n");
				}
			} else if (o > strlen(ibuf) * 4) {
				dotitle(i, j);
				printf("wants too much %d %d\n", o, strlen(ibuf) * 4);
				continue;
			}

			r = strnunvis(rbuf, obuf, sizeof rbuf);

			if (r == -1) {
				dotitle(i, j);
				printf("cannot decode\n");
				printf("%s\n", obuf);
				fail = 1;
			} else if (r != strlen(ibuf)) {
				dotitle(i, j);
				printf("rlen %d != inlen %d\n", r, strlen(ibuf));
				printf("%s\n", obuf);
				printf("%s\n", rbuf);
				fail = 1;
			} else if (bcmp(ibuf, rbuf, r)) {
				dotitle(i, j);
				printf("strings are different\n");
				printf("%s\n", ibuf);
				printf("%s\n", rbuf);
				fail = 1;
			}
		}
	}
	exit(fail);
}
static int
read_spec(struct mtree_reader *r, char *s)
{
	struct mtree_entry	*entry;
	char			 name[MAXPATHLEN];
	char			*slash, *file, *word, *next;
	int			 ret;
	int			 skip = 0;

	/* Try to detect the format if it isn't known yet. */
	if (r->path_last == -1 && detect_format(r, s) == -1)
		return (-1);
	if (r->path_last != 1) {
		/*
		 * Path is surely in the first field, either because we know
		 * the format or there is just one single field.
		 */
		read_word(s, &file, &next);
		assert(file != NULL);

		if (IS_DOTDOT(file)) {
			/* Only change the parent, keywords are ignored. */
			if (r->parent == NULL) {
				mtree_reader_set_error(r, EINVAL,
				    "`..' not allowed, no parent directory");
				return (-1);
			}
			r->parent = r->parent->parent;
			return (0);
		}
	}
	entry = mtree_entry_create_empty();
	if (entry == NULL) {
		mtree_reader_set_error(r, errno, NULL);
		return (-1);
	}

	if (r->path_last != 1) {
		if (next != NULL) {
			/* Read keyword that follow the path. */
			ret = read_keywords(r, next, &entry->data, 1);
			if (ret == -1) {
				mtree_entry_free(entry);
				return (-1);
			}
		}
	} else {
		/* Path is at the end, read the keywords first. */
		for (file = NULL; file == NULL;) {
			read_word(s, &word, &next);
			assert(word != NULL);

			if (next != NULL) {
				ret = read_keyword(r, word, &entry->data, 1);
				if (ret == -1) {
					mtree_entry_free(entry);
					return (-1);
				}
				s = next;
			} else
				file = word;
		}
		assert(file != NULL);

		if (IS_DOTDOT(file)) {
			mtree_reader_set_error(r, EINVAL, "`..' not allowed in "
			    "this format");
			mtree_entry_free(entry);
			return (-1);
		}
	}
	/* Copy /set values to the entry. */
	mtree_entry_data_copy_keywords(&entry->data, &r->defaults,
	    r->defaults.keywords, 0);

	/*
	 * See if we should skip this file.
	 */
	if (SKIP_TYPE(r->options, entry->data.type)) {
		/*
		 * With directories in version 1.0 format, we'll have to worry
		 * about potentially setting the directory as the current
		 * parent, other types can be skipped immediately.
		 */
		if (entry->data.type != MTREE_ENTRY_DIR || r->path_last == 1)
			goto skip;
		else
			skip = 1;
	}

	/* Save the file path and name. */
	if (strnunvis(name, sizeof(name), file) == -1) {
		mtree_reader_set_error(r, ENAMETOOLONG, "File name too long: `%s'",
		    file);
		mtree_entry_free(entry);
		return (-1);
	}
	if ((slash = strchr(name, '/')) != NULL) {
		/*
		 * If the name contains a slash, it is a relative path.
		 * These do not change the working directory.
		 */
		if (skip)
			goto skip;
		ret = mtree_cleanup_path(name, &entry->path, &entry->name);
		if (ret == -1) {
			mtree_reader_set_error(r, errno, NULL);
			mtree_entry_free(entry);
			return (-1);
		}
	} else {
		entry->name = strdup(name);
		if (entry->name == NULL) {
			mtree_reader_set_error(r, errno, NULL);
			mtree_entry_free(entry);
			return (-1);
		}
		entry->parent = r->parent;
		entry->path = create_v1_path(entry);
		if (entry->path == NULL) {
			mtree_reader_set_error(r, errno, NULL);
			mtree_entry_free(entry);
			return (-1);
		}
	}

	/*
	 * We may want to skip this entry if a filter told us to skip
	 * children of a directory, which is a parent of this entry.
	 *
	 * There is also no need to worry about changing the parent if
	 * this happens.
	 */
	if (!skip && r->skip_trie != NULL) {
		char *tok;
		char *endptr;

		for (tok = strtok_r(name, "/", &endptr); tok != NULL;
		     tok = strtok_r(NULL, "/", &endptr)) {
			if (mtree_trie_find(r->skip_trie, tok) != NULL) {
				mtree_entry_free(entry);
				return (0);
			}
		}
	}

	/*
	 * Mark the current entry as the current directory. This only applies
	 * to classic (1.0) entries and must be done after keywords are read.
	 */
	if (slash == NULL && entry->data.type == MTREE_ENTRY_DIR)
		r->parent = entry;
	if (skip)
		goto skip;

	if (r->filter != NULL) {
		int result;

		/* Apply filter. */
		result = r->filter(entry, r->filter_data);
		if (result & MTREE_ENTRY_SKIP_CHILDREN) {
			if (entry->data.type == MTREE_ENTRY_DIR) {
				struct mtree_entry *found, *start;

				if (r->skip_trie == NULL) {
					r->skip_trie = mtree_trie_create(NULL);
					if (r->skip_trie == NULL) {
						mtree_reader_set_error(r, errno,
						    NULL);
						return (-1);
					}
				}
				if (mtree_trie_insert(r->skip_trie, entry->path,
				    TRIE_ITEM) == -1) {
					mtree_reader_set_error(r, errno,
					    NULL);
					return (-1);
				}

				strcpy(name, entry->path);
				strcat(name, "/");
				/*
				 * Remove children that are already in the
				 * list.
				 */
				start = r->entries;
				for (;;) {
					found = mtree_entry_find_prefix(start,
					    name);
					if (found == NULL)
						break;

					start = found->next;
					r->entries = mtree_entry_unlink(
					    r->entries, found);
					mtree_entry_free(found);
				}
			}
		}
		if (result & MTREE_ENTRY_SKIP)
			goto skip;
	}

	r->entries = mtree_entry_prepend(r->entries, entry);
	return (0);
skip:
	/*
	 * Skipping directory which is the current parent would make its files
	 * end up in a wrong directory.
	 *
	 * Keep such entries in a list of `loose' entries instead, these will
	 * be deleted when all the work is done.
	 */
	if (entry == r->parent)
		r->loose = mtree_entry_prepend(r->loose, entry);
	else
		mtree_entry_free(entry);
	return (0);
}
/*
 * Read a single mtree keyword and either set or unset it in `data'.
 */
static int
read_keyword(struct mtree_reader *r, char *s, struct mtree_entry_data *data, int set)
{
	char		*value;
	char		 name[MAXPATHLEN];
	const char	*endptr;
	uint64_t	 keyword;
	int64_t		 num;

	value = strchr(s, '=');
	if (value != NULL)
		*value++ = '\0';

	keyword = mtree_keyword_parse(s);
	if (keyword == 0) {
		/*
		 * Unsupported keyword, this is not an error.
		 */
		WARN("Ignoring unknown keyword `%s'", s);
		return (0);
	}
	if (!set || (r->spec_keywords & keyword) == 0) {
		/* Unset the keyword. */
		data->keywords &= ~keyword;
		return (0);
	}

	/*
	 * Read the keyword value.
	 *
	 * Wherever possible, the value is validated and error is indicated
	 * in case the value is invalid or missing.
	 */
	errno = 0;

	switch (keyword) {
	case MTREE_KEYWORD_CKSUM:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		num = mtree_atol(value, &endptr);
		if (num < 0 || num > UINT32_MAX || *endptr != '\0')
			errno = EINVAL;
		else
			data->cksum = (uint32_t)num;
		break;
	case MTREE_KEYWORD_CONTENTS:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		if (strnunvis(name, sizeof(name), value) == -1)
			errno = ENAMETOOLONG;
		else
			mtree_copy_string(&data->contents, value);
		break;
	case MTREE_KEYWORD_DEVICE:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		if (data->device == NULL) {
			data->device = mtree_device_create();
			if (data->device == NULL)
				break;
		}
		if (mtree_device_parse(data->device, value) == -1)
			mtree_reader_set_error(r, errno, "%s",
			    mtree_device_get_error(data->device));
		break;
	case MTREE_KEYWORD_FLAGS:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->flags, value);
		break;
	case MTREE_KEYWORD_GID:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		data->st_gid = mtree_atol(value, &endptr);
		if (*endptr != '\0')
			errno = EINVAL;
		break;
	case MTREE_KEYWORD_GNAME:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->gname, value);
		break;
	case MTREE_KEYWORD_IGNORE:
		/* No value */
		break;
	case MTREE_KEYWORD_INODE:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		num = mtree_atol(value, &endptr);
		if (num < 0 || *endptr != '\0')
			errno = EINVAL;
		else
			data->st_ino = (uint64_t)num;
		break;
	case MTREE_KEYWORD_LINK:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		if (strnunvis(name, sizeof(name), value) == -1)
			errno = ENAMETOOLONG;
		else
			mtree_copy_string(&data->link, name);
		break;
	case MTREE_KEYWORD_MD5:
	case MTREE_KEYWORD_MD5DIGEST:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->md5digest, value);
		break;
	case MTREE_KEYWORD_MODE:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		if (value[0] >= '0' && value[0] <= '9') {
			data->st_mode = (int)mtree_atol8(value, &endptr);
			if (*endptr != '\0')
				errno = EINVAL;
		} else
			errno = EINVAL;
		break;
	case MTREE_KEYWORD_NLINK:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		data->st_nlink = mtree_atol(value, &endptr);
		if (*endptr != '\0')
			errno = EINVAL;
		break;
	case MTREE_KEYWORD_NOCHANGE:
		/* No value */
		break;
	case MTREE_KEYWORD_OPTIONAL:
		/* No value */
		break;
	case MTREE_KEYWORD_RESDEVICE:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		if (data->resdevice == NULL) {
			data->resdevice = mtree_device_create();
			if (data->resdevice == NULL)
				break;
		}
		if (mtree_device_parse(data->resdevice, value) == -1)
			mtree_reader_set_error(r, errno, "%s",
			    mtree_device_get_error(data->resdevice));
		break;
	case MTREE_KEYWORD_RIPEMD160DIGEST:
	case MTREE_KEYWORD_RMD160:
	case MTREE_KEYWORD_RMD160DIGEST:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->rmd160digest, value);
		break;
	case MTREE_KEYWORD_SHA1:
	case MTREE_KEYWORD_SHA1DIGEST:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->sha1digest, value);
		break;
	case MTREE_KEYWORD_SHA256:
	case MTREE_KEYWORD_SHA256DIGEST:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->sha256digest, value);
		break;
	case MTREE_KEYWORD_SHA384:
	case MTREE_KEYWORD_SHA384DIGEST:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->sha384digest, value);
		break;
	case MTREE_KEYWORD_SHA512:
	case MTREE_KEYWORD_SHA512DIGEST:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->sha512digest, value);
		break;
	case MTREE_KEYWORD_SIZE:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		/*
		 * It doesn't make a lot of sense to allow negative values
		 * here, but this value is related to off_t, which is signed.
		 */
		data->st_size = mtree_atol(value, &endptr);
		if (*endptr != '\0')
			errno = EINVAL;
		break;
	case MTREE_KEYWORD_TAGS:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->tags, value);
		break;
	case MTREE_KEYWORD_TIME:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		num = mtree_atol10(value, &endptr);
		if (num < TIME_T_MIN || num > TIME_T_MAX) {
			errno = EINVAL;
			break;
		}
		if (*endptr != '\0' && *endptr != '.') {
			errno = EINVAL;
			break;
		}
		data->st_mtim.tv_sec = (time_t)num;
		if (*endptr == '.') {
			num = mtree_atol10(endptr + 1, &endptr);
			if (*endptr != '\0') {
				errno = EINVAL;
				break;
			}
			data->st_mtim.tv_nsec = (long)num;
		} else
			data->st_mtim.tv_nsec = 0;
		break;
	case MTREE_KEYWORD_TYPE:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		data->type = mtree_entry_type_parse(value);
		if (data->type == MTREE_ENTRY_UNKNOWN)
			errno = EINVAL;
		break;
	case MTREE_KEYWORD_UID:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		data->st_uid = mtree_atol(value, &endptr);
		if (*endptr != '\0')
			errno = EINVAL;
		break;
	case MTREE_KEYWORD_UNAME:
		if (value == NULL) {
			errno = ENOENT;
			break;
		}
		mtree_copy_string(&data->uname, value);
		break;
	}

	if (errno != 0) {
		if (errno == ENOENT)
			mtree_reader_set_error(r, errno, "`%s': missing keyword "
			    "value", s);
		else if (errno == EINVAL)
			mtree_reader_set_error(r, errno, "`%s': invalid keyword "
			    "value `%s'", s, value);
		else if (errno == ENAMETOOLONG)
			mtree_reader_set_error(r, errno, "`%s': file name too "
			    "long: `%s'", s, value);
		else {
			/* These should be just memory errors. */
			mtree_reader_set_error(r, errno, NULL);
		}
		return (-1);
	}

	data->keywords |= keyword;
	return (0);
}