Annotation For xvfs-create-c.c

Lines of xvfs-create-c.c from check-in 160dcdcda4 that are changed by the sequence of edits moving toward check-in 5aadfc2b05:

                         1: #include <sys/stat.h>
                         2: #include <stdlib.h>
                         3: #include <string.h>
                         4: #include <dirent.h>
                         5: #include <stdio.h>
                         6: #include <ctype.h>
                         7: #include <fcntl.h>
                         8: 
                         9: struct xvfs_options {
                        10: 	char *name;
                        11: 	char *directory;
                        12: };
                        13: 
                        14: struct xvfs_state {
                        15: 	char **children;
                        16: 	unsigned long child_count;
                        17: 	unsigned long child_len;
                        18: 	int bucket_count;
                        19: 	int max_index;
                        20: };
                        21: 
                        22: enum xvfs_minirivet_mode {
                        23: 	XVFS_MINIRIVET_MODE_COPY,
                        24: 	XVFS_MINIRIVET_MODE_TCL,
                        25: 	XVFS_MINIRIVET_MODE_TCL_PRINT
                        26: };
                        27: 
                        28: /*
                        29:  * adler32() function from zlib 1.1.4 and under the same license
                        30:  */
                        31: static unsigned long adler32(unsigned long adler, const unsigned char *buf, unsigned int len) {
                        32: 	const int len_max = 5552;
                        33: 	const unsigned long base = 65521;
                        34: 	unsigned long s1 = adler & 0xffff;
                        35: 	unsigned long s2 = (adler >> 16) & 0xffff;
                        36: 	int k, i;
                        37: 
                        38: 	if (buf == NULL) {
                        39: 		return(1UL);
                        40: 	}
                        41: 
                        42: 	while (len > 0) {
                        43: 		k = len < len_max ? len : len_max;
                        44: 		len -= k;
                        45: 
                        46: 		while (k >= 16) {
                        47: 			for (i = 0; i < 16; i++) {
                        48: 				s2 += buf[i];
                        49: 			}
                        50: 			s1 = buf[15];
                        51: 
                        52: 			buf += 16;
                        53: 			k   -= 16;
                        54: 		}
                        55: 
                        56: 		if (k != 0) {
                        57: 			do {
                        58: 				s1 += *buf++;
                        59: 				s2 += s1;
                        60: 			} while (--k);
                        61: 		}
                        62: 
                        63: 		s1 %= base;
                        64: 		s2 %= base;
                        65: 	}
                        66: 
                        67: 	return((s2 << 16) | s1);
                        68: }
                        69: 
                        70: /*
                        71:  * Handle XVFS Rivet template file substitution
                        72:  */
                        73: static void parse_xvfs_minirivet_file(FILE *outfp, const char * const external_file_name, const char * const internal_file_name) {
                        74: 	FILE *fp;
                        75: 	unsigned long file_size;
                        76: 	unsigned char buf[10];
                        77: 	size_t item_count;
                        78: 	int idx;
                        79: 
                        80: 	fp = fopen(external_file_name, "rb");
                        81: 	if (!fp) {
                        82: 		return;
                        83: 	}
                        84: 
                        85: 	fprintf(outfp, "\t{\n");
                        86: 	fprintf(outfp, "\t\t.name = \"%s\",\n", internal_file_name);
                        87: 	fprintf(outfp, "\t\t.type = XVFS_FILE_TYPE_REG,\n");
                        88: 	fprintf(outfp, "\t\t.data.fileContents = (const unsigned char *) \"");
                        89: 
                        90: 	file_size = 0;
                        91: 	while (1) {
                        92: 		item_count = fread(&buf, 1, sizeof(buf), fp);
                        93: 		if (item_count <= 0) {
                        94: 			break;
                        95: 		}
                        96: 
                        97: 		if (file_size != 0) {
                        98: 			fprintf(outfp, "\n\t\t\t\"");
                        99: 		}
                       100: 
                       101: 		for (idx = 0; idx < item_count; idx++) {
                       102: 			fprintf(outfp, "\\x%02x", (int) buf[idx]);
                       103: 		}
                       104: 		fprintf(outfp, "\"");
                       105: 
                       106: 		file_size += item_count;
                       107: 	}
                       108: 
                       109: 	fclose(fp);
                       110: 
                       111: 	fprintf(outfp, ",\n");
                       112: 	fprintf(outfp, "\t\t.size = %lu\n", file_size);
                       113: 	fprintf(outfp, "\t},\n");
                       114: }
                       115: 
                       116: static void parse_xvfs_minirivet_directory(FILE *outfp, struct xvfs_state *xvfs_state, const char * const directory, const char * const prefix) {
                       117: 	const unsigned int max_path_len = 8192, max_children = 65536;
                       118: 	unsigned long child_idx, child_count;
                       119: 	DIR *dp;
                       120: 	struct dirent *file_info;
                       121: 	struct stat file_stat;
                       122: 	char *full_path_buf;
                       123: 	char *rel_path_buf;
                       124: 	char **children;
                       125: 	int stat_ret;
                       126: 	int snprintf_ret;
                       127: 
                       128: 	dp = opendir(directory);
                       129: 	if (!dp) {
                       130: 		return;
                       131: 	}
                       132: 
                       133: 	full_path_buf = malloc(max_path_len);
                       134: 	rel_path_buf = malloc(max_path_len);
                       135: 	children = malloc(sizeof(*children) * max_children);
                       136: 
                       137: 	child_idx = 0;
                       138: 	while (1) {
                       139: 		file_info = readdir(dp);
                       140: 		if (!file_info) {
                       141: 			break;
                       142: 		}
                       143: 
                       144: 		if (strcmp(file_info->d_name, ".") == 0) {
                       145: 			continue;
                       146: 		}
                       147: 
                       148: 		if (strcmp(file_info->d_name, "..") == 0) {
                       149: 			continue;
                       150: 		}
                       151: 
                       152: 		snprintf_ret = snprintf(full_path_buf, max_path_len, "%s/%s", directory, file_info->d_name);
                       153: 		if (snprintf_ret >= max_path_len) {
                       154: 			continue;
                       155: 		}
                       156: 
                       157: 		snprintf_ret = snprintf(rel_path_buf, max_path_len, "%s%s%s",
                       158: 			prefix,
                       159: 			strcmp(prefix, "") == 0 ? "" : "/",
                       160: 			file_info->d_name
                       161: 		);
                       162: 		if (snprintf_ret >= max_path_len) {
                       163: 			continue;
                       164: 		}
                       165: 
                       166: 		stat_ret = stat(full_path_buf, &file_stat);
                       167: 		if (stat_ret != 0) {
                       168: 			continue;
                       169: 		}
                       170: 
                       171: 		children[child_idx] = strdup(file_info->d_name);
                       172: 		child_idx++;
                       173: 
                       174: 		if (S_ISDIR(file_stat.st_mode)) {
                       175: 			parse_xvfs_minirivet_directory(outfp, xvfs_state, full_path_buf, rel_path_buf);
                       176: 		} else {
                       177: 			parse_xvfs_minirivet_file(outfp, full_path_buf, rel_path_buf);
                       178: 
                       179: 			xvfs_state->children[xvfs_state->child_count] = strdup(rel_path_buf);
                       180: 			xvfs_state->child_count++;
                       181: 		}
                       182: 	}
                       183: 	free(full_path_buf);
                       184: 	free(rel_path_buf);
                       185: 
                       186: 	child_count = child_idx;
                       187: 
                       188: 	fprintf(outfp, "\t{\n");
                       189: 	fprintf(outfp, "\t\t.name = \"%s\",\n", prefix);
                       190: 	fprintf(outfp, "\t\t.type = XVFS_FILE_TYPE_DIR,\n");
                       191: 	fprintf(outfp, "\t\t.data.dirChildren  = (const char *[]) {");
                       192: 	for (child_idx = 0; child_idx < child_count; child_idx++) {
                       193: 		if (child_idx != 0) {
                       194: 			fprintf(outfp, ", ");
                       195: 		}
                       196: 
                       197: 		fprintf(outfp, "\"%s\"", children[child_idx]);
                       198: 
                       199: 		free(children[child_idx]);
                       200: 	}
                       201: 	fprintf(outfp, "},\n");
                       202: 	fprintf(outfp, "\t\t.size = %lu\n", child_count);
                       203: 
                       204: 	free(children);
                       205: 
                       206: 	fprintf(outfp, "\t},\n");
                       207: 
                       208: 	xvfs_state->children[xvfs_state->child_count] = strdup(prefix);
                       209: 	xvfs_state->child_count++;
                       210: 
                       211: 	closedir(dp);
                       212: 
                       213: 	return;
                       214: }
                       215: 
                       216: static void parse_xvfs_minirivet_hashtable_header(FILE *outfp, struct xvfs_state *xvfs_state) {
                       217: 	const int max_bucket_count = 30;
                       218: 	int bucket_count;
                       219: 	int idx1, idx2;
                       220: 	int check_hash;
                       221: 	int first_entry;
                       222: 
                       223: 	if (xvfs_state->child_count > max_bucket_count) {
                       224: 		bucket_count = max_bucket_count;
                       225: 	} else {
                       226: 		bucket_count = xvfs_state->child_count;
                       227: 	}
                       228: 	xvfs_state->bucket_count = bucket_count;
                       229: 	xvfs_state->max_index = xvfs_state->child_count;
                       230: 
                       231: 	fprintf(outfp, "\tlong pathIndex_idx;\n");
                       232: 	fprintf(outfp, "\tint pathIndex_hash;\n");
                       233: 
                       234: 	/*
                       235: 	 * XXX:TODO: Make this not O(n^2)
                       236: 	 */
                       237: 	for (idx1 = 0; idx1 < bucket_count; idx1++) {
                       238: 		fprintf(outfp, "\tstatic const long pathIndex_hashTable_%i[] = {\n", idx1);
                       239: 		fprintf(outfp, "\t\t");
                       240: 		first_entry = 1;
                       241: 
                       242: 		for (idx2 = 0; idx2 < xvfs_state->child_count; idx2++) {
                       243: 			check_hash = adler32(0, (unsigned char *) xvfs_state->children[idx2], strlen(xvfs_state->children[idx2])) % bucket_count;
                       244: 			if (check_hash != idx1) {
                       245: 				continue;
                       246: 			}
                       247: 
                       248: 			if (!first_entry) {
                       249: 				fprintf(outfp, ", ");
                       250: 			}
                       251: 			first_entry = 0;
                       252: 
                       253: 			if (check_hash == idx1) {
                       254: 				fprintf(outfp, "%i", idx2);
                       255: 			}
                       256: 		}
                       257: 
                       258: 		if (!first_entry) {
                       259: 			fprintf(outfp, ", ");
                       260: 		}
                       261: 		fprintf(outfp, "XVFS_NAME_LOOKUP_ERROR");
                       262: 
                       263: 		fprintf(outfp, "\n");
                       264: 
                       265: 		fprintf(outfp, "\t};\n");
                       266: 	}
                       267: 
                       268: 	for (idx2 = 0; idx2 < xvfs_state->child_count; idx2++) {
                       269: 		free(xvfs_state->children[idx2]);
                       270: 	}
                       271: 	free(xvfs_state->children);
                       272: 
                       273: 	fprintf(outfp, "\tstatic const long * const pathIndex_hashTable[%i] = {\n", bucket_count);
                       274: 	for (idx1 = 0; idx1 < bucket_count; idx1++) {
                       275: 		fprintf(outfp, "\t\tpathIndex_hashTable_%i,\n", idx1);
                       276: 	}
                       277: 	fprintf(outfp, "\t};\n");
                       278: 	return;
                       279: }
                       280: 
                       281: static void parse_xvfs_minirivet_hashtable_body(FILE *outfp, struct xvfs_state *xvfs_state) {
                       282: 	fprintf(outfp, "\tpathIndex_hash = Tcl_ZlibAdler32(0, (unsigned char *) path, pathLen) %% %i;\n", xvfs_state->bucket_count);
                       283: 	fprintf(outfp, "\tfor (pathIndex_idx = 0; pathIndex_idx < %i; pathIndex_idx++) {\n", xvfs_state->max_index);
                       284: 	fprintf(outfp, "\t\tpathIndex = pathIndex_hashTable[pathIndex_hash][pathIndex_idx];\n");
                       285: 	fprintf(outfp, "\t\tif (pathIndex == XVFS_NAME_LOOKUP_ERROR) {\n");
                       286: 	fprintf(outfp, "\t\t\tbreak;\n");
                       287: 	fprintf(outfp, "\t\t}\n");
                       288: 	fprintf(outfp, "\n");
                       289: 	fprintf(outfp, "\t\tif (strcmp(path, xvfs_example_data[pathIndex].name) == 0) {\n");
                       290: 	fprintf(outfp, "\t\t\treturn(pathIndex);\n");
                       291: 	fprintf(outfp, "\t\t}\n");
                       292: 	fprintf(outfp, "\t}\n");
                       293: 	return;
                       294: }
                       295: 
                       296: static void parse_xvfs_minirivet_handle_tcl_print(FILE *outfp, const struct xvfs_options * const options, struct xvfs_state *xvfs_state, char *command) {
                       297: 	char *buffer_p, *buffer_e;
                       298: 
                       299: 	buffer_p = command;
                       300: 	while (*buffer_p && isspace(*buffer_p)) {
                       301: 		buffer_p++;
                       302: 	}
                       303: 
                       304: 	buffer_e = buffer_p + strlen(buffer_p) - 1;
                       305: 	while (buffer_e >= buffer_p && isspace(*buffer_e)) {
                       306: 		*buffer_e = '\0';
                       307: 		buffer_e--;
                       308: 	}
                       309: 
                       310: 	if (strcmp(buffer_p, "$::xvfs::fsName") == 0) {
                       311: 		fprintf(outfp, "%s", options->name);
                       312: 	} else if (strcmp(buffer_p, "$::xvfs::fileInfoStruct") == 0) {
                       313: 		fprintf(outfp, "static const struct xvfs_file_data xvfs_");
                       314: 		fprintf(outfp, "%s", options->name);
                       315: 		fprintf(outfp, "_data[] = {\n");
                       316: 		parse_xvfs_minirivet_directory(outfp, xvfs_state, options->directory, "");
                       317: 		fprintf(outfp, "};\n");
                       318: 	} else if (strcmp(buffer_p, "[zlib adler32 $::xvfs::fsName 0]") == 0) {
                       319: 		fprintf(outfp, "%lu", adler32(0, (unsigned char *) options->name, strlen(options->name)));
                       320: 	} else if (strcmp(buffer_p, "$hashTableHeader") == 0) {
                       321: 		parse_xvfs_minirivet_hashtable_header(outfp, xvfs_state);
                       322: 	} else if (strcmp(buffer_p, "[dict get $hashTable body]") == 0) {
                       323: 		parse_xvfs_minirivet_hashtable_body(outfp, xvfs_state);
                       324: 	} else {
                       325: 		fprintf(outfp, "@INVALID@%s@INVALID@", buffer_p);
                       326: 	}
                       327: 
                       328: 	return;
                       329: }
                       330: 
                       331: static int parse_xvfs_minirivet(FILE *outfp, const char * const template, const struct xvfs_options * const options) {
                       332: 	struct xvfs_state xvfs_state;
                       333: 	int ch, ch_buf;
                       334: 	int template_idx = 0;
                       335: 	char tcl_buffer[8192], *tcl_buffer_p;
                       336: 	enum xvfs_minirivet_mode mode;
                       337: 
                       338: 	xvfs_state.child_count = 0;
                       339: 	xvfs_state.child_len   = 65536;
                       340: 	xvfs_state.children    = malloc(sizeof(*xvfs_state.children) * xvfs_state.child_len);
                       341: 
                       342: #define parse_xvfs_minirivet_getbyte(var) var = template[template_idx]; template_idx++; if (var == 0) { break; }
                       343: 
                       344: 	mode = XVFS_MINIRIVET_MODE_COPY;
                       345: 	tcl_buffer_p = NULL;
                       346: 	while (1) {
                       347: 		parse_xvfs_minirivet_getbyte(ch);
                       348: 
                       349: 		switch (mode) {
                       350: 			case XVFS_MINIRIVET_MODE_COPY:
                       351: 				if (ch == '<') {
                       352: 					parse_xvfs_minirivet_getbyte(ch_buf);
                       353: 					if (ch_buf != '?') {
                       354: 						fputc('<', outfp);
                       355: 						ch = ch_buf;
                       356: 
                       357: 						break;
                       358: 					}
                       359: 
                       360: 					tcl_buffer_p = tcl_buffer;
                       361: 					parse_xvfs_minirivet_getbyte(ch_buf);
                       362: 					if (ch_buf == '=') {
                       363: 						mode = XVFS_MINIRIVET_MODE_TCL_PRINT;
                       364: 					} else {
                       365: 						mode = XVFS_MINIRIVET_MODE_TCL;
                       366: 						*tcl_buffer_p = ch_buf;
                       367: 						tcl_buffer_p++;
                       368: 					}
                       369: 					*tcl_buffer_p = '\0';
                       370: 					continue;
                       371: 				}
                       372: 				break;
                       373: 			case XVFS_MINIRIVET_MODE_TCL:
                       374: 			case XVFS_MINIRIVET_MODE_TCL_PRINT:
                       375: 				if (ch == '?') {
                       376: 					parse_xvfs_minirivet_getbyte(ch_buf);
                       377: 					if (ch_buf != '>') {
                       378: 						*tcl_buffer_p = ch;
                       379: 						tcl_buffer_p++;
                       380: 
                       381: 						ch = ch_buf;
                       382: 						
                       383: 						break;
                       384: 					}
                       385: 
                       386: 					*tcl_buffer_p = '\0';
                       387: 
                       388: 					if (mode == XVFS_MINIRIVET_MODE_TCL_PRINT) {
                       389: 						parse_xvfs_minirivet_handle_tcl_print(outfp, options, &xvfs_state, tcl_buffer);
                       390: 					}
                       391: 
                       392: 					mode = XVFS_MINIRIVET_MODE_COPY;
                       393: 					continue;
                       394: 				}
                       395: 				break;
                       396: 		}
                       397: 
                       398: 		switch (mode) {
                       399: 			case XVFS_MINIRIVET_MODE_COPY:
                       400: 				fputc(ch, outfp);
                       401: 				break;
                       402: 			case XVFS_MINIRIVET_MODE_TCL:
                       403: 			case XVFS_MINIRIVET_MODE_TCL_PRINT:
                       404: 				*tcl_buffer_p = ch;
                       405: 				tcl_buffer_p++;
                       406: 				break;
                       407: 		}
                       408: 	}
                       409: 
                       410: #undef parse_xvfs_minirivet_getbyte
                       411: 
                       412: 	return(1);
                       413: }
                       414: 
                       415: static int xvfs_create(FILE *outfp, const struct xvfs_options * const options) {
                       416: 	const int template_len = 65536;
                       417: 	const char * const template_file = "lib/xvfs/xvfs.c.rvt";
                       418: 	FILE *fp;
                       419: 	char *template, *template_p;
                       420: 	int template_remain;
                       421: 	size_t fread_ret;
                       422: 	int retval;
                       423: 
                       424: 	fp = fopen(template_file, "r");
                       425: 	if (!fp) {
                       426: 		return(0);
                       427: 	}
                       428: 
                       429: 	template = malloc(template_len);
                       430: 	template_remain = template_len;
                       431: 	if (!template) {
                       432: 		fclose(fp);
                       433: 
                       434: 		return(0);
                       435: 	}
                       436: 
                       437: 	template_p = template;
                       438: 	while (1) {
                       439: 		fread_ret = fread(template_p, 1, template_remain, fp);
                       440: 		if (fread_ret <= 0) {
                       441: 			break;
                       442: 		}
                       443: 
                       444: 		template_p += fread_ret;
                       445: 		template_remain -= fread_ret;
                       446: 	}
                       447: 	if (template_remain > 0) {
                       448: 		*template_p = '\0';
                       449: 	}
                       450: 
                       451: 	fclose(fp);
                       452: 
                       453: 	retval = parse_xvfs_minirivet(outfp, template, options);
                       454: 
                       455: 	free(template);
                       456: 
                       457: 	return(retval);
                       458: }
                       459: 
                       460: /*
                       461:  * Parse command line options
                       462:  */
                       463: static int parse_options(int argc, char **argv, struct xvfs_options *options) {
                       464: 	char *arg;
                       465: 	char **option;
                       466: 	int idx;
                       467: 	int retval;
                       468: 
                       469: 	for (idx = 0; idx < argc; idx++) {
                       470: 		arg = argv[idx];
                       471: 
                       472: 		if (strcmp(arg, "--directory") == 0) {
                       473: 			option = &options->directory;
                       474: 		} else if (strcmp(arg, "--name") == 0) {
                       475: 			option = &options->name;
                       476: 		} else {
                       477: 			fprintf(stderr, "Invalid argument %s\n", arg);
                       478: 
                       479: 			return(0);
                       480: 		}
                       481: 
                       482: 		idx++;
                       483: 		arg = argv[idx];
                       484: 		*option = arg;
                       485: 	}
                       486: 
                       487: 	retval = 1;
                       488: 	if (!options->directory) {		
                       489: 		fprintf(stderr, "error: --directory must be specified\n");
                       490: 		retval = 0;
                       491: 	}
                       492: 
                       493: 	if (!options->name) {
                       494: 		fprintf(stderr, "error: --name must be specified\n");
                       495: 		retval = 0;
                       496: 	}
                       497: 
                       498: 	return(retval);
                       499: }
                       500: 
                       501: int main(int argc, char **argv) {
                       502: 	struct xvfs_options options = {0};
                       503: 	int parse_options_ret, xvfs_create_ret;
                       504: 
                       505: 	argc--;
                       506: 	argv++;
                       507: 
                       508: 	parse_options_ret = parse_options(argc, argv, &options);
                       509: 	if (!parse_options_ret) {
                       510: 		return(1);
                       511: 	}
                       512: 
                       513: 	xvfs_create_ret = xvfs_create(stdout, &options);
                       514: 	if (!xvfs_create_ret) {
                       515: 		return(1);
                       516: 	}
                       517: 
                       518: 	return(0);
                       519: }