Skip to content
Snippets Groups Projects
ext4_common.c 54.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Uma Shankar's avatar
    Uma Shankar committed
    	}
    	return 0;
    }
    
    static char *ext4fs_read_symlink(struct ext2fs_node *node)
    {
    	char *symlink;
    	struct ext2fs_node *diro = node;
    	int status;
    
    	if (!diro->inode_read) {
    		status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
    		if (status == 0)
    			return 0;
    	}
    	symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1);
    	if (!symlink)
    		return 0;
    
    	if (__le32_to_cpu(diro->inode.size) <= 60) {
    		strncpy(symlink, diro->inode.b.symlink,
    			 __le32_to_cpu(diro->inode.size));
    	} else {
    		status = ext4fs_read_file(diro, 0,
    					   __le32_to_cpu(diro->inode.size),
    					   symlink);
    		if (status == 0) {
    			free(symlink);
    			return 0;
    		}
    	}
    	symlink[__le32_to_cpu(diro->inode.size)] = '\0';
    	return symlink;
    }
    
    static int ext4fs_find_file1(const char *currpath,
    			     struct ext2fs_node *currroot,
    			     struct ext2fs_node **currfound, int *foundtype)
    {
    	char fpath[strlen(currpath) + 1];
    	char *name = fpath;
    	char *next;
    	int status;
    	int type = FILETYPE_DIRECTORY;
    	struct ext2fs_node *currnode = currroot;
    	struct ext2fs_node *oldnode = currroot;
    
    	strncpy(fpath, currpath, strlen(currpath) + 1);
    
    	/* Remove all leading slashes. */
    	while (*name == '/')
    		name++;
    
    	if (!*name) {
    		*currfound = currnode;
    		return 1;
    	}
    
    	for (;;) {
    		int found;
    
    		/* Extract the actual part from the pathname. */
    		next = strchr(name, '/');
    		if (next) {
    			/* Remove all leading slashes. */
    			while (*next == '/')
    				*(next++) = '\0';
    		}
    
    		if (type != FILETYPE_DIRECTORY) {
    			ext4fs_free_node(currnode, currroot);
    			return 0;
    		}
    
    		oldnode = currnode;
    
    		/* Iterate over the directory. */
    		found = ext4fs_iterate_dir(currnode, name, &currnode, &type);
    		if (found == 0)
    			return 0;
    
    		if (found == -1)
    			break;
    
    		/* Read in the symlink and follow it. */
    		if (type == FILETYPE_SYMLINK) {
    			char *symlink;
    
    			/* Test if the symlink does not loop. */
    			if (++symlinknest == 8) {
    				ext4fs_free_node(currnode, currroot);
    				ext4fs_free_node(oldnode, currroot);
    				return 0;
    			}
    
    			symlink = ext4fs_read_symlink(currnode);
    			ext4fs_free_node(currnode, currroot);
    
    			if (!symlink) {
    				ext4fs_free_node(oldnode, currroot);
    				return 0;
    			}
    
    			debug("Got symlink >%s<\n", symlink);
    
    			if (symlink[0] == '/') {
    				ext4fs_free_node(oldnode, currroot);
    				oldnode = &ext4fs_root->diropen;
    			}
    
    			/* Lookup the node the symlink points to. */
    			status = ext4fs_find_file1(symlink, oldnode,
    						    &currnode, &type);
    
    			free(symlink);
    
    			if (status == 0) {
    				ext4fs_free_node(oldnode, currroot);
    				return 0;
    			}
    		}
    
    		ext4fs_free_node(oldnode, currroot);
    
    		/* Found the node! */
    		if (!next || *next == '\0') {
    			*currfound = currnode;
    			*foundtype = type;
    			return 1;
    		}
    		name = next;
    	}
    	return -1;
    }
    
    int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
    	struct ext2fs_node **foundnode, int expecttype)
    {
    	int status;
    	int foundtype = FILETYPE_DIRECTORY;
    
    	symlinknest = 0;
    	if (!path)
    		return 0;
    
    	status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype);
    	if (status == 0)
    		return 0;
    
    	/* Check if the node that was found was of the expected type. */
    	if ((expecttype == FILETYPE_REG) && (foundtype != expecttype))
    		return 0;
    	else if ((expecttype == FILETYPE_DIRECTORY)
    		   && (foundtype != expecttype))
    		return 0;
    
    	return 1;
    }
    
    int ext4fs_open(const char *filename)
    {
    	struct ext2fs_node *fdiro = NULL;
    	int status;
    	int len;
    
    	if (ext4fs_root == NULL)
    		return -1;
    
    	ext4fs_file = NULL;
    	status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro,
    				  FILETYPE_REG);
    	if (status == 0)
    		goto fail;
    
    	if (!fdiro->inode_read) {
    		status = ext4fs_read_inode(fdiro->data, fdiro->ino,
    				&fdiro->inode);
    		if (status == 0)
    			goto fail;
    	}
    	len = __le32_to_cpu(fdiro->inode.size);
    	ext4fs_file = fdiro;
    
    	return len;
    fail:
    	ext4fs_free_node(fdiro, &ext4fs_root->diropen);
    
    	return -1;
    }
    
    int ext4fs_mount(unsigned part_length)
    {
    	struct ext2_data *data;
    	int status;
    	struct ext_filesystem *fs = get_fs();
    	data = zalloc(sizeof(struct ext2_data));
    	if (!data)
    		return 0;
    
    	/* Read the superblock. */
    	status = ext4fs_devread(1 * 2, 0, sizeof(struct ext2_sblock),
    				(char *)&data->sblock);
    
    	if (status == 0)
    		goto fail;
    
    	/* Make sure this is an ext2 filesystem. */
    	if (__le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
    		goto fail;
    
    	if (__le32_to_cpu(data->sblock.revision_level == 0))
    		fs->inodesz = 128;
    	else
    		fs->inodesz = __le16_to_cpu(data->sblock.inode_size);
    
    	debug("EXT2 rev %d, inode_size %d\n",
    	       __le32_to_cpu(data->sblock.revision_level), fs->inodesz);
    
    	data->diropen.data = data;
    	data->diropen.ino = 2;
    	data->diropen.inode_read = 1;
    	data->inode = &data->diropen.inode;
    
    	status = ext4fs_read_inode(data, 2, data->inode);
    	if (status == 0)
    		goto fail;
    
    	ext4fs_root = data;
    
    	return 1;
    fail:
    	printf("Failed to mount ext2 filesystem...\n");
    	free(data);
    	ext4fs_root = NULL;
    
    	return 0;
    }