summaryrefslogtreecommitdiffstats
path: root/sw/z80/kernel/fs/fs.c
blob: 584f934c7485489ad10b2828862c11669019db8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#include "fs/fs.h"
#include "fs/users.h"
#include "fs/dev.h"

/* from users.h */
struct fs_user c_user;

/* from inode.h */
inode_t c_inode;

struct fs_dev devices[FS_MOUNT_LIMIT];

/* filesystem basic implementation */

devsize_t fs_block(blk_t block)
{
    // TODO
    return 0;
}

devsize_t fs_inode(struct fs_inode *buf)
{
    struct fs_superblock * sb;
    devsize_t seek;

    if (FS_USE_ROM(c_inode))
    {
        seek = FS_ROM_SPACE;
        sb = (struct fs_superblock*) seek; 

    } else {

        seek = 0;

        if (c_inode.dev > 0x7)
            panic("Invalid device");    // TODO, still to implement

        sb = &devices[c_inode.dev].superblock; 
    }

    if (c_inode.inode >= sb->imap_size)
    {
        // TODO, set errno
        return 0;   // inode doesn't exist
    }

    seek += sizeof(struct fs_superblock) + 
            sizeof(struct fs_inode) * c_inode.inode;

    if (FS_USE_ROM(c_inode))
        *buf = *(struct fs_inode*)seek;
    else
    {
        /* set sio port */
        sio_port = devices[c_inode.dev].port_no;
        sio_seek = seek;

        if (sio_read((void *)buf, INODE_META_SIZE) < INODE_META_SIZE)
        {
            // TODO, set errno
            return 0;   // cannot read to device
        }
    }

    return seek + INODE_META_SIZE;
}

/* from fd.h */
int8_t __fd_new()
{
    int8_t fd;
    for (int8_t = 0; i < FD_TABLE_SIZE / 8; i++)
    {
        for (uint8_t bit = 0x80, j = 0; bit > 0; bit >>= 1, j++)
        {
            if (!(bit & fd_bmap[i]))
                return i * 8 + j;
        }
    }

    return -1;
}

/* from fd.h */
int8_t __open_c_inode(uint8_t flags)
{
    /* read meta data */
    struct fs_inode inode;

    /* init file_desc buffer */
    struct file_desc desc = {c_inode, 0};
    
    desc.begin = fs_inode(&inode);
    
    /* bind operations */

    if (flags & OPEN_DIR)
    {
        /* dir handler */

        if (inode.type == INODE_TYPE_DIR)
        {
            /* bind dir functions */
            if (FS_USE_ROM(c_inode))
                /* bind address space functions */
                FD_BIND_AS_DIR(desc.opers)
            else
                /* bind serial space functions */
                FD_BIND_SS_DIR(desc.opers)

        } else {

            // TODO, set errno
            return -1;  // not a directory
        }

    } else if (flags & OPEN_LINK) {
        
        /* link handler */

        if (inode.type == INODE_TYPE_LINK)
        {
            if (FS_USE_ROM(c_inode))
                FD_BIND_AS_FILE(desc.opers, flags)
            else
                FD_BIND_SS_FILE(desc.opers, flags)

            if (flags & OPEN_ERASE)
                /* empty file content */
                __inode_empty(desc.begin);

        } else {
            
            // TODO, set errno
            return -1;  // not a link
        }

    } else {

        /* file */

        if (inode.type == INODE_TYPE_FILE)
            ;   // do nothing
        else if (inode.type == INODE_TYPE_SPECIAL) {
            
            // TODO, bind special callbacks
            
        } else {

            // TODO, set errno
            return -1;
        }

        /* bind operations */

        if (FS_USE_ROM(c_inode))
        {
            if (flags & OPEN_BIN)
                FD_BIND_AS_BINFILE(desc.opers, flags)
            else
                FD_BIND_AS_FILE(desc.opers, flags) 

        } else {
            
            if (flags & OPEN_BIN)
                FD_BIND_SS_BINFILE(desc.opers, flags)
            else
                FD_BIND_SS_FILE(desc.opers, flags)
        }
    }

    /* find a free fd space */
    
    int8_t fd = __fd_new();

    if (fd < 0)
    {
        // TODO, set errno, fd not available

    } else
        fd_table[fd] = desc; // copy buffer into the table

    return fd;
}

inode_t fs_rec_path(const char *path);

inode_t fs_parse_path(const char *path)
{
    inode_t ino, cwd = c_inode;

    switch (path[0])
    {
        case '0':
        FS_INODE_NULL(ino)
        return ino;

        case '/':
        FS_INODE_ROOT(ino)
        c_inode = ino;       // set cwd to root
        path++;
        break;

        case '~':

        if (path[1] = '/')
        {
            c_inode.dev = FS_DEV_ROM;
            c_inode.inode = c_user.home;  // set cwd to home
            path += 2;
        }
            
        break;
   }

   ino = fs_rec_path(path);
   c_inode = cwd;
   return ino;
}

inode_t fs_rec_path(const char *path)
{
    devsize_t inode = fs_inode(c_inode.inode); 
    inode_t rel;

    if (!inode)   // if not exists
    {
        FS_INODE_NULL(rel)
        return rel;
    }

    // TODO, check if dir or file
    // TODO, if dir, find name
    // TODO, set fs_cwd to new inode
    // TODO, recall fs_rec_path
}