Ext2: reading directory entries reads zeros.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

Wait, I'm gonna run Linux. 5 secs :D
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

This is my structures. I don't see any mistakes.

Code: Select all

struct ext2_superblock
{
	uint32_t inodes_count;
	uint32_t blocks_count;
	uint32_t reserved_blocks_count;
	uint32_t unallocated_blocks_count;
	uint32_t unallocated_inodes_count;
	uint32_t superblock_block_number;
	uint32_t block_size;
	uint32_t fragment_size;
	uint32_t blocks_count_in_blk_group;
	uint32_t fragments_count_in_blk_group;
	uint32_t inodes_count_in_blk_group;
	uint32_t last_mount_time;
	uint32_t last_written_time;
	uint16_t times_mounted_after_check;
	uint16_t mounts_before_check;
	uint16_t signature;
	uint16_t fs_state;
	uint16_t action_on_error;
	uint16_t ver_minor;
	uint32_t last_check_time;
	uint32_t check_interval;
	uint32_t creator_id;
	uint32_t ver_major;
	uint16_t reserved_blocks_uid;
	uint16_t reserved_blocks_gid;
	uint32_t first_nonreserved_inode;
	uint16_t inode_size;
	uint16_t superblock_block_group;
	uint32_t optional_features;
	uint32_t required_features;
	uint32_t features_to_read_write;
	uint8_t  fs_id[16];
	char     volume_label[16];
	char     last_mount_path[64];
	uint32_t compression_algorithms_used;
	uint8_t blocks_to_preallocate_for_files;
	uint8_t blocks_to_preallocate_for_dirs;
	uint16_t unused;
	uint8_t  journal_id[16];
	uint32_t journal_inode;
	uint32_t journal_device;
	uint32_t orphan_inode_list_head;
} __attribute__((packed));
struct ext2_inode
{
	uint16_t type_and_perms;
	uint16_t owner_uid;
	uint32_t size_low;
	uint32_t access_time;
	uint32_t creation_time;
	uint32_t modified_time;
	uint32_t deletion_time;
	uint16_t owner_gid;
	uint16_t link_count; //These links are "pointers" to this inode.
	uint32_t sector_count;
	uint32_t flags;
	uint32_t os_specific;
	uint32_t direct_block_pointers[12]; //For medium-size files this is enough.
	uint32_t singly_indir_block_pointer;
	uint32_t double_indir_block_pointer;
	uint32_t triple_indir_block_pointer;
	uint32_t generation_number;
	uint32_t file_acl;
	uint32_t dir_acl_or_file_size_high;
	uint32_t fragment_address;
	uint8_t  os_specific_2[12];
} __attribute__((packed));
struct ext2_block_group_descriptor
{
	uint32_t block_usage_address;
	uint32_t inode_usage_address;
	uint32_t inode_table_address;
	uint16_t unallocated_blocks_count;
	uint16_t unallocated_inodes_count;
	uint16_t directories_in_group;
	uint16_t unused[7];
} __attribute__((packed));
struct ext2_directory_entry
{
	uint32_t inode;
	uint16_t size;
	uint8_t  name_length_low;
	uint8_t  type_or_name_length_high;
	//As you can see, structure misses name field. It's because C doesn't allow variable-length arrays in structures, because it will prevent compile-time structure size computing.
} __attribute__((packed));
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

Anybody?
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
crunch
Member
Member
Posts: 81
Joined: Wed Aug 31, 2016 9:53 pm
Libera.chat IRC: crunch
Location: San Diego, CA

Re: Ext2: reading directory entries reads zeros.

Post by crunch »

I'd suggest you try and test your code on a host machine, with disk images. That's how I got my ext2 code sorted out.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

My driver fails to find drives, IDK why. But disk reads finely when it exists, as I previosly said many times.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

catnikita255 wrote:Anybody?
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

Also you may need ATA driver, this is ata.c file:

Code: Select all

#include <string.h>
#include <stdint.h>
#include <arch/i686/ata.h>
#include <stdio.h>
#include <io.h>
#include <debug.h>
#include <time.h>

#define ATA_BLOCKSIZE 512

#define ATA_IRQ0	32+14
#define ATA_IRQ1	32+15
#define ATA_IRQ2	32+11
#define ATA_IRQ3	32+9

#define ATA_BASE0	0x1F0
#define ATA_BASE1	0x170
#define ATA_BASE2	0x1E8
#define ATA_BASE3	0x168

#define ATA_TIMEOUT     3

#define ATA_DATA	0   /* data register */
#define ATA_ERROR	1   /* error register */
#define ATA_COUNT	2   /* sectors to transfer */
#define ATA_SECTOR	3   /* sector number */
#define ATA_CYL_LO	4   /* low byte of cylinder number */
#define ATA_CYL_HI	5   /* high byte of cylinder number */
#define ATA_FDH		6   /* flags, drive and head */
#define ATA_STATUS	7
#define ATA_COMMAND	7
#define ATA_CONTROL	0x206

#define ATA_FLAGS_ECC	0x80	/* enable error correction */
#define ATA_FLAGS_LBA	0x40	/* enable linear addressing */
#define ATA_FLAGS_SEC	0x20	/* enable 512-byte sectors */
#define ATA_FLAGS_SLV	0x10	/* address the slave drive */

#define ATA_STATUS_BSY	0x80    /* controller busy */
#define ATA_STATUS_RDY	0x40    /* drive ready */
#define ATA_STATUS_WF	0x20    /* write fault */
#define ATA_STATUS_SC	0x10    /* seek complete (obsolete) */
#define ATA_STATUS_DRQ	0x08    /* data transfer request */
#define ATA_STATUS_CRD	0x04    /* corrected data */
#define ATA_STATUS_IDX	0x02    /* index pulse */
#define ATA_STATUS_ERR	0x01    /* error */

#define ATA_COMMAND_IDLE		0x00
#define ATA_COMMAND_READ		0x20    /* read data */
#define ATA_COMMAND_WRITE		0x30    /* write data */
#define ATA_COMMAND_IDENTIFY		0xec

#define ATAPI_COMMAND_IDENTIFY 0xa1
#define ATAPI_COMMAND_PACKET   0xa0

#define ATAPI_FEATURE	1
#define ATAPI_IRR 2
#define ATAPI_SAMTAG 3
#define ATAPI_COUNT_LO 4
#define ATAPI_COUNT_HI 5
#define ATAPI_DRIVE 6
#define ATAPI_BLOCKSIZE 2048

#define SCSI_READ10            0x28
#define SCSI_SENSE             0x03

#define ATA_CONTROL_RESET	0x04
#define ATA_CONTROL_DISABLEINT	0x02

static const int ata_base[4] = {
	ATA_BASE0,
	ATA_BASE0,
	ATA_BASE1,
	ATA_BASE1
};
struct ata_drive_info
{
	uint8_t  attached;
	const char *name;
	int block_size;
	uint64_t size;
};
static struct ata_drive_info drives[4];
void ata_reset(int id) {
	outb(ata_base[id] + ATA_CONTROL, ATA_CONTROL_RESET);
	sleep(10);
	outb(ata_base[id] + ATA_CONTROL, 0);
	sleep(10);
}

static int ata_wait(int id, int mask, int state) {
	int t;
	int time=0;
	while(1) {
		t = inb(ata_base[id] + ATA_STATUS);
		if((t&mask) == state) {
			return 1;
		}
		if(t&ATA_STATUS_ERR) {
			debug_print(ERROR, "ATA error.");
			ata_reset(id);
			return 0;
		}
		if(time>=ATA_TIMEOUT*100)
		{
			debug_print(NOTICE, "ata_wait: timed out!");
			ata_reset(id);
			return 0;
		}
		sleep(1);
		time++;
	}
}

static void ata_pio_read(int id, void *buffer, int size) {
	uint16_t *wbuffer = (uint16_t*)buffer;
	while(size > 0) {
		*wbuffer = inw(ata_base[id] + ATA_DATA);
		wbuffer++;
		size -= 2;
	}
}

static void ata_pio_write(int id, const void *buffer, int size) {
	uint16_t *wbuffer = (uint16_t*)buffer;
	while(size > 0) {
		outw(ata_base[id] + ATA_DATA, *wbuffer);
		wbuffer++;
		size-=2;
	}
}

static int ata_begin(int id, int command, int nblocks, int offset) {
	int base = ata_base[id];
	int sector, clow, chigh, flags;

	flags = ATA_FLAGS_ECC | ATA_FLAGS_LBA | ATA_FLAGS_SEC;
	if(id % 2) flags |= ATA_FLAGS_SLV;

	sector = (offset >> 0) & 0xff;
	clow = (offset >> 8) & 0xff;
	chigh = (offset >> 16) & 0xff;
	flags |= (offset >> 24) & 0x0f;

	if(!ata_wait(id, ATA_STATUS_BSY, 0)) return 0;
	outb(base + ATA_FDH, flags);
	int ready;
	if(command == ATAPI_COMMAND_IDENTIFY) ready = ata_wait(id, ATA_STATUS_BSY,0);
	else ready = ata_wait(id, ATA_STATUS_BSY | ATA_STATUS_RDY, ATA_STATUS_RDY);

	if(!ready) return 0;

	outb(base + ATA_CONTROL, 0);
	outb(base + ATA_COUNT, nblocks);
	outb(base + ATA_SECTOR, sector);
	outb(base + ATA_CYL_LO, clow);
	outb(base + ATA_CYL_HI, chigh);
	outb(base + ATA_FDH, flags);
	outb(base + ATA_COMMAND, command);

	return 1;
}

static int ata_read_unlocked(int id, void *buffer, int nblocks, int offset) {
	int i;
	if(!ata_begin(id,ATA_COMMAND_READ,nblocks,offset)) return 0;
	for(i = 0;i < nblocks; i++) {
		if(!ata_wait(id, ATA_STATUS_DRQ, ATA_STATUS_DRQ)) return 0;
		ata_pio_read(id,buffer, ATA_BLOCKSIZE);
		buffer = ((char*)buffer) + ATA_BLOCKSIZE;
		offset++;
	}
	if(!ata_wait(id, ATA_STATUS_BSY, 0)) return 0;
	return nblocks;
}

int ata_read(int id, void *buffer, int nblocks, int offset) {
	int result;
	result = ata_read_unlocked(id, buffer, nblocks, offset);
	return result;
}

int ata_read_bytes(int id, void *buffer, int nbytes, int offset)
{
	int nblocks=nbytes/drives[id].block_size;
	if(nbytes % drives[id].block_size)
		nblocks++;
	return ata_read(id, buffer, nblocks, offset/drives[id].block_size);
}
static int atapi_begin(int id, void *data, int length) {
	int base = ata_base[id];
	int flags;

	flags = ATA_FLAGS_ECC | ATA_FLAGS_LBA | ATA_FLAGS_SEC;
	if(id%2) flags |= ATA_FLAGS_SLV;
	if(!ata_wait(id, ATA_STATUS_BSY,0)) return 0;
	outb(base+ATA_FDH, flags);

	if(!ata_wait(id, ATA_STATUS_BSY,0)) return 0;

	outb(base+ ATAPI_FEATURE, 0);
	outb(base+ ATAPI_IRR, 0);
	outb(base+ ATAPI_SAMTAG, 0);
	outb(base + ATAPI_COUNT_LO, length & 0xff);
	outb(base + ATAPI_COUNT_HI, length >> 8);
	outb(base + ATA_COMMAND, ATAPI_COMMAND_PACKET);

	if(!ata_wait(id, ATA_STATUS_BSY | ATA_STATUS_DRQ, ATA_STATUS_DRQ)) {}
	ata_pio_write(id, data, length);

	return 1;
}

static int atapi_read_unlocked(int id, void *buffer, int nblocks, int offset) {
	uint8_t packet[12];
	int length = sizeof(packet);
	int i;

	packet[0] = SCSI_READ10;
	packet[1] = 0;
	packet[2] = offset >>24;
	packet[3] = offset >>16;
	packet[4] = offset >>8;
	packet[5] = offset >>0;
	packet[6] = 0;
	packet[7] = nblocks >>8;
	packet[8] = nblocks >>0;
	packet[9] = 0;
	packet[10] = 0;
	packet[11] = 0;

	if(!atapi_begin(id,packet,length)) return 0;

	for(i = 0;i < nblocks; i++) {
		if(!ata_wait(id, ATA_STATUS_DRQ, ATA_STATUS_DRQ)) return 0;
		ata_pio_read(id, buffer, ATAPI_BLOCKSIZE);
		buffer = ((char*)buffer) + ATAPI_BLOCKSIZE;
		offset++;
	}

	return nblocks;
}

int atapi_read(int id, void *buffer, int nblocks, int offset) {

	int result;
	result = atapi_read_unlocked(id, buffer, nblocks, offset);
	return result;
}

static int ata_write_unlocked(int id, const void *buffer, int nblocks, int offset) {
	int i;
	if(!ata_begin(id, ATA_COMMAND_WRITE, nblocks, offset)) return 0;

	for(i = 0; i < nblocks; i++) {
		if(!ata_wait(id, ATA_STATUS_DRQ, ATA_STATUS_DRQ)) return 0;
		ata_pio_write(id, buffer, ATA_BLOCKSIZE);
		buffer = ((char*)buffer) + ATA_BLOCKSIZE;
		offset++;
	}
	if(!ata_wait(id, ATA_STATUS_BSY, 0)) return 0;
	return nblocks;
}

int ata_write(int id, void *buffer, int nblocks, int offset) {
	int result;
	result = ata_write_unlocked(id, buffer, nblocks, offset);
	return result;
}
int ata_write_bytes(int id, void *buffer, int nbytes, int offset)
{
	return ata_write(id, buffer, nbytes*drives[id].block_size, offset);
}
static int ata_identify(int id, int command, void *buffer) {
	if(!ata_begin(id, command, 0, 0)) return 0;
	if(!ata_wait(id, ATA_STATUS_DRQ, ATA_STATUS_DRQ)) return 0;
	ata_pio_read(id, buffer, 512);
	return 1;
}

int ata_probe( int id, int *nblocks, int *blocksize, char *name ) {
	uint16_t buffer[256];
	char *cbuffer = (char*)buffer;

	uint8_t t = inb(ata_base[id] + ATA_STATUS);
	if(t == 0xff) {
		debug_print(NOTICE, "ATA: Nothing attached.");
		drives[id].name="Not attached!";
		drives[id].block_size=0;
		drives[id].size=0;
		drives[id].attached=0;
		return 0;
	}
	ata_reset(id);
	memset(cbuffer,0,512);
	if(ata_identify(id, ATA_COMMAND_IDENTIFY, cbuffer)) {
		*nblocks = buffer[1] * buffer[3] * buffer[6];
		*blocksize = 512;
 	} else if(ata_identify(id, ATAPI_COMMAND_IDENTIFY, cbuffer)) {
		*nblocks = 337920;
		*blocksize = 2048;
	} else {
		debug_print(NOTICE, "ATA: Identity command failed!");
		drives[id].name="Identify command failed! (Maybe nothing attached?)";
		drives[id].block_size=0;
		drives[id].size=0;
		drives[id].attached=0;
		return 0;
	}

	uint32_t i;
	for(i = 0; i < 512; i += 2) {
		t = cbuffer[i];
		cbuffer[i] = cbuffer[i + 1];
		cbuffer[i + 1] = t;
	}

	cbuffer[256]=0;
	strcpy(name, &cbuffer[54]);
	name[40] = 0;
	debug_print(SUCCESS, "ATA: Found connected disk. Printing info to the screen.");
	printf("ATA device #%d: type: %s, size: %f MB, name: %s\n", id, (*blocksize)==512 ? "ATA disk" : "ATAPI CDROM", (float)(*nblocks)*(*blocksize)/1024/1024, name);
	debug_print(NOTICE, "ATA: Writing info to drive list...");
	drives[id].name=name;
	drives[id].block_size=*blocksize;
	drives[id].size=*nblocks * *blocksize;
	return 1;
}

void ata_init() {
	debug_print(INIT, "ATA: Starting ATA initialization. Thanks to GUGDUN!");
	int i;
	int nblocks;
	int blocksizes[4];
	char disk_names[40][4];

	debug_print(INIT, "ATA: Probing devices");

	/*interrupt_register(ATA_IRQ0, ata_interrupt);
	interrupt_enable(ATA_IRQ0);

	interrupt_register(ATA_IRQ1, ata_interrupt);
	interrupt_enable(ATA_IRQ1);*/

	for(i = 0; i < 4; i++) ata_probe(i, &nblocks, &blocksizes[i], disk_names[i]);
	printf("ATA device block sizes:\n\t%u, %u, %u, %u.\n", drives[0].block_size, blocksizes[1], blocksizes[2], blocksizes[3]);
}

Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

catnikita255 wrote:
catnikita255 wrote:Anybody?
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
brunexgeek
Member
Member
Posts: 45
Joined: Wed Dec 25, 2013 11:51 am

Re: Ext2: reading directory entries reads zeros.

Post by brunexgeek »

crunch wrote:I'd suggest you try and test your code on a host machine, with disk images. That's how I got my ext2 code sorted out.
catnikita255 wrote:Anybody?
Did you followed crunch's suggestion? This way you could isolate the ext2 code and check if it's working (and if not, find out what's wrong). Use an image created with dd + mke2fs. A hexadecimal file viewer (hexdump, bless, etc.) could be used to look the image.

And if you have any questions, tell people how you created the image (block size, disk size, etc.) and the values your code read.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

Oops, didn't get what crunch meant. Starting the work.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

On my host OS output is exactly same, so problem isn't in ATA driver but in my code. Also I want to ask: is that

Code: Select all

Filename: '
           $��'
filename means something? I don't know why, but this "magneted" my attention to it.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: Ext2: reading directory entries reads zeros.

Post by osdever »

catnikita255 wrote:
catnikita255 wrote:
catnikita255 wrote:Anybody?
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: Ext2: reading directory entries reads zeros.

Post by Octocontrabass »

You aren't getting any replies because (as far as we can tell) you haven't tried to debug your code.

Since you're testing your ext2 driver on disk images under a fully-functional OS, you can easily do some printf() debugging. Print out intermediate values, compare them against what you should see according to the ext2 specifications, and find where your code stops matching your expectations.
User avatar
crunch
Member
Member
Posts: 81
Joined: Wed Aug 31, 2016 9:53 pm
Libera.chat IRC: crunch
Location: San Diego, CA

Re: Ext2: reading directory entries reads zeros.

Post by crunch »

Octocontrabass wrote:You aren't getting any replies because (as far as we can tell) you haven't tried to debug your code.

Since you're testing your ext2 driver on disk images under a fully-functional OS, you can easily do some printf() debugging. Print out intermediate values, compare them against what you should see according to the ext2 specifications, and find where your code stops matching your expectations.
Yep. Quite frankly, I don't have the time to work on my own projects as much as I'd like, let alone read through and debug hundreds of lines of someone else's code. There are lots of great resources for ext2 out there, and I have provided links to my own code as well.
ch3ll0v3k
Posts: 10
Joined: Sat Oct 01, 2016 1:26 am

Re: Ext2: reading directory entries reads zeros.

Post by ch3ll0v3k »

I have also strange extra characters at the end of each "file_name". can"t figure out what can it be.
#-o

on the second screenshot it is better visible
It must be:

Code: Select all

/.
/ ..
/.Trash-1000
/bin
/.Trash-0
/usr
/src
/boot
/os.iso
/root_dir_12
/root_dir_11
/root_dir_13
/lib
/var
/etc
/dev
/tmp
/run
/root_dir_15
/root_dir_14
Attachments
directory_list_bug_2.png
directory_list_bug_2.png (9.88 KiB) Viewed 2604 times
directory_list_bug.png
Post Reply