[io] implementing IO_OP_OPEN_AT with FILE_OPEN_RESTRICT flag for sandboxing file access
This commit is contained in:
		
							parent
							
								
									c041b212ab
								
							
						
					
					
						commit
						b2d2d2a587
					
				|  | @ -7,7 +7,6 @@ | |||
| *****************************************************************/ | ||||
| 
 | ||||
| #include"platform_io.h" | ||||
| 
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| // File stream read/write API
 | ||||
| //------------------------------------------------------------------------------
 | ||||
|  |  | |||
|  | @ -0,0 +1,61 @@ | |||
| /************************************************************//**
 | ||||
| * | ||||
| *	@file: platform_io_internal.c | ||||
| *	@author: Martin Fouilleul | ||||
| *	@date: 11/06/2023 | ||||
| * | ||||
| *****************************************************************/ | ||||
| 
 | ||||
| #include"platform_io_internal.h" | ||||
| 
 | ||||
| file_table __globalFileTable = {0}; | ||||
| 
 | ||||
| file_slot* file_slot_alloc(file_table* table) | ||||
| { | ||||
| 	file_slot* slot = list_pop_entry(&table->freeList, file_slot, freeListElt); | ||||
| 	if(!slot && table->nextSlot < ORCA_MAX_FILE_SLOTS) | ||||
| 	{ | ||||
| 		slot = &table->slots[table->nextSlot]; | ||||
| 		slot->generation = 1; | ||||
| 		slot->fd = -1; | ||||
| 		table->nextSlot++; | ||||
| 	} | ||||
| 	return(slot); | ||||
| } | ||||
| 
 | ||||
| void file_slot_recycle(file_table* table, file_slot* slot) | ||||
| { | ||||
| 	slot->generation++; | ||||
| 	list_push(&table->freeList, &slot->freeListElt); | ||||
| } | ||||
| 
 | ||||
| file_handle file_handle_from_slot(file_table* table, file_slot* slot) | ||||
| { | ||||
| 	u64 index = slot - table->slots; | ||||
| 	u64 generation = slot->generation; | ||||
| 	file_handle handle = {.h = (generation<<32) | index }; | ||||
| 	return(handle); | ||||
| } | ||||
| 
 | ||||
| file_slot* file_slot_from_handle(file_table* table, file_handle handle) | ||||
| { | ||||
| 	file_slot* slot = 0; | ||||
| 
 | ||||
| 	u64 index = handle.h & 0xffffffff; | ||||
| 	u64 generation = handle.h>>32; | ||||
| 
 | ||||
| 	if(index < table->nextSlot) | ||||
| 	{ | ||||
| 		file_slot* candidate = &table->slots[index]; | ||||
| 		if(candidate->generation == generation) | ||||
| 		{ | ||||
| 			slot = candidate; | ||||
| 		} | ||||
| 	} | ||||
| 	return(slot); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_wait_single_req(io_req* req) | ||||
| { | ||||
| 	return(io_wait_single_req_with_table(req, &__globalFileTable)); | ||||
| } | ||||
|  | @ -0,0 +1,52 @@ | |||
| /************************************************************//**
 | ||||
| * | ||||
| *	@file: platform_io_internal.h | ||||
| *	@author: Martin Fouilleul | ||||
| *	@date: 10/06/2023 | ||||
| * | ||||
| *****************************************************************/ | ||||
| #ifndef __PLATFORM_IO_INTERNAL_H_ | ||||
| #define __PLATFORM_IO_INTERNAL_H_ | ||||
| 
 | ||||
| #include"platform_io.h" | ||||
| #include"platform.h" | ||||
| 
 | ||||
| #if PLATFORM_MACOS || PLATFORM_LINUX | ||||
| 	#define PLATFORM_IO_NATIVE_MEMBER int fd | ||||
| #elif PLATFORM_WINDOWS | ||||
| 	#define WIN32_LEAN_AND_MEAN | ||||
| 	#include<windows> | ||||
| 	#define PLATFORM_IO_NATIVE_MEMBER HANDLE h | ||||
| #endif | ||||
| 
 | ||||
| typedef struct file_slot | ||||
| { | ||||
| 	u32 generation; | ||||
| 	io_error error; | ||||
| 	bool fatal; | ||||
| 	list_elt freeListElt; | ||||
| 
 | ||||
| 	PLATFORM_IO_NATIVE_MEMBER; | ||||
| 
 | ||||
| } file_slot; | ||||
| 
 | ||||
| enum | ||||
| { | ||||
| 	ORCA_MAX_FILE_SLOTS = 256, | ||||
| }; | ||||
| 
 | ||||
| typedef struct file_table | ||||
| { | ||||
| 	file_slot slots[ORCA_MAX_FILE_SLOTS]; | ||||
| 	u32 nextSlot; | ||||
| 	list_info freeList; | ||||
| } file_table; | ||||
| 
 | ||||
| file_slot* file_slot_alloc(file_table* table); | ||||
| void file_slot_recycle(file_table* table, file_slot* slot); | ||||
| file_handle file_handle_from_slot(file_table* table, file_slot* slot); | ||||
| file_slot* file_slot_from_handle(file_table* table, file_handle handle); | ||||
| 
 | ||||
| io_cmp io_wait_single_req_with_table(io_req* req, file_table* table); | ||||
| 
 | ||||
| #endif //__PLATFORM_IO_INTERNAL_H_
 | ||||
|  | @ -13,75 +13,7 @@ | |||
| #include<limits.h> | ||||
| 
 | ||||
| #include"platform_io_common.c" | ||||
| 
 | ||||
| typedef struct file_slot | ||||
| { | ||||
| 	u32 generation; | ||||
| 	int fd; | ||||
| 	io_error error; | ||||
| 	bool fatal; | ||||
| 	list_elt freeListElt; | ||||
| 
 | ||||
| } file_slot; | ||||
| 
 | ||||
| enum | ||||
| { | ||||
| 	ORCA_MAX_FILE_SLOTS = 256, | ||||
| }; | ||||
| 
 | ||||
| typedef struct file_table | ||||
| { | ||||
| 	file_slot slots[ORCA_MAX_FILE_SLOTS]; | ||||
| 	u32 nextSlot; | ||||
| 	list_info freeList; | ||||
| } file_table; | ||||
| 
 | ||||
| file_table __globalFileTable = {0}; | ||||
| 
 | ||||
| file_slot* file_slot_alloc(file_table* table) | ||||
| { | ||||
| 	file_slot* slot = list_pop_entry(&table->freeList, file_slot, freeListElt); | ||||
| 	if(!slot && table->nextSlot < ORCA_MAX_FILE_SLOTS) | ||||
| 	{ | ||||
| 		slot = &table->slots[table->nextSlot]; | ||||
| 		slot->generation = 1; | ||||
| 		slot->fd = -1; | ||||
| 		table->nextSlot++; | ||||
| 	} | ||||
| 	return(slot); | ||||
| } | ||||
| 
 | ||||
| void file_slot_recycle(file_table* table, file_slot* slot) | ||||
| { | ||||
| 	slot->generation++; | ||||
| 	list_push(&table->freeList, &slot->freeListElt); | ||||
| } | ||||
| 
 | ||||
| file_handle file_handle_from_slot(file_table* table, file_slot* slot) | ||||
| { | ||||
| 	u64 index = slot - table->slots; | ||||
| 	u64 generation = slot->generation; | ||||
| 	file_handle handle = {.h = (generation<<32) | index }; | ||||
| 	return(handle); | ||||
| } | ||||
| 
 | ||||
| file_slot* file_slot_from_handle(file_table* table, file_handle handle) | ||||
| { | ||||
| 	file_slot* slot = 0; | ||||
| 
 | ||||
| 	u64 index = handle.h & 0xffffffff; | ||||
| 	u64 generation = handle.h>>32; | ||||
| 
 | ||||
| 	if(index < table->nextSlot) | ||||
| 	{ | ||||
| 		file_slot* candidate = &table->slots[index]; | ||||
| 		if(candidate->generation == generation) | ||||
| 		{ | ||||
| 			slot = candidate; | ||||
| 		} | ||||
| 	} | ||||
| 	return(slot); | ||||
| } | ||||
| #include"platform_io_internal.c" | ||||
| 
 | ||||
| io_error io_convert_errno(int e) | ||||
| { | ||||
|  | @ -219,11 +151,203 @@ int io_convert_open_flags(file_open_flags flags) | |||
| 	return(oflags); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_open_at(file_slot* atSlot, io_req* req) | ||||
| typedef struct io_open_restrict_result | ||||
| { | ||||
| 	io_error error; | ||||
| 	int fd; | ||||
| 
 | ||||
| } io_open_restrict_result; | ||||
| 
 | ||||
| io_open_restrict_result io_open_restrict(int dirFd, str8 path, int flags, mode_t mode) | ||||
| { | ||||
| 	io_open_restrict_result result = {.fd = -1}; | ||||
| 
 | ||||
| 	mem_arena_scope scratch = mem_scratch_begin(); | ||||
| 
 | ||||
| 	str8_list sep = {0}; | ||||
| 	str8_list_push(scratch.arena, &sep, STR8("/")); | ||||
| 	str8_list pathElements = str8_split(scratch.arena, path, sep); | ||||
| 
 | ||||
| 	result.fd = dirFd; | ||||
| 	if(result.fd < 0) | ||||
| 	{ | ||||
| 		result.error = io_convert_errno(errno); | ||||
| 		goto error; | ||||
| 	} | ||||
| 	struct stat dirStat; | ||||
| 	if(fstat(result.fd, &dirStat)) | ||||
| 	{ | ||||
| 		result.error = io_convert_errno(errno); | ||||
| 		goto error; | ||||
| 	} | ||||
| 	ino_t baseInode = dirStat.st_ino; | ||||
| 	ino_t currentInode = baseInode; | ||||
| 
 | ||||
| 	for_list(&pathElements.list, elt, str8_elt, listElt) | ||||
| 	{ | ||||
| 		str8 name = elt->string; | ||||
| 
 | ||||
| 		if(!str8_cmp(name, STR8("."))) | ||||
| 		{ | ||||
| 			//NOTE: skip
 | ||||
| 			continue; | ||||
| 		} | ||||
| 		else if(!str8_cmp(name, STR8(".."))) | ||||
| 		{ | ||||
| 			//NOTE: check that we don't escape 'root' dir
 | ||||
| 			if(currentInode == baseInode) | ||||
| 			{ | ||||
| 				result.error = IO_ERR_WALKOUT; | ||||
| 				goto error; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				// open that dir and continue
 | ||||
| 				int nextFd = openat(result.fd, "..", O_RDONLY); | ||||
| 				if(!nextFd) | ||||
| 				{ | ||||
| 					result.error = io_convert_errno(errno); | ||||
| 					goto error; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					close(result.fd); | ||||
| 					result.fd = nextFd; | ||||
| 					if(fstat(result.fd, &dirStat)) | ||||
| 					{ | ||||
| 						result.error = io_convert_errno(errno); | ||||
| 						goto error; | ||||
| 					} | ||||
| 					currentInode = dirStat.st_ino; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			char* nameCStr = str8_to_cstring(scratch.arena, name); | ||||
| 
 | ||||
| 			if(faccessat(result.fd, nameCStr, F_OK, AT_SYMLINK_NOFOLLOW)) | ||||
| 			{ | ||||
| 				//NOTE: file does not exist. if we're not at the end of path, or we don't have create flag,
 | ||||
| 				//      return a IO_ERR_NO_ENTRY
 | ||||
| 				if(&elt->listElt != list_last(&pathElements.list) && !(flags & O_CREAT)) | ||||
| 				{ | ||||
| 					result.error = IO_ERR_NO_ENTRY; | ||||
| 					goto error; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					//NOTE create the flag and return
 | ||||
| 					int nextFd = openat(result.fd, nameCStr, flags); | ||||
| 					if(!nextFd) | ||||
| 					{ | ||||
| 						result.error = io_convert_errno(errno); | ||||
| 						goto error; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						close(result.fd); | ||||
| 						result.fd = nextFd; | ||||
| 					} | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			struct stat st; | ||||
| 			if(fstatat(result.fd, nameCStr, &st, AT_SYMLINK_NOFOLLOW)) | ||||
| 			{ | ||||
| 				result.error = io_convert_errno(errno); | ||||
| 				goto error; | ||||
| 			} | ||||
| 
 | ||||
| 			int type = st.st_mode & S_IFMT; | ||||
| 
 | ||||
| 			if(type == S_IFLNK) | ||||
| 			{ | ||||
| 				// symlink, check that it's relative, and insert it in elements
 | ||||
| 				char buff[PATH_MAX+1]; | ||||
| 				int r = readlinkat(result.fd, nameCStr, buff, PATH_MAX); | ||||
| 				if(r<0) | ||||
| 				{ | ||||
| 					result.error = io_convert_errno(errno); | ||||
| 					goto error; | ||||
| 				} | ||||
| 				else if(r == 0) | ||||
| 				{ | ||||
| 					//NOTE: skip
 | ||||
| 				} | ||||
| 				else if(buff[0] == '/') | ||||
| 				{ | ||||
| 					result.error = IO_ERR_WALKOUT; | ||||
| 					goto error; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					buff[r] = '\0'; | ||||
| 
 | ||||
| 					str8_list linkElements = str8_split(scratch.arena, str8_from_buffer(r, buff), sep); | ||||
| 					if(!list_empty(&linkElements.list)) | ||||
| 					{ | ||||
| 						//NOTE: insert linkElements into pathElements after elt
 | ||||
| 						list_elt* tmp = elt->listElt.next; | ||||
| 						elt->listElt.next = linkElements.list.first; | ||||
| 						linkElements.list.last->next = tmp; | ||||
| 						if(!tmp) | ||||
| 						{ | ||||
| 							pathElements.list.last = linkElements.list.last; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else if(type == S_IFDIR) | ||||
| 			{ | ||||
| 				// dir, open it and continue
 | ||||
| 				int nextFd = openat(result.fd, nameCStr, O_RDONLY); | ||||
| 				if(!nextFd) | ||||
| 				{ | ||||
| 					result.error = io_convert_errno(errno); | ||||
| 					goto error; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					close(result.fd); | ||||
| 					result.fd = nextFd; | ||||
| 					currentInode = st.st_ino; | ||||
| 				} | ||||
| 			} | ||||
| 			else if(type == S_IFREG) | ||||
| 			{ | ||||
| 				// regular file, check that we're at the last element
 | ||||
| 				if(&elt->listElt != list_last(&pathElements.list)) | ||||
| 				{ | ||||
| 					result.error = IO_ERR_NOT_DIR; | ||||
| 					goto error; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				result.error = IO_ERR_NOT_DIR; | ||||
| 				goto error; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	goto end; | ||||
| 
 | ||||
| 	error: | ||||
| 	{ | ||||
| 		close(result.fd); | ||||
| 		result.fd = -1; | ||||
| 	} | ||||
| 	end: | ||||
| 	mem_scratch_end(scratch); | ||||
| 	return(result); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table) | ||||
| { | ||||
| 	io_cmp cmp = {0}; | ||||
| 
 | ||||
| 	file_slot* slot = file_slot_alloc(&__globalFileTable); | ||||
| 	file_slot* slot = file_slot_alloc(table); | ||||
| 	if(!slot) | ||||
| 	{ | ||||
| 		cmp.error = IO_ERR_MAX_FILES; | ||||
|  | @ -231,7 +355,7 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req) | |||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		cmp.handle = file_handle_from_slot(&__globalFileTable, slot); | ||||
| 		cmp.handle = file_handle_from_slot(table, slot); | ||||
| 
 | ||||
| 		int flags = io_convert_open_flags(req->openFlags); | ||||
| 
 | ||||
|  | @ -247,46 +371,72 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req) | |||
| 		mem_arena_scope scratch = mem_scratch_begin(); | ||||
| 
 | ||||
| 		str8 path = str8_from_buffer(req->size, req->buffer); | ||||
| 		char* pathCStr = str8_to_cstring(scratch.arena, path); | ||||
| 
 | ||||
| 
 | ||||
| 		//TODO: if FILE_OPEN_RESTRICT, do the file traversal to check that path is in the
 | ||||
| 		//      subtree rooted at atSlot->fd
 | ||||
| 		int fd = -1; | ||||
| 		slot->fd = -1; | ||||
| 		if(atSlot) | ||||
| 		{ | ||||
| 			fd = openat(atSlot->fd, pathCStr, flags, mode); | ||||
| 			if(path.len && path.ptr[0] == '/') | ||||
| 			{ | ||||
| 				//NOTE: if path is absolute, change for a relative one, otherwise openat ignores fd.
 | ||||
| 				str8_list list = {0}; | ||||
| 				str8_list_push(scratch.arena, &list, STR8(".")); | ||||
| 				str8_list_push(scratch.arena, &list, path); | ||||
| 				path = str8_list_join(scratch.arena, list); | ||||
| 			} | ||||
| 			char* pathCStr = str8_to_cstring(scratch.arena, path); | ||||
| 
 | ||||
| 			if(req->openFlags & FILE_OPEN_RESTRICT) | ||||
| 			{ | ||||
| 				io_open_restrict_result res = io_open_restrict(atSlot->fd, path, flags, mode); | ||||
| 				if(res.error == IO_OK) | ||||
| 				{ | ||||
| 					slot->fd = res.fd; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 			fd = open(pathCStr, flags, mode); | ||||
| 					slot->fatal = true; | ||||
| 					slot->error = res.error; | ||||
| 				} | ||||
| 
 | ||||
| 		mem_scratch_end(scratch); | ||||
| 
 | ||||
| 		if(fd >= 0) | ||||
| 		{ | ||||
| 			slot->fd = fd; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 			slot->fd = -1; | ||||
| 				slot->fd = openat(atSlot->fd, pathCStr, flags, mode); | ||||
| 				if(slot->fd < 0) | ||||
| 				{ | ||||
| 					slot->fatal = true; | ||||
| 					slot->error = io_convert_errno(errno); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			char* pathCStr = str8_to_cstring(scratch.arena, path); | ||||
| 			slot->fd = open(pathCStr, flags, mode); | ||||
| 			if(slot->fd < 0) | ||||
| 			{ | ||||
| 				slot->fatal = true; | ||||
| 				slot->error = io_convert_errno(errno); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		mem_scratch_end(scratch); | ||||
| 		cmp.error = slot->error; | ||||
| 	} | ||||
| 
 | ||||
| 	return(cmp); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_close(file_slot* slot, io_req* req) | ||||
| io_cmp io_close(file_slot* slot, io_req* req, file_table* table) | ||||
| { | ||||
| 	io_cmp cmp = {0}; | ||||
| 	if(slot->fd >= 0) | ||||
| 	{ | ||||
| 		close(slot->fd); | ||||
| 	} | ||||
| 	file_slot_recycle(&__globalFileTable, slot); | ||||
| 	file_slot_recycle(table, slot); | ||||
| 	return(cmp); | ||||
| } | ||||
| 
 | ||||
|  | @ -430,11 +580,11 @@ io_cmp io_get_error(file_slot* slot, io_req* req) | |||
| 	return(cmp); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_wait_single_req(io_req* req) | ||||
| io_cmp io_wait_single_req_with_table(io_req* req, file_table* table) | ||||
| { | ||||
| 	io_cmp cmp = {0}; | ||||
| 
 | ||||
| 	file_slot* slot = file_slot_from_handle(&__globalFileTable, req->handle); | ||||
| 	file_slot* slot = file_slot_from_handle(table, req->handle); | ||||
| 	if(!slot) | ||||
| 	{ | ||||
| 		if(req->op != IO_OP_OPEN_AT) | ||||
|  | @ -442,7 +592,9 @@ io_cmp io_wait_single_req(io_req* req) | |||
| 			cmp.error = IO_ERR_HANDLE; | ||||
| 		} | ||||
| 	} | ||||
| 	else if(slot->fatal && req->op != IO_OP_CLOSE) | ||||
| 	else if(  slot->fatal | ||||
| 	       && req->op != IO_OP_CLOSE | ||||
| 	       && req->op != IO_OP_ERROR) | ||||
| 	{ | ||||
| 		cmp.error = IO_ERR_PREV; | ||||
| 	} | ||||
|  | @ -452,7 +604,7 @@ io_cmp io_wait_single_req(io_req* req) | |||
| 		switch(req->op) | ||||
| 		{ | ||||
| 			case IO_OP_OPEN_AT: | ||||
| 				cmp = io_open_at(slot, req); | ||||
| 				cmp = io_open_at(slot, req, table); | ||||
| 				break; | ||||
| 
 | ||||
| 			case IO_OP_FSTAT: | ||||
|  | @ -460,7 +612,7 @@ io_cmp io_wait_single_req(io_req* req) | |||
| 				break; | ||||
| 
 | ||||
| 			case IO_OP_CLOSE: | ||||
| 				cmp = io_close(slot, req); | ||||
| 				cmp = io_close(slot, req, table); | ||||
| 				break; | ||||
| 
 | ||||
| 			case IO_OP_READ: | ||||
|  |  | |||
|  | @ -9,77 +9,9 @@ | |||
| #include<errno.h> | ||||
| #include<limits.h> | ||||
| 
 | ||||
| #include"platform_io_internal.c" | ||||
| #include"platform_io_common.c" | ||||
| 
 | ||||
| typedef struct file_slot | ||||
| { | ||||
| 	u32 generation; | ||||
| 	HANDLE h; | ||||
| 	io_error error; | ||||
| 	bool fatal; | ||||
| 	list_elt freeListElt; | ||||
| 
 | ||||
| } file_slot; | ||||
| 
 | ||||
| enum | ||||
| { | ||||
| 	ORCA_MAX_FILE_SLOTS = 256, | ||||
| }; | ||||
| 
 | ||||
| typedef struct file_table | ||||
| { | ||||
| 	file_slot slots[ORCA_MAX_FILE_SLOTS]; | ||||
| 	u32 nextSlot; | ||||
| 	list_info freeList; | ||||
| } file_table; | ||||
| 
 | ||||
| file_table __globalFileTable = {0}; | ||||
| 
 | ||||
| file_slot* file_slot_alloc(file_table* table) | ||||
| { | ||||
| 	file_slot* slot = list_pop_entry(&table->freeList, file_slot, freeListElt); | ||||
| 	if(!slot && table->nextSlot < ORCA_MAX_FILE_SLOTS) | ||||
| 	{ | ||||
| 		slot = &table->slots[table->nextSlot]; | ||||
| 		slot->generation = 1; | ||||
| 		slot->h = NULL; | ||||
| 		table->nextSlot++; | ||||
| 	} | ||||
| 	return(slot); | ||||
| } | ||||
| 
 | ||||
| void file_slot_recycle(file_table* table, file_slot* slot) | ||||
| { | ||||
| 	slot->generation++; | ||||
| 	list_push(&table->freeList, &slot->freeListElt); | ||||
| } | ||||
| 
 | ||||
| file_handle file_handle_from_slot(file_table* table, file_slot* slot) | ||||
| { | ||||
| 	u64 index = slot - table->slots; | ||||
| 	u64 generation = slot->generation; | ||||
| 	file_handle handle = {.h = (generation<<32) | index }; | ||||
| 	return(handle); | ||||
| } | ||||
| 
 | ||||
| file_slot* file_slot_from_handle(file_table* table, file_handle handle) | ||||
| { | ||||
| 	file_slot* slot = 0; | ||||
| 
 | ||||
| 	u64 index = handle.h & 0xffffffff; | ||||
| 	u64 generation = handle.h>>32; | ||||
| 
 | ||||
| 	if(index < table->nextSlot) | ||||
| 	{ | ||||
| 		file_slot* candidate = &table->slots[index]; | ||||
| 		if(candidate->generation == generation) | ||||
| 		{ | ||||
| 			slot = candidate; | ||||
| 		} | ||||
| 	} | ||||
| 	return(slot); | ||||
| } | ||||
| 
 | ||||
| io_error io_convert_win32_error(int winError) | ||||
| { | ||||
| 	io_error error = 0; | ||||
|  | @ -136,11 +68,11 @@ io_error io_convert_win32_error(int winError) | |||
| 	return(error); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_open_at(file_slot* atSlot, io_req* req) | ||||
| io_cmp io_open_at(file_slot* atSlot, io_req* req, file_table* table) | ||||
| { | ||||
| 	io_cmp cmp = {0}; | ||||
| 
 | ||||
| 	file_slot* slot = file_slot_alloc(&__globalFileTable); | ||||
| 	file_slot* slot = file_slot_alloc(table); | ||||
| 	if(!slot) | ||||
| 	{ | ||||
| 		cmp.error = IO_ERR_MAX_FILES; | ||||
|  | @ -148,7 +80,7 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req) | |||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		cmp.handle = file_handle_from_slot(&__globalFileTable, slot); | ||||
| 		cmp.handle = file_handle_from_slot(table, slot); | ||||
| 
 | ||||
| 		//NOTE: open
 | ||||
| 		mem_arena_scope scratch = mem_scratch_begin(); | ||||
|  | @ -232,14 +164,14 @@ io_cmp io_open_at(file_slot* atSlot, io_req* req) | |||
| 	return(cmp); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_close(file_slot* slot, io_req* req) | ||||
| io_cmp io_close(file_slot* slot, io_req* req, file_table* table) | ||||
| { | ||||
| 	io_cmp cmp = {0}; | ||||
| 	if(slot->h) | ||||
| 	{ | ||||
| 		CloseHandle(slot->h); | ||||
| 	} | ||||
| 	file_slot_recycle(&__globalFileTable, slot); | ||||
| 	file_slot_recycle(table, slot); | ||||
| 	return(cmp); | ||||
| } | ||||
| 
 | ||||
|  | @ -401,11 +333,11 @@ io_cmp io_get_error(file_slot* slot, io_req* req) | |||
| 	return(cmp); | ||||
| } | ||||
| 
 | ||||
| io_cmp io_wait_single_req(io_req* req) | ||||
| io_cmp io_wait_single_req_with_table(io_req* req, file_table* table) | ||||
| { | ||||
| 	io_cmp cmp = {0}; | ||||
| 
 | ||||
| 	file_slot* slot = file_slot_from_handle(&__globalFileTable, req->handle); | ||||
| 	file_slot* slot = file_slot_from_handle(table, req->handle); | ||||
| 	if(!slot) | ||||
| 	{ | ||||
| 		if(req->op != IO_OP_OPEN_AT) | ||||
|  | @ -423,7 +355,7 @@ io_cmp io_wait_single_req(io_req* req) | |||
| 		switch(req->op) | ||||
| 		{ | ||||
| 			case IO_OP_OPEN_AT: | ||||
| 				cmp = io_open_at(slot, req); | ||||
| 				cmp = io_open_at(slot, req, table); | ||||
| 				break; | ||||
| 
 | ||||
| 			case IO_OP_FSTAT: | ||||
|  | @ -431,7 +363,7 @@ io_cmp io_wait_single_req(io_req* req) | |||
| 				break; | ||||
| 
 | ||||
| 			case IO_OP_CLOSE: | ||||
| 				cmp = io_close(slot, req); | ||||
| 				cmp = io_close(slot, req, table); | ||||
| 				break; | ||||
| 
 | ||||
| 			case IO_OP_READ: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue