1 /*
2 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3 */
4
5 #include <stddef.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include "vfs_types.h"
11 #include "vfs_api.h"
12 #include "vfs_conf.h"
13
14 #include "vfs_inode.h"
15 #include "vfs_adapt.h"
16
17 static vfs_inode_t g_vfs_nodes[VFS_DEVICE_NODES];
18 #ifdef VFS_CONFIG_ROOTFS
19 static vfs_inode_t *g_rootfs_node;
20 #endif
21
vfs_inode_set_name(const char * path,vfs_inode_t ** p_node)22 static int32_t vfs_inode_set_name(const char *path, vfs_inode_t **p_node)
23 {
24 int32_t len;
25 void *mem;
26
27 len = strlen(path);
28 mem = (void *)vfs_malloc(len + 1);
29 if (mem == NULL) {
30 return VFS_ERR_NOMEM;
31 }
32
33 memcpy(mem, (const void *)path, len);
34
35 (*p_node)->i_name = (char *)mem;
36 (*p_node)->i_name[len] = '\0';
37
38 return VFS_OK;
39 }
40
vfs_inode_init(void)41 int32_t vfs_inode_init(void)
42 {
43 memset(g_vfs_nodes, 0, sizeof(vfs_inode_t) * VFS_DEVICE_NODES);
44
45 return VFS_OK;
46 }
47
vfs_inode_alloc(void)48 int32_t vfs_inode_alloc(void)
49 {
50 int32_t idx;
51
52 for (idx = 0; idx < VFS_DEVICE_NODES; idx++) {
53 if (g_vfs_nodes[idx].type == VFS_TYPE_NOT_INIT) {
54 return idx;
55 }
56 }
57
58 return VFS_ERR_NOMEM;
59 }
60
close_all_files_on_node(vfs_inode_t * node)61 static void close_all_files_on_node(vfs_inode_t *node)
62 {
63 int idx;
64 vfs_file_t *f;
65
66 for (idx = 0; idx < VFS_MAX_FILE_NUM; idx++) {
67 f = vfs_file_get(idx);
68 if (f && f->node == node) {
69 if (INODE_IS_FS(node)) {
70 if (node->ops.i_fops->close) {
71 node->ops.i_fops->close(f);
72 }
73 } else {
74 if (node->ops.i_ops->close) {
75 node->ops.i_ops->close(f);
76 }
77 }
78 }
79 }
80 }
81
vfs_inode_del(vfs_inode_t * node)82 int32_t vfs_inode_del(vfs_inode_t *node)
83 {
84 #if 0
85 if (node->refs > 0) {
86 return VFS_ERR_BUSY;
87 }
88
89 if (node->refs == 0) {
90 if (node->i_name != NULL) {
91 vfs_free(node->i_name);
92 }
93
94 node->i_name = NULL;
95 node->i_arg = NULL;
96 node->i_flags = 0;
97 node->type = VFS_TYPE_NOT_INIT;
98 }
99
100 return VFS_OK;
101 #else
102 if (vfs_lock(node->lock) != VFS_OK)
103 {
104 VFS_ERROR("%s failed to lock inode %p!\n\r", __func__, node);
105 return VFS_ERR_LOCK;
106 }
107
108 if (node->refs > 0)
109 {
110 node->status = VFS_INODE_INVALID;
111 // ensure to close all files at this point since
112 // ops will become unavailable soon!!
113 close_all_files_on_node(node);
114
115 if (vfs_unlock(node->lock) != VFS_OK)
116 {
117 VFS_ERROR("%s failed to unlock inode %p!\n\r", __func__, node);
118 return VFS_ERR_LOCK;
119 }
120 }
121 else
122 {
123 if (node->i_name != NULL)
124 {
125 vfs_free(node->i_name);
126 }
127
128 node->i_name = NULL;
129 node->i_arg = NULL;
130 node->i_flags = 0;
131 node->type = VFS_TYPE_NOT_INIT;
132
133 if (vfs_lock_free(node->lock) != VFS_OK)
134 {
135 VFS_ERROR("%s failed to free lock for node %p\n\r", __func__, node);
136 return VFS_ERR_LOCK;
137 }
138 }
139
140 return VFS_OK;
141 #endif
142 }
143
vfs_inode_open(const char * path)144 vfs_inode_t *vfs_inode_open(const char *path)
145 {
146 int32_t idx;
147 vfs_inode_t *node;
148 #ifdef VFS_CONFIG_ROOTFS
149 bool fs_match = false;
150 #endif
151
152 for (idx = 0; idx < VFS_DEVICE_NODES; idx++) {
153 node = &g_vfs_nodes[idx];
154
155 if (node->i_name == NULL) {
156 continue;
157 }
158
159 if (INODE_IS_TYPE(node, VFS_TYPE_FS_DEV)) {
160 if (strncmp(node->i_name, path, strlen(node->i_name)) == 0) {
161 #ifdef VFS_CONFIG_ROOTFS
162 fs_match = true;
163 #endif
164 if (*(path + strlen(node->i_name)) == '/') {
165 return node;
166 }
167 }
168 }
169
170 if (strcmp(node->i_name, path) == 0) {
171 return node;
172 }
173 }
174
175 #ifdef VFS_CONFIG_ROOTFS
176 if (fs_match) {
177 return g_rootfs_node;
178 }
179 #endif
180
181 return NULL;
182 }
183
vfs_inode_ptr_get(int32_t fd,vfs_inode_t ** p_node)184 int32_t vfs_inode_ptr_get(int32_t fd, vfs_inode_t **p_node)
185 {
186 if (fd < 0 || fd >= VFS_DEVICE_NODES) {
187 return VFS_ERR_INVAL;
188 }
189
190 *p_node = &g_vfs_nodes[fd];
191
192 return VFS_OK;
193 }
194
vfs_inode_avail_count(void)195 int32_t vfs_inode_avail_count(void)
196 {
197 int32_t idx, count = 0;
198
199 for (idx = 0; idx < VFS_DEVICE_NODES; idx++){
200 if (g_vfs_nodes[count].type == VFS_TYPE_NOT_INIT) {
201 count++;
202 }
203 }
204
205 return count;
206 }
207
vfs_inode_ref(vfs_inode_t * node)208 void vfs_inode_ref(vfs_inode_t *node)
209 {
210 if (!node)
211 {
212 return;
213 }
214
215 if (vfs_lock(node->lock) != VFS_OK) {
216 VFS_ERROR("%s failed to lock inode %p!\n\r", __func__, node);
217 return;
218 }
219
220 node->refs++;
221
222 if (vfs_unlock(node->lock) != VFS_OK) {
223 VFS_ERROR("%s failed to unlock inode %p!\n\r", __func__, node);
224 return;
225 }
226 }
227
vfs_inode_unref(vfs_inode_t * node)228 void vfs_inode_unref(vfs_inode_t *node)
229 {
230 bool delete = false, detach = false;;
231
232 if (!node) return;
233
234 if (vfs_lock(node->lock) != VFS_OK) {
235 VFS_ERROR("%s failed to lock inode %p!\n\r", __func__, node);
236 return;
237 }
238
239 if (node->refs > 0) {
240 node->refs--;
241 }
242
243 if (node->refs == 0) {
244 if (node->status == VFS_INODE_INVALID) {
245 delete = true;
246 } else if (node->status == VFS_INODE_DETACHED) {
247 detach = true;
248 }
249 }
250
251 if (vfs_unlock(node->lock) != VFS_OK) {
252 VFS_ERROR("%s failed to unlock inode %p!\n\r", __func__, node);
253 return;
254 }
255
256 if (delete) {
257 vfs_inode_del(node);
258 } else if (detach) {
259 // umount(node->i_name);
260 }
261 }
262
vfs_inode_busy(vfs_inode_t * node)263 int32_t vfs_inode_busy(vfs_inode_t *node)
264 {
265 int32_t ret;
266
267 if (!node) return VFS_ERR_INVAL;
268
269 if (vfs_lock(node->lock) != VFS_OK) {
270 VFS_ERROR("%s failed to lock inode %p!\n\r", __func__, node);
271 return VFS_ERR_LOCK;
272 }
273
274 ret = node->refs > 0 ? 1 : 0;
275
276 if (vfs_unlock(node->lock) != VFS_OK) {
277 VFS_ERROR("%s failed to unlock inode %p!\n\r", __func__, node);
278 return VFS_ERR_LOCK;
279 }
280
281 return ret;
282 }
283
vfs_inode_busy_by_name(const char * name)284 int32_t vfs_inode_busy_by_name(const char *name)
285 {
286 for (int i = 0; i < VFS_DEVICE_NODES; i++) {
287 if (strcmp(g_vfs_nodes[i].i_name, name) == 0) {
288 return vfs_inode_busy(&(g_vfs_nodes[i]));
289 }
290 }
291
292 return 0;
293 }
294
vfs_inode_detach(vfs_inode_t * node)295 int32_t vfs_inode_detach(vfs_inode_t *node)
296 {
297 if (vfs_lock(node->lock) != VFS_OK) {
298 VFS_ERROR("%s failed to lock inode %p!\n\r", __func__, node);
299 return VFS_ERR_LOCK;
300 }
301
302 node->status = VFS_INODE_DETACHED;
303
304 if (vfs_unlock(node->lock) != VFS_OK) {
305 VFS_ERROR("%s failed to unlock inode %p!\n\r", __func__, node);
306 return VFS_ERR_LOCK;
307 }
308
309 return VFS_OK;
310 }
311
312 /* only used by FS inode to umount itself after it ceases to be busy */
vfs_inode_detach_by_name(const char * name)313 int32_t vfs_inode_detach_by_name(const char *name)
314 {
315 int32_t ret = -1;
316
317 for (int i = 0; i < VFS_DEVICE_NODES; i++) {
318 if ((g_vfs_nodes[i].type == VFS_TYPE_FS_DEV) && (strcmp(g_vfs_nodes[i].i_name, name) == 0)) {
319 ret = vfs_inode_detach(&(g_vfs_nodes[i]));
320 }
321 }
322
323 return ret;
324 }
325
vfs_inode_reserve(const char * path,vfs_inode_t ** p_node)326 int32_t vfs_inode_reserve(const char *path, vfs_inode_t **p_node)
327 {
328 int32_t ret;
329
330 vfs_inode_t *node = NULL;
331
332 if ((path == NULL) || (p_node == NULL)) {
333 return VFS_ERR_INVAL;
334 }
335
336 *p_node = NULL;
337
338 /* Handle paths that are interpreted as the root directory */
339 #ifdef _WIN32
340 if ((path[0] == '\0') || (path[1] != ':')) {
341 #else
342 if ((path[0] == '\0') || (path[0] != '/')) {
343 #endif
344 return VFS_ERR_INVAL;
345 }
346
347 ret = vfs_inode_alloc();
348 if (ret == VFS_ERR_NOMEM) {
349 return ret;
350 }
351
352 vfs_inode_ptr_get(ret, &node);
353 if (node == NULL) {
354 return VFS_ERR_NOMEM;
355 }
356
357 node->lock = vfs_lock_create();
358 if (node->lock == NULL) {
359 VFS_ERROR("%s faile to create lock for inode %p\r\n", __func__, node);
360 return VFS_ERR_LOCK;
361 }
362
363 ret = vfs_inode_set_name(path, &node);
364 if (ret != VFS_OK) {
365 return ret;
366 }
367
368 node->status = VFS_INODE_VALID;
369 *p_node = node;
370
371 #ifdef VFS_CONFIG_ROOTFS
372 /* for rootfs use */
373 if (strcmp(path, "/") == 0) g_rootfs_node = node;
374 #endif
375
376 return VFS_OK;
377 }
378
379 int32_t vfs_inode_release(const char *path)
380 {
381 int32_t ret;
382 vfs_inode_t *node;
383
384 if (path == NULL) {
385 return VFS_ERR_INVAL;
386 }
387
388 node = vfs_inode_open(path);
389 if (node == NULL) {
390 return VFS_ERR_NODEV;
391 }
392
393 ret = vfs_inode_del(node);
394
395 return ret;
396 }
397
398 int32_t vfs_inode_list(vfs_list_type_t type)
399 {
400 int32_t idx;
401
402 for (idx = 0; idx < VFS_DEVICE_NODES; idx++) {
403 if (VFS_LIST_TYPE_FS == type) {
404 if (g_vfs_nodes[idx].type == VFS_TYPE_FS_DEV) {
405 printf("%s\r\n", g_vfs_nodes[idx].i_name);
406 }
407 } else if (VFS_LIST_TYPE_DEVICE == type) {
408 if (g_vfs_nodes[idx].type == VFS_TYPE_CHAR_DEV ||
409 g_vfs_nodes[idx].type == VFS_TYPE_BLOCK_DEV) {
410 printf("%s\r\n", g_vfs_nodes[idx].i_name);
411 }
412 }
413 }
414
415 return VFS_OK;
416 }
417
418 uint32_t vfs_get_match_dev_node(const char *name, char *match_name)
419 {
420 int32_t idx;
421 uint32_t match_count = 0;
422 int32_t match_idx = 0;
423 for (idx = 0; idx < VFS_DEVICE_NODES; idx++) {
424 if (g_vfs_nodes[idx].type == VFS_TYPE_CHAR_DEV ||
425 g_vfs_nodes[idx].type == VFS_TYPE_BLOCK_DEV) {
426 if (name == NULL) {
427 printf("%s ", g_vfs_nodes[idx].i_name + strlen("/dev/"));
428 } else if (!strncmp(name, g_vfs_nodes[idx].i_name + strlen("/dev/"), strlen(name))) {
429 match_count++;
430
431 if (1 == match_count) {
432 match_idx = idx;
433 } else if (match_count == 2) {
434 printf("%s %s",
435 g_vfs_nodes[match_idx].i_name + strlen("/dev/"),
436 g_vfs_nodes[idx].i_name + strlen("/dev/"));
437 } else {
438 printf(" %s", g_vfs_nodes[idx].i_name + strlen("/dev/"));
439 }
440 }
441 }
442 }
443
444 if (1 == match_count) {
445 strncpy(match_name,
446 g_vfs_nodes[match_idx].i_name + strlen("/dev/"),
447 strlen(g_vfs_nodes[match_idx].i_name + strlen("/dev/")));
448 }
449
450 return match_count;
451 }
452
453 int vfs_inode_get_names(const char *path, char names[][64], uint32_t* size)
454 {
455 uint32_t idx;
456 uint32_t index = 0;
457 uint32_t len = 0;
458
459 if (path == NULL)
460 return VFS_ERR_INVAL;
461
462 for (idx = 0; idx < VFS_DEVICE_NODES; idx++) {
463 if (g_vfs_nodes[idx].type == VFS_TYPE_FS_DEV &&
464 strncmp(path, g_vfs_nodes[idx].i_name, strlen(path)) == 0) {
465 memset(names[index], 0, 64);
466 len = strlen(g_vfs_nodes[idx].i_name) + 1;
467 if (len > 64) {
468 strncpy(names[index], g_vfs_nodes[idx].i_name, 63);
469 names[index][63] = '\0';
470 index++;
471 } else {
472 strncpy(names[index++], g_vfs_nodes[idx].i_name, len);
473 }
474 }
475 }
476 *size = index;
477
478 return VFS_OK;
479 }
480