3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include <partition.h>
34 #define ZEXFS_INITBLOCK_SECTOR 63
35 #define ZEXFS_DIRENT_SECTOR 64
36 #define ZEXFS_IDIRENT_SECTOR ZEXFS_DIRENT_SECTOR+30
37 #define ZEXFS_BLKENT_SECTOR 1024
38 #define ZEXFS_IBLKENT_SECTOR 2048
40 #define ZEXFS_DIRENT_PREALLOC 512 /* you can create # new dirents in fs */
41 #define ZEXFS_BLKENT_PREALLOC 512 /* you can create # new blkents in fs */
43 #define ZEXFS_DIRENT_FREE 0x0
44 #define ZEXFS_DIRENT_DIR 0x1
45 #define ZEXFS_DIRENT_FILE 0x2
47 #define ZEXFS_BLKENT_FREE 0x0
48 #define ZEXFS_BLKENT_USED 0x1
50 #define __PACKED__ __attribute__ ((__packed__))
52 /* zexos filesystem structures */
54 /* main variables of this ent */
55 unsigned char magic
[5]; /* Magic ID of zexfs */
56 unsigned short dirents
; /* Count of created dirents */
57 unsigned short blkents
; /* Count of created blkents */
61 /* main variables of this ent */
62 unsigned char flags
; /* Flags for this ent */
64 unsigned short parent
; /* Parent node */
65 short children
; /* Children node */
68 unsigned char tm_sec
; /* Seconds. [0-60] (1 leap second) */
69 unsigned char tm_min
; /* Minutes. [0-59] */
70 unsigned char tm_hour
; /* Hours. [0-23] */
71 unsigned char tm_mday
; /* Day. [1-31] */
72 unsigned char tm_mon
; /* Month. [0-11] */
73 unsigned char tm_year
; /* Year = 2000 + tm_year */
75 unsigned char name
[21];
76 } __PACKED__ zexfs_dirent
;
81 } __PACKED__ zexfs_blk_header
;
83 /* zexos filesystem structure */
85 zexfs_infoblock iblock
;
87 unsigned char *dirents
;
88 unsigned char *blkents
;
90 unsigned char cache
[512];
92 unsigned short node_curr
;
93 unsigned short node_prev
;
98 /* clear and pre-set dir[] structure */
99 void zexfs_dir_flush ()
103 // if (zexfs.node_curr != 0) {
107 for (; i
< 223; i
++)
108 memset (dir
[i
].name
, 0, 10);
111 /* read 1024 byte block */
112 unsigned zexfs_block_read (partition_t
*p
, unsigned sector
, unsigned char *block
)
114 lba28_drive_read (p
, sector
, (unsigned char *) block
);
115 lba28_drive_read (p
, sector
+1, (unsigned char *) block
+512);
120 int zexfs_blkent_create (partition_t
*p
)
125 /* find free dirent in array */
126 for (i
= 0; i
< zexfs
.iblock
.blkents
+ ZEXFS_BLKENT_PREALLOC
; i
++) {
127 if (zexfs
.blkents
[i
] == ZEXFS_BLKENT_FREE
) {
128 /* match dirent as file or directory */
129 zexfs
.blkents
[i
] = ZEXFS_BLKENT_USED
;
131 lba28_drive_write (p
, ZEXFS_BLKENT_SECTOR
+y
, zexfs
.blkents
+(i
/512));
133 /* increase dirents count in infoblock structure */
134 zexfs
.iblock
.blkents
++;
136 /* update initblock on drive */
137 memset (zexfs
.cache
+sizeof (zexfs
.iblock
), 0, 512-sizeof (zexfs
.iblock
));
138 memcpy (zexfs
.cache
, &zexfs
.iblock
, sizeof (zexfs
.iblock
));
139 lba28_drive_write (p
, ZEXFS_INITBLOCK_SECTOR
, (unsigned char *) zexfs
.cache
);
141 DPRINT (DBG_DRIVER
| DBG_FS
, "ZeXFS -> blkent %d:%d created", i
, zexfs
.iblock
.blkents
);
147 kprintf ("ZeXFS -> Sorry, but your filesystem blkent table is full, please reboot or delete some files for correct the problem\n");
150 /* function for write data of file */
151 unsigned zexfs_write_file (partition_t
*p
, unsigned char *name
, vfs_content_t
*content
)
159 zexfs_dirent
*dirent
= 0;
161 for (i
= 0; i
< zexfs
.iblock
.dirents
+ ZEXFS_DIRENT_PREALLOC
; i
++) {
162 if (zexfs
.dirents
[i
] != ZEXFS_DIRENT_FREE
) {
163 s
= i
* sizeof (zexfs_dirent
);
167 /* read data from sector to cache */
169 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
171 unsigned char *l
= zexfs
.cache
+ (s
-(y
*512));
172 dirent
= (zexfs_dirent
*) l
;
174 if (zexfs
.node_curr
== dirent
->parent
) {
175 // kprintf ("cd_root: %d : %s\n", (s-(y*512)), dirent->name);
177 if (!strcmp (dirent
->name
, name
)) {
178 z
= dirent
->children
;
180 // kprintf ("z: %d: %d\n", z, y);
190 kprintf ("ZeXFS -> file %s not found\n", name
);
194 /* is file block already created ? */
196 z
= zexfs_blkent_create (p
);
199 kprintf ("ZeXFS -> Drive is full\n");
203 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
205 dirent
->children
= z
;
206 /* in memory just rewrite dirent structure */
207 memcpy (zexfs
.cache
+(s
-(y
*512)), (void *) dirent
, sizeof (zexfs_dirent
));
209 /* write new data from cache */
210 lba28_drive_write (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
213 zexfs_blk_header blk
;
217 for (l
= 0; l
< content
->len
; l
+= (512-sizeof (zexfs_blk_header
))) {
218 blk
.next
= (content
->len
> (l
+ (512-sizeof (zexfs_blk_header
)))) ? 1 : 0;
221 blk
.next
= zexfs_blkent_create (p
) - z2
;
222 blk
.len
= 512-sizeof (zexfs_blk_header
);
224 blk
.len
= content
->len
- l
;
225 //kprintf ("next: %d | %d | %d | %d\n", blk.next, ZEXFS_IBLKENT_SECTOR, z, l);
227 memcpy (zexfs
.cache
, &blk
, sizeof (zexfs_blk_header
));
228 memcpy (zexfs
.cache
+sizeof (zexfs_blk_header
), content
->ptr
+l
, 512-sizeof (zexfs_blk_header
));
230 lba28_drive_write (p
, ZEXFS_IBLKENT_SECTOR
+z
+l
, zexfs
.cache
);
237 /* function for read data of file */
238 unsigned zexfs_read_file (partition_t
*p
, unsigned char *name
, vfs_content_t
*content
)
246 zexfs_dirent
*dirent
= 0;
248 for (i
= 0; i
< zexfs
.iblock
.dirents
+ ZEXFS_DIRENT_PREALLOC
; i
++) {
249 if (zexfs
.dirents
[i
] != ZEXFS_DIRENT_FREE
) {
250 s
= i
* sizeof (zexfs_dirent
);
254 /* read data from sector to cache */
256 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
258 unsigned char *l
= zexfs
.cache
+ (s
-(y
*512));
259 dirent
= (zexfs_dirent
*) l
;
261 if (zexfs
.node_curr
== dirent
->parent
) {
262 // kprintf ("cd_root: %d : %s\n", (s-(y*512)), dirent->name);
264 if (!strcmp (dirent
->name
, name
)) {
265 z
= dirent
->children
;
276 kprintf ("ZeXFS -> file %s not found\n", name
);
280 /* is file block already created ? */
282 kprintf ("ZeXFS -> file %s is empty\n", name
);
286 zexfs_blk_header
*blk
= (zexfs_blk_header
*) &zexfs
.cache
;
288 cache_t
*cache
= cache_create (0, 0, 0);
295 for (l
= 0; ; l
+= (512-sizeof (zexfs_blk_header
))) {
296 lba28_drive_read (p
, ZEXFS_IBLKENT_SECTOR
+z
+l
, zexfs
.cache
);
300 cache_add (zexfs
.cache
+sizeof (zexfs_blk_header
), blk
->len
);
306 content
->ptr
= (char *) &cache
->data
;
307 content
->len
= cache
->limit
;
313 /* NOTE: I dont want to use realloc, so we use preallocated memory block for new dirents */
314 int zexfs_dirent_create (partition_t
*p
, zexfs_dirent
*dirent
)
319 /* find free dirent in array */
320 for (i
= 0; i
< zexfs
.iblock
.dirents
+ ZEXFS_DIRENT_PREALLOC
; i
++) {
321 if (zexfs
.dirents
[i
] == ZEXFS_DIRENT_FREE
) {
322 /* match dirent as file or directory */
323 zexfs
.dirents
[i
] = dirent
->flags
& ZEXFS_DIRENT_FILE
? ZEXFS_DIRENT_FILE
: ZEXFS_DIRENT_DIR
;
325 lba28_drive_write (p
, ZEXFS_DIRENT_SECTOR
+y
, zexfs
.dirents
+(i
/512));
327 /* increase dirents count in infoblock structure */
328 zexfs
.iblock
.dirents
++;
330 /* update initblock on drive */
331 memset (zexfs
.cache
+sizeof (zexfs
.iblock
), 0, 512-sizeof (zexfs
.iblock
));
332 memcpy (zexfs
.cache
, &zexfs
.iblock
, sizeof (zexfs
.iblock
));
333 lba28_drive_write (p
, ZEXFS_INITBLOCK_SECTOR
, (unsigned char *) zexfs
.cache
);
335 DPRINT (DBG_DRIVER
| DBG_FS
, "ZeXFS -> dirent %d:%d created", i
, zexfs
.iblock
.dirents
);
341 kprintf ("ZeXFS -> Sorry, but your filesystem dirent table is full, please reboot or delete some files for correct the problem\n");
346 int zexfs_dirent_find (partition_t
*p
, zexfs_dirent
*mydirent
, unsigned char *name
)
352 /* find free dirent in array */
353 for (i
= 0; i
< zexfs
.iblock
.dirents
+ ZEXFS_DIRENT_PREALLOC
; i
++) {
354 if (zexfs
.dirents
[i
] & ZEXFS_DIRENT_DIR
) {
355 unsigned s
= i
* sizeof (zexfs_dirent
);
359 /* read data from sector to cache */
361 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
363 unsigned char *l
= zexfs
.cache
+ (s
-(y
*512));
364 zexfs_dirent
*dirent
= (zexfs_dirent
*) l
;
366 /* we need find same parent node as current node */
367 if (dirent
->parent
== zexfs
.node_curr
)
368 if (!strcmp (name
, dirent
->name
)) { /* verify name of dirent with searched name */
369 /* copy structure from founded dirent to our dirent structure */
370 memcpy (&mydirent
, &dirent
, sizeof (zexfs_dirent
));
381 int zexfs_dirent_findbynode (partition_t
*p
, zexfs_dirent
*mydirent
, unsigned short node
)
386 if (i
> zexfs
.iblock
.dirents
+ ZEXFS_DIRENT_PREALLOC
)
389 if (zexfs
.dirents
[i
] == ZEXFS_DIRENT_FREE
)
392 unsigned s
= i
* sizeof (zexfs_dirent
);
396 /* read data from sector to cache */
397 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
398 //kprintf ("r: %d\n", s-(y*512));
399 unsigned char *l
= zexfs
.cache
+ (s
-(y
*512));
400 zexfs_dirent
*dirent
= (zexfs_dirent
*) l
;
402 /* copy structure from founded dirent to our dirent structure */
403 memcpy (mydirent
, dirent
, sizeof (zexfs_dirent
));
408 /* function for create blank file or directory */
409 unsigned zexfs_create_entity (partition_t
*p
, unsigned char *name
, unsigned flags
)
413 memset (&dirent
, 0, sizeof (zexfs_dirent
));
415 dirent
.flags
|= flags
;
416 dirent
.parent
= zexfs
.node_curr
;
418 if (flags
& ZEXFS_DIRENT_FILE
)
419 dirent
.children
= -1;
421 unsigned l
= strlen (name
);
422 memcpy (dirent
.name
, name
, l
);
423 dirent
.name
[l
] = '\0';
425 int r
= zexfs_dirent_create (p
, &dirent
);
430 r
*= sizeof (zexfs_dirent
);
432 unsigned x
= r
/512; /* sizeof (zexfs_dirent) must be dividable by sector size */
434 // kprintf ("he: %d .. %d .. %d\n", x, r, r-(x*512));
437 for (i
= 0; i
< 223; i
++)
441 strcpy (dir
[i
].name
, name
);
443 /* first read old sector data to cache */
444 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+x
, zexfs
.cache
);
446 /* in memory just rewrite dirent structure */
447 memcpy (zexfs
.cache
+(r
-(x
*512)), &dirent
, sizeof (zexfs_dirent
));
449 /* write new data from cache */
450 lba28_drive_write (p
, ZEXFS_IDIRENT_SECTOR
+x
, zexfs
.cache
);
455 /* go to next directory placed in current directory */
456 unsigned zexfs_cd (partition_t
*p
, unsigned char *name
)
461 // kprintf ("name: %s : %d\n", name, strlen (name));
462 if (!strcmp (name
, "..")) {
463 zexfs
.node_curr
= zexfs
.node_prev
;
465 r
= zexfs_dirent_findbynode (p
, &dirent
, zexfs
.node_prev
);
466 // kprintf ("he: %d\n", r);
468 kprintf ("ZeXFS -> dirent with this name not found\n");
472 zexfs
.node_prev
= dirent
.parent
;
474 // kprintf ("zexfs.node_prev: %d\n", zexfs.node_prev);
476 r
= zexfs_dirent_find (p
, &dirent
, name
);
477 // kprintf ("he2: %d\n", r);
479 kprintf ("ZeXFS -> dirent with this name not found\n");
483 zexfs
.node_prev
= zexfs
.node_curr
;
487 // kprintf ("node_curr: %d\n", r);
488 // kprintf ("name: %s\n", dirent.name);
497 if (zexfs
.node_curr
) {
498 strcpy (dir
[0].name
, "..");
502 for (i
= 0; i
< zexfs
.iblock
.dirents
+ ZEXFS_DIRENT_PREALLOC
; i
++) {
503 if (zexfs
.dirents
[i
] != ZEXFS_DIRENT_FREE
) {
504 unsigned s
= i
* sizeof (zexfs_dirent
);
508 /* read data from sector to cache */
510 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
512 unsigned char *l
= zexfs
.cache
+ (s
-(y
*512));
513 zexfs_dirent
*dirent
= (zexfs_dirent
*) l
;
515 if (zexfs
.node_curr
== dirent
->parent
) {
516 // kprintf ("cd_root: %d : %s\n", (s-(y*512)), dirent->name);
518 memcpy (dir
[id
].name
, dirent
->name
, 10);
519 dir
[id
].dir
= dirent
->flags
& ZEXFS_DIRENT_DIR
? 1 : 0;
531 /* go to root '/' directory on partition */
532 unsigned zexfs_cd_root (partition_t
*p
)
543 for (i
= 0; i
< zexfs
.iblock
.dirents
+ 32; i
++) {
544 if (zexfs
.dirents
[i
] != ZEXFS_DIRENT_FREE
) {
545 unsigned s
= i
* sizeof (zexfs_dirent
);
549 /* read data from sector to cache */
551 lba28_drive_read (p
, ZEXFS_IDIRENT_SECTOR
+y
, zexfs
.cache
);
553 unsigned char *l
= zexfs
.cache
+ (s
-(y
*512));
554 zexfs_dirent
*dirent
= (zexfs_dirent
*) l
;
556 if (zexfs
.node_curr
== dirent
->parent
) {
557 kprintf ("cd_root: %d : %s\n", (s
-(y
*512)), dirent
->name
);
559 memcpy (dir
[id
].name
, dirent
->name
, 10);
560 dir
[id
].dir
= dirent
->flags
& ZEXFS_DIRENT_DIR
? 1 : 0;
572 /* mkzexfs utility for create zexfs filesystem on partition */
573 unsigned mkzexfs (partition_t
*p
)
578 printf ("mkzexfs\n");
581 for (i
= 0; i
< zexfs
.iblock
.dirents
+ ZEXFS_DIRENT_PREALLOC
; i
++)
582 zexfs
.dirents
[i
] = ZEXFS_DIRENT_FREE
;
584 memcpy (zexfs
.iblock
.magic
, "zexfs", 5);
586 zexfs
.iblock
.dirents
= 0;
587 zexfs
.iblock
.blkents
= 0;
589 memset (zexfs
.cache
, 0, 512);
590 memcpy (zexfs
.cache
, (void *) &zexfs
.iblock
, sizeof (zexfs_infoblock
));
592 if (!lba28_drive_write (p
, ZEXFS_INITBLOCK_SECTOR
, zexfs
.cache
))
595 memset (zexfs
.cache
, 0, 512);
597 for (i
= ZEXFS_DIRENT_SECTOR
; i
< ZEXFS_IDIRENT_SECTOR
; i
++) {
598 if (!lba28_drive_write (p
, i
, zexfs
.cache
))
602 for (i
= ZEXFS_IDIRENT_SECTOR
; i
< ZEXFS_IDIRENT_SECTOR
+10; i
++) {
603 if (!lba28_drive_write (p
, ZEXFS_IDIRENT_SECTOR
, zexfs
.cache
))
607 if (!lba28_drive_write (p
, ZEXFS_BLKENT_SECTOR
, zexfs
.cache
))
613 /* create dirent with node id 0 - root directory */
614 zexfs_create_entity (p
, ".", ZEXFS_DIRENT_FILE
);
616 printf ("zexfs filesystem was succefully created\n");
621 /* zexos filesystem initialization function */
622 unsigned zexfs_init (partition_t
*p
)
624 lba28_drive_read (p
, ZEXFS_INITBLOCK_SECTOR
, (unsigned char *) zexfs
.cache
);
626 memcpy (&zexfs
.iblock
, zexfs
.cache
, sizeof (zexfs
.iblock
));
628 if (strncmp (zexfs
.iblock
.magic
, "zexfs", 5)) {
629 kprintf ("ZeXFS not found\n");
633 kprintf ("ZeXFS -> filesystem contain %d dirents\n", zexfs
.iblock
.dirents
);
634 kprintf ("ZeXFS -> filesystem contain %d blkents\n", zexfs
.iblock
.blkents
);
636 /* alloc memory for dirents array */
637 zexfs
.dirents
= (unsigned char *) kmalloc ((zexfs
.iblock
.dirents
+ZEXFS_DIRENT_PREALLOC
) * sizeof (unsigned char));
639 if (!zexfs
.dirents
) {
640 kprintf ("ZeXFS -> zexfs.dirents : out of memory\n");
645 /* alloc memory for blkents array */
646 zexfs
.blkents
= (unsigned char *) kmalloc ((zexfs
.iblock
.blkents
+ZEXFS_BLKENT_PREALLOC
) * sizeof (unsigned char));
648 if (!zexfs
.blkents
) {
649 kprintf ("ZeXFS -> zexfs.blkents : out of memory\n");
650 kfree (zexfs
.dirents
);
655 /* clean end of memory block, where physical data are'nt loaded */
656 if (zexfs
.iblock
.dirents
>= ZEXFS_DIRENT_PREALLOC
)
657 memset (zexfs
.dirents
-ZEXFS_DIRENT_PREALLOC
, 0, ZEXFS_DIRENT_PREALLOC
);
659 memset (zexfs
.dirents
, 0, ZEXFS_DIRENT_PREALLOC
);
661 /* clean end of memory block, where physical data are'nt loaded */
662 if (zexfs
.iblock
.blkents
>= ZEXFS_BLKENT_PREALLOC
)
663 memset (zexfs
.blkents
-ZEXFS_BLKENT_PREALLOC
, 0, ZEXFS_BLKENT_PREALLOC
);
665 memset (zexfs
.blkents
, 0, ZEXFS_BLKENT_PREALLOC
);
670 /* read dirent database from drive */
671 for (i
= 0; i
< zexfs
.iblock
.dirents
; i
+= 512)
672 lba28_drive_read (p
, ZEXFS_DIRENT_SECTOR
+(i
/512), (unsigned char *) ((unsigned char *) zexfs
.dirents
+((i
/512)*512)));
674 /* read blkent database from drive */
675 for (i
= 0; i
< zexfs
.iblock
.blkents
; i
+= 512)
676 lba28_drive_read (p
, ZEXFS_BLKENT_SECTOR
+(i
/512), (unsigned char *) ((unsigned char *) zexfs
.blkents
+((i
/512)*512)));
683 /* handler which is used by device management and pretty needed
684 for communication between zexos and this filesystem */
685 bool zexfs_handler (unsigned act
, char *block
, unsigned n
, unsigned long l
)
690 return zexfs_init ((partition_t
*) block
);
695 return zexfs_read_file (curr_part
, dir
[n
].name
, (vfs_content_t
*) block
);
700 return zexfs_write_file (curr_part
, dir
[n
].name
, (vfs_content_t
*) block
);
706 return zexfs_cd_root (curr_part
);
708 /* go to another directory */
709 return zexfs_cd (curr_part
, block
);
714 return zexfs_create_entity (curr_part
, block
, ZEXFS_DIRENT_DIR
);
719 return zexfs_create_entity (curr_part
, block
, ZEXFS_DIRENT_FILE
);