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