• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "virpart.h"
33 #include "errno.h"
34 #include "fatfs.h"
35 #include "errcode_fat.h"
36 #include "disk.h"
37 #include "fs/mount.h"
38 
39 #ifdef LOSCFG_FS_FAT_CACHE
40 #include "bcache.h"
41 #endif
42 
43 #include "virpartff.h"
44 
45 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
46 
47 char g_devPartName[DISK_NAME + 1] = {0};
48 
FatFsCheckPercent(virpartinfo * virtualinfo)49 static INT FatFsCheckPercent(virpartinfo *virtualinfo)
50 {
51     double virtPercent = 0.0;
52     INT partCount;
53 
54     for (partCount = 0; partCount < virtualinfo->virpartnum; partCount++) {
55         if (virtualinfo->virpartpercent[partCount] <= _FLOAT_ACC ||
56             virtualinfo->virpartpercent[partCount] >= (1 - _FLOAT_ACC)) {
57             set_errno(VIRERR_PARMPERCENTERR);
58             g_fatVirPart.isparamset = FALSE;
59             return -1;
60         }
61         virtPercent += virtualinfo->virpartpercent[partCount];
62     }
63 
64     if (virtPercent >= (1 + _FLOAT_ACC)) {
65         set_errno(VIRERR_PARMPERCENTERR);
66         g_fatVirPart.isparamset = FALSE;
67         return -1;
68     }
69 
70     return 0;
71 }
72 
FatFsCheckName(virpartinfo * virtualinfo)73 static INT FatFsCheckName(virpartinfo *virtualinfo)
74 {
75     INT partCount, loopCount, len;
76     FRESULT res;
77 
78     for (partCount = 0; partCount < virtualinfo->virpartnum; partCount++) {
79         len = ff_strnlen(virtualinfo->virpartname[partCount], _MAX_ENTRYLENGTH + 1);
80         if (len <= 0 || len > _MAX_ENTRYLENGTH) {
81             set_errno(VIRERR_PARMNAMEERR);
82             g_fatVirPart.isparamset = FALSE;
83             return -1;
84         }
85 
86         res = f_checkname(virtualinfo->virpartname[partCount]);
87         if (res != FR_OK) {
88             set_errno(VIRERR_PARMNAMEERR);
89             g_fatVirPart.isparamset = FALSE;
90             return -1;
91         }
92     }
93 
94     for (partCount = 0; partCount < virtualinfo->virpartnum; partCount++) {
95         for (loopCount = partCount + 1; loopCount < virtualinfo->virpartnum; loopCount++) {
96             if ((memcmp(virtualinfo->virpartname[partCount], virtualinfo->virpartname[loopCount],
97                         _MAX_ENTRYLENGTH)) == 0) {
98                 set_errno(VIRERR_PARMNAMEERR);
99                 g_fatVirPart.isparamset = FALSE;
100                 return -1;
101             }
102         }
103     }
104 
105     return 0;
106 }
107 
los_set_virpartparam(virpartinfo virtualinfo)108 INT los_set_virpartparam(virpartinfo virtualinfo)
109 {
110     INT ret;
111     UINT minSize;
112     UINT dstNameSize;
113     char devHead[DISK_NAME + 1] = "/dev/";
114 
115     g_fatVirPart.virtualinfo.devpartpath = g_devPartName;
116 
117     if (g_fatVirPart.isparamset == TRUE) {
118         set_errno(VIRERR_PARMLOCKED);
119         return -1;
120     }
121 
122     g_fatVirPart.isparamset = TRUE;
123 
124     if (virtualinfo.virpartnum < 1 || virtualinfo.virpartnum > _MAX_VIRVOLUMES) {
125         set_errno(VIRERR_PARMNUMERR);
126         g_fatVirPart.isparamset = FALSE;
127         return -1;
128     }
129 
130     ret = FatFsCheckPercent(&virtualinfo);
131     if (ret != 0) {
132         return ret;
133     }
134 
135     ret = FatFsCheckName(&virtualinfo);
136     if (ret != 0) {
137         return ret;
138     }
139 
140     if (strlen(virtualinfo.devpartpath) <= strlen(devHead)) {
141         set_errno(VIRERR_PARMDEVERR);
142         g_fatVirPart.isparamset = FALSE;
143         return -1;
144     }
145 
146     if (memcmp(virtualinfo.devpartpath, devHead, strlen(devHead)) != 0) {
147         set_errno(VIRERR_PARMDEVERR);
148         g_fatVirPart.isparamset = FALSE;
149         return -1;
150     }
151 
152     dstNameSize = sizeof(g_devPartName);
153     minSize = dstNameSize < strlen(virtualinfo.devpartpath) ? dstNameSize : strlen(virtualinfo.devpartpath);
154     ret = strncpy_s(g_fatVirPart.virtualinfo.devpartpath, dstNameSize, virtualinfo.devpartpath, minSize);
155     if (ret != EOK) {
156         set_errno(VIRERR_PARMNAMEERR);
157         g_fatVirPart.isparamset = FALSE;
158         return -1;
159     }
160     g_fatVirPart.virtualinfo.devpartpath[dstNameSize - 1] = '\0';
161 
162     (void)memcpy_s(g_fatVirPart.virtualinfo.virpartname, sizeof(g_fatVirPart.virtualinfo.virpartname),
163                    virtualinfo.virpartname, sizeof(virtualinfo.virpartname));
164     (void)memcpy_s(g_fatVirPart.virtualinfo.virpartpercent, sizeof(g_fatVirPart.virtualinfo.virpartpercent),
165                    virtualinfo.virpartpercent, sizeof(virtualinfo.virpartpercent));
166     g_fatVirPart.virtualinfo.virpartnum = virtualinfo.virpartnum;
167 
168     return 0;
169 }
170 
FatfsDisablePart(void * handle)171 static INT FatfsDisablePart(void *handle)
172 {
173     FATFS *fs = (FATFS *)handle;
174     return fatfs_2_vfs(f_disvirfs(fs));
175 }
176 
177 /*
178  * FatfsScanFat:
179  * Scan the FAT inside the boundary of CHILD FATFS limit, and update the free cluster and last cluster
180  * for all CHILD FATFS.
181  * Acceptable Return Value:
182  * - FR_OK              : Successfully scanned the FAT and update field.
183  * Others Return Value:
184  * - FR_INVAILD_FATFS   : The FATFS object has error or the info in it has been occuried
185  * - FR_DENIED          : The virtual partition feature has been shut down by switcher
186  * - FR_DISK_ERR        : A disk error happened
187  */
FatfsScanFat(void * handle)188 static INT FatfsScanFat(void *handle)
189 {
190     FATFS *fat = (FATFS *)handle;
191     UINT i;
192     INT ret = FR_OK;
193 
194     for (i = 0; i < fat->vir_amount; i++) {
195         /* Assert error will not abort the scanning process */
196         ret = f_scanfat(CHILDFS(fat, i));
197         if (ret != FR_OK) {
198             break;
199         }
200     }
201 
202     return fatfs_2_vfs(ret);
203 }
204 
205 /*
206  * FatfsScanClear:
207  * Scan the root directory clean completely, regardless of the virtual partition entry.
208  * Acceptable Return Value:
209  * - FR_OK          : The root directory is completely clean.
210  * - FR_NOTCLEAR    : The root dircotory is not clean.
211  * Others Return Value:
212  * Followed the by the lower API.
213  */
FatfsScanClear(INT vol)214 static FRESULT FatfsScanClear(INT vol)
215 {
216     FRESULT ret;
217     DIR dir;
218     FILINFO fno;
219     CHAR path[MAX_LFNAME_LENGTH];
220     INT num;
221     INT res;
222 
223     /* num : for the amount of all item in root directory */
224     num = 0;
225 
226     (void)memset_s(path, sizeof(path), 0, sizeof(path));
227 
228     res = snprintf_s(path, MAX_LFNAME_LENGTH, MAX_LFNAME_LENGTH - 1, "%d:/", vol);
229     if (res < 0) {
230         return FR_INVALID_NAME;
231     }
232 
233     ret = f_opendir(&dir, path);
234     if (ret != FR_OK) {
235         return ret;
236     }
237 
238     /* Scan all entry for searching virtual partition directory and others in root directory */
239     while (1) {
240         (void)memset_s(&fno, sizeof(FILINFO), 0, sizeof(FILINFO));
241         ret = f_readdir(&dir, &fno);
242         /* Reach the end of directory, or the root direcotry is empty, abort the scanning operation */
243         if (fno.fname[0] == 0x00 || fno.fname[0] == (TCHAR)0xFF) {
244             break;
245         }
246 
247         if (ret != FR_OK) {
248             (void)f_closedir(&dir);
249             return ret;
250         }
251         num++;
252     }
253 
254     /* Close the directory */
255     ret = f_closedir(&dir);
256     if ((ret == FR_OK) && (num != 0)) {
257         return FR_NOTCLEAR;
258     }
259 
260     return ret;
261 }
262 
263 /*
264  * FatfsBuildEntry:
265  * Scan virtual partition entry in root directory, and try to rebuild the
266  * error virtual partition, according to the scanning result.
267  * Acceptable Return Value:
268  * - FR_OK          : The root directory is completely clean.
269  * - FR_OCCUPIED    : The virtual partition entry has been occupied by the same name file.
270  * - FR_CHAIN_ERR   : The virtual partition entry has been rebuilt along the invalid cluster
271  *                    chain.
272  * Others Return Value:
273  * Followed the by the lower API
274  */
FatfsBuildEntry(FATFS * fat,INT vol)275 static FRESULT FatfsBuildEntry(FATFS *fat, INT vol)
276 {
277     UINT i;
278     CHAR path[MAX_LFNAME_LENGTH];
279     FRESULT ret;
280     DIR dir;
281     INT res;
282 
283     for (i = 0; i < fat->vir_amount; i++) {
284         res = snprintf_s(path, MAX_LFNAME_LENGTH, MAX_LFNAME_LENGTH - 1, "%d:%s", vol, CHILDFS(fat, i)->namelabel);
285         if (res < 0) {
286             return FR_INVALID_NAME;
287         }
288 
289         ret = f_mkdir(path);
290         if (ret == FR_EXIST) {
291             (void)memset_s(&dir, sizeof(dir), 0, sizeof(dir));
292             ret = f_opendir(&dir, path);
293             if (ret == FR_NO_DIR) {
294                 return FR_OCCUPIED;
295             }
296             if (ret == FR_OK) {
297                 ret = f_boundary(CHILDFS(fat, i), dir.obj.sclust);
298                 if (ret != FR_OK) {
299                     (void)f_closedir(&dir);
300                     return ret;
301                 }
302             } else {
303                 return ret;
304             }
305             ret = f_closedir(&dir);
306             if (ret != FR_OK) {
307                 return ret;
308             }
309         } else if (ret != FR_OK) {
310             return ret;
311         }
312     }
313 
314     return FR_OK;
315 }
316 
317 /*
318  * FatFsUnbindVirPart:
319  * Uninitialized the CHILD FATFS object
320  *
321  * Acceptable Return Value:
322  * - ENOERR : Successfully initialized the CHILD FATFS object.
323  */
FatFsUnbindVirPart(void * handle)324 INT FatFsUnbindVirPart(void *handle)
325 {
326     INT ret;
327     FATFS *fat = (FATFS *)handle;
328     ret = f_unregvirfs(fat);
329     return fatfs_2_vfs(ret);
330 }
331 
332 /*
333  * FatFsBindVirPart:
334  * Bind the virtual partition
335  *
336  * Acceptable Return Value:
337  * - FR_OK : Finished the virtual partition.
338  * The virtual partition result can refer by API
339  */
FatFsBindVirPart(void * handle,BYTE vol)340 INT FatFsBindVirPart(void *handle, BYTE vol)
341 {
342     INT ret;
343     FATFS *fat = (FATFS *)handle;
344     char path[MAX_LFNAME_LENGTH] = {0};
345 
346     if (fat == NULL) {
347         return -EINVAL;
348     }
349 
350     ret = snprintf_s(path, sizeof(path), sizeof(path) - 1, "%u:/", vol);
351     if (ret < 0) {
352         return -EINVAL;
353     }
354 
355     /* Detect the information in the reserve sector and try to set virtual partition by sector info */
356     ret = f_checkvirpart(fat, path, vol);
357     if (ret == FR_NOVIRPART) {
358         /* Failed to use the External SD setting, try to use the current setting to external SD and rebuild entries */
359         /* Check the enviorment whether it is fit for virtual parition */
360         ret = FatfsScanClear(vol);
361         if (ret != FR_OK) {
362             /* A error happened in the file operation */
363             (void)FatfsDisablePart(fat);
364             return fatfs_2_vfs(ret);
365         }
366         /* Ready to fit the SD card to virtual partition featrue */
367         ret = f_makevirpart(fat, path, vol);
368         if (ret != FR_OK) {
369             (void)FatfsDisablePart(fat);
370             return fatfs_2_vfs(ret);
371         }
372     } else if (ret != FR_OK) {
373         return fatfs_2_vfs(ret);
374     }
375     /* Try to build the virtual entry */
376     ret = FatfsBuildEntry(fat, vol);
377     if (ret != FR_OK) {
378         (void)FatfsDisablePart(fat);
379         return fatfs_2_vfs(ret);
380     }
381 #ifdef LOSCFG_FS_FAT_CACHE
382     los_part *part = NULL;
383     if (ret == FR_OK) {
384         part = get_part((int)fat->pdrv);
385         if (part != NULL) {
386             ret = OsSdSync(part->disk_id);
387             if (ret < 0) {
388                 ret = -EIO;
389             }
390         } else {
391             return -ENODEV;
392         }
393     }
394 #endif
395     if (ret == FR_OK) {
396         ret = FatfsScanFat(fat);
397         if (ret != FR_OK) {
398             (void)FatfsDisablePart(fat);
399             return fatfs_2_vfs(ret);
400         }
401     }
402     return fatfs_2_vfs(ret);
403 }
404 
405 /*
406  * FatFsMakeVirPart:
407  * Bind the virtual partition
408  *
409  * Acceptable Return Value:
410  * - FR_OK : Finished the virtual partition.
411  * The virtual partition result can refer by API
412  */
FatFsMakeVirPart(void * handle,BYTE vol)413 INT FatFsMakeVirPart(void *handle, BYTE vol)
414 {
415     INT ret;
416     FATFS *fat = (FATFS *)handle;
417     char path[MAX_LFNAME_LENGTH] = {0};
418 
419     if (fat == NULL) {
420         return -EINVAL;
421     }
422 
423     ret = snprintf_s(path, sizeof(path), sizeof(path) - 1, "%u:/", vol);
424     if (ret < 0) {
425         return -EINVAL;
426     }
427 
428     /* Ready to fit the SD card to virtual partition featrue */
429     ret = f_makevirpart(fat, path, vol);
430     if (ret != FR_OK) {
431         (void)FatfsDisablePart(fat);
432         return fatfs_2_vfs(ret);
433     }
434 
435     /* Try to build the virtual entry */
436     ret = FatfsBuildEntry(fat, vol);
437     if (ret != FR_OK) {
438         (void)FatfsDisablePart(fat);
439         return fatfs_2_vfs(ret);
440     }
441 
442     return fatfs_2_vfs(ret);
443 }
444 
fatfs_virstatfs_internel(struct Vnode * mountpt,const char * relpath,struct statfs * buf)445 INT fatfs_virstatfs_internel(struct Vnode *mountpt, const char *relpath, struct statfs *buf)
446 {
447     char drive[MAX_LFNAME_LENGTH];
448     DWORD freClust, allClust;
449     FATFS *fat = NULL;
450     INT result, vol;
451 
452     fat = (FATFS *)(mountpt->originMount->data);
453     if (fat == NULL) {
454         return -EINVAL;
455     }
456 
457     if (fat->vir_flag != FS_PARENT) {
458         return -EINVAL;
459     }
460 
461     vol = fatfs_get_vol(fat);
462     if (vol < 0 || vol > FF_VOLUMES) {
463         return -ENOENT;
464     }
465 
466     if (strlen(relpath) > MAX_LFNAME_LENGTH) {
467         return -EFAULT;
468     }
469 
470     result = snprintf_s(drive, sizeof(drive), sizeof(drive) - 1, "%d:%s", vol, relpath);
471     if (result < 0) {
472         return -EINVAL;
473     }
474 
475     result = f_getvirfree(drive, &freClust, &allClust);
476     if (result != FR_OK) {
477         result = fatfs_2_vfs(result);
478         goto EXIT;
479     }
480 
481     (void)memset_s((void *)buf, sizeof(struct statfs), 0, sizeof(struct statfs));
482     buf->f_type = MSDOS_SUPER_MAGIC;
483     buf->f_bfree = freClust;
484     buf->f_bavail = freClust;
485     buf->f_blocks = allClust;
486 #if FF_MAX_SS != FF_MIN_SS
487     buf->f_bsize = fat->ssize * fat->csize;
488 #else
489     buf->f_bsize = FF_MIN_SS * fat->csize;
490 #endif
491 #if FF_USE_LFN
492     buf->f_namelen = FF_MAX_LFN; /* Maximum length of filenames */
493 #else
494     /*
495      * Maximum length of filenames,'8' is the effective length, '1' is the terminator,
496      * and '3' is the special length
497      */
498     buf->f_namelen = (8 + 1 + 3);
499 #endif
500 
501 EXIT:
502     return result;
503 }
504 
505 #endif
506