feat: fstat now handle symbolic link
[lunaix-os.git] / lunaix-os / kernel / device / devfs.c
1 #include <lunaix/device.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/fs/devfs.h>
4 #include <lunaix/spike.h>
5
6 #include <usr/lunaix/dirent_defs.h>
7
8 extern struct v_inode_ops devfs_inode_ops;
9 extern struct v_file_ops devfs_file_ops;
10
11 int
12 devfs_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
13 {
14     assert(inode->data);
15
16     struct device* dev = (struct device*)inode->data;
17
18     if (!dev->ops.read) {
19         return ENOTSUP;
20     }
21
22     return dev->ops.read(dev, buffer, fpos, len);
23 }
24
25 int
26 devfs_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
27 {
28     assert(inode->data);
29
30     struct device* dev = (struct device*)inode->data;
31
32     if (!dev->ops.write) {
33         return ENOTSUP;
34     }
35
36     return dev->ops.write(dev, buffer, fpos, len);
37 }
38
39 int
40 devfs_read_page(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
41 {
42     assert(inode->data);
43
44     struct device* dev = (struct device*)inode->data;
45
46     if (!dev->ops.read_page) {
47         return ENOTSUP;
48     }
49
50     return dev->ops.read_page(dev, buffer, fpos);
51 }
52
53 int
54 devfs_write_page(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
55 {
56     assert(inode->data);
57
58     struct device* dev = (struct device*)inode->data;
59
60     if (!dev->ops.read_page) {
61         return ENOTSUP;
62     }
63
64     return dev->ops.read_page(dev, buffer, fpos);
65 }
66
67 int
68 devfs_get_itype(struct device* dev)
69 {
70     int itype = VFS_IFFILE;
71     int dev_if = dev->dev_type & DEV_MSKIF;
72     if (dev_if == DEV_IFCAT) {
73         itype = VFS_IFDIR;
74     } else if (dev_if == DEV_IFVOL) {
75         itype |= VFS_IFVOLDEV;
76     } else if (dev_if == DEV_IFSEQ) {
77         itype |= VFS_IFSEQDEV;
78     } else {
79         itype |= VFS_IFDEV;
80     }
81     return itype;
82 }
83
84 int
85 devfs_get_dtype(struct device* dev)
86 {
87     switch (dev->dev_type & DEV_MSKIF) {
88         case DEV_IFCAT:
89             return DT_DIR;
90
91         default:
92             return DT_FILE;
93     }
94 }
95
96 int
97 devfs_mknod(struct v_dnode* dnode, struct device* dev)
98 {
99     assert(dev);
100
101     struct v_inode* devnod = vfs_i_find(dnode->super_block, dev->dev_uid);
102     if (!devnod) {
103         if ((devnod = vfs_i_alloc(dnode->super_block))) {
104             devnod->id = dev->dev_uid;
105             devnod->data = dev;
106             devnod->itype = devfs_get_itype(dev);
107
108             vfs_i_addhash(devnod);
109         } else {
110             return ENOMEM;
111         }
112     }
113
114     vfs_assign_inode(dnode, devnod);
115     return 0;
116 }
117
118 int
119 devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
120 {
121     struct device* dev =
122       device_getbyhname((struct device*)this->data, &dnode->name);
123     if (!dev) {
124         return ENOENT;
125     }
126     return devfs_mknod(dnode, dev);
127 }
128
129 int
130 devfs_readdir(struct v_file* file, struct dir_context* dctx)
131 {
132     struct device* dev =
133       device_getbyoffset((struct device*)(file->inode->data), dctx->index);
134     if (!dev) {
135         return 0;
136     }
137     dctx->read_complete_callback(
138       dctx, dev->name.value, dev->name.len, devfs_get_dtype(dev));
139     return 1;
140 }
141
142 void
143 devfs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
144 {
145     inode->ops = &devfs_inode_ops;
146     inode->default_fops = &devfs_file_ops;
147 }
148
149 int
150 devfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
151 {
152     vsb->ops.init_inode = devfs_init_inode;
153
154     struct v_inode* rootnod = vfs_i_alloc(vsb);
155
156     if (!rootnod) {
157         return ENOMEM;
158     }
159
160     rootnod->id = -1;
161     rootnod->itype = VFS_IFDIR;
162
163     vfs_i_addhash(rootnod);
164     vfs_assign_inode(mount_point, rootnod);
165
166     return 0;
167 }
168
169 int
170 devfs_unmount(struct v_superblock* vsb)
171 {
172     return 0;
173 }
174
175 void
176 devfs_init()
177 {
178     struct filesystem* fs = fsm_new_fs("devfs", 5);
179     fsm_register(fs);
180     fs->mount = devfs_mount;
181     fs->unmount = devfs_unmount;
182 }
183 EXPORT_FILE_SYSTEM(devfs, devfs_init);
184
185 struct v_inode_ops devfs_inode_ops = { .dir_lookup = devfs_dirlookup,
186                                        .open = default_inode_open,
187                                        .mkdir = default_inode_mkdir,
188                                        .rmdir = default_inode_rmdir };
189
190 struct v_file_ops devfs_file_ops = { .close = default_file_close,
191                                      .read = devfs_read,
192                                      .read_page = devfs_read_page,
193                                      .write = devfs_write,
194                                      .write_page = devfs_write_page,
195                                      .seek = default_file_seek,
196                                      .readdir = devfs_readdir };