xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/uffs/uffs_mtb.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5 
6   UFFS is free software; you can redistribute it and/or modify it under
7   the GNU Library General Public License as published by the Free Software
8   Foundation; either version 2 of the License, or (at your option) any
9   later version.
10 
11   UFFS is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   or GNU Library General Public License, as applicable, for more details.
15 
16   You should have received a copy of the GNU General Public License
17   and GNU Library General Public License along with UFFS; if not, write
18   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   Boston, MA  02110-1301, USA.
20 
21   As a special exception, if other files instantiate templates or use
22   macros or inline functions from this file, or you compile this file
23   and link it with other works to produce a work based on this file,
24   this file does not by itself cause the resulting work to be covered
25   by the GNU General Public License. However the source code for this
26   file must still be made available in accordance with section (3) of
27   the GNU General Public License v2.
28 
29   This exception does not invalidate any other reasons why a work based
30   on this file might be covered by the GNU General Public License.
31 */
32 
33 /**
34  * \file uffs_mtb.c
35  * \brief mount table operations
36  * \author Ricky Zheng, created 11th July, 2009
37  */
38 #include "uffs_config.h"
39 #include "uffs/uffs_types.h"
40 #include "uffs/uffs_public.h"
41 #include "uffs/uffs_tree.h"
42 #include "uffs/uffs_mtb.h"
43 #include "uffs/uffs_fd.h"
44 #include "uffs/uffs_utils.h"
45 #include "uffs/uffs_fs.h"
46 #include <string.h>
47 
48 #define PFX "mtb : "
49 
50 static struct uffs_MountTableEntrySt *m_head = NULL;		// list of mounted entries
51 static struct uffs_MountTableEntrySt *m_free_head = NULL;	// list of unmounted entries
52 
53 /** Return mounted entries header */
uffs_MtbGetMounted(void)54 uffs_MountTable * uffs_MtbGetMounted(void)
55 {
56 	return m_head;
57 }
58 
59 /** Return unmounted entries header */
uffs_MtbGetUnMounted(void)60 uffs_MountTable * uffs_MtbGetUnMounted(void)
61 {
62 	return m_free_head;
63 }
64 
65 /**
66  * \brief Register mount table
67  * \param mtb mount table entry
68  * \return 0 succ
69  *         -1 failed (e.g. already registered and mounted)
70  */
uffs_RegisterMountTable(uffs_MountTable * mtb)71 int uffs_RegisterMountTable(uffs_MountTable *mtb)
72 {
73 	uffs_MountTable *work = NULL;
74 	static int dev_num = 0;
75 
76 	if (mtb == NULL)
77 		return -1;
78 
79 	for (work = m_head; work; work = work->next) {
80 		if (work == mtb)
81 			return -1; // already mounted ?
82 	}
83 
84 	for (work = m_free_head; work; work = work->next) {
85 		if (work == mtb)
86 			return 0; // already registered.
87 	}
88 
89 	/* replace the free head */
90 	if (m_free_head)
91 		m_free_head->prev = mtb;
92 	mtb->prev = NULL;
93 	mtb->next = m_free_head;
94 	m_free_head = mtb;
95 
96 	mtb->dev->dev_num = ++dev_num;
97 
98 	return 0;
99 }
100 
101 /**
102  * \brief Remove mount entry from the table
103  * \param mtb mount table entry
104  * \return 0 removed succ
105  *         -1 entry in used or not in the 'unmounted' list
106  */
uffs_UnRegisterMountTable(uffs_MountTable * mtb)107 int uffs_UnRegisterMountTable(uffs_MountTable *mtb)
108 {
109 	uffs_MountTable *work = NULL;
110 
111 	if (mtb == NULL)
112 		return -1;
113 
114 	for (work = m_head; work; work = work->next) {
115 		if (work == mtb)
116 			return -1;	// in the mounted list ? busy, return
117 	}
118 
119 	for (work = m_free_head; work; work = work->next) {
120 		if (work == mtb) {
121 			// found, remove it from the list
122 			if (work->next)
123 				work->next->prev = work->prev;
124 			if (work->prev)
125 				work->prev->next = work->next;
126 			if (work == m_free_head)
127 				m_free_head = work->next;
128 
129 			break;
130 		}
131 	}
132 
133 	return work ? 0 : -1;
134 }
135 
uffs_GetMountTableByMountPoint(const char * mount,uffs_MountTable * head)136 static uffs_MountTable * uffs_GetMountTableByMountPoint(const char *mount, uffs_MountTable *head)
137 {
138 	uffs_MountTable *work = NULL;
139 
140 	for (work = head; work; work = work->next) {
141 		if (strcmp(work->mount, mount) == 0)
142 			break;
143 	}
144 	return work;
145 }
146 
147 /**
148  * \brief mount partition
149  * \param[in] mount partition mount point
150  * \return 0 succ
151  *         <0 fail
152  *
153  * \note use uffs_RegisterMountTable() register mount entry before you can mount it.
154  *       mount point should ended with '/', e.g. '/sys/'
155  */
uffs_Mount(const char * mount)156 int uffs_Mount(const char *mount)
157 {
158 	uffs_MountTable *mtb;
159 
160 	if (uffs_GetMountTableByMountPoint(mount, m_head) != NULL) {
161 		uffs_Perror(UFFS_MSG_NOISY,	"'%s' already mounted", mount);
162 		return -1; // already mounted ?
163 	}
164 
165 	mtb = uffs_GetMountTableByMountPoint(mount, m_free_head);
166 	if (mtb == NULL) {
167 		uffs_Perror(UFFS_MSG_NOISY,	"'%s' not registered", mount);
168 		return -1;	// not registered ?
169 	}
170 
171 	uffs_Perror(UFFS_MSG_NOISY,
172 				"init device for mount point %s ...",
173 				mtb->mount);
174 
175 	mtb->dev->par.start = mtb->start_block;
176 	if (mtb->end_block < 0) {
177 		mtb->dev->par.end =
178 			mtb->dev->attr->total_blocks + mtb->end_block;
179 	}
180 	else {
181 		mtb->dev->par.end = mtb->end_block;
182 	}
183 
184 	if (mtb->dev->Init(mtb->dev) == U_FAIL) {
185 		uffs_Perror(UFFS_MSG_SERIOUS,
186 					"init device for mount point %s fail",
187 					mtb->mount);
188 		return -1;
189 	}
190 
191 	uffs_Perror(UFFS_MSG_NOISY, "mount partiton: %d,%d",
192 		mtb->dev->par.start, mtb->dev->par.end);
193 
194 	if (uffs_InitDevice(mtb->dev) != U_SUCC) {
195 		uffs_Perror(UFFS_MSG_SERIOUS, "init device fail !");
196 		return -1;
197 	}
198 
199 	/* now break it from unmounted list */
200 	if (mtb->prev)
201 		mtb->prev->next = mtb->next;
202 	if (mtb->next)
203 		mtb->next->prev = mtb->prev;
204 	if (m_free_head == mtb)
205 		m_free_head = mtb->next;
206 
207 	/* link to mounted list */
208 	mtb->prev = NULL;
209 	mtb->next = m_head;
210 	if (m_head)
211 		m_head->prev = mtb;
212 	m_head = mtb;
213 
214 	return 0;
215 }
216 
217 /**
218  * \brief unmount parttion
219  * \param[in] mount partition mount point
220  * \return 0 succ
221  *         <0 fail
222  */
uffs_UnMount(const char * mount)223 int uffs_UnMount(const char *mount)
224 {
225 	uffs_MountTable *mtb = uffs_GetMountTableByMountPoint(mount, m_head);
226 
227 	if (mtb == NULL) {
228 		uffs_Perror(UFFS_MSG_NOISY,	"'%s' not mounted ?", mount);
229 		return -1;  // not mounted ?
230 	}
231 
232 	if (uffs_GetMountTableByMountPoint(mount, m_free_head) != NULL) {
233 		uffs_Perror(UFFS_MSG_NOISY,	"'%s' already unmounted ?", mount);
234 		return -1;  // already unmounted ?
235 	}
236 
237 	if (mtb->dev->ref_count != 0) {
238 		uffs_Perror(UFFS_MSG_NORMAL, "Can't unmount '%s' - busy", mount);
239 		return -1;
240 	}
241 
242 	if (uffs_ReleaseDevice(mtb->dev) == U_FAIL) {
243 		uffs_Perror(UFFS_MSG_NORMAL, "Can't release device for mount point '%s'", mount);
244 		return -1;
245 	}
246 
247 	mtb->dev->Release(mtb->dev);
248 
249 	// break from mounted list
250 	if (mtb->prev)
251 		mtb->prev->next = mtb->next;
252 	if (mtb->next)
253 		mtb->next->prev = mtb->prev;
254 	if (mtb == m_head)
255 		m_head = mtb->next;
256 
257 	// put to unmounted list
258 	mtb->prev = NULL;
259 	mtb->next = m_free_head;
260 	if (m_free_head)
261 		m_free_head->prev = mtb;
262 	m_free_head = mtb;
263 
264 	return 0;
265 }
266 
267 /**
268  * find the matched mount point from a given full absolute path.
269  *
270  * \param[in] path full path
271  * \return the length of mount point.
272  */
uffs_GetMatchedMountPointSize(const char * path)273 int uffs_GetMatchedMountPointSize(const char *path)
274 {
275 	int pos;
276 	uffs_Device *dev;
277 
278 	if (path[0] != '/')
279 		return 0;
280 
281 	pos = strlen(path);
282 
283 	while (pos > 0) {
284 		if ((dev = uffs_GetDeviceFromMountPointEx(path, pos)) != NULL ) {
285 			uffs_PutDevice(dev);
286 			return pos;
287 		}
288 		else {
289 			if (path[pos-1] == '/')
290 				pos--;
291 			//back forward search the next '/'
292 			for (; pos > 0 && path[pos-1] != '/'; pos--)
293 				;
294 		}
295 	}
296 
297 	return pos;
298 }
299 
300 /**
301  * get device from mount point.
302  *
303  * \param[in] mount mount point name.
304  * \return NULL if mount point is not found.
305  */
uffs_GetDeviceFromMountPoint(const char * mount)306 uffs_Device * uffs_GetDeviceFromMountPoint(const char *mount)
307 {
308 	uffs_MountTable *mtb = uffs_GetMountTableByMountPoint(mount, m_head);
309 
310 	if (mtb) {
311 		mtb->dev->ref_count++;
312 		return mtb->dev;
313 	}
314 
315 	return NULL;
316 }
317 
318 /**
319  * get device from mount point.
320  *
321  * \param[in] mount mount point name.
322  * \param[in] len mount point name length.
323  * \return NULL if mount point is not found.
324  */
uffs_GetDeviceFromMountPointEx(const char * mount,int len)325 uffs_Device * uffs_GetDeviceFromMountPointEx(const char *mount, int len)
326 {
327 	uffs_MountTable *work = NULL;
328 
329 	for (work = m_head; work; work = work->next) {
330 		if (strlen(work->mount) == len &&
331 				strncmp(mount, work->mount, len) == 0) {
332 			work->dev->ref_count++;
333 			return work->dev;
334 		}
335 	}
336 
337 	return NULL;
338 }
339 
340 
341 /**
342  * return mount point from device
343  *
344  * \param[in] dev uffs device
345  * \return NULL if mount point is not found,
346  *		otherwise return mount point name in mount table.
347  */
uffs_GetDeviceMountPoint(uffs_Device * dev)348 const char * uffs_GetDeviceMountPoint(uffs_Device *dev)
349 {
350 	uffs_MountTable *work = NULL;
351 
352 	for (work = m_head; work; work = work->next) {
353 		if (work->dev == dev) {
354 			return work->mount;
355 		}
356 	}
357 
358 	return NULL;
359 }
360 
uffs_PutDevice(uffs_Device * dev)361 void uffs_PutDevice(uffs_Device *dev)
362 {
363 	dev->ref_count--;
364 }
365 
366 
367