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