1 /*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
2  *
3  *                 Copyright (c) 2014-2015 Datalight, Inc.
4  *                     All Rights Reserved Worldwide.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; use version 2 of the License.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
12  *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 /*  Businesses and individuals that for commercial or other reasons cannot
21  *  comply with the terms of the GPLv2 license may obtain a commercial license
22  *  before incorporating Reliance Edge into proprietary software for
23  *  distribution in any form.  Visit http://www.datalight.com/reliance-edge for
24  *  more information.
25  */
26 
27 /** @file
28  *  @brief Implements the Reliance Edge file system formatter.
29  */
30 #include <redfs.h>
31 #include <redcoreapi.h>
32 #include <redcore.h>
33 
34 #if FORMAT_SUPPORTED
35 
36 
37 /** @brief Format a file system volume.
38  *
39  *  @return A negated ::REDSTATUS code indicating the operation result.
40  *
41  *  @retval 0           Operation was successful.
42  *  @retval -RED_EBUSY  Volume is mounted.
43  *  @retval -RED_EIO    A disk I/O error occurred.
44  */
RedVolFormat(void)45     REDSTATUS RedVolFormat( void )
46     {
47         REDSTATUS ret;
48 
49         if( gpRedVolume->fMounted )
50         {
51             ret = -RED_EBUSY;
52         }
53         else
54         {
55             ret = RedOsBDevOpen( gbRedVolNum, BDEV_O_RDWR );
56         }
57 
58         if( ret == 0 )
59         {
60             MASTERBLOCK * pMB;
61             REDSTATUS ret2;
62 
63             /*  Overwrite the master block with zeroes, so that if formatting is
64              *  interrupted, the volume will not be mountable.
65              */
66             ret = RedBufferGet( BLOCK_NUM_MASTER, BFLAG_NEW | BFLAG_DIRTY, CAST_VOID_PTR_PTR( &pMB ) );
67 
68             if( ret == 0 )
69             {
70                 ret = RedBufferFlush( BLOCK_NUM_MASTER, 1U );
71 
72                 RedBufferDiscard( pMB );
73             }
74 
75             if( ret == 0 )
76             {
77                 ret = RedIoFlush( gbRedVolNum );
78             }
79 
80             #if REDCONF_IMAP_EXTERNAL == 1
81                 if( ( ret == 0 ) && !gpRedCoreVol->fImapInline )
82                 {
83                     uint32_t ulImapBlock;
84                     uint32_t ulImapBlockLimit = gpRedCoreVol->ulImapStartBN + ( gpRedCoreVol->ulImapNodeCount * 2U );
85                     uint16_t uImapFlags = ( uint16_t ) ( ( uint32_t ) BFLAG_META_IMAP | BFLAG_NEW | BFLAG_DIRTY );
86 
87                     /*  Technically it is only necessary to create one copy of each imap
88                      *  node (the copy the metaroot points at), but creating them both
89                      *  avoids headaches during disk image analysis from stale imaps
90                      *  left over from previous formats.
91                      */
92                     for( ulImapBlock = gpRedCoreVol->ulImapStartBN; ulImapBlock < ulImapBlockLimit; ulImapBlock++ )
93                     {
94                         IMAPNODE * pImap;
95 
96                         ret = RedBufferGet( ulImapBlock, uImapFlags, CAST_VOID_PTR_PTR( &pImap ) );
97 
98                         if( ret != 0 )
99                         {
100                             break;
101                         }
102 
103                         RedBufferPut( pImap );
104                     }
105                 }
106             #endif /* if REDCONF_IMAP_EXTERNAL == 1 */
107 
108             /*  Write the first metaroot.
109              */
110             if( ret == 0 )
111             {
112                 RedMemSet( gpRedMR, 0U, sizeof( *gpRedMR ) );
113 
114                 gpRedMR->ulFreeBlocks = gpRedVolume->ulBlocksAllocable;
115                 #if REDCONF_API_POSIX == 1
116                     gpRedMR->ulFreeInodes = gpRedVolConf->ulInodeCount;
117                 #endif
118                 gpRedMR->ulAllocNextBlock = gpRedCoreVol->ulFirstAllocableBN;
119 
120                 /*  The branched flag is typically set automatically when bits in
121                  *  the imap change.  It is set here explicitly because the imap has
122                  *  only been initialized, not changed.
123                  */
124                 gpRedCoreVol->fBranched = true;
125 
126                 ret = RedVolTransact();
127             }
128 
129             #if REDCONF_API_POSIX == 1
130 
131                 /*  Create the root directory.
132                  */
133                 if( ret == 0 )
134                 {
135                     CINODE rootdir;
136 
137                     rootdir.ulInode = INODE_ROOTDIR;
138                     ret = RedInodeCreate( &rootdir, INODE_INVALID, RED_S_IFDIR );
139 
140                     if( ret == 0 )
141                     {
142                         RedInodePut( &rootdir, 0U );
143                     }
144                 }
145             #endif /* if REDCONF_API_POSIX == 1 */
146 
147             #if REDCONF_API_FSE == 1
148 
149                 /*  The FSE API does not support creating or deletes files, so all the
150                  *  inodes are created during setup.
151                  */
152                 if( ret == 0 )
153                 {
154                     uint32_t ulInodeIdx;
155 
156                     for( ulInodeIdx = 0U; ulInodeIdx < gpRedVolConf->ulInodeCount; ulInodeIdx++ )
157                     {
158                         CINODE ino;
159 
160                         ino.ulInode = INODE_FIRST_FREE + ulInodeIdx;
161                         ret = RedInodeCreate( &ino, INODE_INVALID, RED_S_IFREG );
162 
163                         if( ret == 0 )
164                         {
165                             RedInodePut( &ino, 0U );
166                         }
167                     }
168                 }
169             #endif /* if REDCONF_API_FSE == 1 */
170 
171             /*  Write the second metaroot.
172              */
173             if( ret == 0 )
174             {
175                 ret = RedVolTransact();
176             }
177 
178             /*  Populate and write out the master block.
179              */
180             if( ret == 0 )
181             {
182                 ret = RedBufferGet( BLOCK_NUM_MASTER, ( uint16_t ) ( ( uint32_t ) BFLAG_META_MASTER | BFLAG_NEW | BFLAG_DIRTY ), CAST_VOID_PTR_PTR( &pMB ) );
183             }
184 
185             if( ret == 0 )
186             {
187                 pMB->ulVersion = RED_DISK_LAYOUT_VERSION;
188                 RedStrNCpy( pMB->acBuildNum, RED_BUILD_NUMBER, sizeof( pMB->acBuildNum ) );
189                 pMB->ulFormatTime = RedOsClockGetTime();
190                 pMB->ulInodeCount = gpRedVolConf->ulInodeCount;
191                 pMB->ulBlockCount = gpRedVolume->ulBlockCount;
192                 pMB->uMaxNameLen = REDCONF_NAME_MAX;
193                 pMB->uDirectPointers = REDCONF_DIRECT_POINTERS;
194                 pMB->uIndirectPointers = REDCONF_INDIRECT_POINTERS;
195                 pMB->bBlockSizeP2 = BLOCK_SIZE_P2;
196 
197                 #if REDCONF_API_POSIX == 1
198                     pMB->bFlags |= MBFLAG_API_POSIX;
199                 #endif
200                 #if REDCONF_INODE_TIMESTAMPS == 1
201                     pMB->bFlags |= MBFLAG_INODE_TIMESTAMPS;
202                 #endif
203                 #if REDCONF_INODE_BLOCKS == 1
204                     pMB->bFlags |= MBFLAG_INODE_BLOCKS;
205                 #endif
206                 #if ( REDCONF_API_POSIX == 1 ) && ( REDCONF_API_POSIX_LINK == 1 )
207                     pMB->bFlags |= MBFLAG_INODE_NLINK;
208                 #endif
209 
210                 ret = RedBufferFlush( BLOCK_NUM_MASTER, 1U );
211 
212                 RedBufferPut( pMB );
213             }
214 
215             if( ret == 0 )
216             {
217                 ret = RedIoFlush( gbRedVolNum );
218             }
219 
220             ret2 = RedOsBDevClose( gbRedVolNum );
221 
222             if( ret == 0 )
223             {
224                 ret = ret2;
225             }
226         }
227 
228         /*  Discard the buffers so a subsequent format will not run into blocks it
229          *  does not expect.
230          */
231         if( ret == 0 )
232         {
233             ret = RedBufferDiscardRange( 0U, gpRedVolume->ulBlockCount );
234         }
235 
236         return ret;
237     }
238 
239 
240 #endif /* FORMAT_SUPPORTED */
241