[ros-kernel] doserrno, errno

Mark Weaver mark at npsl.co.uk
Mon Nov 17 09:08:55 CET 2003


I've found a bit of time to do some reactos coding (finally), and am
starting with msvcrt, since I think this fits with what I know about.

The first think I've noted is that errno/doserrno don't seem to be set
correctly in general.  Typically any Win32 API function that is called and
fails should set both of these; the former is the POSIX type error, and the
latter is the win32 error code.  There exists an undocumented mapping
between the two which it is possible to extract using the undocumented
"_dosmaperr" function.  This function is not present in MSVCRT itself, but
shows up in the static link library.  The attached is a program to make a
mapping table by parsing winerror.h and errno.h, calling _dosmaperr for each
error code, and spitting out the result.  I believe this is a valid method
of extracting the required information without digging around in the MSVCRT
source code (it requires you to possess MSVC itself of course).  Sample
output is also attached.

I'm just sending this for initial comments, if OK, I'll go on to add the map
function into stdlib/errno.c and then go around changing functions so that
they call this to set errno/doserrno from API functions.

Oh, and, the overall motivation is that MSVCRT functions fail in a way
compatible with Microsoft's implementation.

Mark
-------------- next part --------------
/* doserrmap.h: auto-generated from winerror.h and errno.h using undoc'd _dosmaperr. */

#ifndef doserrmap_h
#define doserrmap_h

struct {
	unsigned long winerr;
	int en;
} doserrmap[] = {
	{ ERROR_FILE_NOT_FOUND, ENOENT }
	{ ERROR_PATH_NOT_FOUND, ENOENT }
	{ ERROR_TOO_MANY_OPEN_FILES, EMFILE }
	{ ERROR_ACCESS_DENIED, EACCES }
	{ ERROR_INVALID_HANDLE, EBADF }
	{ ERROR_ARENA_TRASHED, ENOMEM }
	{ ERROR_NOT_ENOUGH_MEMORY, ENOMEM }
	{ ERROR_INVALID_BLOCK, ENOMEM }
	{ ERROR_BAD_ENVIRONMENT, E2BIG }
	{ ERROR_BAD_FORMAT, ENOEXEC }
	{ ERROR_INVALID_DRIVE, ENOENT }
	{ ERROR_CURRENT_DIRECTORY, EACCES }
	{ ERROR_NOT_SAME_DEVICE, EXDEV }
	{ ERROR_NO_MORE_FILES, ENOENT }
	{ ERROR_WRITE_PROTECT, EACCES }
	{ ERROR_BAD_UNIT, EACCES }
	{ ERROR_NOT_READY, EACCES }
	{ ERROR_BAD_COMMAND, EACCES }
	{ ERROR_CRC, EACCES }
	{ ERROR_BAD_LENGTH, EACCES }
	{ ERROR_SEEK, EACCES }
	{ ERROR_NOT_DOS_DISK, EACCES }
	{ ERROR_SECTOR_NOT_FOUND, EACCES }
	{ ERROR_OUT_OF_PAPER, EACCES }
	{ ERROR_WRITE_FAULT, EACCES }
	{ ERROR_READ_FAULT, EACCES }
	{ ERROR_GEN_FAILURE, EACCES }
	{ ERROR_SHARING_VIOLATION, EACCES }
	{ ERROR_LOCK_VIOLATION, EACCES }
	{ ERROR_WRONG_DISK, EACCES }
	{ ERROR_SHARING_BUFFER_EXCEEDED, EACCES }
	{ ERROR_BAD_NETPATH, ENOENT }
	{ ERROR_NETWORK_ACCESS_DENIED, EACCES }
	{ ERROR_BAD_NET_NAME, ENOENT }
	{ ERROR_FILE_EXISTS, EEXIST }
	{ ERROR_CANNOT_MAKE, EACCES }
	{ ERROR_FAIL_I24, EACCES }
	{ ERROR_NO_PROC_SLOTS, EAGAIN }
	{ ERROR_DRIVE_LOCKED, EACCES }
	{ ERROR_BROKEN_PIPE, EPIPE }
	{ ERROR_DISK_FULL, ENOSPC }
	{ ERROR_INVALID_TARGET_HANDLE, EBADF }
	{ ERROR_WAIT_NO_CHILDREN, ECHILD }
	{ ERROR_CHILD_NOT_COMPLETE, ECHILD }
	{ ERROR_DIRECT_ACCESS_HANDLE, EBADF }
	{ ERROR_SEEK_ON_DEVICE, EACCES }
	{ ERROR_DIR_NOT_EMPTY, ENOTEMPTY }
	{ ERROR_NOT_LOCKED, EACCES }
	{ ERROR_BAD_PATHNAME, ENOENT }
	{ ERROR_MAX_THRDS_REACHED, EAGAIN }
	{ ERROR_LOCK_FAILED, EACCES }
	{ ERROR_ALREADY_EXISTS, EEXIST }
	{ ERROR_INVALID_STARTING_CODESEG, ENOEXEC }
	{ ERROR_INVALID_STACKSEG, ENOEXEC }
	{ ERROR_INVALID_MODULETYPE, ENOEXEC }
	{ ERROR_INVALID_EXE_SIGNATURE, ENOEXEC }
	{ ERROR_EXE_MARKED_INVALID, ENOEXEC }
	{ ERROR_BAD_EXE_FORMAT, ENOEXEC }
	{ ERROR_ITERATED_DATA_EXCEEDS_64k, ENOEXEC }
	{ ERROR_INVALID_MINALLOCSIZE, ENOEXEC }
	{ ERROR_DYNLINK_FROM_INVALID_RING, ENOEXEC }
	{ ERROR_IOPL_NOT_ENABLED, ENOEXEC }
	{ ERROR_INVALID_SEGDPL, ENOEXEC }
	{ ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC }
	{ ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC }
	{ ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC }
	{ ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC }
	{ ERROR_FILENAME_EXCED_RANGE, ENOENT }
	{ ERROR_NESTING_NOT_ALLOWED, EAGAIN }
	{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM }
};

#endif /* doserrmap_h */
-------------- next part --------------
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE 2048

typedef struct symbol_s {
	char			*symbol;
	unsigned long	value;
} symbol_t;

typedef struct symbol_table_s {
	int 		nsymbols, nalloc;
	symbol_t 	*symbol;
} symbol_table_t;


void symbol_table_init(symbol_table_t *t)
{
	t->nsymbols = t->nalloc = 0;
	t->symbol = NULL;
}

void symbol_table_free(symbol_table_t *t)
{
	int i;
	for (i = 0; i < t->nsymbols; ++i) 
		free(t->symbol[i].symbol);
	free(t->symbol);
}

void symbol_table_add(symbol_table_t *t, const char *symbol, unsigned long value)
{
	if (t->nsymbols + 1 > t->nalloc) {
		t->nalloc += 8;
		t->symbol = realloc(t->symbol, t->nalloc * sizeof(symbol_t));
		if (t->symbol == NULL) {
			fprintf(stderr, "Not enough memory.\n");
			exit(1);
		}
	}
	if ( (t->symbol[t->nsymbols].symbol = strdup(symbol)) == NULL ) {
		fprintf(stderr, "Not enough memory.\n");
		exit(1);
	}
	t->symbol[t->nsymbols].value = value;
	++t->nsymbols;
}

const char *symbol_table_search(symbol_table_t *t, unsigned long value)
{
	int i;
	for (i = 0; i < t->nsymbols; ++i) {
		if (t->symbol[i].value == value)
			return t->symbol[i].symbol;
	}
	return NULL;
}

int symbol_value_compare(const void *a1, const void *a2)
{
	const symbol_t *s1 = (const symbol_t *)a1;
	const symbol_t *s2 = (const symbol_t *)a2;
	return (int)(s1->value - s2->value);
}

int parse_header(symbol_table_t *t, const char *path, const char *prefix)
{
	FILE 	*fp;
	char 	line[MAX_LINE], name[MAX_LINE];
	
	symbol_table_init(t);
	
	if ( (fp = fopen(path, "rt")) == NULL ) {
		fprintf(stderr, "Opening %s failed.\n", path);
		return -1;
	}
	while (fgets(line, MAX_LINE, fp)) {
		/* Do messy extraction: basically looking for #define ERROR_ code or #define E* code */
		char *p = line, *n, *v;
		unsigned long e;
		
		while (isspace(*p)) ++p;
		if (*p != '#')
			continue;
		++p;
		while (isspace(*p)) ++p;
		if (strncmp(p, "define", 6) != 0)
			continue;
		p += 6;
		while (isspace(*p)) ++p;
		n = name;
		while (!isspace(*p)) {
			*n++ = *p++;
		}
		*n = 0;
		if (!isspace(*p))
			continue;	
		while (isspace(*p)) ++p;
		e = strtoul(p, &n, 0);
		if (p == n)
			continue;
		if (strncmp(name, prefix, strlen(prefix)) != 0)
			continue;
#if 0
		printf("found #define of %s to %u\n", name, e);
#endif		
		/* Map the error code */
		symbol_table_add(t, name, e);
	}
	
	fclose(fp);
	return 0;
}

int main(int argc, char *argv[])
{
	symbol_table_t	winerrsyms, errnosyms;
	int				i;
	
	if (argc < 3) {
		fprintf(stderr, "Syntax: makedoserr path-to-winerror.h path-to-errno.h\n");
		return 0;
	}
	
	if ( parse_header(&winerrsyms, argv[1], "ERROR_") == -1 )
		return 1;
	if ( parse_header(&errnosyms, argv[2], "E") == -1 )
		return 1;

	/* sort the winerr table by value so we can use a binary chop search on the result */
	qsort(winerrsyms.symbol, winerrsyms.nsymbols, sizeof(symbol_t), symbol_value_compare);
	
	/* print header code */
	printf(
"/* doserrmap.h: auto-generated from winerror.h and errno.h using undoc'd _dosmaperr. */\n"
"\n"
"#ifndef doserrmap_h\n"
"#define doserrmap_h\n"
"\n"
"struct {\n"
	"\tunsigned long winerr;\n"
	"\tint en;\n"
"} doserrmap[] = {\n");

	/* do the mapping */
	for (i = 0; i < winerrsyms.nsymbols; ++i) {
		const char *ens;
		int en;
		
		/* use undoc'd _dosmaperr present in static MSVC lib to find the value of errno */
		_dosmaperr(	winerrsyms.symbol[i].value );
		en = errno;
		
		/* map this to errno symbol */
		if ( (ens = symbol_table_search(&errnosyms, en)) == NULL ) {
			fprintf(stderr, "Warning: could not map errno code %u (resulting from winerror %s = %u) to an errno value.\n",
				en, winerrsyms.symbol[i].symbol, winerrsyms.symbol[i].value);
			continue;
		}
		
		/* it appears that EINVAL is the default, so we omit this from the generated table */
		if ( en != EINVAL ) {
			printf("\t{ %s, %s }\n", 
				winerrsyms.symbol[i].symbol, ens);
		}
	}
	printf(
"};\n\n"
"#endif /* doserrmap_h */\n");
	return 0;
}


More information about the Ros-kernel mailing list