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