1 /*
2  * Copyright (c) 2006-2025 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2005-02-22     Bernard      The first version.
9  * 2010-06-30     Bernard      Optimize for RT-Thread RTOS
10  * 2011-03-12     Bernard      fix the filesystem lookup issue.
11  * 2017-11-30     Bernard      fix the filesystem_operation_table issue.
12  * 2017-12-05     Bernard      fix the fs type search issue in mkfs.
13  * 2023-05-05     Bernard      change to dfs v2.0
14  */
15 
16 #include <dfs_fs.h>
17 #include <dfs_file.h>
18 #include <dfs_dentry.h>
19 #include <dfs_mnt.h>
20 #include "dfs_private.h"
21 
22 #ifdef RT_USING_PAGECACHE
23 #include "dfs_pcache.h"
24 #endif
25 
26 #define DBG_TAG "DFS.fs"
27 #define DBG_LVL DBG_INFO
28 #include <rtdbg.h>
29 
30 static struct dfs_filesystem_type *file_systems = NULL;
31 extern rt_list_t _mnt_list;
32 
33 /**
34  * @addtogroup group_fs_api
35  */
36 /*@{*/
37 
38 /**
39  * @brief Find a filesystem type by name
40  *
41  * This function searches the global filesystem type list for a filesystem
42  * matching the given name. It returns a pointer to the pointer that holds
43  * the matching filesystem type (or the end-of-list pointer if not found).
44  *
45  * @param[in] name The name of the filesystem type to find
46  * @return struct dfs_filesystem_type** Pointer to the pointer containing
47  *         the matching filesystem type, or the end-of-list pointer if not found
48  */
_find_filesystem(const char * name)49 static struct dfs_filesystem_type **_find_filesystem(const char *name)
50 {
51     struct dfs_filesystem_type **type;
52     for (type = &file_systems; *type; type = &(*type)->next)
53     {
54         if (strcmp((*type)->fs_ops->name, name) == 0)
55             break;
56     }
57 
58     return type;
59 }
60 
61 /**
62  * @brief Get the list of registered filesystem types
63  *
64  * This function returns a pointer to the head of the global filesystem type list.
65  *
66  * @return struct dfs_filesystem_type* Pointer to the head of the filesystem type list
67  */
dfs_filesystems(void)68 struct dfs_filesystem_type *dfs_filesystems(void)
69 {
70     return file_systems;
71 }
72 
73 /**
74  * @brief Register a filesystem type
75  *
76  * This function registers a new filesystem type with the global filesystem type list.
77  *
78  * @param[in] fs Pointer to the filesystem type to register
79  * @return int 0 on success, or a negative error code on failure
80  */
dfs_register(struct dfs_filesystem_type * fs)81 int dfs_register(struct dfs_filesystem_type *fs)
82 {
83     int ret = 0;
84     struct dfs_filesystem_type **type = _find_filesystem(fs->fs_ops->name);
85 
86     LOG_D("register %s file system.", fs->fs_ops->name);
87 
88     if (*type)
89     {
90         ret = -EBUSY;
91     }
92     else
93     {
94         *type = fs;
95     }
96 
97     return ret;
98 }
99 
100 /**
101  * @brief Unregister a filesystem type
102  *
103  * This function unregisters a filesystem type from the global filesystem type list.
104  *
105  * @param[in] fs Pointer to the filesystem type to unregister
106  * @return int 0 on success, or a negative error code on failure
107  */
dfs_unregister(struct dfs_filesystem_type * fs)108 int dfs_unregister(struct dfs_filesystem_type *fs)
109 {
110     int ret = 0;
111     struct dfs_filesystem_type **type;
112 
113     if (fs)
114     {
115         LOG_D("unregister %s file system.", fs->fs_ops->name);
116 
117         for (type = &file_systems; *type; type = &(*type)->next)
118         {
119             if (strcmp((*type)->fs_ops->name, fs->fs_ops->name) == 0)
120             {
121                 *type = (*type)->next;
122                 break;
123             }
124         }
125 
126         if (!*type) ret = -EINVAL;
127     }
128 
129     return ret;
130 }
131 
132 #define REMNT_UNSUPP_FLAGS (~(MS_REMOUNT | MS_RMT_MASK)) /* remount unsupported flags */
133 
134 /**
135  * @brief Remount a filesystem
136  *
137  * This function remounts a filesystem at the specified path with the given flags.
138  *
139  * @param[in] path The path of the filesystem to remount
140  * @param[in] flags The remount flags (see MS_REMOUNT and MS_RMT_MASK)
141  * @param[in] data Pointer to additional data required for remounting
142  * @return int 0 on success, or a negative error code on failure
143  */
dfs_remount(const char * path,rt_ubase_t flags,void * data)144 int dfs_remount(const char *path, rt_ubase_t flags, void *data)
145 {
146     int rc = 0;
147     char *fullpath = RT_NULL;
148     struct dfs_mnt *mnt = RT_NULL;
149 
150     if (flags & REMNT_UNSUPP_FLAGS)
151     {
152         return -EINVAL;
153     }
154 
155     fullpath = dfs_normalize_path(RT_NULL, path);
156     if (!fullpath)
157     {
158         rc = -ENOENT;
159     }
160     else
161     {
162         DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
163         mnt = dfs_mnt_lookup(fullpath);
164         if (mnt)
165         {
166             dfs_lock();
167             dfs_mnt_setflags(mnt, flags);
168             dfs_unlock();
169         }
170         else
171         {
172             struct stat buf = {0};
173             if (dfs_file_stat(fullpath, &buf) == 0 && S_ISBLK(buf.st_mode))
174             {
175                 /* path was not already mounted on target */
176                 rc = -EINVAL;
177             }
178             else
179             {
180                 /* path is not a directory */
181                 rc = -ENOTDIR;
182             }
183         }
184     }
185 
186     return rc;
187 }
188 
189 /*
190  *    parent(mount path)
191  *    mnt_parent <- - - - - - -  +
192  *         |                     |
193  *         |- mnt_child <- - - - - -+ (1 refcount)
194  *                 |             |
195  *                 |- parent - - + (1 refcount)
196  */
197 
198 /**
199  * @brief Mount a filesystem at the specified path
200  *
201  * This function mounts a filesystem of the specified type at the given path with optional device.
202  * It handles both root filesystem mounting and regular filesystem mounting scenarios.
203  *
204  * @param[in] device_name The name of the device to mount (optional)
205  * @param[in] path The path of the mount point
206  * @param[in] filesystemtype The type of the filesystem to mount
207  * @param[in] rwflag The read/write flags (see MS_RDONLY, MS_RDWR, etc.)
208  * @param[in] data Pointer to additional data required for mounting
209  *
210  * @return int RT_EOK on success, negative error code on failure:
211  *             - EPERM: Path normalization failed or mount operation failed
212  *             - ENODEV: Filesystem type not found or device not available
213  *             - ENOMEM: Memory allocation failure
214  *             - EIO: Filesystem lacks mount method
215  *             - ENOTDIR: Mount point doesn't exist
216  *             - EEXIST: Mount point already mounted
217  *
218  * @note Special handling for root filesystem ("/")
219  * @note Automatic reference counting management for mount points
220  */
dfs_mount(const char * device_name,const char * path,const char * filesystemtype,unsigned long rwflag,const void * data)221 int dfs_mount(const char *device_name,
222               const char *path,
223               const char *filesystemtype,
224               unsigned long rwflag,
225               const void *data)
226 {
227     int ret = RT_EOK;
228     char *fullpath = RT_NULL;
229     rt_device_t dev_id = RT_NULL;
230     struct dfs_mnt *mnt_parent = RT_NULL, *mnt_child = RT_NULL;
231     struct dfs_dentry *mntpoint_dentry = RT_NULL;
232     struct dfs_filesystem_type *type = *_find_filesystem(filesystemtype);
233 
234     /* normalize the mount path */
235     if (type)
236     {
237         fullpath = dfs_normalize_path(RT_NULL, path);
238         if (!fullpath)
239         {
240             rt_set_errno(EPERM);
241             ret = -1;
242         }
243     }
244     else
245     {
246         rt_set_errno(ENODEV);
247         ret = -1;
248     }
249 
250     /* Main mounting procedure */
251     if (fullpath)
252     {
253         DLOG(note, "mnt", "mount %s(%s) on path: %s", device_name, filesystemtype, fullpath);
254 
255         /* open specific device */
256         if (device_name) dev_id = rt_device_find(device_name);
257 
258         /* Check device requirements */
259         if (!(type->fs_ops->flags & FS_NEED_DEVICE) ||
260             ((type->fs_ops->flags & FS_NEED_DEVICE) && dev_id))
261         {
262             DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_lookup(%s)", fullpath);
263             mnt_parent = dfs_mnt_lookup(fullpath); /* Find parent mount point */
264 
265             /* Handle root filesystem mounting */
266             if ((!mnt_parent && (strcmp(fullpath, "/") == 0 || strcmp(fullpath, "/dev") == 0))
267                 || (mnt_parent && strcmp(fullpath, "/") == 0 && strcmp(mnt_parent->fullpath, fullpath) != 0))
268             {
269                 LOG_D("no mnt found @ mount point %s, should be root.", fullpath);
270                 DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "no mnt");
271 
272                 /* it's the root file system */
273                 /* the mount point dentry is the same as root dentry. */
274                 /* Create root filesystem mount point */
275                 DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_create(path)");
276                 mnt_parent = dfs_mnt_create(fullpath); /* mnt->ref_count should be 1. */
277                 if (mnt_parent)
278                 {
279                     DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "return mnt, ref_count=1");
280 
281                     mnt_parent->fs_ops = type->fs_ops;
282                     mnt_parent->dev_id = dev_id;
283                     if (mnt_parent->fs_ops->mount)
284                     {
285                         DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "fs_ops->mount(mnt_parent, rwflag, data)");
286                         ret = mnt_parent->fs_ops->mount(mnt_parent, rwflag, data);
287                         if (ret == RT_EOK)
288                         {
289                             DLOG(msg, type->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK, ret root_dentry");
290 
291                             /* Mark as mounted and insert into mount table */
292                             mnt_child = mnt_parent;
293                             mnt_child->flags |= MNT_IS_MOUNTED;
294 
295                             DLOG(note_right, "mnt", "mount sucessfully");
296                             DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(, mnt_child)");
297                             dfs_mnt_insert(RT_NULL, mnt_child);
298 
299                             /* unref it, because the ref_count = 1 when create */
300                             DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_parent)");
301                             dfs_mnt_unref(mnt_parent);
302 
303                             /*
304                              * About root mnt:
305                              * There are two ref_count:
306                              * 1. the gobal root reference.
307                              * 1. the mnt->parent reference.
308                              */
309                         }
310                         else
311                         {
312                             LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
313                             DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent)");
314                             dfs_mnt_destroy(mnt_parent);
315                             mnt_parent = RT_NULL;
316                             rt_set_errno(EPERM);
317                             ret = -1;
318                         }
319                     }
320                     else
321                     {
322                         LOG_W("no mount method on file system type: %s", type->fs_ops->name);
323                         DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent), no mount method");
324                         dfs_mnt_destroy(mnt_parent);
325                         mnt_parent = RT_NULL;
326                         rt_set_errno(EIO);
327                         ret = -1;
328                     }
329                 }
330                 else
331                 {
332                     LOG_E("create a mnt point failed.");
333                     rt_set_errno(ENOMEM);
334                     ret = -1;
335                 }
336             }
337             else if (mnt_parent && (strcmp(mnt_parent->fullpath, fullpath) != 0)) /* Handle regular filesystem mounting */
338             {
339                 DLOG(msg, "dfs", "dentry", DLOG_MSG, "mntpoint_dentry = dfs_dentry_lookup(mnt_parent, %s, 0)", fullpath);
340                 mntpoint_dentry = dfs_dentry_lookup(mnt_parent, fullpath, 0); /* Find mount point directory entry */
341                 if (mntpoint_dentry)
342                 {
343                     DLOG(msg, "dentry", "dfs", DLOG_MSG_RET, "dentry exist");
344                     DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_child = dfs_mnt_create(path)");
345                     mnt_child = dfs_mnt_create(fullpath); /* Create child mount point */
346                     if (mnt_child)
347                     {
348                         LOG_D("create mnt point %p", mnt_child);
349 
350                         mnt_child->fs_ops = type->fs_ops;
351                         mnt_child->dev_id = dev_id;
352 
353                         if (mnt_child->fs_ops->mount)
354                         {
355                             DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "root_dentry = fs_ops->mount(mnt_child, rwflag, data)");
356                             ret = mnt_child->fs_ops->mount(mnt_child, rwflag, data);
357                             if (ret == RT_EOK)
358                             {
359                                 mnt_child->flags |= MNT_IS_MOUNTED;
360 
361                                 LOG_D("mount %s sucessfully", fullpath);
362                                 DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK");
363 
364                                 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(mnt_parent, mnt_child)");
365                                 dfs_mnt_insert(mnt_parent, mnt_child);
366 
367                                 /* unref it, because the ref_count = 1 when create */
368                                 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_child)");
369                                 dfs_mnt_unref(mnt_child);
370                             }
371                             else
372                             {
373                                 LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
374                                 DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount failed");
375                                 dfs_mnt_destroy(mnt_child);
376                                 rt_set_errno(EPERM);
377                                 ret = -1;
378                             }
379                         }
380                         else
381                         {
382                             LOG_W("no mount method on file system type: %s", type->fs_ops->name);
383                             dfs_mnt_destroy(mnt_child);
384                             rt_set_errno(EIO);
385                             ret = -1;
386                         }
387                     }
388                     else
389                     {
390                         LOG_E("create a mnt point failed.");
391                         rt_set_errno(ENOMEM);
392                         ret = -1;
393                     }
394                     dfs_dentry_unref(mntpoint_dentry);
395                 }
396                 else
397                 {
398                     LOG_W("no mount point (%s) in file system: %s", fullpath, mnt_parent->fullpath);
399                     rt_set_errno(ENOTDIR);
400                     ret = -1;
401                 }
402             }
403             else
404             {
405                 LOG_E("mount point (%s) already mounted!", fullpath);
406                 rt_set_errno(EEXIST);
407                 ret = -1;
408             }
409         }
410         else
411         {
412             LOG_E("No device found for this file system.");
413             rt_set_errno(ENODEV);
414             ret = -1;
415         }
416         rt_free(fullpath);
417     }
418 
419     return ret;
420 }
421 
422 /**
423  * @brief Unmount a filesystem from the specified path
424  *
425  * This function unmounts a filesystem from the given path. It performs the following operations:
426  * 1. Normalizes the target path
427  * 2. Looks up the mount point
428  * 3. Checks if the filesystem can be safely unmounted
429  * 4. Performs cleanup operations if unmounting is successful
430  *
431  * @param[in] specialfile The path of the filesystem to unmount
432  * @param[in] flags Unmount flags (MNT_FORCE for forced unmount)
433  *
434  * @return int RT_EOK on success, negative error code on failure:
435  *             - EBUSY: Filesystem is busy (in use or has child mounts)
436  *             - EINVAL: Path is not a mount point
437  *             - ENOTDIR: Invalid path format
438  *
439  * @note Forced unmount (MNT_FORCE) can unmount even if reference count > 1
440  * @note Automatically handles page cache cleanup if RT_USING_PAGECACHE is enabled
441  * @note The function will fail if:
442  *       - The mount point is locked (MNT_IS_LOCKED)
443  *       - There are child mounts present
444  *       - Reference count > 1 and MNT_FORCE not specified
445  */
dfs_umount(const char * specialfile,int flags)446 int dfs_umount(const char *specialfile, int flags)
447 {
448     int ret = -1;
449     char *fullpath = RT_NULL;
450     struct dfs_mnt *mnt = RT_NULL;
451 
452     fullpath = dfs_normalize_path(NULL, specialfile);
453     if (fullpath)
454     {
455         DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
456         mnt = dfs_mnt_lookup(fullpath);
457         if (mnt)
458         {
459             if (strcmp(mnt->fullpath, fullpath) == 0)
460             {
461                 /* is the mount point */
462                 rt_base_t ref_count = rt_atomic_load(&(mnt->ref_count));
463 
464                 if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
465                 {
466 #ifdef RT_USING_PAGECACHE
467                     dfs_pcache_unmount(mnt);
468 #endif
469                     /* destroy this mount point */
470                     DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt)");
471                     ret = dfs_mnt_destroy(mnt);
472                 }
473                 else
474                 {
475                     LOG_I("the file system is busy!");
476                     ret = -EBUSY;
477                 }
478             }
479             else
480             {
481                 LOG_I("the path:%s is not a mountpoint!", fullpath);
482                 ret = -EINVAL;
483             }
484         }
485         else
486         {
487             LOG_I("no filesystem found.");
488         }
489         rt_free(fullpath);
490     }
491     else
492     {
493         rt_set_errno(-ENOTDIR);
494     }
495 
496     return ret;
497 }
498 
499 /* for compatibility */
dfs_unmount(const char * specialfile)500 int dfs_unmount(const char *specialfile)
501 {
502     return dfs_umount(specialfile, 0);
503 }
504 
505 /**
506  * @brief Check if a mount point is mounted
507  *
508  * This function checks if the given mount point is mounted. It returns 0 if the mount point is mounted,
509  * and -1 otherwise.
510  *
511  * @param[in] mnt The mount point to check
512  *
513  * @return int 0 if mounted, -1 otherwise
514  */
dfs_is_mounted(struct dfs_mnt * mnt)515 int dfs_is_mounted(struct dfs_mnt *mnt)
516 {
517     int ret = 0;
518 
519     if (mnt && !(mnt->flags & MNT_IS_MOUNTED))
520     {
521         ret = -1;
522     }
523 
524     return ret;
525 }
526 
527 /**
528  * @brief Create a filesystem on the specified device
529  *
530  * This function creates a filesystem of the specified type on the given device.
531  * It performs the following operations:
532  * 1. Looks up the filesystem type
533  * 2. Validates device requirements
534  * 3. Calls the filesystem-specific mkfs operation
535  * 4. Handles page cache cleanup if successful (when RT_USING_PAGECACHE is enabled)
536  *
537  * @param[in] fs_name Name of the filesystem type to create (e.g., "elm", "romfs")
538  * @param[in] device_name Name of the device to create filesystem on (optional)
539  *
540  * @return int RT_EOK on success, negative error code on failure:
541  *             - RT_ERROR: General error
542  *             - ENODEV: Filesystem type not found or device not available
543  *
544  * @note For filesystems that don't require a device (FS_NEED_DEVICE not set),
545  *       the device_name parameter can be NULL
546  * @note Automatically unmounts any existing filesystem on the device
547  *       when RT_USING_PAGECACHE is enabled
548  * @note The function will fail if:
549  *       - The filesystem type is not found
550  *       - Device is required but not found
551  *       - The filesystem doesn't implement mkfs operation
552  */
dfs_mkfs(const char * fs_name,const char * device_name)553 int dfs_mkfs(const char *fs_name, const char *device_name)
554 {
555     rt_device_t dev_id = NULL;
556     struct dfs_filesystem_type *type;
557     int ret = -RT_ERROR;
558 
559     type = *_find_filesystem(fs_name);
560     if (!type)
561     {
562         rt_kprintf("no file system: %s found!\n", fs_name);
563         return ret;
564     }
565     else
566     {
567         if (type->fs_ops->flags & FS_NEED_DEVICE)
568         {
569             /* check device name, and it should not be NULL */
570             if (device_name != NULL)
571                 dev_id = rt_device_find(device_name);
572 
573             if (dev_id == NULL)
574             {
575                 rt_set_errno(-ENODEV);
576                 rt_kprintf("Device (%s) was not found", device_name);
577                 return ret;
578             }
579         }
580         else
581         {
582             dev_id = RT_NULL;
583         }
584     }
585 
586     if (type->fs_ops->mkfs)
587     {
588         ret = type->fs_ops->mkfs(dev_id, type->fs_ops->name);
589 #ifdef RT_USING_PAGECACHE
590         if (ret == RT_EOK)
591         {
592             struct dfs_mnt *mnt = RT_NULL;
593 
594             mnt = dfs_mnt_dev_lookup(dev_id);
595             if (mnt)
596             {
597                 dfs_pcache_unmount(mnt);
598             }
599         }
600 #endif
601     }
602 
603     return ret;
604 }
605 
606 /**
607  * @brief Get filesystem statistics for the specified path
608  *
609  * This function retrieves filesystem statistics (like total/available space)
610  * for the filesystem containing the given path. It performs the following operations:
611  * 1. Normalizes the input path
612  * 2. Looks up the mount point for the path
613  * 3. Calls the filesystem-specific statfs operation if available
614  *
615  * @param[in] path The path to query filesystem statistics for
616  * @param[out] buffer Pointer to statfs structure to store the results
617  *
618  * @return int RT_EOK on success, negative error code on failure:
619  *             - RT_ERROR: General error (invalid path or filesystem not found)
620  *
621  * @note The function will fail if:
622  *       - The path cannot be normalized
623  *       - No mount point is found for the path
624  *       - The filesystem doesn't implement statfs operation
625  *       - The filesystem is not currently mounted
626  * @note The buffer parameter must point to valid memory allocated by the caller
627  */
dfs_statfs(const char * path,struct statfs * buffer)628 int dfs_statfs(const char *path, struct statfs *buffer)
629 {
630     struct dfs_mnt *mnt;
631     char *fullpath;
632     int ret = -RT_ERROR;
633 
634     fullpath = dfs_normalize_path(NULL, path);
635     if (!fullpath)
636     {
637         return ret;
638     }
639 
640     DLOG(msg, "dfs_file", "mnt", DLOG_MSG, "dfs_mnt_lookup(%s)", fullpath);
641     mnt = dfs_mnt_lookup(fullpath);
642     if (mnt)
643     {
644         if (mnt->fs_ops->statfs)
645         {
646             if (dfs_is_mounted(mnt) == 0)
647             {
648                 ret = mnt->fs_ops->statfs(mnt, buffer);
649             }
650         }
651     }
652 
653     return ret;
654 }
655 
656 /**
657  * this function will return the mounted path for specified device.
658  *
659  * @param[in] device the device object which is mounted.
660  *
661  * @return the mounted path or NULL if none device mounted.
662  */
dfs_filesystem_get_mounted_path(struct rt_device * device)663 const char *dfs_filesystem_get_mounted_path(struct rt_device *device)
664 {
665     const char *path = NULL;
666 
667     return path;
668 }
669 
670 /**
671  * this function will fetch the partition table on specified buffer.
672  *
673  * @param[out] part the returned partition structure.
674  * @param[in] buf the buffer contains partition table.
675  * @param[in] pindex the index of partition table to fetch.
676  *
677  * @return RT_EOK on successful or -RT_ERROR on failed.
678  */
dfs_filesystem_get_partition(struct dfs_partition * part,uint8_t * buf,uint32_t pindex)679 int dfs_filesystem_get_partition(struct dfs_partition *part,
680                                  uint8_t *buf,
681                                  uint32_t pindex)
682 {
683 #define DPT_ADDRESS     0x1be       /* device partition offset in Boot Sector */
684 #define DPT_ITEM_SIZE   16          /* partition item size */
685 
686     uint8_t *dpt;
687     uint8_t type;
688 
689     RT_ASSERT(part != NULL);
690     RT_ASSERT(buf != NULL);
691 
692     dpt = buf + DPT_ADDRESS + pindex * DPT_ITEM_SIZE;
693 
694     /* check if it is a valid partition table */
695     if ((*dpt != 0x80) && (*dpt != 0x00))
696         return -EIO;
697 
698     /* get partition type */
699     type = *(dpt + 4);
700     if (type == 0)
701         return -EIO;
702 
703     /* set partition information
704      *    size is the number of 512-Byte */
705     part->type = type;
706     part->offset = *(dpt + 8) | *(dpt + 9) << 8 | *(dpt + 10) << 16 | *(dpt + 11) << 24;
707     part->size = *(dpt + 12) | *(dpt + 13) << 8 | *(dpt + 14) << 16 | *(dpt + 15) << 24;
708 
709     rt_kprintf("found part[%d], begin: %ld, size: ",
710                pindex, part->offset * 512);
711     if ((part->size >> 11) == 0)
712         rt_kprintf("%ld%s", part->size >> 1, "KB\n"); /* KB */
713     else
714     {
715         unsigned int part_size;
716         part_size = part->size >> 11;                /* MB */
717         if ((part_size >> 10) == 0)
718             rt_kprintf("%d.%ld%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
719         else
720             rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
721     }
722 
723     return RT_EOK;
724 }
725 
726 /* @} */