Compare commits
	
		
			3 Commits
		
	
	
		
			552e574cde
			...
			049405989b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 049405989b | |||
| 1dbdbd20d3 | |||
| db6187be39 | 
							
								
								
									
										4
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								config.h
									
									
									
									
									
								
							| @ -26,8 +26,8 @@ | |||||||
| #define FS_MAX_PATH_LEN 512 | #define FS_MAX_PATH_LEN 512 | ||||||
| #define FS_MAX_OPEN_FD 32 | #define FS_MAX_OPEN_FD 32 | ||||||
| #define FS_MAX_FNAME_LEN 11 | #define FS_MAX_FNAME_LEN 11 | ||||||
| #define FS_MAX_DIRECTORY_DEPTH 512 | #define FS_MAX_DIRECTORY_DEPTH 2048 | ||||||
| #define FS_MAX_SYMLINK_FOLLOWING_DEPTH 1024 | #define FS_MAX_SYMLINK_FOLLOWS 1024 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
							
								
								
									
										261
									
								
								src/fs.c
									
									
									
									
									
								
							
							
						
						
									
										261
									
								
								src/fs.c
									
									
									
									
									
								
							| @ -24,6 +24,7 @@ static unsigned int fs_cwd_inode_ptr; | |||||||
| static struct fs_file_description fs_file_descriptions[FS_MAX_OPEN_FD]; | static struct fs_file_description fs_file_descriptions[FS_MAX_OPEN_FD]; | ||||||
| 
 | 
 | ||||||
| static int extract_basename(char *path, char *name); | static int extract_basename(char *path, char *name); | ||||||
|  | static int read_symlink(int symlink_inode_ptr, char *path); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static int read_block(unsigned int block_no, void *data) | static int read_block(unsigned int block_no, void *data) | ||||||
| @ -907,18 +908,21 @@ fs_remove_fname_from_directory_finish: | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void resolve_path(struct resolved_path *rp, char *path, unsigned int params) | static void resolve_path(struct resolved_path * const rp, const char * const original_path, const unsigned int params) | ||||||
| { | { | ||||||
| 	rp->parent_inode_ptr = -1; | 	rp->parent_inode_ptr = -1; | ||||||
| 	rp->target_inode_ptr = -1; | 	rp->target_inode_ptr = -1; | ||||||
| 
 | 
 | ||||||
| 	int path_len = strlen(path); | 	int path_len = strlen(original_path); | ||||||
| 
 | 
 | ||||||
| 	if (!path_len) { | 	if (!path_len) { | ||||||
| 		pr_err("no path specified\n"); | 		pr_err("no path specified\n"); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	char path[FS_MAX_PATH_LEN+1]; | ||||||
|  | 	strcpy(path, original_path); | ||||||
|  | 
 | ||||||
| 	if (!strcmp(path, "/")) { | 	if (!strcmp(path, "/")) { | ||||||
| 		rp->parent_inode_ptr = 0; | 		rp->parent_inode_ptr = 0; | ||||||
| 		rp->target_inode_ptr = 0; | 		rp->target_inode_ptr = 0; | ||||||
| @ -931,6 +935,8 @@ static void resolve_path(struct resolved_path *rp, char *path, unsigned int para | |||||||
| 	int current_inode_ptr; | 	int current_inode_ptr; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
|  | 	unsigned int symlinks_followed = 0; | ||||||
|  | 
 | ||||||
| 	if (path[0] == '/') { | 	if (path[0] == '/') { | ||||||
| 		current_inode_ptr = 0; | 		current_inode_ptr = 0; | ||||||
| 		rp->parent_inode_ptr = 0; | 		rp->parent_inode_ptr = 0; | ||||||
| @ -950,65 +956,149 @@ static void resolve_path(struct resolved_path *rp, char *path, unsigned int para | |||||||
| 		if (path[i] != '/') { | 		if (path[i] != '/') { | ||||||
| 			next_fname[next_fname_ptr] = path[i]; | 			next_fname[next_fname_ptr] = path[i]; | ||||||
| 			next_fname_ptr++; | 			next_fname_ptr++; | ||||||
| 			continue; |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// path[i] == '/', trying to change current directory
 | 		if ((path[i] != '/') && (i+1 < path_len)) | ||||||
|  | 			continue; | ||||||
| 
 | 
 | ||||||
| 		if (!next_fname_ptr) | 		if (!next_fname_ptr) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		if (i+1 == path_len) |  | ||||||
| 			continue; |  | ||||||
| 
 |  | ||||||
| 		{ |  | ||||||
| 			int res = find_fname_in_directory(current_inode_ptr, next_fname); |  | ||||||
| 			if (res < 0) { |  | ||||||
| 				pr_warn("directory '%s' does not exist\n", next_fname); |  | ||||||
| 				rp->parent_inode_ptr = -1; |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			{ |  | ||||||
| 				struct fs_inode d; |  | ||||||
| 				read_block(read_inode_ptr(res), &d); |  | ||||||
| 
 |  | ||||||
| 				if (d.ftype == REGULAR) { |  | ||||||
| 					pr_warn("'%s' is a regular file\n", next_fname); |  | ||||||
| 					rp->parent_inode_ptr = -1; |  | ||||||
| 					break; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			pr("Found directory '%s'\n", next_fname); |  | ||||||
| 			current_inode_ptr = res; |  | ||||||
| 			rp->parent_inode_ptr = res; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		next_fname_ptr = 0; |  | ||||||
| 		strcpy(current_fname, next_fname); |  | ||||||
| 		memset(next_fname, 0, FS_MAX_FNAME_LEN); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (rp->parent_inode_ptr < 0) { |  | ||||||
| 		rp->target_inode_ptr = -1; |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	strcpy(rp->parent_fname, current_fname); |  | ||||||
| 
 |  | ||||||
| 	{ |  | ||||||
| 		int res = find_fname_in_directory(current_inode_ptr, next_fname); | 		int res = find_fname_in_directory(current_inode_ptr, next_fname); | ||||||
| 		if (res < 0) { | 		if (res < 0) { | ||||||
| 			pr_warn("target fname '%s' does not exist\n", next_fname); | 			if (i+1 < path_len) { | ||||||
| 			rp->target_inode_ptr = -1; | 				pr_warn("parent '%s' does not exist\n", next_fname); | ||||||
| 		} else { | 				rp->parent_inode_ptr = -1; | ||||||
| 			rp->target_inode_ptr = res; | 			} | ||||||
| 			strcpy(rp->target_fname, next_fname); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	return; | 			rp->target_inode_ptr = -1; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		struct fs_inode d; | ||||||
|  | 		read_block(read_inode_ptr(res), &d); | ||||||
|  | 
 | ||||||
|  | 		if (d.ftype == SYMLINK) { | ||||||
|  | 			if (i+1 < path_len) { | ||||||
|  | 				symlinks_followed++; | ||||||
|  | 				if (symlinks_followed > FS_MAX_SYMLINK_FOLLOWS) { | ||||||
|  | 					pr_err("too many symlink follows\n"); | ||||||
|  | 					rp->parent_inode_ptr = -1; | ||||||
|  | 					rp->target_inode_ptr = -1; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				char symlink_path[FS_MAX_PATH_LEN+1]; | ||||||
|  | 				int symlink_path_len = read_symlink(res, symlink_path); | ||||||
|  | 
 | ||||||
|  | 				if (symlink_path_len < 0) { | ||||||
|  | 					pr_warn("broken symlink\n"); | ||||||
|  | 					rp->parent_inode_ptr = -1; | ||||||
|  | 					rp->target_inode_ptr = -1; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (symlink_path[0] == '/') { | ||||||
|  | 					memmove(&(path[symlink_path_len]), &(path[i+1]), path_len-i-1); | ||||||
|  | 					strcpy(path, &(symlink_path[1])); | ||||||
|  | 					path[symlink_path_len-1] = '/'; | ||||||
|  | 					path_len = symlink_path_len + path_len - i - 1; | ||||||
|  | 					i = -1; | ||||||
|  | 
 | ||||||
|  | 					next_fname_ptr = 0; | ||||||
|  | 					strcpy(current_fname, "/"); | ||||||
|  | 					memset(next_fname, 0, FS_MAX_FNAME_LEN); | ||||||
|  | 				} else { | ||||||
|  | 					memmove(&(path[symlink_path_len+1]), &(path[i+1]), path_len-i-1); | ||||||
|  | 					strcpy(path, symlink_path); | ||||||
|  | 					path[symlink_path_len] = '/'; | ||||||
|  | 					path_len = symlink_path_len + path_len - i; | ||||||
|  | 					i = -1; | ||||||
|  | 
 | ||||||
|  | 					next_fname_ptr = 0; | ||||||
|  | 					strcpy(current_fname, next_fname); | ||||||
|  | 					memset(next_fname, 0, FS_MAX_FNAME_LEN); | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				if (!(params & FOLLOW_LAST_SYMLINK)) { | ||||||
|  | 					rp->target_inode_ptr = res; | ||||||
|  | 					strcpy(rp->parent_fname, current_fname); | ||||||
|  | 					strcpy(rp->target_fname, next_fname); | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				symlinks_followed++; | ||||||
|  | 				if (symlinks_followed > FS_MAX_SYMLINK_FOLLOWS) { | ||||||
|  | 					pr_err("too many symlink follows\n"); | ||||||
|  | 					rp->parent_inode_ptr = -1; | ||||||
|  | 					rp->target_inode_ptr = -1; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				char symlink_path[FS_MAX_PATH_LEN+1]; | ||||||
|  | 				int symlink_path_len = read_symlink(res, symlink_path); | ||||||
|  | 
 | ||||||
|  | 				if (symlink_path_len < 0) { | ||||||
|  | 					pr_warn("broken symlink\n"); | ||||||
|  | 					rp->parent_inode_ptr = -1; | ||||||
|  | 					rp->target_inode_ptr = -1; | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (!strcmp(symlink_path, "/")) { | ||||||
|  | 					rp->parent_inode_ptr = 0; | ||||||
|  | 					rp->target_inode_ptr = 0; | ||||||
|  | 					strcpy(rp->parent_fname, "/"); | ||||||
|  | 					strcpy(rp->target_fname, "/"); | ||||||
|  | 					break; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if (symlink_path[0] == '/') { | ||||||
|  | 					strcpy(path, &(symlink_path[1])); | ||||||
|  | 					path_len = symlink_path_len - 1; | ||||||
|  | 					i = -1; | ||||||
|  | 
 | ||||||
|  | 					next_fname_ptr = 0; | ||||||
|  | 					strcpy(current_fname, "/"); | ||||||
|  | 					memset(next_fname, 0, FS_MAX_FNAME_LEN); | ||||||
|  | 				} else { | ||||||
|  | 					strcpy(path, symlink_path); | ||||||
|  | 					path_len = symlink_path_len; | ||||||
|  | 					i = -1; | ||||||
|  | 
 | ||||||
|  | 					next_fname_ptr = 0; | ||||||
|  | 					strcpy(current_fname, next_fname); | ||||||
|  | 					memset(next_fname, 0, FS_MAX_FNAME_LEN); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} else if (d.ftype == REGULAR) { | ||||||
|  | 			if (i+1 < path_len) { | ||||||
|  | 				pr_warn("'%s': regular file not in the end of a path\n", next_fname); | ||||||
|  | 				rp->parent_inode_ptr = -1; | ||||||
|  | 				rp->target_inode_ptr = -1; | ||||||
|  | 				break; | ||||||
|  | 			} else { | ||||||
|  | 				rp->target_inode_ptr = res; | ||||||
|  | 				strcpy(rp->parent_fname, current_fname); | ||||||
|  | 				strcpy(rp->target_fname, next_fname); | ||||||
|  | 			} | ||||||
|  | 		} else if (d.ftype == DIRECTORY) { | ||||||
|  | 			if (i+1 < path_len) { | ||||||
|  | 				pr("Found directory '%s'\n", next_fname); | ||||||
|  | 				current_inode_ptr = res; | ||||||
|  | 				rp->parent_inode_ptr = res; | ||||||
|  | 
 | ||||||
|  | 				next_fname_ptr = 0; | ||||||
|  | 				strcpy(current_fname, next_fname); | ||||||
|  | 				memset(next_fname, 0, FS_MAX_FNAME_LEN); | ||||||
|  | 			} else { | ||||||
|  | 				rp->target_inode_ptr = res; | ||||||
|  | 				strcpy(rp->parent_fname, current_fname); | ||||||
|  | 				strcpy(rp->target_fname, next_fname); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -1631,6 +1721,73 @@ int fs_ln(void *d) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int read_symlink(int symlink_inode_ptr, char *path) | ||||||
|  | { | ||||||
|  | 	struct fs_inode i; | ||||||
|  | 	read_block(read_inode_ptr(symlink_inode_ptr), &i); | ||||||
|  | 
 | ||||||
|  | 	path[0] = '\0'; | ||||||
|  | 	int bytes_read = 0; | ||||||
|  | 
 | ||||||
|  | 	for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE; j++) { | ||||||
|  | 		if (!i.blocks[j]) { | ||||||
|  | 			pr_err("inode size (%d) indicates existing block but it's address is absent in inode, symlink at inode_ptr=%d might be broken\n", | ||||||
|  | 					i.size, symlink_inode_ptr); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		char data[FS_BLOCK_SIZE]; | ||||||
|  | 		read_block(i.blocks[j], data); | ||||||
|  | 
 | ||||||
|  | 		if (i.size - bytes_read < FS_BLOCK_SIZE) { | ||||||
|  | 			memcpy(&(path[bytes_read]), data, i.size - bytes_read); | ||||||
|  | 			bytes_read = i.size; | ||||||
|  | 			path[bytes_read] = '\0'; | ||||||
|  | 		} else { | ||||||
|  | 			memcpy(&(path[bytes_read]), data, FS_BLOCK_SIZE); | ||||||
|  | 			bytes_read += FS_BLOCK_SIZE; | ||||||
|  | 			path[bytes_read] = '\0'; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (i.size == bytes_read) | ||||||
|  | 			goto finish_reading; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (unsigned int next_ext = i.next_extension; ; ) { | ||||||
|  | 		struct fs_inode_extension ext; | ||||||
|  | 		read_block(next_ext, &ext); | ||||||
|  | 
 | ||||||
|  | 		for (int j = 0; j < BLOCK_ADDRESSES_PER_INODE_EXTENSION; j++) { | ||||||
|  | 			if (!ext.blocks[j]) { | ||||||
|  | 				pr_err("inode size (%d) indicates existing block but it's address is absent in inode extension, symlink at inode_ptr=%d might be broken\n", | ||||||
|  | 						i.size, symlink_inode_ptr); | ||||||
|  | 				return -1; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			char data[FS_BLOCK_SIZE]; | ||||||
|  | 			read_block(ext.blocks[j], data); | ||||||
|  | 
 | ||||||
|  | 			if (i.size - bytes_read < FS_BLOCK_SIZE) { | ||||||
|  | 				memcpy(&(path[bytes_read]), data, i.size - bytes_read); | ||||||
|  | 				bytes_read = i.size; | ||||||
|  | 				path[bytes_read] = '\0'; | ||||||
|  | 			} else { | ||||||
|  | 				memcpy(&(path[bytes_read]), data, FS_BLOCK_SIZE); | ||||||
|  | 				bytes_read += FS_BLOCK_SIZE; | ||||||
|  | 				path[bytes_read] = '\0'; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (i.size == bytes_read) | ||||||
|  | 				goto finish_reading; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		next_ext = ext.next_extension; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | finish_reading: | ||||||
|  | 	return bytes_read; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int fs_symlink(void *d) | int fs_symlink(void *d) | ||||||
| { | { | ||||||
| 	char *target_path = ((char **) d)[0]; | 	char *target_path = ((char **) d)[0]; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user