unsigned char *squashfs_readdir(int fd, int root_entries, unsigned int directory_start_block, int offset, int size, unsigned int *last_directory_block, squashfs_super_block *sBlk, void (push_directory_entry)(char *, squashfs_inode, int, int)) { squashfs_dir_header dirh; char buffer[sizeof(squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1]; squashfs_dir_entry *dire = (squashfs_dir_entry *) buffer; unsigned char *directory_table = NULL; int byte, bytes = 0, dir_count; long long start = sBlk->directory_table_start + directory_start_block, last_start_block = -1; size += offset; if((directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) & ~(SQUASHFS_METADATA_SIZE - 1))) == NULL) return NULL; while(bytes < size) { TRACE("squashfs_readdir: reading block 0x%llx, bytes read so far %d\n", start, bytes); last_start_block = start; if((byte = read_block(fd, start, &start, directory_table + bytes, sBlk)) == 0) { free(directory_table); return NULL; } bytes += byte; } if(!root_entries) goto all_done; bytes = offset; while(bytes < size) { if(swap) { squashfs_dir_header sdirh; memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh); } else memcpy(&dirh, directory_table + bytes, sizeof(dirh)); dir_count = dirh.count + 1; TRACE("squashfs_readdir: Read directory header @ byte position 0x%x, 0x%x directory entries\n", bytes, dir_count); bytes += sizeof(dirh); while(dir_count--) { if(swap) { squashfs_dir_entry sdire; memcpy(&sdire, directory_table + bytes, sizeof(sdire)); SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire); } else memcpy(dire, directory_table + bytes, sizeof(*dire)); bytes += sizeof(*dire); memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_readdir: pushing directory entry %s, inode %x:%x, type 0x%x\n", dire->name, dirh.start_block, dire->offset, dire->type); push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dirh.inode_number + dire->inode_number, dire->type); bytes += dire->size + 1; } } all_done: *last_directory_block = (unsigned int) last_start_block - sBlk->directory_table_start; return directory_table; }
unsigned char *squashfs_readdir(int fd, int root_entries, unsigned int directory_start_block, int offset, int size, unsigned int *last_directory_block, struct squashfs_super_block *sBlk, void (push_directory_entry)(char *, squashfs_inode, int, int)) { struct squashfs_dir_header dirh; char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1] __attribute__ ((aligned)); struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer; unsigned char *directory_table = NULL; int byte, bytes = 0, dir_count; long long start = sBlk->directory_table_start + directory_start_block, last_start_block = start; size += offset; directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) & ~(SQUASHFS_METADATA_SIZE - 1)); if(directory_table == NULL) MEM_ERROR(); while(bytes < size) { int expected = (size - bytes) >= SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : 0; TRACE("squashfs_readdir: reading block 0x%llx, bytes read so " "far %d\n", start, bytes); last_start_block = start; byte = read_block(fd, start, &start, expected, directory_table + bytes); if(byte == 0) { ERROR("Failed to read directory\n"); ERROR("Filesystem corrupted?\n"); free(directory_table); return NULL; } bytes += byte; } if(!root_entries) goto all_done; bytes = offset; while(bytes < size) { SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh); dir_count = dirh.count + 1; TRACE("squashfs_readdir: Read directory header @ byte position " "0x%x, 0x%x directory entries\n", bytes, dir_count); bytes += sizeof(dirh); while(dir_count--) { SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire); bytes += sizeof(*dire); memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_readdir: pushing directory entry %s, " "inode %x:%x, type 0x%x\n", dire->name, dirh.start_block, dire->offset, dire->type); push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dirh.inode_number + dire->inode_number, dire->type); bytes += dire->size + 1; } } all_done: *last_directory_block = (unsigned int) last_start_block - sBlk->directory_table_start; return directory_table; }