Annotation of truecrypt/common/fat.c, revision 1.1.1.20

1.1.1.10  root        1: /*
1.1.1.12  root        2:  Legal Notice: Some portions of the source code contained in this file were
                      3:  derived from the source code of Encryption for the Masses 2.02a, which is
                      4:  Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
                      5:  Agreement for Encryption for the Masses'. Modifications and additions to
1.1.1.18  root        6:  the original source code (contained in this file) and all other portions
1.1.1.19  root        7:  of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association
                      8:  and are governed by the TrueCrypt License 3.0 the full text of which is
1.1.1.18  root        9:  contained in the file License.txt included in TrueCrypt binary and source
                     10:  code distribution packages. */
1.1.1.10  root       11: 
                     12: #include <stdlib.h>
                     13: #include <string.h>
                     14: #include <time.h>
1.1.1.6   root       15: 
                     16: #include "Tcdefs.h"
                     17: 
                     18: #include "Crypto.h"
1.1.1.10  root       19: #include "Common/Endian.h"
1.1.1.6   root       20: #include "Format.h"
                     21: #include "Fat.h"
                     22: #include "Progress.h"
1.1.1.8   root       23: #include "Random.h"
1.1.1.19  root       24: #include "Volumes.h"
1.1       root       25: 
                     26: void
                     27: GetFatParams (fatparams * ft)
                     28: {
1.1.1.19  root       29:        uint64 volumeSize = (uint64) ft->num_sectors * ft->sector_size;
1.1.1.10  root       30:        unsigned int fatsecs;
1.1.1.19  root       31: 
1.1.1.5   root       32:        if(ft->cluster_size == 0)       // 'Default' cluster size
1.1       root       33:        {
1.1.1.19  root       34:                uint32 clusterSize;
                     35: 
                     36:                // Determine optimal cluster size to minimize FAT size (mounting delay), maximize number of files, keep 4 KB alignment, etc.
                     37:                if (volumeSize >= 2 * BYTES_PER_TB)
                     38:                        clusterSize = 256 * BYTES_PER_KB;
                     39:                else if (volumeSize >= 512 * BYTES_PER_GB)
                     40:                        clusterSize = 128 * BYTES_PER_KB;
                     41:                else if (volumeSize >= 128 * BYTES_PER_GB)
                     42:                        clusterSize = 64 * BYTES_PER_KB;
                     43:                else if (volumeSize >= 64 * BYTES_PER_GB)
                     44:                        clusterSize = 32 * BYTES_PER_KB;
                     45:                else if (volumeSize >= 32 * BYTES_PER_GB)
                     46:                        clusterSize = 16 * BYTES_PER_KB;
                     47:                else if (volumeSize >= 16 * BYTES_PER_GB)
                     48:                        clusterSize = 8 * BYTES_PER_KB;
                     49:                else if (volumeSize >= 512 * BYTES_PER_MB)
                     50:                        clusterSize = 4 * BYTES_PER_KB;
                     51:                else if (volumeSize >= 256 * BYTES_PER_MB)
                     52:                        clusterSize = 2 * BYTES_PER_KB;
                     53:                else if (volumeSize >= 1 * BYTES_PER_MB)
                     54:                        clusterSize = 1 * BYTES_PER_KB;
1.1       root       55:                else
1.1.1.19  root       56:                        clusterSize = 512;
                     57: 
                     58:                ft->cluster_size = clusterSize / ft->sector_size;
                     59:                
                     60:                if (ft->cluster_size == 0)
1.1       root       61:                        ft->cluster_size = 1;
1.1.1.19  root       62: 
                     63:                if (ft->cluster_size * ft->sector_size > TC_MAX_FAT_CLUSTER_SIZE)
                     64:                        ft->cluster_size = TC_MAX_FAT_CLUSTER_SIZE / ft->sector_size;
                     65: 
                     66:                if (ft->cluster_size > 128)
                     67:                        ft->cluster_size = 128;
1.1       root       68:        }
                     69: 
1.1.1.19  root       70:        if (volumeSize <= TC_MAX_FAT_CLUSTER_SIZE * 4)
                     71:                ft->cluster_size = 1;
                     72: 
1.1       root       73:        // Geometry always set to SECTORS/1/1
                     74:        ft->secs_track = 1; 
                     75:        ft->heads = 1; 
                     76: 
                     77:        ft->dir_entries = 512;
                     78:        ft->fats = 2;
                     79:        ft->media = 0xf8;
1.1.1.11  root       80:        ft->hidden = 0;
1.1       root       81: 
                     82:        ft->size_root_dir = ft->dir_entries * 32;
                     83: 
1.1.1.6   root       84:        // FAT12
1.1       root       85:        ft->size_fat = 12;
1.1.1.6   root       86:        ft->reserved = 2;
1.1.1.19  root       87:        fatsecs = ft->num_sectors - (ft->size_root_dir + ft->sector_size - 1) / ft->sector_size - ft->reserved;
1.1.1.20! root       88:        ft->cluster_count = (int) (((__int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size));
1.1.1.19  root       89:        ft->fat_length = (((ft->cluster_count * 3 + 1) >> 1) + ft->sector_size - 1) / ft->sector_size;
1.1       root       90: 
1.1.1.6   root       91:        if (ft->cluster_count >= 4085) // FAT16
1.1       root       92:        {
                     93:                ft->size_fat = 16;
1.1.1.11  root       94:                ft->reserved = 2;
1.1.1.19  root       95:                fatsecs = ft->num_sectors - (ft->size_root_dir + ft->sector_size - 1) / ft->sector_size - ft->reserved;
1.1.1.20! root       96:                ft->cluster_count = (int) (((__int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size));
1.1.1.19  root       97:                ft->fat_length = (ft->cluster_count * 2 + ft->sector_size - 1) / ft->sector_size;
1.1       root       98:        }
1.1.1.6   root       99:        
                    100:        if(ft->cluster_count >= 65525) // FAT32
1.1       root      101:        {
                    102:                ft->size_fat = 32;
1.1.1.19  root      103:                ft->reserved = 32 - 1;
                    104: 
                    105:                do
                    106:                {
                    107:                        ft->reserved++;
                    108: 
                    109:                        fatsecs = ft->num_sectors - ft->reserved;
                    110:                        ft->size_root_dir = ft->cluster_size * ft->sector_size;
1.1.1.20! root      111:                        ft->cluster_count = (int) (((__int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size));
1.1.1.19  root      112:                        ft->fat_length = (ft->cluster_count * 4 + ft->sector_size - 1) / ft->sector_size;
                    113: 
                    114:                // Align data area on TC_MAX_VOLUME_SECTOR_SIZE
                    115: 
                    116:                } while (ft->sector_size == TC_SECTOR_SIZE_LEGACY
                    117:                                && (ft->reserved * ft->sector_size + ft->fat_length * ft->fats * ft->sector_size) % TC_MAX_VOLUME_SECTOR_SIZE != 0);
1.1       root      118:        }
                    119: 
1.1.1.20! root      120:        ft->cluster_count -= ft->fat_length * ft->fats / ft->cluster_size;
        !           121: 
1.1       root      122:        if (ft->num_sectors >= 65536 || ft->size_fat == 32)
                    123:        {
                    124:                ft->sectors = 0;
                    125:                ft->total_sect = ft->num_sectors;
                    126:        }
                    127:        else
                    128:        {
1.1.1.17  root      129:                ft->sectors = (uint16) ft->num_sectors;
1.1       root      130:                ft->total_sect = 0;
                    131:        }
                    132: }
                    133: 
                    134: void
                    135: PutBoot (fatparams * ft, unsigned char *boot)
                    136: {
                    137:        int cnt = 0;
                    138: 
                    139:        boot[cnt++] = 0xeb;     /* boot jump */
                    140:        boot[cnt++] = 0x3c;
                    141:        boot[cnt++] = 0x90;
1.1.1.6   root      142:        memcpy (boot + cnt, "MSDOS5.0", 8); /* system id */
1.1       root      143:        cnt += 8;
1.1.1.10  root      144:        *(__int16 *)(boot + cnt) = LE16(ft->sector_size);       /* bytes per sector */
1.1       root      145:        cnt += 2;
1.1.1.10  root      146:        boot[cnt++] = (__int8) ft->cluster_size;                        /* sectors per cluster */
                    147:        *(__int16 *)(boot + cnt) = LE16(ft->reserved);          /* reserved sectors */
1.1.1.6   root      148:        cnt += 2;
1.1.1.10  root      149:        boot[cnt++] = (__int8) ft->fats;                                        /* 2 fats */
1.1       root      150: 
                    151:        if(ft->size_fat == 32)
                    152:        {
                    153:                boot[cnt++] = 0x00;
                    154:                boot[cnt++] = 0x00;
                    155:        }
                    156:        else
                    157:        {
1.1.1.10  root      158:                *(__int16 *)(boot + cnt) = LE16(ft->dir_entries);       /* 512 root entries */
1.1       root      159:                cnt += 2;
                    160:        }
                    161: 
1.1.1.10  root      162:        *(__int16 *)(boot + cnt) = LE16(ft->sectors);           /* # sectors */
1.1       root      163:        cnt += 2;
1.1.1.10  root      164:        boot[cnt++] = (__int8) ft->media;                                       /* media byte */
1.1       root      165: 
                    166:        if(ft->size_fat == 32)  
                    167:        {
                    168:                boot[cnt++] = 0x00;
                    169:                boot[cnt++] = 0x00;
                    170:        }
                    171:        else 
                    172:        { 
1.1.1.17  root      173:                *(__int16 *)(boot + cnt) = LE16((uint16) ft->fat_length);       /* fat size */
1.1       root      174:                cnt += 2;
                    175:        }
                    176: 
1.1.1.10  root      177:        *(__int16 *)(boot + cnt) = LE16(ft->secs_track);        /* # sectors per track */
1.1       root      178:        cnt += 2;
1.1.1.10  root      179:        *(__int16 *)(boot + cnt) = LE16(ft->heads);                     /* # heads */
1.1       root      180:        cnt += 2;
1.1.1.10  root      181:        *(__int32 *)(boot + cnt) = LE32(ft->hidden);            /* # hidden sectors */
1.1.1.6   root      182:        cnt += 4;
1.1.1.10  root      183:        *(__int32 *)(boot + cnt) = LE32(ft->total_sect);        /* # huge sectors */
1.1       root      184:        cnt += 4;
                    185: 
                    186:        if(ft->size_fat == 32)
                    187:        {
1.1.1.10  root      188:                *(__int32 *)(boot + cnt) = LE32(ft->fat_length); cnt += 4;      /* fat size 32 */
1.1.1.6   root      189:                boot[cnt++] = 0x00;     /* ExtFlags */
1.1       root      190:                boot[cnt++] = 0x00;
                    191:                boot[cnt++] = 0x00;     /* FSVer */
                    192:                boot[cnt++] = 0x00;
                    193:                boot[cnt++] = 0x02;     /* RootClus */
                    194:                boot[cnt++] = 0x00;
                    195:                boot[cnt++] = 0x00;
                    196:                boot[cnt++] = 0x00;
                    197:                boot[cnt++] = 0x01;     /* FSInfo */
                    198:                boot[cnt++] = 0x00;
                    199:                boot[cnt++] = 0x06;     /* BkBootSec */
                    200:                boot[cnt++] = 0x00;
                    201:                memset(boot+cnt, 0, 12); cnt+=12;       /* Reserved */
                    202:        }
                    203: 
1.1.1.6   root      204:        boot[cnt++] = 0x00;     /* drive number */   // FIXED 80 > 00
1.1       root      205:        boot[cnt++] = 0x00;     /* reserved */
                    206:        boot[cnt++] = 0x29;     /* boot sig */
1.1.1.13  root      207: 
1.1.1.19  root      208:        memcpy (boot + cnt, ft->volume_id, 4);          /* vol id */
1.1       root      209:        cnt += 4;
1.1.1.13  root      210: 
1.1.1.6   root      211:        memcpy (boot + cnt, ft->volume_name, 11);       /* vol title */
1.1       root      212:        cnt += 11;
                    213: 
                    214:        switch(ft->size_fat) /* filesystem type */
                    215:        {
                    216:                case 12: memcpy (boot + cnt, "FAT12   ", 8); break;
                    217:                case 16: memcpy (boot + cnt, "FAT16   ", 8); break;
                    218:                case 32: memcpy (boot + cnt, "FAT32   ", 8); break;
                    219:        }
                    220:        cnt += 8;
                    221: 
                    222:        memset (boot + cnt, 0, ft->size_fat==32 ? 420:448);     /* boot code */
                    223:        cnt += ft->size_fat==32 ? 420:448;
                    224:        boot[cnt++] = 0x55;
                    225:        boot[cnt++] = 0xaa;     /* boot sig */
                    226: }
                    227: 
1.1.1.10  root      228: 
1.1       root      229: /* FAT32 FSInfo */
1.1.1.17  root      230: static void PutFSInfo (unsigned char *sector, fatparams *ft)
1.1       root      231: {
1.1.1.19  root      232:        memset (sector, 0, ft->sector_size);
1.1.1.6   root      233:        sector[3]=0x41; /* LeadSig */
                    234:        sector[2]=0x61; 
                    235:        sector[1]=0x52; 
                    236:        sector[0]=0x52; 
                    237:        sector[484+3]=0x61; /* StrucSig */
                    238:        sector[484+2]=0x41; 
                    239:        sector[484+1]=0x72; 
                    240:        sector[484+0]=0x72; 
1.1.1.13  root      241: 
                    242:        // Free cluster count
1.1.1.19  root      243:        *(uint32 *)(sector + 488) = LE32 (ft->cluster_count - ft->size_root_dir / ft->sector_size / ft->cluster_size);
1.1.1.13  root      244: 
1.1.1.17  root      245:        // Next free cluster
                    246:        *(uint32 *)(sector + 492) = LE32 (2);
                    247: 
1.1.1.6   root      248:        sector[508+3]=0xaa; /* TrailSig */
                    249:        sector[508+2]=0x55;
                    250:        sector[508+1]=0x00;
                    251:        sector[508+0]=0x00;
1.1       root      252: }
                    253: 
                    254: 
                    255: int
1.1.1.8   root      256: FormatFat (unsigned __int64 startSector, fatparams * ft, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat)
1.1       root      257: {
                    258:        int write_buf_cnt = 0;
1.1.1.19  root      259:        char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf;
1.1.1.4   root      260:        unsigned __int64 nSecNo = startSector;
1.1       root      261:        int x, n;
1.1.1.6   root      262:        int retVal;
1.1.1.12  root      263:        char temporaryKey[MASTER_KEYDATA_SIZE];
1.1       root      264: 
1.1.1.8   root      265:        LARGE_INTEGER startOffset;
                    266:        LARGE_INTEGER newOffset;
                    267: 
1.1.1.4   root      268:        // Seek to start sector
1.1.1.19  root      269:        startOffset.QuadPart = startSector * ft->sector_size;
1.1.1.6   root      270:        if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN)
                    271:                || newOffset.QuadPart != startOffset.QuadPart)
1.1.1.4   root      272:        {
                    273:                return ERR_VOL_SEEKING;
                    274:        }
1.1       root      275: 
1.1.1.4   root      276:        /* Write the data area */
1.1       root      277: 
1.1.1.17  root      278:        write_buf = (char *)TCalloc (FormatWriteBufferSize);
1.1.1.15  root      279:        if (!write_buf)
                    280:                return ERR_OUTOFMEMORY;
                    281: 
1.1.1.19  root      282:        memset (sector, 0, ft->sector_size);
                    283: 
                    284:        RandgetBytes (ft->volume_id, sizeof (ft->volume_id), FALSE);
1.1       root      285: 
                    286:        PutBoot (ft, (unsigned char *) sector);
1.1.1.6   root      287:        if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      288:                cryptoInfo) == FALSE)
1.1       root      289:                goto fail;
                    290: 
                    291:        /* fat32 boot area */
                    292:        if (ft->size_fat == 32)                         
                    293:        {
                    294:                /* fsinfo */
1.1.1.13  root      295:                PutFSInfo((unsigned char *) sector, ft);
1.1.1.6   root      296:                if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      297:                        cryptoInfo) == FALSE)
1.1       root      298:                        goto fail;
                    299: 
                    300:                /* reserved */
1.1.1.4   root      301:                while (nSecNo - startSector < 6)
1.1       root      302:                {
1.1.1.19  root      303:                        memset (sector, 0, ft->sector_size);
1.1       root      304:                        sector[508+3]=0xaa; /* TrailSig */
                    305:                        sector[508+2]=0x55;
1.1.1.6   root      306:                        if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      307:                                cryptoInfo) == FALSE)
1.1       root      308:                                goto fail;
                    309:                }
                    310:                
                    311:                /* bootsector backup */
1.1.1.19  root      312:                memset (sector, 0, ft->sector_size);
1.1       root      313:                PutBoot (ft, (unsigned char *) sector);
1.1.1.6   root      314:                if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      315:                                 cryptoInfo) == FALSE)
1.1       root      316:                        goto fail;
                    317: 
1.1.1.13  root      318:                PutFSInfo((unsigned char *) sector, ft);
1.1.1.6   root      319:                if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      320:                        cryptoInfo) == FALSE)
1.1       root      321:                        goto fail;
1.1.1.6   root      322:        }
1.1       root      323: 
1.1.1.6   root      324:        /* reserved */
1.1.1.8   root      325:        while (nSecNo - startSector < (unsigned int)ft->reserved)
1.1.1.6   root      326:        {
1.1.1.19  root      327:                memset (sector, 0, ft->sector_size);
1.1.1.6   root      328:                if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      329:                        cryptoInfo) == FALSE)
1.1.1.6   root      330:                        goto fail;
1.1       root      331:        }
                    332: 
                    333:        /* write fat */
                    334:        for (x = 1; x <= ft->fats; x++)
                    335:        {
                    336:                for (n = 0; n < ft->fat_length; n++)
                    337:                {
1.1.1.19  root      338:                        memset (sector, 0, ft->sector_size);
1.1       root      339: 
                    340:                        if (n == 0)
                    341:                        {
                    342:                                unsigned char fat_sig[12];
                    343:                                if (ft->size_fat == 32)
                    344:                                {
                    345:                                        fat_sig[0] = (unsigned char) ft->media;
                    346:                                        fat_sig[1] = fat_sig[2] = 0xff;
                    347:                                        fat_sig[3] = 0x0f;
                    348:                                        fat_sig[4] = fat_sig[5] = fat_sig[6] = 0xff;
                    349:                                        fat_sig[7] = 0x0f;
                    350:                                        fat_sig[8] = fat_sig[9] = fat_sig[10] = 0xff;
                    351:                                        fat_sig[11] = 0x0f;
                    352:                                        memcpy (sector, fat_sig, 12);
                    353:                                }                               
                    354:                                else if (ft->size_fat == 16)
                    355:                                {
                    356:                                        fat_sig[0] = (unsigned char) ft->media;
                    357:                                        fat_sig[1] = 0xff;
                    358:                                        fat_sig[2] = 0xff;
                    359:                                        fat_sig[3] = 0xff;
                    360:                                        memcpy (sector, fat_sig, 4);
                    361:                                }
                    362:                                else if (ft->size_fat == 12)
                    363:                                {
                    364:                                        fat_sig[0] = (unsigned char) ft->media;
                    365:                                        fat_sig[1] = 0xff;
                    366:                                        fat_sig[2] = 0xff;
                    367:                                        fat_sig[3] = 0x00;
                    368:                                        memcpy (sector, fat_sig, 4);
                    369:                                }
                    370:                        }
                    371: 
1.1.1.6   root      372:                        if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      373:                                    cryptoInfo) == FALSE)
1.1       root      374:                                goto fail;
                    375:                }
                    376:        }
                    377: 
                    378: 
                    379:        /* write rootdir */
1.1.1.19  root      380:        for (x = 0; x < ft->size_root_dir / ft->sector_size; x++)
1.1       root      381:        {
1.1.1.19  root      382:                memset (sector, 0, ft->sector_size);
1.1.1.6   root      383:                if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      384:                                 cryptoInfo) == FALSE)
1.1       root      385:                        goto fail;
                    386: 
                    387:        }
                    388: 
1.1.1.7   root      389:        /* Fill the rest of the data area with random data */
1.1.1.4   root      390: 
1.1       root      391:        if(!quickFormat)
                    392:        {
1.1.1.13  root      393:                if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
                    394:                        goto fail;
                    395: 
1.1.1.7   root      396:                /* Generate a random temporary key set to be used for "dummy" encryption that will fill
                    397:                the free disk space (data area) with random data.  This is necessary for plausible
                    398:                deniability of hidden volumes (and also reduces the amount of predictable plaintext
                    399:                within the volume). */
1.1       root      400: 
1.1.1.9   root      401:                // Temporary master key
                    402:                if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE))
                    403:                        goto fail;
1.1.1.12  root      404: 
                    405:                // Temporary secondary key (XTS mode)
                    406:                if (!RandgetBytes (cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE))               
1.1.1.9   root      407:                        goto fail;
1.1.1.6   root      408: 
1.1.1.7   root      409:                retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
1.1.1.12  root      410:                if (retVal != ERR_SUCCESS)
1.1.1.7   root      411:                {
                    412:                        burn (temporaryKey, sizeof(temporaryKey));
1.1.1.6   root      413:                        return retVal;
1.1.1.7   root      414:                }
                    415:                if (!EAInitMode (cryptoInfo))
                    416:                {
                    417:                        burn (temporaryKey, sizeof(temporaryKey));
                    418:                        return ERR_MODE_INIT_FAILED;
                    419:                }
1.1       root      420: 
1.1.1.19  root      421:                x = ft->num_sectors - ft->reserved - ft->size_root_dir / ft->sector_size - ft->fat_length * 2;
1.1       root      422:                while (x--)
                    423:                {
1.1.1.6   root      424:                        if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8   root      425:                                cryptoInfo) == FALSE)
1.1       root      426:                                goto fail;
                    427:                }
1.1.1.19  root      428:                UpdateProgressBar (nSecNo * ft->sector_size);
1.1       root      429:        }
1.1.1.3   root      430:        else
1.1.1.19  root      431:                UpdateProgressBar ((uint64) ft->num_sectors * ft->sector_size);
1.1.1.8   root      432: 
1.1.1.13  root      433:        if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
1.1       root      434:                goto fail;
                    435: 
                    436:        TCfree (write_buf);
1.1.1.7   root      437:        burn (temporaryKey, sizeof(temporaryKey));
1.1       root      438:        return 0;
                    439: 
1.1.1.7   root      440: fail:
1.1       root      441: 
                    442:        TCfree (write_buf);
1.1.1.7   root      443:        burn (temporaryKey, sizeof(temporaryKey));
1.1       root      444:        return ERR_OS_ERROR;
                    445: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.