@@ -26,10 +26,20 @@ export class DigestStorage implements IDigestStorage {
2626 public async saveDigest ( uri : Uri , signature : string ) {
2727 const fileLocation = await this . getFileLocation ( uri ) ;
2828 // Since the signature is a hex digest, the character 'z' is being used to delimit the start and end of a single digest
29- await this . fs . appendFile ( fileLocation , `z${ signature } z\n` ) ;
30- if ( ! this . loggedFileLocations . has ( fileLocation ) ) {
31- traceInfo ( `Wrote trust for ${ uri . toString ( ) } to ${ fileLocation } ` ) ;
32- this . loggedFileLocations . add ( fileLocation ) ;
29+ try {
30+ await this . saveDigestInner ( uri , fileLocation , signature ) ;
31+ } catch ( err ) {
32+ // The nbsignatures dir is only initialized on extension activation.
33+ // If the user deletes it to reset trust, the next attempt to trust
34+ // an untrusted notebook in the same session will fail because the parent
35+ // directory does not exist.
36+ if ( isFileNotFoundError ( err ) ) {
37+ // Gracefully recover from such errors by reinitializing directory and retrying
38+ await this . initDir ( ) ;
39+ await this . saveDigestInner ( uri , fileLocation , signature ) ;
40+ } else {
41+ traceError ( err ) ;
42+ }
3343 }
3444 }
3545
@@ -46,6 +56,14 @@ export class DigestStorage implements IDigestStorage {
4656 }
4757 }
4858
59+ private async saveDigestInner ( uri : Uri , fileLocation : string , signature : string ) {
60+ await this . fs . appendFile ( fileLocation , `z${ signature } z\n` ) ;
61+ if ( ! this . loggedFileLocations . has ( fileLocation ) ) {
62+ traceInfo ( `Wrote trust for ${ uri . toString ( ) } to ${ fileLocation } ` ) ;
63+ this . loggedFileLocations . add ( fileLocation ) ;
64+ }
65+ }
66+
4967 private async getFileLocation ( uri : Uri ) : Promise < string > {
5068 const normalizedName = os . platform ( ) === 'win32' ? uri . fsPath . toLowerCase ( ) : uri . fsPath ;
5169 const hashedName = createHash ( 'sha256' ) . update ( normalizedName ) . digest ( 'hex' ) ;
0 commit comments