Page 1 of 2

Next Filesystem to Implement

Posted: Fri Feb 02, 2007 11:56 am
by frank
I was wondering which filesystem I should implement after FAT 12/16/32. I'm looking for something that is easy and a good step up from FAT.

Posted: Fri Feb 02, 2007 12:06 pm
by Tyler
Preferably one you already know quite well and won't have to research in such detail. Especially if you have experience with it. If not i would probably pick whatever the default is in Linux atm. Somethign like Ext2fs which is well documented will be best.

Posted: Sun Feb 04, 2007 9:14 pm
by Mike
Ext2 looks pretty simple. Although I have not implemented it myself, I have looked at the spec.

Plus then you will have a nice balance of the Windows and Linux worlds. :)

Posted: Mon Feb 05, 2007 3:39 pm
by frank
Does any one know of a good way to create and access EXT2 filesystems from withing Windows XP?

Posted: Mon Feb 05, 2007 5:26 pm
by Brynet-Inc
frank wrote:Does any one know of a good way to create and access EXT2 filesystems from withing Windows XP?
A Google search showed a few results, This one is the most notable.. Looks like it's still fairly maintained...

It's under the GPL licence, Supports both read/write operations.

http://www.ext2fsd.com/

One can always just use a UNIX-like system full time though :wink:

Posted: Tue Feb 06, 2007 12:18 pm
by frank
Thanks
Brynet-Inc wrote:One can always just use a UNIX-like system full time though :wink:
I would if I could, but I don't have high speed internet, so I can't download it, and I have yet to find a UNIX-like system that works well with my WIN modem. Plus I have no money. :wink:

Re: Next Filesystem to Implement

Posted: Tue Feb 06, 2007 3:22 pm
by Brendan
Hi,
frank wrote:I was wondering which filesystem I should implement after FAT 12/16/32. I'm looking for something that is easy and a good step up from FAT.
I'd probably try to implement ISO9660 (CD-ROM) - mostly because I refuse to implement file system code that may be used to break the security (file system permissions, etc) of other OSs....


Cheers,

Brendan

Re: Next Filesystem to Implement

Posted: Tue Feb 06, 2007 3:59 pm
by frank
I'd probably try to implement ISO9660 (CD-ROM)
Thanks, I was looking into that one two.

Posted: Wed Feb 07, 2007 10:23 am
by Dex
Or you could implement a basic NTFS.

Posted: Wed Feb 07, 2007 12:33 pm
by Brynet-Inc
Dex wrote:Or you could implement a basic NTFS.
Now that wouldn't be productive or useful.. or in any way fun.. now would it ;)

Posted: Wed Feb 07, 2007 2:20 pm
by Alboin
frank wrote:Thanks
Brynet-Inc wrote:One can always just use a UNIX-like system full time though :wink:
I would if I could, but I don't have high speed internet, so I can't download it, and I have yet to find a UNIX-like system that works well with my WIN modem. Plus I have no money. :wink:
Aye, a WinModem isn't compatible with any Linux\Unix\BSD\SkyOS I know of. I had one, and when I installed Linux it was my first problem. I found that I had to buy a US Robotics Modem, which work quite nicely.

For an easy file system: Why not Minix? I'm sure it's well documented. :)

Posted: Wed Feb 07, 2007 5:30 pm
by Brynet-Inc
One of the main reasons that winmodems don't work on these systems is the actual cards are blank slate.

There firmware is usually located in a closed source binary driver, Targeting Windows normally :P..

Also, Not many of these winmodems are in any way identical, so making a driver that supporting them all is... improbable.

Still, The Linux community has lower standards against binary blobs, There are a few closed source winmodem drivers.

http://linmodems.org/
http://www.google.ca/search?hl=en&safe= ... arch&meta=

Few links above, but again.. Anyone who supports such vendor lock-in is really pathetic.

As Alboin said, Quite a few older (ISA usually) cards work perfectly.. (Normally appearing simply as communications ports, /dev/cua01 would be COM2 OpenBSD as an example..)

For the subject at hand anyway, frank.. You could possibly add support for OpenBSD's Berkeley FFS implementation, Or FreeBSD's UFS2 or w/e.

...Not sure why anyone would implement Minix's file system Alboin :?

Posted: Wed Feb 07, 2007 5:30 pm
by Dex
Brynet-Inc wrote:
Dex wrote:Or you could implement a basic NTFS.
Now that wouldn't be productive or useful.. or in any way fun.. now would it ;)
This code will find and load a file from a ntfs partion, Sorry its not in C ;).
Here is "mtrdr.asm"

Code: Select all

; KolibriOS bootloader
; this code has been written by diamond in 2005 specially for KolibriOS

; this code is loaded by ntldr to 0D00:0000
; and by io.sys from config.sys to xxxx:0100
	format	binary
	use16

	org	0xD000
; entry point for 9x booting
	jmp	@f
	db	'd' xor 'i' xor 'a' xor 'm' xor 'o' xor 'n' xor 'd'
	db	'NTFS'
@@:
	mov	si, load_question + 100h - 0D000h
	call	out_string
;	mov	si, answer + 100h - 0D000h	; already is
xxy:	mov	ah, 0
	int	16h
	or	al, 20h
	mov	[si], al
	cmp	al, 'y'
	jz	xxz
	cmp	al, 'n'
	jnz	xxy
; continue load Windows
;       call    out_string
;       ret
out_string:
	lodsb
	test	al, al
	jz	.xxx
	mov	ah, 0Eh
	mov	bx, 7
	int	10h
	jmp	out_string
.xxx:	ret
xxz:
; boot KolibriOS
	call	out_string
	push	0
	pop	ds
	mov	word [4], new01handler + 100h - 0D000h
	mov	[6], cs
	pushf
	pop	ax
	or	ah, 1
	push	ax
	popf
;	int	19h
;	pushf		; there will be no iret
	call	far [19h*4]
xxt:
; TF has been cleared when entered new01handler
;	pushf
;	pop	ax
;	and	ah, not 1
;	push	ax
;	popf
	xor	di, di
	mov	ds, di
	cmp	word [8*4+2], 0F000h
	jz	@f
	les	bx, [8*4]
	mov	eax, [es:bx+1]
	mov	[8*4], eax
@@:
	mov	eax, [8*4]
	mov	[20h*4], eax
	mov	si, 100h
	push	cs
	pop	ds
	push	0D00h
	pop	es
	mov	cx, 2000h/2
	rep	movsw
	jmp	0D00h:0256h
load_question	db	'Load KolibriOS? [y/n]: ',0
answer	db	?
	db	13,10,0

new01handler:
; [sp]=ip, [sp+2]=cs, [sp+4]=flags
	push	bp
	mov	bp, sp
	push	bx
	push	ds
	lds	bx, [bp+2]
	cmp	word [bx], 19cdh
	jz	xxt
	pop	ds
	pop	bx
	pop	bp
	iret

relative_read:
	add	eax, [partition_start]

; read from hard disk
; drive_size must be already initialized
; in: eax = absolute sector
;     cx = number of sectors
;     es:bx -> buffer
read:
	pushad
	cmp	eax, [drive_size]
	jb	.old_style
; new style - LBA, function 42
	cmp	[has_lba], 0
	jz	disk_error
; allocate disk address packet on the stack
; qword +8: absolute block number
	push	dword 0 	; dword +C is high dword
	push	eax		; dword +8 is low dword
; dword +4: buffer address
	push	es		; word +6 is segment
	push	bx		; word +4 is offset
; word +2: number of blocks = 1
; word +0: size of packet = 10h
	push	dword 10010h
; now pair ss:sp contain address of disk address packet
.patch1:
	mov	ax, 4200h
	mov	dl, [boot_drive]
	mov	si, sp
	push	ds
	push	ss
	pop	ds
	int	13h
	pop	ds
	add	sp, 10h
.end:
	popad
	jc	disk_error
	add	bx, 200h
	inc	eax
	dec	cx
	jnz	read
	ret
.old_style:
; old style - CHS, function 2
; convert absolute sector in eax to cylinder-head-sector coordinates
; calculate sector
	xor	edx, edx
	movzx	ecx, [sectors]
	div	ecx
; sectors are counted from 1
	inc	dl
	mov	cl, dl		; low 6 bits of cl = sector number
; calculate head number
	shld	edx, eax, 10h	; convert eax to dx:ax
	div	[heads]
	mov	dh, dl		; dh = head
	mov	ch, al		; ch = low 8 bits of cylinder
	shl	ah, 6
	or	cl, ah		; high 2 bits of cl = high 2 bits of cylinder
.patch2:
	mov	ax, 201h	; function 2, al=1 - number of sectors
	mov	dl, [boot_drive]
	int	13h
	jmp	.end

disk_error:
	mov	si, disk_error_msg
	call	out_string
	jmp	$

has_lba db	0

disk_error_msg	db	'Disk read error!',0
start_msg	db	2,' KolibriOS bootloader, running on ',0
errfs_msg	db	'unknown filesystem, cannot continue',0
fat16_msg	db	'FAT12/FAT16 - unsupported',13,10,0
fat32_msg	db	'FAT32',13,10,0
ntfs_msg	db	'NTFS',13,10,0
error_msg	db	'Error'
colon		db	': ',0
mft_string	db	'MFT',0
root_string	db	'\',0
nodata_string	db	'$DATA not found',0
noindex_string	db	'$INDEX_ROOT not found',0
invalid_read_request_string db 'cannot read attribute',0
notfound_string db	'not found',0
directory_string db	'is a directory',0
fragmented_string db	'too fragmented file',0
exmem_string	db	'extended memory error',0
bad_cluster_string db	'bad cluster',0

; init procedure - ntldr jmps here
	repeat	0D256h - $
		db	1
	end	repeat
start:
; cs=es=0D00, ds=07C0, ss=0
; esi=edi=ebp=0, esp=7C00
	xor	ax, ax
	mov	ds, ax
	mov	es, ax
; our stack is 4Kb-2b!!! (0xFFE)
	mov	ss, ax
	mov	esp, 0FFFEh

; we are booting from first hard disk
	mov	dl, 80h
	mov	[boot_drive], dl
	cld
	sti
; calculate drive size
	mov	ah, 8	; 8 = get drive parameters
	int	13h
; now: CF is set on error;
; ch = low 8 bits of maximum cylinder number
; cl : low 6 bits makes maximum sector number, high 2 bits are high 2 bits of maximum cylinder number
; dh = maximum head number
	jnc	@f
	mov	cx, -1
	mov	dh, cl
@@:
	movzx	ax, dh
	inc	ax
; ax = number of heads
	mov	[heads], ax
	mov	dl, cl
	and	dx, 3Fh
; dx = number of sectors
; (note that sectors are counted from 1, and maximum sector number = number of sectors)
	mov	[sectors], dx
	mul	dx
	xchg	cl, ch
	shr	ch, 6
	inc	cx
; cx = number of cylinders
	mov	[cyls], cx
	mul	cx
	mov	word [drive_size], ax
	mov	word [drive_size+2], dx
; this drive supports LBA?
	mov	dl, [boot_drive]
	mov	ah, 41h
	mov	bx, 55AAh
	int	13h
	jc	.no_lba
	cmp	bx, 0AA55h
	jnz	.no_lba
	test	cl, 1
	jz	.no_lba
	inc	[has_lba]
.no_lba:
; say hi to user
	mov	si, start_msg
	call	out_string
; now read first sector to determine file system type
; first sector of disk is MBR sector
	xor	eax, eax
	mov	cx, 1
	mov	bx, 500h
	call	read
	mov	eax, [6C6h]	; first disk
	mov	[partition_start], eax
	mov	cx, 1
	mov	bx, 500h
	call	read
	movzx	ax, byte [50Dh]
	mov	[sect_per_clust], ax
; determine file system
	cmp	dword [536h], 'FAT1'
	jz	fat1x
	cmp	dword [552h], 'FAT3'
	jz	fat32
	cmp	dword [503h], 'NTFS'
	jz	ntfs
;       mov     si, errfs_msg           ; already is
	call	out_string
	jmp	$
fat1x:
	mov	si, fat16_msg
	call	out_string
	jmp	$
fat32:
	mov	si, fat32_msg
	call	out_string
	movzx	eax, word [50Bh]	; bytes_per_sect
	movzx	ebx, byte [50Dh]	; sects_per_clust
	mul	ebx
	mov	[cluster_size], eax
	movzx	ebx, word [50Eh]	; reserved_sect
	add	ebx, [51Ch]		; hidden
	mov	[fat_start], ebx
	movzx	eax, byte [510h]	; num_fats
	mul	dword [524h]		; sect_fat
	add	eax, ebx
; cluster 2 begins from sector eax
	movzx	ebx, byte [50Dh]	; sects_per_clust
	sub	eax, ebx
	sub	eax, ebx
	sub	eax, [51Ch]	; we will use relative_read
	mov	[data_start], eax
	mov	eax, [52Ch]		; root_cluster
	push	menuet_img_name
	mov	[cur_obj], root_string
	call	fat32_parse_dir
; parse FAT chunk
; runlist at 2000:0000
	mov	di, 5
	push	2000h
	pop	es
	mov	byte [es:di-5], 1	; of course, non-resident
	mov	dword [es:di-4], 1
	stosd
.parsefat:
	push	es
	push	ds
	pop	es
	call	next_cluster
	pop	es
	jnc	.done
	mov	ecx, [es:di-8]
	add	ecx, [es:di-4]
	cmp	eax, ecx
	jz	.contc
	mov	dword [es:di], 1
	add	di, 4
	stosd
	jmp	.parsefat
.contc:
	inc	dword [es:di-8]
	jmp	.parsefat
.done:
	xor	eax, eax
	stosd
	jmp	read_img_file

ntfs:
	mov	si, ntfs_msg
	call	out_string
	movzx	eax, word [50Bh]	; bpb_bytes_per_sect
	push	eax
	movzx	ebx, byte [50Dh]	; bpb_sects_per_clust
	mul	ebx
	mov	[cluster_size], eax
	mov	[data_start], 0
	mov	ecx, [540h]		; frs_size
	cmp	cl, 0
	jg	.1
	neg	cl
	xor	eax, eax
	inc	eax
	shl	eax, cl
	jmp	.2
.1:
	mul	ecx
.2:
	mov	[frs_size], eax
	pop	ebx
	xor	edx, edx
	div	ebx
	mov	[frs_sectors], ax
; read first MFT record - description of MFT itself
	mov	[cur_obj], mft_string
	movzx	eax, byte [50Dh]	; bpb_sects_per_clust
	mul	dword [530h]		; mft_cluster
	mov	cx, [frs_sectors]
	mov	bx, 4000h
	mov	di, bx
	push	bx
	call	relative_read
	call	restore_usa
; scan for unnamed $DATA attribute
	pop	di
	mov	ax, 80h		; $DATA
	mov	bx, 700h
	call	load_attr
	mov	si, nodata_string
	jc	find_error_si
	mov	[free], bx
; load menuet.img
; find entry
	mov	eax, 5
	push	menuet_img_name
	mov	[cur_obj], root_string
	call	ntfs_parse_dir
read_img_file:
	xor	si, si
	push	es
	pop	fs
; yes! Now read file to 0x100000
	lods byte [fs:si]
	cmp	al, 0	; assume nonresident attr
	mov	si, invalid_read_request_string
	jz	find_error_si
	mov	si, 1
	xor	edi, edi
; read buffer to 1000:0000 and move it to extended memory
	push	1000h
	pop	es
	xor	bx, bx
.img_read_block:
	lods dword [fs:si]		; eax=length
	xchg	eax, ecx
	jecxz	.img_read_done
	lods dword [fs:si]		; eax=disk cluster
.img_read_cluster:
	pushad
; read part of file
	movzx	ecx, byte [50Dh]
	mul	ecx
	add	eax, [data_start]
	call	relative_read
; move it to extended memory
	mov	ah, 87h
	mov	ecx, [cluster_size]
	push	ecx
	shr	cx, 1
	mov	si, movedesc
	push	es
	push	ds
	pop	es
	int	15h
	pop	es
	cmp	ah, 0
	mov	si, exmem_string
	jnz	find_error_si
	pop	ecx
	add	[dest_addr], ecx
	popad
	inc	eax
	loop	.img_read_cluster
	jmp	.img_read_block
.img_read_done:
; menuet.img loaded; now load kernel.mnt
load_kernel:
	push	ds
	pop	es
	mov	[cur_obj], kernel_mnt_name
; read boot sector
	xor	eax, eax
	mov	bx, 500h
	mov	cx, 1
	call	read_img
; init vars
	mov	ax, [50Eh]	; reserved_sect
	add	ax, [51Ch]	; hidden
	mov	word [fat_start], ax
	xchg	ax, bx
	movzx	ax, byte [510h]		; num_fats
	mul	word [516h]		; fat_length
	add	ax, bx
; read root dir
	mov	bx, 700h
	mov	cx, [511h]	; dir_entries
	add	cx, 0Fh
	shr	cx, 4
	call	read_img
	add	ax, cx
	mov	[img_data_start], ax
	shl	cx, 9
	mov	di, bx
	add	bx, cx
	mov	byte [bx], 0
.scan_loop:
	cmp	byte [di], 0
	mov	si, notfound_string
	jz	find_error_si
	mov	si, kernel_mnt_name
	call	fat_compare_name
	jz	.found
	and	di, not 1Fh
	add	di, 20h
	jmp	.scan_loop
.found:
	and	di, not 1Fh
	mov	si, directory_string
	test	byte [di+0Bh], 10h
	jnz	find_error_si
; found, now load it to 1000h:0000h
	mov	ax, [di+1Ah]
; first cluster of kernel.mnt in ax
; translate it to sector on disk in menuet.img
	push	ax
	dec	ax
	dec	ax
	movzx	cx, byte [50Dh]
	mul	cx
	add	ax, [img_data_start]
; now ax is sector in menuet.img
	mov	[kernel_mnt_in_img], ax
	div	[sect_per_clust]
; now ax is cluster in menuet.img and
; dx is offset from the beginning of cluster
	movzx	eax, ax
	push	2000h
	pop	ds
	mov	si, 1
.scani:
	sub	eax, [si]
	jb	.scanidone
; sanity check
	cmp	dword [si], 0
	push	invalid_read_request_string
	jz	find_error_sp
	pop	cx
; next chunk
	add	si, 8
	jmp	.scani
.scanidone:
	add	eax, [si]	; undo last subtract
	add	eax, [si+4]	; get cluster
	push	0
	pop	ds
	movzx	ecx, [sect_per_clust]
	push	dx
	mul	ecx		; get sector
	pop	dx
	movzx	edx, dx
	add	eax, edx
	add	eax, [data_start]
	mov	[kernel_mnt_1st], eax
	pop	ax
	push	1000h
	pop	es
.read_loop:
	push	ax
	xor	bx, bx
	call	img_read_cluster
	shl	cx, 9-4
	mov	ax, es
	add	ax, cx
	mov	es, ax
	pop	ax
	call	img_next_cluster
	jc	.read_loop
	mov	eax, 'KLBR'
	mov	si, loader_block
	jmp	1000h:0000h

img_next_cluster:
	mov	bx, 700h
	push	ax
	shr	ax, 1
	add	ax, [esp]
	mov	dx, ax
	shr	ax, 9
	add	ax, word [fat_start]
	mov	cx, 2
	push	es
	push	ds
	pop	es
	call	read_img
	pop	es
	and	dx, 1FFh
	add	bx, dx
	mov	ax, [bx]
	pop	cx
	test	cx, 1
	jz	.1
	shr	ax, 4
.1:
	and	ax, 0FFFh
	mov	si, bad_cluster_string
	cmp	ax, 0FF7h
	jz	find_error_si
	ret
img_read_cluster:
	dec	ax
	dec	ax
	movzx	cx, byte [50Dh]	; sects_per_clust
	mul	cx
	add	ax, [img_data_start]
	movzx	eax, ax
;	call	read_img
;	ret
read_img:
; in: ax = sector, es:bx->buffer, cx=length in sectors
	pushad
	movzx	ebx, bx
	mov	si, movedesc
	shl	eax, 9
	add	eax, 93100000h
	mov	dword [si+sou_addr-movedesc], eax
	mov	eax, 9300000h
	mov	ax, es
	shl	eax, 4
	add	eax, ebx
	mov	[si+dest_addr-movedesc], eax
	mov	ah, 87h
	shl	cx, 8	; mul 200h/2
	push	es
	push	0
	pop	es
	int	15h
	pop	es
	cmp	ah, 0
	mov	si, exmem_string
	jnz	find_error_si
	popad
	ret

movedesc:
	times 16 db 0
; source
	dw	0xFFFF		; segment length
sou_addr dw	0000h		; linear address
	db	1		; linear address
	db	93h		; access rights
	dw	0
; destination
	dw	0xFFFF		; segment length
dest_addr dd	93100000h	; high byte contains access rights
				; three low bytes contains linear address (updated when reading)
	dw	0
	times 32 db 0

find_error_si:
	push	si
find_error_sp:
	mov	si, error_msg
	call	out_string
	mov	si, [cur_obj]
	call	out_string
	mov	si, colon
	call	out_string
	pop	si
	call	out_string
	jmp	$

file_not_found:
	mov	si, [esp+2]
	mov	[cur_obj], si
	push	notfound_string
	jmp	find_error_sp

	include 'fat32.inc'
	include	'ntfs.inc'

write1st:
; callback from kernel.mnt
; write first sector of kernel.mnt from 1000:0000 back to disk
	push	cs
	pop	ds
	push	cs
	pop	es
; sanity check
	mov	bx, 500h
	mov	si, bx
	mov	cx, 1
	push	cx
	mov	eax, [kernel_mnt_1st]
	push	eax
	call	relative_read
	push	1000h
	pop	es
	xor	di, di
	mov	cx, 8
	repz	cmpsw
	mov	si, data_error_msg
	jnz	find_error_si
; ok, now write back to disk
	or	byte [read.patch1+2], 1
	or	byte [read.patch2+2], 1
	xor	bx, bx
	pop	eax
	pop	cx
	call	relative_read
	and	byte [read.patch1+1], not 1
	and	byte [read.patch2+2], not 2
; and to image in memory (probably this may be done by kernel.mnt itself?)
	mov	dword [sou_addr], 93010000h
	movzx	eax, [kernel_mnt_in_img]
	shl	eax, 9
	add	eax, 93100000h
	mov	dword [dest_addr], eax
	mov	si, movedesc
	push	ds
	pop	es
	mov	ah, 87h
	mov	cx, 100h
	int	15h
	cmp	ah, 0
	mov	si, exmem_string
	jnz	find_error_si
	retf
data_error_msg db 'data error',0

loader_block:
	db	1	; version
	dw	1	; flags - image is loaded
	dw	write1st	; offset
	dw	0		; segment

fat_cur_sector dd -1

; -----------------------------------------------
; ------------------ Settings -------------------
; -----------------------------------------------

; must be in lowercase, see ntfs_parse_dir.scan, fat32_parse_dir.scan
kernel_mnt_name 	db	'kernel.mnt',0
menuet_img_name 	db	'menuet.img',0

; uninitialized data follows
drive_size		dd	?	; in sectors
boot_drive		db	?
heads			dw	?
sectors 		dw	?
cyls			dw	?
partition_start 	dd	?
free			dw	?
cur_obj 		dw	?
data_start		dd	?
img_data_start		dw	?
sect_per_clust		dw	?
kernel_mnt_in_img	dw	?
kernel_mnt_1st		dd	?
; NTFS data
cluster_size		dd	?	; in bytes
frs_size		dd	?	; in bytes
frs_sectors		dw	?	; in sectors
mft_data_attr		dw	?
index_root		dw	?
index_alloc		dw	?
ofs			dw	?
dir			dw	?
; FAT32 data
fat_start		dd	?
cur_cluster		dd	?
; file must be 16 sectors long

	repeat	0F000h - $
		db	2
	end	repeat
Here is "ntfs.inc"

Code: Select all

restore_usa:
; Update Sequence Array restore
	mov	bx, [di+4]
	mov	cx, [di+6]
	inc	bx
	add	bx, di
	inc	bx
	add	di, 1feh
	dec	cx
@@:
	mov	ax, [bx]
	stosw
	inc	bx
	inc	bx
	add	di, 1feh
	loop	@b
	ret

find_attr:
; in: di->file record, ax=attribute
; out: di->attribute or di=0 if not found
	add	di, [di+14h]
.1:
; attributes codes are formally dwords, but all they fit in word
	cmp	word [di], -1
	jz	.notfound
	cmp	word [di], ax
	jnz	.continue
; for $DATA attribute, scan only unnamed
	cmp	ax, 80h
	jnz	.found
	cmp	byte [di+9], 0
	jz	.found
.continue:
	add	di, [di+4]
	jmp	.1
.notfound:
	xor	di, di
.found:
	ret

process_mcb_nonres:
; in: si->attribute, es:di->buffer
; out: di->buffer end
	add	si, [si+20h]
	xor	ebx, ebx
.loop:
	lodsb
	test	al, al
	jz	.done
	push	invalid_read_request_string
	movzx	cx, al
	shr	cx, 4
	jz	find_error_sp
	xchg	ax, dx
	and	dx, 0Fh
	jz	find_error_sp
	add	si, cx
	add	si, dx
	pop	ax
	push	si
	dec	si
	movsx	eax, byte [si]
	dec	cx
	jz	.l1e
.l1:
	dec	si
	shl	eax, 8
	mov	al, [si]
	loop	.l1
.l1e:
	xchg	ebp, eax
	dec	si
	movsx	eax, byte [si]
	mov	cx, dx
	dec	cx
	jz	.l2e
.l2:
	dec	si
	shl	eax, 8
	mov	al, byte [si]
	loop	.l2
.l2e:
	pop	si
	add	ebx, ebp
; eax=length, ebx=disk block
	stosd
	mov	eax, ebx
	stosd
	jmp	.loop
.done:
	xor	eax, eax
	stosd
	ret

load_attr:
; in: ax=attribute, es:bx->buffer, di->base record
; out: bx->buffer end; CF set if not found
	push	di
	push	ax
	mov	byte [es:bx], 1
	inc	bx
	push	bx
	mov	[ofs], bx
; scan for attrubute
	add	di, [di+14h]
@@:
	call	find_attr.1
	test	di, di
	jz	.notfound1
	cmp	byte [di+8], 0
	jnz	.nonresident
; resident attribute
	mov	si, di
	pop	di
	dec	di
	mov	al, 0
	stosb
	mov	ax, [si+10h]
	stosw
	xchg	ax, cx
	add	si, [si+14h]
	rep	movsb
	mov	bx, di
	pop	ax
	pop	di
	ret
.nonresident:
; nonresident attribute
	cmp	dword [di+10h], 0
	jnz	@b
; read start of data
	mov	si, di
	pop	di
	call	process_mcb_nonres
	push	di
.notfound1:
; $ATTRIBUTE_LIST is always in base file record
	cmp	word [esp+2], 20h
	jz	.nofragmented
; scan for $ATTRIBUTE_LIST = 20h
	mov	di, [esp+4]
	mov	ax, 20h
	call	find_attr
	test	di, di
	jz	.nofragmented
; load $ATTRIBUTE_LIST itself
	push	es
	mov	bx, 0C000h
	mov	di, [esp+4]
	push	bx
	push	[ofs]
	push	ds
	pop	es
	call	load_attr
	pop	[ofs]
	pop	si
	mov	bx, 8000h
	push	bx
	push	si
	call	read_attr_full
	pop	si
	pop	bx
	add	dx, bx
	mov	ax, [esp+2]
	pop	es
.1:
	cmp	[bx], ax
	jnz	.continue1
; only unnamed $DATA attributes!
	cmp	ax, 80h
	jnz	@f
	cmp	byte [bx+6], 0
	jnz	.continue1
@@:
	cmp	dword [bx+10h], 0
	jz	.continue1
	cmp	dword [bx+8], 0
	jnz	@f
	push	ax
	mov	ax, [esp+2]
	cmp	ax, [ofs]
	pop	ax
	jnz	.continue1
@@:
	pushad
	mov	eax, [bx+10h]
	mov	bx, dx
	push	[ofs]
	push	es
	push	ds
	pop	es
	call	read_file_record
	pop	es
	pop	[ofs]
	popad
	pushad
	mov	di, dx
	add	di, [di+14h]
.2:
	call	find_attr.1
	mov	eax, [bx+8]
	cmp	eax, [di+10h]
	jnz	.2
	mov	si, di
	mov	di, [esp+20h]
	sub	di, 4
	call	process_mcb_nonres
	mov	[esp+20h], di
	popad
.continue1:
	add	bx, [bx+4]
	cmp	bx, dx
	jb	.1
.nofragmented:
	pop	bx
	pop	ax
	pop	di
	cmp	bx, [ofs]
	jnz	@f
	dec	bx
	stc
@@:
	ret

read_attr_full:
; in: si->decoded attribute data, bx->buffer
; out: edx=length in bytes
	lodsb
	cmp	al, 0
	jnz	.nonresident
; resident
	lodsw
	movzx	edx, ax
	xchg	ax, cx
	mov	di, bx
	rep	movsb
	ret
.nonresident:
; nonresident :-)
	xor	edx, edx
.loop:
	lodsd
	xchg	ecx, eax
	jecxz	.loopend
	lodsd
	xchg	edi, eax
; read ecx clusters from cluster edi to es:bx
.intloop:
	push	ecx
; read 1 cluster from physical cluster edi to es:bx
	mov	ecx, [cluster_size]
	mov	eax, edi
	mul	ecx
	push	bx
	call	relative_read
	pop	bx
	pop	ecx
	inc	edi
	mov	eax, [cluster_size]
	add	edx, eax
	shr	eax, 4
	mov	bp, es
	add	bp, ax
	mov	es, bp
	loop	.intloop
	jmp	.loop
.loopend:
	mov	es, cx
	ret

read_file_record:
; in: eax=index of record, bx=buffer
	mov	si, 700h
	mov	ecx, [frs_size]
	mul	ecx
	push	bx
	push	[cur_obj]
	mov	[cur_obj], mft_string
	call	read_attr
	pop	[cur_obj]
	pop	di
	call	restore_usa
	ret
read_attr:
; in: edx:eax=offset in bytes, ecx=size in bytes, bx=buffer, si=attribute
	push	invalid_read_request_string
	cmp	byte [si], 0
	jnz	.nonresident
	test	edx, edx
	jnz	find_error_sp
	cmp	eax, 10000h
	jae	find_error_sp
	cmp	ecx, 10000h
	jae	find_error_sp
	cmp	ax, [si+2]
	jae	find_error_sp
	cmp	cx, [si+2]
	ja	find_error_sp
	add	si, 3
	add	si, ax
	mov	di, bx
	rep	movsb
	pop	ax
	ret
.nonresident:
	mov	edi, [cluster_size]
	div	edi
	mov	[ofs], dx
	add	cx, dx
	push	eax
	xchg	eax, ecx
	xor	edx, edx
	dec	eax
	div	edi
	inc	eax
	xchg	eax, ecx
	pop	eax
	add	si, 1
	xor	edx, edx
	push	bx
; eax=offset in clusters, ecx=size in clusters
.scan:
	mov	ebx, [si]
	test	ebx, ebx
	jz	.notfound
	add	edx, ebx
	add	si, 8
	cmp	eax, edx
	jae	.scan
	mov	edi, [si-4]
; now edx=end of block, ebx=length of block, edi=start of block on disk
; eax=required offset, ecx=required length
	push	edx
	push	edi
	sub	edx, eax
	add	edi, ebx
	sub	edi, edx
	cmp	edx, ecx
	jb	@f
	mov	edx, ecx
@@:
; read (edx) clusters from (edi=disk offset in clusters) to ([esp+8])
	cmp	[ofs], 0
	jnz	.ofs_read
.cont:
	pushad
	movzx	ebx, byte [50Dh]
;       xchg    eax, edx
;       mul     ebx
	xchg	ax, dx
	mul	bx
	xchg	cx, ax
	xchg	eax, edi
	mul	ebx
	mov	bx, [esp+8+20h]
	call	relative_read
	mov	[esp+8+20h], bx
	popad
.cont2:
	add	eax, edx
	sub	ecx, edx
.cont3:
	pop	edi
	pop	edx
	jnz	.scan
	pop	bx
	pop	ax
	ret
.ofs_read:
	push	ecx
	movzx	ecx, byte [50Dh]	; bpb_sects_per_clust
	mov	eax, edi
	push	edx
	mul	ecx
	push	1000h
	pop	es
	xor	bx, bx
	call	relative_read
	mov	cx, bx
	push	si
	push	di
	mov	si, [ofs]
	mov	di, [esp+8+12]
	sub	cx, si
	push	ds
	push	es
	pop	ds
	pop	es
	rep	movsb
	mov	[esp+8+12], di
	push	es
	pop	ds
	pop	di
	pop	si
	pop	edx
	pop	ecx
	inc	edi
	mov	[ofs], 0
	inc	eax
	dec	ecx
	jz	.cont3
	dec	edx
	jnz	.cont
	jmp	.cont2
.notfound:
	mov	si, invalid_read_request_string
	jmp	find_error_si

ntfs_parse_dir:
; in: eax=directory iRecord, [word sp+2]=filename
; out: si=$DATA attribute of file
	mov	bx, [free]
	mov	[dir], bx
	push	bx
	call	read_file_record
	mov	ax, word [frs_size]
	add	[free], ax
	pop	di
; find attributes $INDEX_ROOT, $INDEX_ALLOCATION, $BITMAP
	mov	ax, 90h 	; $INDEX_ROOT
	push	di
	mov	bx, [free]
	mov	[index_root], bx
	call	load_attr
	mov	si, noindex_string
	jc	find_error_si
	mov	[free], bx
	pop	di
	mov	ax, 0A0h	; $INDEX_ALLOCATION
	mov	bx, [free]
	mov	[index_alloc], bx
	call	load_attr
	jnc	@f
	mov	[index_alloc], 0
@@:
	mov	[free], bx
; search for entry
	mov	si, [index_root]
	mov	bx, [free]
	call	read_attr_full
	mov	ebp, [bx+8]	; subnode_size
	add	bx, 10h
.scan_record:
	add	bx, [bx]
.scan:
	test	byte [bx+0Ch], 2
	jnz	.not_found
	mov	si, [esp+2]
	movzx	cx, byte [bx+50h]	; namelen
	lea	di, [bx+52h]		; name
	xor	ax, ax
@@:
	lodsb
	cmp	al, 'a'
	jb	.notletter
	cmp	al, 'z'
	ja	.notletter
	or	byte [di], 20h
.notletter:
	scasw
	loopz	@b
	jz	.file_found
	jb	.not_found
	add	bx, [bx+8]
	jmp	.scan
.not_found:
	test	byte [bx+0Ch], 1
	jz	file_not_found
	cmp	[index_alloc], 0
	jz	file_not_found
	add	bx, [bx+8]
	mov	eax, [bx-8]
	mul	[cluster_size]
	mov	si, [index_alloc]
	mov	ecx, ebp
	mov	bx, [free]
	call	read_attr
	mov	di, [free]
	call	restore_usa
	mov	bx, [free]
	add	bx, 18h
	jmp	.scan_record
.file_found:
	mov	si, [esp+2]
	mov	[cur_obj], si
	mov	si, directory_string
	test	byte [bx+48h+3], 10h	; directory?
	jnz	find_error_si
; read entry
	mov	eax, [bx]
	mov	bx, [dir]
	mov	[free], bx
	mov	bx, 4000h
	push	bx
	call	read_file_record
	pop	di
	mov	ax, 80h
	push	2000h
	pop	es
	xor	bx, bx
	call	load_attr
	mov	si, nodata_string
	jz	find_error_si
	mov	[free], bx
	ret	2
Here is fat.inc

Code: Select all

fat32_parse_dir:
; in: eax=directory cluster
; out: eax=entry cluster
	mov	bx, 900h
	mov	di, bx
	push	eax
	call	read_cluster
	mov	cx, word [cluster_size]
	shr	cx, 5		; div 20h
.scan_cluster:
	pop	eax
	cmp	byte [di], 0
	jz	file_not_found
	mov	si, [esp+2]
	push	eax
	call	fat_compare_name
	jz	.file_found
	and	di, not 1Fh
	add	di, 20h
	loop	.scan_cluster
	pop	eax
	call	next_cluster
	jnc	file_not_found
	jc	fat32_parse_dir
.file_found:
	pop	eax
	mov	si, [esp+2]
	mov	[cur_obj], si
	and	di, not 1Fh
	mov	si, directory_string
	test	byte [di+0Bh], 10h
	jnz	find_error_si
	mov	ax, [di+14h]
	shl	eax, 10h
	mov	ax, [di+1Ah]
	test	eax, eax
	mov	si, nodata_string
	jz	find_error_si
	ret	2

fat_compare_name:
	push	cx
	mov	cx, 9
.scan:
	lodsb
	cmp	al, '.'
	jz	.ext
	cmp	al, 0
	jz	.nameend
	cmp	al, 'a'
	jb	.notletter
	cmp	al, 'z'
	ja	.notletter
	or	byte [di], 20h
.notletter:
	scasb
	loopz	.scan
.notfound:
	inc	cx	; to clear ZF flag
	pop	cx
	ret
.ext:
	mov	al, ' '
	dec	cx
	repz	scasb
	jnz	.notfound
	test	di, 1
	jnz	.notfound
	mov	cx, 4
	jmp	.scan
.nameend:
	mov	al, ' '
	dec	cx
	repz	scasb
	jnz	.notfound
	test	di, 1
	jnz	.file_found
	mov	cx, 3
	repz	scasb
	jnz	.notfound
.file_found:
	xor	cx, cx	; to set ZF flag
	pop	cx
	ret

read_cluster:
; in: eax=cluster,bx->buffer
	and	eax, 0FFFFFFFh
	movzx	ecx, byte [50Dh]	; sects_per_clust
	mul	ecx
	add	eax, [data_start]
;	call	read
;	ret
	jmp	relative_read
next_cluster:
	mov	bx, 700h
; sector is 200h bytes long, one entry in FAT occupies 4 bytes => 80h entries in sector
	push	eax
	shr	eax, 7		; div 80h
	cmp	eax, [fat_cur_sector]
	jz	@f
	mov	[fat_cur_sector], eax
	add	eax, [fat_start]
	mov	cx, 1
	call	read
@@:
	pop	eax
	and	eax, 7Fh
	mov	eax, [700h+eax*4]
	and	eax, 0FFFFFFFh
	cmp	eax, 0FFFFFF7h
	mov	si, bad_cluster_string
	jz	find_error_si
	ret

Posted: Wed Feb 07, 2007 6:41 pm
by Alboin
Brynet-Inc wrote:...Not sure why anyone would implement Minix's file system Alboin :?
Well, I figured it's well documented, and shouldn't be too hard to implement. Moreover, it's probably a little better than FATx. (x being whatever you want it to be.) And well.....that's all really..... Just a suggestion....Besides, it's just about as useful as UFS.

Posted: Wed Feb 07, 2007 7:27 pm
by frank
I know a winmodem won't work on linux, thats why I can't get linux, I don't have enough money for a real modem.

@Dex
Thanks for the code, I will try to look though it when I get the time