Skip to content
Snippets Groups Projects
ext4_common.c 59 KiB
Newer Older
  • Learn to ignore specific revisions
  • Uma Shankar's avatar
    Uma Shankar committed
    			char filename[dirent.namelen + 1];
    			struct ext2fs_node *fdiro;
    			int type = FILETYPE_UNKNOWN;
    
    			status = ext4fs_read_file(diro,
    						  fpos +
    						  sizeof(struct ext2_dirent),
    
    						  dirent.namelen, filename,
    						  &actread);
    			if (status < 0)
    
    Uma Shankar's avatar
    Uma Shankar committed
    				return 0;
    
    			fdiro = zalloc(sizeof(struct ext2fs_node));
    			if (!fdiro)
    				return 0;
    
    			fdiro->data = diro->data;
    
    			fdiro->ino = le32_to_cpu(dirent.inode);
    
    Uma Shankar's avatar
    Uma Shankar committed
    
    			filename[dirent.namelen] = '\0';
    
    			if (dirent.filetype != FILETYPE_UNKNOWN) {
    				fdiro->inode_read = 0;
    
    				if (dirent.filetype == FILETYPE_DIRECTORY)
    					type = FILETYPE_DIRECTORY;
    				else if (dirent.filetype == FILETYPE_SYMLINK)
    					type = FILETYPE_SYMLINK;
    				else if (dirent.filetype == FILETYPE_REG)
    					type = FILETYPE_REG;
    			} else {
    				status = ext4fs_read_inode(diro->data,
    
    Uma Shankar's avatar
    Uma Shankar committed
    							   (dirent.inode),
    							   &fdiro->inode);
    				if (status == 0) {
    					free(fdiro);
    					return 0;
    				}
    				fdiro->inode_read = 1;
    
    
    				if ((le16_to_cpu(fdiro->inode.mode) &
    
    Uma Shankar's avatar
    Uma Shankar committed
    				     FILETYPE_INO_MASK) ==
    				    FILETYPE_INO_DIRECTORY) {
    					type = FILETYPE_DIRECTORY;
    
    				} else if ((le16_to_cpu(fdiro->inode.mode)
    
    Uma Shankar's avatar
    Uma Shankar committed
    					    & FILETYPE_INO_MASK) ==
    					   FILETYPE_INO_SYMLINK) {
    					type = FILETYPE_SYMLINK;
    
    				} else if ((le16_to_cpu(fdiro->inode.mode)
    
    Uma Shankar's avatar
    Uma Shankar committed
    					    & FILETYPE_INO_MASK) ==
    					   FILETYPE_INO_REG) {
    					type = FILETYPE_REG;
    				}
    			}
    #ifdef DEBUG
    			printf("iterate >%s<\n", filename);
    #endif /* of DEBUG */
    			if ((name != NULL) && (fnode != NULL)
    			    && (ftype != NULL)) {
    				if (strcmp(filename, name) == 0) {
    					*ftype = type;
    					*fnode = fdiro;
    					return 1;
    				}
    			} else {
    				if (fdiro->inode_read == 0) {
    					status = ext4fs_read_inode(diro->data,
    
    Uma Shankar's avatar
    Uma Shankar committed
    								 dirent.inode),
    								 &fdiro->inode);
    					if (status == 0) {
    						free(fdiro);
    						return 0;
    					}
    					fdiro->inode_read = 1;
    				}
    				switch (type) {
    				case FILETYPE_DIRECTORY:
    					printf("<DIR> ");
    					break;
    				case FILETYPE_SYMLINK:
    					printf("<SYM> ");
    					break;
    				case FILETYPE_REG:
    					printf("      ");
    					break;
    				default:
    					printf("< ? > ");
    					break;
    				}
    
    				       le32_to_cpu(fdiro->inode.size),
    
    Uma Shankar's avatar
    Uma Shankar committed
    					filename);
    			}
    			free(fdiro);
    		}
    
    		fpos += le16_to_cpu(dirent.direntlen);
    
    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;
    
    Uma Shankar's avatar
    Uma Shankar committed
    
    	if (!diro->inode_read) {
    		status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
    		if (status == 0)
    
    Uma Shankar's avatar
    Uma Shankar committed
    	}
    
    	symlink = zalloc(le32_to_cpu(diro->inode.size) + 1);
    
    Uma Shankar's avatar
    Uma Shankar committed
    	if (!symlink)
    
    	if (le32_to_cpu(diro->inode.size) < sizeof(diro->inode.b.symlink)) {
    
    Uma Shankar's avatar
    Uma Shankar committed
    		strncpy(symlink, diro->inode.b.symlink,
    
    			 le32_to_cpu(diro->inode.size));
    
    Uma Shankar's avatar
    Uma Shankar committed
    	} else {
    		status = ext4fs_read_file(diro, 0,
    
    					   le32_to_cpu(diro->inode.size),
    
    		if ((status < 0) || (actread == 0)) {
    
    Uma Shankar's avatar
    Uma Shankar committed
    			free(symlink);
    
    	symlink[le32_to_cpu(diro->inode.size)] = '\0';
    
    Uma Shankar's avatar
    Uma Shankar committed
    	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, loff_t *len)
    
    Uma Shankar's avatar
    Uma Shankar committed
    {
    	struct ext2fs_node *fdiro = NULL;
    	int status;
    
    	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);
    
    Uma Shankar's avatar
    Uma Shankar committed
    	ext4fs_file = fdiro;
    
    
    Uma Shankar's avatar
    Uma Shankar committed
    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(SUPERBLOCK_SIZE);
    
    Uma Shankar's avatar
    Uma Shankar committed
    	if (!data)
    		return 0;
    
    	/* Read the superblock. */
    
    	status = ext4_read_superblock((char *)&data->sblock);
    
    Uma Shankar's avatar
    Uma Shankar committed
    
    	if (status == 0)
    		goto fail;
    
    	/* Make sure this is an ext2 filesystem. */
    
    	if (le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
    
    Uma Shankar's avatar
    Uma Shankar committed
    		goto fail;
    
    
    	/*
    	 * The 64bit feature was enabled when metadata_csum was enabled
    	 * and we do not support metadata_csum (and cannot reliably find
    	 * files when it is set.  Refuse to mount.
    	 */
    
    	if (le32_to_cpu(data->sblock.feature_incompat) & EXT4_FEATURE_INCOMPAT_64BIT) {
    
    		printf("Unsupported feature found (64bit, possibly metadata_csum), not mounting\n");
    		goto fail;
    	}
    
    
    	if (le32_to_cpu(data->sblock.revision_level) == 0) {
    
    Uma Shankar's avatar
    Uma Shankar committed
    		fs->inodesz = 128;
    
    	} else {
    		debug("EXT4 features COMPAT: %08x INCOMPAT: %08x RO_COMPAT: %08x\n",
    		      __le32_to_cpu(data->sblock.feature_compatibility),
    		      __le32_to_cpu(data->sblock.feature_incompat),
    		      __le32_to_cpu(data->sblock.feature_ro_compat));
    
    
    		fs->inodesz = le16_to_cpu(data->sblock.inode_size);
    
    		fs->gdsize = le32_to_cpu(data->sblock.feature_incompat) &
    			EXT4_FEATURE_INCOMPAT_64BIT ?
    			le16_to_cpu(data->sblock.descriptor_size) : 32;
    	}
    
    	debug("EXT2 rev %d, inode_size %d, descriptor size %d\n",
    	      le32_to_cpu(data->sblock.revision_level),
    	      fs->inodesz, fs->gdsize);
    
    Uma Shankar's avatar
    Uma Shankar committed
    
    	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;
    }