1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 Bootlin
4  *
5  * Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
6  */
7 
8 #include <errno.h>
9 #include <linux/types.h>
10 #include <asm/byteorder.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 #include "sqfs_filesystem.h"
16 #include "sqfs_utils.h"
17 
sqfs_is_dir(u16 type)18 bool sqfs_is_dir(u16 type)
19 {
20 	return type == SQFS_DIR_TYPE || type == SQFS_LDIR_TYPE;
21 }
22 
23 /*
24  * Receives a pointer (void *) to a position in the inode table containing the
25  * directory's inode. Returns directory inode offset into the directory table.
26  * m_list contains each metadata block's position, and m_count is the number of
27  * elements of m_list. Those metadata blocks come from the compressed directory
28  * table.
29  */
sqfs_dir_offset(void * dir_i,u32 * m_list,int m_count)30 int sqfs_dir_offset(void *dir_i, u32 *m_list, int m_count)
31 {
32 	struct squashfs_base_inode *base = dir_i;
33 	struct squashfs_ldir_inode *ldir;
34 	struct squashfs_dir_inode *dir;
35 	u32 start_block;
36 	int j, offset;
37 
38 	switch (get_unaligned_le16(&base->inode_type)) {
39 	case SQFS_DIR_TYPE:
40 		dir = (struct squashfs_dir_inode *)base;
41 		start_block = get_unaligned_le32(&dir->start_block);
42 		offset = get_unaligned_le16(&dir->offset);
43 		break;
44 	case SQFS_LDIR_TYPE:
45 		ldir = (struct squashfs_ldir_inode *)base;
46 		start_block = get_unaligned_le32(&ldir->start_block);
47 		offset = get_unaligned_le16(&ldir->offset);
48 		break;
49 	default:
50 		printf("Error: this is not a directory.\n");
51 		return -EINVAL;
52 	}
53 
54 	if (offset < 0)
55 		return -EINVAL;
56 
57 	for (j = 0; j < m_count; j++) {
58 		if (m_list[j] == start_block)
59 			return (++j * SQFS_METADATA_BLOCK_SIZE) + offset;
60 	}
61 
62 	if (start_block == 0)
63 		return offset;
64 
65 	printf("Error: invalid inode reference to directory table.\n");
66 
67 	return -EINVAL;
68 }
69 
sqfs_is_empty_dir(void * dir_i)70 bool sqfs_is_empty_dir(void *dir_i)
71 {
72 	struct squashfs_base_inode *base = dir_i;
73 	struct squashfs_ldir_inode *ldir;
74 	struct squashfs_dir_inode *dir;
75 	u32 file_size;
76 
77 	switch (get_unaligned_le16(&base->inode_type)) {
78 	case SQFS_DIR_TYPE:
79 		dir = (struct squashfs_dir_inode *)base;
80 		file_size = get_unaligned_le16(&dir->file_size);
81 		break;
82 	case SQFS_LDIR_TYPE:
83 		ldir = (struct squashfs_ldir_inode *)base;
84 		file_size = get_unaligned_le16(&ldir->file_size);
85 		break;
86 	default:
87 		printf("Error: this is not a directory.\n");
88 		return false;
89 	}
90 
91 	return file_size == SQFS_EMPTY_FILE_SIZE;
92 }
93