EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.impl.store.raw]

COVERAGE SUMMARY FOR SOURCE FILE [RawStore.java]

nameclass, %method, %block, %line, %
RawStore.java100% (1/1)90%  (52/58)78%  (1265/1629)80%  (283.7/354)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class RawStore100% (1/1)90%  (52/58)78%  (1265/1629)80%  (283.7/354)
<static initializer> 100% (1/1)100% (20/20)100% (1/1)
RawStore (): void 100% (1/1)100% (6/6)100% (3/3)
backup (File): void 100% (1/1)77%  (267/349)75%  (60/80)
backup (String): void 100% (1/1)47%  (16/34)41%  (4.1/10)
backupAndEnableLogArchiveMode (File, boolean): void 0%   (0/1)0%   (0/11)0%   (0/5)
backupAndEnableLogArchiveMode (String, boolean): void 100% (1/1)100% (11/11)100% (5/5)
boot (boolean, Properties): void 100% (1/1)100% (230/230)100% (48/48)
canSupport (Properties): boolean 100% (1/1)100% (2/2)100% (1/1)
changeBootPassword (Properties, Serializable): Serializable 100% (1/1)74%  (26/35)70%  (7/10)
checkpoint (): void 100% (1/1)100% (11/11)100% (2/2)
createFinished (): void 100% (1/1)100% (7/7)100% (3/3)
decrypt (byte [], int, int, byte [], int): int 100% (1/1)88%  (21/24)75%  (3/4)
disableLogArchiveMode (boolean): void 100% (1/1)100% (9/9)100% (4/4)
enableLogArchiveMode (): void 100% (1/1)100% (4/4)100% (2/2)
encrypt (byte [], int, int, byte [], int): int 100% (1/1)88%  (21/24)75%  (3/4)
findUserTransaction (ContextManager, String): Transaction 100% (1/1)100% (7/7)100% (1/1)
freeze (): void 100% (1/1)100% (17/17)100% (4/4)
freezePersistentStore (): void 0%   (0/1)0%   (0/14)0%   (0/3)
getDaemon (): DaemonService 100% (1/1)100% (3/3)100% (1/1)
getDataFactoryModule (): String 100% (1/1)100% (2/2)100% (1/1)
getEncryptionBlockSize (): int 100% (1/1)100% (3/3)100% (1/1)
getLockFactory (): LockFactory 100% (1/1)100% (4/4)100% (1/1)
getLogFactoryModule (): String 100% (1/1)100% (2/2)100% (1/1)
getMaxContainerId (): long 100% (1/1)100% (4/4)100% (1/1)
getRawStoreProperties (PersistentSet): void 100% (1/1)100% (5/5)100% (2/2)
getTransactionFactoryModule (): String 100% (1/1)100% (2/2)100% (1/1)
getTransactionInfo (): TransactionInfo [] 100% (1/1)100% (4/4)100% (1/1)
getXAResourceManager (): Object 100% (1/1)100% (4/4)100% (1/1)
idle (): void 100% (1/1)100% (4/4)100% (2/2)
isReadOnly (): boolean 100% (1/1)100% (4/4)100% (1/1)
logHistory (OutputStreamWriter, String): void 100% (1/1)100% (22/22)100% (4/4)
markCorrupt (StandardException): StandardException 100% (1/1)100% (17/17)100% (4/4)
openFlushedScan (DatabaseInstant, int): ScanHandle 0%   (0/1)0%   (0/6)0%   (0/1)
privCopyDirectory (File, StorageFile): boolean 100% (1/1)100% (9/9)100% (1/1)
privCopyDirectory (File, StorageFile, byte [], String []): boolean 100% (1/1)80%  (39/49)90%  (10.8/12)
privCopyDirectory (StorageFile, File): boolean 0%   (0/1)0%   (0/9)0%   (0/1)
privCopyDirectory (StorageFile, File, byte [], String []): boolean 100% (1/1)80%  (39/49)90%  (10.8/12)
privCopyFile (File, StorageFile): boolean 100% (1/1)55%  (24/44)76%  (6.1/8)
privDelete (File): boolean 0%   (0/1)0%   (0/32)0%   (0/6)
privExists (File): boolean 100% (1/1)56%  (18/32)76%  (4.6/6)
privExists (StorageFile): boolean 100% (1/1)56%  (18/32)76%  (4.6/6)
privFileWriter (StorageFile, boolean): OutputStreamWriter 100% (1/1)62%  (18/29)68%  (4.8/7)
privIsDirectory (File): boolean 100% (1/1)56%  (18/32)76%  (4.6/6)
privList (File): String [] 100% (1/1)52%  (15/29)70%  (3.5/5)
privMkdirs (File): boolean 100% (1/1)56%  (18/32)76%  (4.6/6)
privRemoveDirectory (File): boolean 100% (1/1)56%  (18/32)76%  (4.6/6)
privRenameTo (File, File): boolean 100% (1/1)55%  (24/44)76%  (6.1/8)
random (): int 100% (1/1)89%  (8/9)88%  (0.9/1)
restoreRemainingFromBackup (String): void 100% (1/1)85%  (58/68)85%  (11/13)
run (): Object 100% (1/1)92%  (86/93)86%  (12/14)
startGlobalTransaction (ContextManager, int, byte [], byte []): Transaction 100% (1/1)100% (9/9)100% (1/1)
startInternalTransaction (ContextManager): Transaction 100% (1/1)100% (6/6)100% (1/1)
startNestedReadOnlyUserTransaction (Object, ContextManager, String): Transaction 100% (1/1)100% (8/8)100% (1/1)
startNestedUpdateUserTransaction (ContextManager, String): Transaction 100% (1/1)100% (7/7)100% (1/1)
startTransaction (ContextManager, String): Transaction 100% (1/1)100% (7/7)100% (1/1)
stop (): void 100% (1/1)100% (56/56)100% (13/13)
unfreeze (): void 100% (1/1)100% (7/7)100% (3/3)
unfreezePersistentStore (): void 0%   (0/1)0%   (0/4)0%   (0/2)

1/*
2 
3   Derby - Class org.apache.derby.impl.store.raw.RawStore
4 
5   Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21package org.apache.derby.impl.store.raw;
22 
23import org.apache.derby.iapi.services.daemon.DaemonFactory;
24import org.apache.derby.iapi.services.daemon.DaemonService;
25import org.apache.derby.iapi.services.context.ContextManager;
26import org.apache.derby.iapi.services.context.ContextService;
27import org.apache.derby.iapi.services.crypto.CipherFactoryBuilder;
28import org.apache.derby.iapi.services.crypto.CipherFactory;
29import org.apache.derby.iapi.services.crypto.CipherProvider;
30import org.apache.derby.iapi.services.locks.LockFactory;
31import org.apache.derby.iapi.services.monitor.Monitor;
32import org.apache.derby.iapi.services.monitor.ModuleControl;
33import org.apache.derby.iapi.services.monitor.ModuleSupportable;
34import org.apache.derby.iapi.services.monitor.PersistentService;
35import org.apache.derby.iapi.services.sanity.SanityManager;
36 
37import org.apache.derby.iapi.error.StandardException;
38import org.apache.derby.iapi.services.i18n.MessageService;
39 
40import org.apache.derby.iapi.services.property.PersistentSet;
41import org.apache.derby.iapi.store.access.TransactionInfo;
42import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
43import org.apache.derby.iapi.store.access.FileResource;
44import org.apache.derby.iapi.store.raw.ScanHandle;
45import org.apache.derby.iapi.store.raw.RawStoreFactory;
46import org.apache.derby.iapi.store.raw.Transaction;
47import org.apache.derby.iapi.store.raw.xact.RawTransaction;
48import org.apache.derby.iapi.store.raw.xact.TransactionFactory;
49import org.apache.derby.iapi.store.raw.data.DataFactory;
50import org.apache.derby.iapi.store.raw.log.LogFactory;
51import org.apache.derby.iapi.store.raw.log.LogInstant;
52import org.apache.derby.impl.services.monitor.UpdateServiceProperties;
53 
54import org.apache.derby.io.StorageFactory;
55import org.apache.derby.io.WritableStorageFactory;
56import org.apache.derby.io.StorageFile;
57import org.apache.derby.iapi.store.access.DatabaseInstant;
58import org.apache.derby.catalog.UUID;
59import org.apache.derby.iapi.services.property.PropertyUtil;
60import org.apache.derby.iapi.services.io.FileUtil;
61import org.apache.derby.iapi.util.ReuseFactory;
62import org.apache.derby.iapi.util.StringUtil;
63import org.apache.derby.iapi.reference.Attribute;
64import org.apache.derby.iapi.reference.SQLState;
65import org.apache.derby.iapi.reference.MessageId;
66import org.apache.derby.iapi.reference.Property;
67 
68import java.security.AccessController;
69import java.security.PrivilegedActionException;
70import java.security.PrivilegedExceptionAction;
71import java.security.SecureRandom;
72 
73import java.util.Date;
74import java.util.Properties;
75import java.io.Serializable;
76import java.io.File;
77import java.io.FileOutputStream;
78import java.io.FileInputStream;
79import java.io.IOException;
80import java.io.FileNotFoundException;
81import java.io.OutputStreamWriter;
82 
83import java.net.MalformedURLException;
84import java.net.URL;
85 
86import java.security.PrivilegedExceptionAction;
87import java.lang.SecurityException;
88 
89 
90/**
91        A Raw store that implements the RawStoreFactory module by delegating all the
92        work to the lower modules TransactionFactory, LogFactory and DataFactory.
93        <PRE>
94        String TransactionFactoryId=<moduleIdentifier>
95        </PRE>
96        
97        <P>
98        Class is final as it has methods with privilege blocks
99        and implements PrivilegedExceptionAction.
100*/
101 
102public final class RawStore implements RawStoreFactory, ModuleControl, ModuleSupportable, PrivilegedExceptionAction
103{
104        private static final String BACKUP_HISTORY = "BACKUP.HISTORY";
105        protected TransactionFactory        xactFactory;
106        protected DataFactory                        dataFactory;
107        protected LogFactory                        logFactory;
108    private StorageFactory storageFactory;
109 
110        private SecureRandom random;
111        private boolean databaseEncrypted;
112    private boolean encryptDatabase;
113        private CipherProvider encryptionEngine;
114        private CipherProvider decryptionEngine;
115    private CipherProvider newEncryptionEngine;
116        private CipherProvider newDecryptionEngine;
117        private CipherFactory  currentCipherFactory;
118        private int counter_encrypt;
119        private int counter_decrypt;
120        private int encryptionBlockSize = RawStoreFactory.DEFAULT_ENCRYPTION_BLOCKSIZE;
121 
122        String dataDirectory;                                         // where files are stored        
123 
124        // this daemon takes care of all daemon work for this raw store
125        protected DaemonService                        rawStoreDaemon;
126 
127    private int actionCode;
128    private static final int FILE_WRITER_ACTION = 1;
129    private StorageFile actionStorageFile;
130    private boolean actionAppend;
131    private static final int REGULAR_FILE_EXISTS_ACTION = 2;
132    private File actionRegularFile;
133    private static final int STORAGE_FILE_EXISTS_ACTION = 3;
134    private static final int REGULAR_FILE_DELETE_ACTION = 4;
135    private static final int REGULAR_FILE_MKDIRS_ACTION = 5;
136    private static final int REGULAR_FILE_IS_DIRECTORY_ACTION = 6;
137    private static final int REGULAR_FILE_REMOVE_DIRECTORY_ACTION = 7;
138    private static final int REGULAR_FILE_RENAME_TO_ACTION = 8;
139    private File actionRegularFile2;
140    private static final int COPY_STORAGE_DIRECTORY_TO_REGULAR_ACTION = 9;
141    private byte[] actionBuffer;
142    private String[] actionFilter;
143    private boolean actionCopySubDirs;
144    private static final int COPY_REGULAR_DIRECTORY_TO_STORAGE_ACTION = 10;
145    private static final int COPY_REGULAR_FILE_TO_STORAGE_ACTION = 11;
146    private static final int REGULAR_FILE_LIST_DIRECTORY_ACTION = 12;
147    private static final int STORAGE_FILE_LIST_DIRECTORY_ACTION = 13;
148    private static final int COPY_STORAGE_FILE_TO_REGULAR_ACTION = 14;
149    private static final int REGULAR_FILE_GET_CANONICALPATH_ACTION = 15;
150    private static final int STORAGE_FILE_GET_CANONICALPATH_ACTION = 16;
151 
152        public RawStore() {
153        }
154 
155        /*
156        ** Methods of ModuleControl
157        */
158 
159        /**
160          We use this RawStore for all databases.
161          */
162        public boolean canSupport(Properties startParams) {
163                return true;
164        }
165 
166        public void        boot(boolean create, Properties properties)
167                throws StandardException
168        {
169                dataDirectory = properties.getProperty(PersistentService.ROOT);
170                DaemonFactory daemonFactory =
171                        (DaemonFactory)Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.DaemonFactory);
172                rawStoreDaemon = daemonFactory.createNewDaemon("rawStoreDaemon");
173                xactFactory = (TransactionFactory)
174                                        Monitor.bootServiceModule(
175                                                create, this, getTransactionFactoryModule(), properties);
176 
177                dataFactory = (DataFactory)
178                                        Monitor.bootServiceModule(
179                                          create, this, getDataFactoryModule(), properties);
180                storageFactory = dataFactory.getStorageFactory();
181 
182        String restoreFromBackup = null;
183        boolean reEncrypt = false;
184        CipherFactory newCipherFactory = null;
185 
186                if (properties != null)
187                {
188            // check if this is a restore from a backup copy. 
189            restoreFromBackup = properties.getProperty(Attribute.CREATE_FROM);
190            if(restoreFromBackup == null)
191                restoreFromBackup = properties.getProperty(Attribute.RESTORE_FROM);
192            if(restoreFromBackup == null)
193                restoreFromBackup =
194                    properties.getProperty(Attribute.ROLL_FORWARD_RECOVERY_FROM);
195 
196 
197                        /***********************************************
198                         * encryption
199                         **********************************************/
200            
201            // check if user has requested to encrypt the database or it is an
202            // encrypted database.
203 
204            String dataEncryption = 
205                properties.getProperty(Attribute.DATA_ENCRYPTION);
206            databaseEncrypted = Boolean.valueOf(dataEncryption).booleanValue(); 
207 
208 
209            if (!create && restoreFromBackup == null) {
210                // check if database is already encrypted, by directly peeking at the
211                // database service propertes instead of the properties passed 
212                // to this method. By looking at properties to the boot method ,
213                // one can not differentiate if user is requesting for database
214                // encryption or the database is already encrypted because 
215                // Attribute.DATA_ENCRYPTION is used  to store in the 
216                // service properties to indicate that database
217                // is encrypted and also users can specify it as URL attribute 
218                // to encrypt and existing database. 
219                               
220                String name = Monitor.getMonitor().getServiceName(this);
221                PersistentService ps = Monitor.getMonitor().getServiceType(this);
222                String canonicalName = ps.getCanonicalServiceName(name);
223                Properties serviceprops = ps.getServiceProperties(canonicalName, 
224                                                                  (Properties)null);
225                dataEncryption = serviceprops.getProperty(Attribute.DATA_ENCRYPTION);
226                boolean encryptedDatabase = Boolean.valueOf(dataEncryption).booleanValue();
227 
228                if (!encryptedDatabase  && databaseEncrypted) {
229                    // it it not an encrypted database, user is asking to 
230                    // encrypt an un-encrypted database. 
231                    encryptDatabase = true;
232                    // set database as un-encrypted, we will set it as encrypted 
233                    // after encrypting the existing data. 
234                    databaseEncrypted = false;
235                } else {
236                    // check if the user has requested to renecrypt  an
237                    // encrypted datbase with new encryption password/key.
238                    if (encryptedDatabase) {
239                        if (properties.getProperty(
240                                       Attribute.NEW_BOOT_PASSWORD) != null) {
241                            reEncrypt = true;
242                        }
243                        else if (properties.getProperty(
244                                       Attribute.NEW_CRYPTO_EXTERNAL_KEY) != null){
245                            reEncrypt = true;
246                        };
247                        encryptDatabase = reEncrypt;
248                    }
249 
250                }
251                
252                // NOTE: if user specifies Attribute.DATA_ENCRYPTION on the
253                // connection URL by mistake on an already encrypted database, 
254                // it is ignored.
255 
256            }
257 
258            // setup encryption engines. 
259                        if (databaseEncrypted || encryptDatabase)
260                        {
261                // check if database is configured for encryption, during
262                // configuration  some of the properties database; so that
263                // user does not have to specify them on the URL everytime.
264                // Incase of re-encryption of an already of encrypted database
265                // only some information needs to updated; it is not treated 
266                // like the configuring the database for encryption first time. 
267                boolean setupEncryption = create || (encryptDatabase &&  !reEncrypt);
268 
269                // start the cipher factory module, that is is used to create 
270                // instances of the cipher factory with specific enctyption 
271                // properties. 
272 
273                CipherFactoryBuilder cb =  (CipherFactoryBuilder)
274                    Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.CipherFactoryBuilder);
275 
276                // create instance of the cipher factory with the 
277                // specified encryption properties. 
278                currentCipherFactory = cb.createCipherFactory(setupEncryption, 
279                                                              properties, 
280                                                              false);
281 
282                // The database can be encrypted using an encryption key that is given at
283                 // connection url. For security reasons, this key is not made persistent
284                // in the database. But it is necessary to verify the encryption key 
285                // whenever booting the database if it is similar to the key that was used
286                // during creation time. This needs to happen before we access the data/logs to 
287                // avoid the risk of corrupting the database because of a wrong encryption key.
288                
289                // Please note this verification process does not provide any added security
290                // but is intended to allow to fail gracefully if a wrong encryption key 
291                // is used during boot time
292  
293 
294                currentCipherFactory.verifyKey(setupEncryption, storageFactory, properties);
295 
296                // Initializes the encryption and decryption engines
297                encryptionEngine = currentCipherFactory.
298                    createNewCipher(CipherFactory.ENCRYPT);
299                
300                // At creation time of an encrypted database, store the encryption block size
301                // for the algorithm. Store this value as property given by  
302                // RawStoreFactory.ENCRYPTION_BLOCKSIZE. This value
303                // is made persistent by storing it in service.properties
304                // To connect to an existing database, retrieve the value and use it for
305                // appropriate padding.
306                // The  default value of encryption block size is 8,
307                // to allow for downgrade issues
308                // Before support for AES (beetle6023), default encryption block size supported
309                // was 8
310 
311                if(setupEncryption) 
312                {
313                    encryptionBlockSize = encryptionEngine.getEncryptionBlockSize();
314                    // in case of database create, store the encryption block
315                    // size. Incase of reconfiguring the existing datbase, this
316                    // will be saved after encrypting the exisiting data. 
317                    if (create)
318                        properties.put(RawStoreFactory.ENCRYPTION_BLOCKSIZE,
319                                       String.valueOf(encryptionBlockSize));
320                }
321                else
322                {
323                    if(properties.getProperty(RawStoreFactory.ENCRYPTION_BLOCKSIZE) != null)
324                        encryptionBlockSize = Integer.parseInt(properties.getProperty
325                                                               (RawStoreFactory.ENCRYPTION_BLOCKSIZE));
326                    else
327                        encryptionBlockSize = encryptionEngine.getEncryptionBlockSize();
328                }   
329 
330                decryptionEngine = currentCipherFactory.
331                    createNewCipher(CipherFactory.DECRYPT);
332 
333                random = currentCipherFactory.getSecureRandom();
334                    
335                if (encryptDatabase) {
336 
337                    if (reEncrypt) {
338                        // create new cipher factory with the new encrytpion
339                        // properties specified by the user. This cipher factory
340                        // is used to create the new encryption/decryption
341                        // engines to reencrypt the database with the new
342                        // encryption keys. 
343                        newCipherFactory = 
344                            cb.createCipherFactory(setupEncryption, 
345                                                   properties, 
346                                                   true);
347                        newDecryptionEngine = 
348                            newCipherFactory.createNewCipher(CipherFactory.DECRYPT);
349                        newEncryptionEngine = 
350                            newCipherFactory.createNewCipher(CipherFactory.ENCRYPT);
351                    } else {
352                        // there is only one engine when configuring an 
353                        // unencrypted database for encryption 
354                        newDecryptionEngine = decryptionEngine;
355                        newEncryptionEngine = encryptionEngine;
356 
357                    }
358                }
359 
360                // save the encryption properties if encryption is enabled 
361                // at database creation time. 
362                if(create)
363                    currentCipherFactory.saveProperties(properties) ;
364                        }
365                }
366 
367 
368                // let everyone knows who their rawStoreFactory is and they can use it
369                // to get to other modules
370                // pass in create and properties to dataFactory so it can boot the log
371                // factory
372 
373                dataFactory.setRawStoreFactory(this, create, properties);
374                xactFactory.setRawStoreFactory(this);
375 
376        if( properties instanceof UpdateServiceProperties)
377        {
378            if( storageFactory instanceof WritableStorageFactory)
379                ((UpdateServiceProperties)properties).setStorageFactory( (WritableStorageFactory) storageFactory);
380        }
381        
382                // log factory is booted by the data factory
383                logFactory =(LogFactory) Monitor.findServiceModule(this, getLogFactoryModule());
384 
385        if (databaseEncrypted) {
386            // let log factory know if the database is encrypted . 
387            logFactory.setDatabaseEncrypted();
388            // let data factory know if the database is encrypted. 
389            dataFactory.setDatabaseEncrypted();
390        }
391 
392 
393                //save the service properties to a file if we are doing a restore from
394                if(restoreFromBackup !=null)
395                {
396                        //copy the jar files.etc from backup if they don't exist
397                        restoreRemainingFromBackup(restoreFromBackup);
398                        ((UpdateServiceProperties)properties).saveServiceProperties();
399                }
400 
401                // If the log is at another location, make sure  service.properties
402                // file has it.
403                String logDevice = properties.getProperty(Attribute.LOG_DEVICE);
404                if (logDevice !=null)
405                {
406            if (!isReadOnly() // We do not care about log location if read only
407                && (create 
408                    || !logDevice.equals(logFactory.getCanonicalLogPath()) 
409                    || restoreFromBackup!=null))
410                        {
411                                // get the real location from the log factory
412                                properties.put(Attribute.LOG_DEVICE, logFactory.getCanonicalLogPath());
413                                //make the log device param stored in backup is same as current log device.
414                                properties.put(Property.LOG_DEVICE_AT_BACKUP, logFactory.getCanonicalLogPath());
415                        }
416        
417                }else{
418                        //when we restore from a backup logDevice param does not exists 
419                        //in service.properties to support restore using OS commands to work. 
420                        //Instead of logDevice, we user logDeviceWhenBackedUp parameter to
421                        //identify the log location while restoring createFrom/restoreFrom/rollForwardRecoveryFrom
422                        //attribute , following make sures the logDevice parameter gets 
423                        //into service.propertues in such cases.
424                        if(restoreFromBackup!=null && logFactory.getCanonicalLogPath()!=null)
425                        {
426                                //logdevice might have got changed because of backup restore. 
427                                properties.put(Attribute.LOG_DEVICE,  logFactory.getCanonicalLogPath());
428                        }
429                        else{
430                                //might have been OS copy restore. We default log to db home
431                                properties.remove(Property.LOG_DEVICE_AT_BACKUP);
432                        }
433                }
434 
435                
436                //save the service properties to a file if we are doing a restore from
437                if(restoreFromBackup !=null)
438                {
439                        //copy the jar files.etc from backup if they don't exist
440                        restoreRemainingFromBackup(restoreFromBackup);
441                        ((UpdateServiceProperties)properties).saveServiceProperties();
442                }
443 
444 
445 
446                /**
447                 * Note: service.properties file acts as flags to indicate
448                 * that the copy from backup is successful.
449                 * If we reached so far while restoring from backup means
450                 * we copied all the necessary data from backup. Only thing
451                 * that remains is roll forwarding the logs. Incase if we crash at this
452                 * point and user re boots the datbase again without any restore flags
453                 * it shoud boot without any problem.
454                 **/
455 
456                // no need to tell log factory which raw store factory it belongs to
457                // since this is passed into the log factory for recovery
458                // after the factories are loaded, recover the database
459                logFactory.recover(this, dataFactory, xactFactory);
460 
461        // if user requested to encrpty an unecrypted database or encrypt with
462        // new alogorithm then do that now.  
463        if (encryptDatabase) {
464            configureDatabaseForEncryption(properties, 
465                                           reEncrypt, 
466                                           newCipherFactory);
467        }
468        }
469 
470        public void        stop() {
471 
472                if (SanityManager.DEBUG)
473                {
474                        if (databaseEncrypted)
475                                SanityManager.DEBUG_PRINT("encryption statistics",
476                                                "Encryption called " + counter_encrypt + " times, " +
477                                                "decryption called " + counter_decrypt + " times");
478                }
479 
480                if (rawStoreDaemon != null)
481                        rawStoreDaemon.stop();
482 
483                if (logFactory == null)
484                        return;
485 
486                try {
487 
488                        if (logFactory.checkpoint(this, dataFactory, xactFactory, false))
489                        {
490                                if (dataFactory != null)
491                                        dataFactory.removeStubsOK();
492                        }
493 
494                } catch (StandardException se) {
495                        // checkpoint failed, stop all factory from shutting down normally
496                        markCorrupt(se);
497                }
498        }
499 
500        /*
501        ** Methods of RawStoreFactory
502        */
503 
504        /**
505                Is the store read-only.
506                @see RawStoreFactory#isReadOnly
507        */
508        public boolean isReadOnly() {
509                return dataFactory.isReadOnly();
510        }
511 
512        public LockFactory getLockFactory() {
513                return xactFactory.getLockFactory();
514        }
515 
516    
517    /**
518                Get the Transaction Factory to use with this store.
519        */
520        public TransactionFactory getXactFactory() {
521        return xactFactory;  
522    }
523 
524        /*
525         * Return the module providing XAresource interface to the transaction
526     * table.
527     *
528         * @exception StandardException Standard cloudscape exception policy.
529         */
530        public /* XAResourceManager */ Object getXAResourceManager()
531        throws StandardException
532    {
533        return(xactFactory.getXAResourceManager());
534    }
535 
536 
537        public Transaction startGlobalTransaction(
538    ContextManager  contextMgr,
539    int             format_id,
540    byte[]          global_id,
541    byte[]          branch_id)
542        throws StandardException
543    {
544                return xactFactory.startGlobalTransaction(
545                    this, contextMgr, format_id, global_id, branch_id);
546        }
547 
548        public Transaction startTransaction(ContextManager contextMgr, String transName)
549        throws StandardException
550    {
551                return xactFactory.startTransaction(this, contextMgr, transName);
552        }
553 
554        public Transaction startNestedReadOnlyUserTransaction(
555    Object          compatibilitySpace,
556    ContextManager  contextMgr,
557    String          transName)
558        throws StandardException
559    {
560                return(
561            xactFactory.startNestedReadOnlyUserTransaction(
562                this, compatibilitySpace, contextMgr, transName));
563        }
564 
565        public Transaction startNestedUpdateUserTransaction(
566    ContextManager  contextMgr,
567    String          transName)
568        throws StandardException
569    {
570                return(
571            xactFactory.startNestedUpdateUserTransaction(
572                this, contextMgr, transName));
573        }
574 
575        public Transaction findUserTransaction(
576        ContextManager contextMgr,
577        String transName)
578                 throws StandardException
579        {
580                return xactFactory.findUserTransaction(this, contextMgr, transName);
581        }
582 
583 
584        public Transaction startInternalTransaction(ContextManager contextMgr) throws StandardException {
585 
586                return xactFactory.startInternalTransaction(this, contextMgr);
587        }
588 
589        public void checkpoint() throws StandardException
590        {
591                logFactory.checkpoint(this, dataFactory, xactFactory, false);
592        }
593 
594        public void freeze() throws StandardException
595        {
596                logFactory.checkpoint(this, dataFactory, xactFactory, true);
597                dataFactory.freezePersistentStore();
598                logFactory.freezePersistentStore();
599        }
600 
601        public void unfreeze() throws StandardException
602        {
603                logFactory.unfreezePersistentStore();
604                dataFactory.unfreezePersistentStore();
605        }
606 
607    /**
608     * Backup the database to a backup directory.
609     *
610     * @param backupDir the name of the directory where the backup should be
611     *                  stored. This directory will be created if it 
612     *                  does not exist.
613     * @param wait if <tt>true</tt>, waits for  all the backup blocking 
614     *             operations in progress to finish.
615     * @exception StandardException thrown on error
616     */
617    public void backup(String backupDir, boolean wait) 
618        throws StandardException 
619    {
620                if (backupDir == null || backupDir.equals(""))
621        {
622                        throw StandardException.newException(
623                SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY, (File)null);
624        }
625 
626                // in case this is an URL form
627                String backupDirURL = null;
628                try {
629                        URL url = new URL(backupDir);
630                        backupDirURL = url.getFile();
631                } catch (MalformedURLException ex) {}
632 
633                if (backupDirURL != null)
634                        backupDir = backupDirURL;
635 
636 
637                // find the user transaction, it is necessary for online backup 
638                // to open the container through page cache
639                RawTransaction t = 
640            xactFactory.findUserTransaction(this,
641                ContextService.getFactory().getCurrentContextManager(), 
642                AccessFactoryGlobals.USER_TRANS_NAME);
643 
644                try {
645 
646            // check if  any backup blocking operations are in progress
647            // in the same transaction backup is being executed? Backup is 
648            // not allowed if the transaction has uncommitted
649            // unlogged operations that are blocking the backup.
650            
651            if (t.isBlockingBackup())
652            {
653                throw StandardException.newException(
654                      SQLState.BACKUP_OPERATIONS_NOT_ALLOWED);  
655            }
656 
657 
658            // check if any backup blocking operations are in progress
659            // and stop new ones from starting until the backup is completed.
660            if (!xactFactory.blockBackupBlockingOperations(wait))
661            {
662                throw StandardException.newException(
663                      SQLState.BACKUP_BLOCKING_OPERATIONS_IN_PROGRESS);  
664            }
665 
666            // perform backup
667            backup(t, new File(backupDir));
668        }finally {
669            // let the xactfatory know that backup is done, so that
670            // it can allow backup blocking operations. 
671            xactFactory.unblockBackupBlockingOperations();
672        }
673        }
674 
675 
676        /*
677         * Backup the database.
678         * Online backup copies all the database files (log, seg0  ...Etc) to the
679         * specified backup location without blocking any user operation for the 
680         * duration of the backup. Stable copy is made of each page using using 
681     * page level latches and in some cases with the help of monitors.  
682     * Transaction log is also backed up, this is used to bring the database to 
683     * the consistent state on restore.
684         * 
685     * <P> MT- only one thread  is allowed to perform backup at any given time. 
686     *  Synchronized on this. Parallel backups are not supported. 
687         */
688        public synchronized void backup(Transaction t, 
689                                    File backupDir) 
690        throws StandardException
691        {
692        if (!privExists(backupDir))
693                {
694            if (!privMkdirs(backupDir))
695            {
696                throw StandardException.newException(
697                    SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
698                    (File) backupDir);
699            }
700                }
701                else
702                {
703            if (!privIsDirectory(backupDir))
704            {
705                                throw StandardException.newException(
706                    SQLState.RAWSTORE_CANNOT_BACKUP_TO_NONDIRECTORY,
707                    (File) backupDir);
708            }
709 
710            // check if a user has given the backup as a database directory by
711            // mistake, backup path can not be a derby database directory. 
712            // If a directory contains PersistentService.PROPERTIES_NAME, it 
713            // is assumed as derby database directory because derby databases
714            // always has this file. 
715 
716            if (privExists(new File(backupDir, PersistentService.PROPERTIES_NAME))) { 
717                throw StandardException.newException(
718                    SQLState.RAWSTORE_CANNOT_BACKUP_INTO_DATABASE_DIRECTORY,
719                    (File) backupDir); 
720            }
721                }
722                
723                boolean error = true;
724                boolean renamed = false;
725                boolean renameFailed = false;
726                File oldbackup = null;
727                File backupcopy = null;
728                OutputStreamWriter historyFile = null;
729        StorageFile dbHistoryFile = null;
730        File backupHistoryFile = null;
731                LogInstant backupInstant = logFactory.getFirstUnflushedInstant();
732        
733                try
734                {
735                        // first figure out our name
736                        StorageFile dbase = storageFactory.newStorageFile( null); // The database directory
737            String canonicalDbName = storageFactory.getCanonicalName();
738            int lastSep = canonicalDbName.lastIndexOf( storageFactory.getSeparator());
739                        String dbname = canonicalDbName.substring( lastSep + 1);
740 
741                        // append to end of history file
742                        historyFile = privFileWriter( storageFactory.newStorageFile( BACKUP_HISTORY), true);
743            
744                        backupcopy = new File(backupDir, dbname);
745 
746                        logHistory(historyFile,
747                        MessageService.getTextMessage(
748                            MessageId.STORE_BACKUP_STARTED, 
749                            canonicalDbName, 
750                            getFilePath(backupcopy)));
751 
752            
753            // check if a backup copy of this database already exists,
754            if (privExists(backupcopy))
755                        {
756                                // first make a backup of the backup
757                                oldbackup = new File(backupDir, dbname+".OLD");
758                if (privExists(oldbackup))
759                                {
760                    if (privIsDirectory(oldbackup))
761                        privRemoveDirectory(oldbackup);
762                                        else
763                        privDelete(oldbackup);
764                                }
765 
766                if (!privRenameTo(backupcopy,oldbackup))
767                {
768                    renameFailed = true;
769                    throw StandardException.
770                        newException(SQLState.RAWSTORE_ERROR_RENAMING_FILE,
771                                     backupcopy, oldbackup);
772                }
773                                else
774                                {
775                                        logHistory(
776                        historyFile,
777                        MessageService.getTextMessage(
778                            MessageId.STORE_MOVED_BACKUP,
779                            getFilePath(backupcopy),
780                            getFilePath(oldbackup)));
781                                        renamed = true;
782                                }
783                        }
784 
785            // create the backup database directory
786            if (!privMkdirs(backupcopy))
787            {
788                throw StandardException.newException(
789                    SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
790                    (File) backupcopy);
791            }
792 
793            dbHistoryFile = storageFactory.newStorageFile(BACKUP_HISTORY);
794            backupHistoryFile = new File(backupcopy, BACKUP_HISTORY); 
795            // copy the history file into the backup. 
796            if(!privCopyFile(dbHistoryFile, backupHistoryFile))
797                throw StandardException. 
798                    newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
799                                 dbHistoryFile, backupHistoryFile);  
800 
801 
802            // if they are any jar file stored in the database, copy them into
803            // the backup. 
804            StorageFile jarDir = 
805                storageFactory.newStorageFile(FileResource.JAR_DIRECTORY_NAME);
806            if (privExists(jarDir)) {
807 
808                // find the list of schema directories under the jar dir and
809                // then copy only the plain files under those directories. One could
810                // just use the recursive copy of directory to copy all the files
811                // under the jar dir, but the problem with that is if a user 
812                // gives jar directory as the backup path by mistake, copy will 
813                // fail while copying the backup dir onto itself in recursion
814 
815                String [] jarSchemaList = privList(jarDir);
816                File backupJarDir = new File(backupcopy, 
817                                             FileResource.JAR_DIRECTORY_NAME);
818                // Create the backup jar directory
819                if (!privMkdirs(backupJarDir))
820                {
821                    throw StandardException.newException(
822                          SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
823                          (File) backupJarDir);
824                }
825 
826                for (int i = 0; i < jarSchemaList.length; i++)
827                {
828                    StorageFile jarSchemaDir = 
829                        storageFactory.newStorageFile(jarDir, jarSchemaList[i]);
830                    File backupJarSchemaDir = new File(backupJarDir, jarSchemaList[i]);
831                    if (!privCopyDirectory(jarSchemaDir, backupJarSchemaDir, 
832                                           (byte[])null, null, false)) {
833                        throw StandardException.
834                            newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
835                                         jarSchemaDir, backupJarSchemaDir);  
836                    }
837                }
838            }
839 
840 
841            // save service properties into the backup, Read in property 
842            // from service.properties file, remove logDevice from it, 
843            // then write it to the backup.
844 
845            StorageFile logdir = logFactory.getLogDirectory();
846            
847            try {
848                
849                String name = Monitor.getMonitor().getServiceName(this);
850                PersistentService ps = Monitor.getMonitor().getServiceType(this);
851                String fullName = ps.getCanonicalServiceName(name);
852                Properties prop = ps.getServiceProperties(fullName, (Properties)null);
853                StorageFile defaultLogDir = 
854                    storageFactory.newStorageFile( LogFactory.LOG_DIRECTORY_NAME);
855 
856                if (!logdir.equals(defaultLogDir))  
857                {
858                    prop.remove(Attribute.LOG_DEVICE);
859                    if (SanityManager.DEBUG)
860                        SanityManager.ASSERT(prop.getProperty(Attribute.LOG_DEVICE) == null,
861                                             "cannot get rid of logDevice property");
862                    logHistory(historyFile,
863                               MessageService.getTextMessage(
864                               MessageId.STORE_EDITED_SERVICEPROPS));
865                }
866            
867                // save the service properties into the backup.
868                ps.saveServiceProperties( backupcopy.getPath(), prop, false);
869 
870            }catch(StandardException se) {
871                logHistory(historyFile,
872                           MessageService.getTextMessage(
873                           MessageId.STORE_ERROR_EDIT_SERVICEPROPS)
874                           + se);
875 
876                return; // skip the rest and let finally block clean up
877            }
878 
879            // Incase of encrypted database and the key is an external 
880            // encryption key, there is an extra file with name  
881            // Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE , this file should be
882            // copied in to the backup.
883            StorageFile verifyKeyFile = 
884                storageFactory.newStorageFile(
885                                 Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
886            if (privExists(verifyKeyFile)) {
887                File backupVerifyKeyFile = 
888                    new File(backupcopy, Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
889                if(!privCopyFile(verifyKeyFile, backupVerifyKeyFile))
890                   throw StandardException.
891                       newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
892                                    verifyKeyFile, backupVerifyKeyFile);  
893            }
894                
895                        File logBackup = new File(backupcopy, LogFactory.LOG_DIRECTORY_NAME);
896 
897                        // this is wierd, delete it
898            if (privExists(logBackup))
899                        {
900                privRemoveDirectory(logBackup);
901                        }
902 
903                        // Create the log directory
904            if (!privMkdirs(logBackup))
905            {
906                throw StandardException.newException(
907                    SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
908                    (File) logBackup);
909            }
910 
911                        // do a checkpoint to get the persistent store up to date.
912                        logFactory.checkpoint(this, dataFactory, xactFactory, true);
913                        
914                        // start the transaction log  backup. 
915            logFactory.startLogBackup(logBackup);
916 
917                        File segBackup = new File(backupcopy, "seg0");
918                        
919                        // Create the data segment directory
920            if (!privMkdirs(segBackup))
921            {
922                throw StandardException.newException(
923                    SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
924                    (File) segBackup);
925            }
926 
927 
928                        // backup all the information in the data segment.
929                        dataFactory.backupDataFiles(t, segBackup);
930 
931            logHistory(historyFile,
932                   MessageService.getTextMessage(
933                   MessageId.STORE_DATA_SEG_BACKUP_COMPLETED,
934                   getFilePath(segBackup)));
935 
936 
937            // copy the log that got generated after the backup started to
938                        // backup location and tell the logfactory that backup has come to end.
939                        logFactory.endLogBackup(logBackup);
940                                                                                                                                                  
941                        logHistory(historyFile,
942                MessageService.getTextMessage(
943                    MessageId.STORE_COPIED_LOG,
944                    getFilePath(logdir),
945                    getFilePath(logBackup)));
946 
947                        error = false;
948                }
949                catch (IOException ioe)
950                {
951                        throw StandardException.newException(
952                    SQLState.RAWSTORE_UNEXPECTED_EXCEPTION, ioe);
953                }
954                finally
955                {
956 
957                        try
958                        {
959                                if (error)
960                                {
961                                        
962                                        // Abort all activity related to backup in the log factory.
963                                        logFactory.abortLogBackup();
964 
965                                        // remove the half backed up copy
966                                        // unless the error occured during  rename process;
967                                        // inwhich case 'backupcopy' refers to the previous backup
968                                        // not an half backed one.
969                                        if(!renameFailed)
970                                                privRemoveDirectory(backupcopy);
971 
972                                        if (renamed)
973                                                // recover the old backup
974                        privRenameTo(oldbackup,backupcopy);
975 
976                                        logHistory(historyFile,
977                        MessageService.getTextMessage(
978                            MessageId.STORE_BACKUP_ABORTED));
979 
980                                 }
981                                else
982                                {
983                                        // success, remove the old backup copy
984                    if (renamed && privExists(oldbackup))
985                                        {
986                                                // get rid of the old backup
987                        privRemoveDirectory(oldbackup);
988                                                logHistory(historyFile,
989                            MessageService.getTextMessage(
990                                MessageId.STORE_REMOVED_BACKUP,
991                                getFilePath(oldbackup)));
992                                         }
993                                        logHistory(historyFile,
994                        MessageService.getTextMessage(
995                            MessageId.STORE_BACKUP_COMPLETED,
996                            backupInstant));
997 
998                    // copy the updated version of history file with current
999                    // backup information into the backup.
1000                    if(!privCopyFile(dbHistoryFile, backupHistoryFile))
1001                        throw StandardException. 
1002                            newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
1003                                         dbHistoryFile, backupHistoryFile);  
1004                                }
1005 
1006                                historyFile.close();
1007                        }
1008                        catch (IOException ioe)
1009                        {
1010                try
1011                {
1012                    historyFile.close();
1013                }
1014                catch (IOException ioe2){};
1015                throw StandardException.newException(
1016                        SQLState.RAWSTORE_UNEXPECTED_EXCEPTION, ioe);
1017                        }
1018                }
1019 
1020        }
1021 
1022    /**
1023     * Backup the database to a backup directory and enable the log archive
1024         * mode that will keep the archived log files required for roll-forward
1025         * from this version backup.
1026     *
1027     * @param backupDir the name of the directory where the backup should be
1028     *                  stored. This directory will be created if it 
1029     *                  does not exist.   
1030     *
1031     * @param deleteOnlineArchivedLogFiles  
1032     *                  If true deletes online archived 
1033     *                  log files that exist before this backup, delete 
1034     *                  will occur  only after the backup is  complete.
1035     *
1036     * @param wait      if <tt>true</tt>, waits for  all the backup blocking 
1037     *                  operations in progress to finish.
1038     *
1039     * @exception StandardException thrown on error.
1040     */
1041    public void backupAndEnableLogArchiveMode(
1042    String backupDir,
1043    boolean deleteOnlineArchivedLogFiles,
1044    boolean wait) 
1045                throws StandardException
1046        {
1047        boolean enabledLogArchive = false;
1048        try {
1049            // Enable the log archive mode, if it is not already enabled.
1050            if(!logFactory.logArchived()) {
1051                logFactory.enableLogArchiveMode();
1052                enabledLogArchive = true ;
1053            }
1054 
1055            backup(backupDir, wait);
1056            
1057            // After successful backup delete the archived log files
1058            // that are not necessary to do a roll-forward recovery
1059            // from this backup if requested.
1060            if (deleteOnlineArchivedLogFiles)
1061            {
1062                logFactory.deleteOnlineArchivedLogFiles();
1063            }
1064        }catch (Throwable error) {
1065            // On any errors , disable the log archive, if it 
1066            // is enabled on this call. 
1067            if (enabledLogArchive)
1068                logFactory.disableLogArchiveMode();
1069            throw StandardException.plainWrapException(error);
1070        }
1071        }
1072 
1073 
1074    /*
1075     * Disable the log archive mode and delete the archived log files 
1076     * if requested. 
1077     *
1078     * @param deleteOnlineArchivedLogFiles  
1079     *              If true deletes online archived 
1080     *              log files that exist before this backup, delete 
1081     *              will occur  only after the backup is  complete.
1082     * @exception StandardException thrown on error.
1083     */
1084        public void disableLogArchiveMode(boolean deleteOnlineArchivedLogFiles)
1085                throws StandardException
1086        {
1087                logFactory.disableLogArchiveMode();
1088                if(deleteOnlineArchivedLogFiles)
1089                {
1090            logFactory.deleteOnlineArchivedLogFiles();
1091        }
1092        }
1093 
1094        
1095        //copies the files from the backup that does not need
1096        //any special handling like jars.
1097        private void restoreRemainingFromBackup(String backupPath) throws StandardException
1098        {
1099                /** 
1100                 *copy the files from the backup except the ones that we already
1101                 *copied in the boot methods(like log directory and data segments)
1102                 *AND Service.properties file which we create last to
1103                 *indicate the end of copy from backup.
1104                 */
1105 
1106                File backuploc = new File(backupPath);
1107                String[] fromList = privList(backuploc);
1108                for(int i =0 ; i < fromList.length ; i++)
1109                {
1110                        StorageFile toFile = storageFactory.newStorageFile( fromList[i]);
1111                        if(privExists(toFile) || 
1112                           fromList[i].equals(PersistentService.PROPERTIES_NAME)){
1113                                continue;
1114                        }
1115 
1116                        File fromFile = new File(backuploc, fromList[i]);
1117                        if(privIsDirectory(fromFile))
1118                        {
1119                                if (!privCopyDirectory(fromFile, toFile)){
1120                                        throw StandardException.newException(
1121                         SQLState.UNABLE_TO_COPY_FILE_FROM_BACKUP, 
1122                         fromFile, toFile);
1123                                }
1124                        }else{
1125                                if (!privCopyFile(fromFile, toFile)){
1126                                        throw StandardException.newException(
1127                         SQLState.UNABLE_TO_COPY_FILE_FROM_BACKUP,
1128                         fromFile, toFile);
1129                                }
1130                        }
1131                }
1132        }
1133 
1134        public void idle() throws StandardException {
1135                dataFactory.idle();
1136        }
1137 
1138 
1139        public TransactionInfo[] getTransactionInfo()
1140        {
1141                return xactFactory.getTransactionInfo();
1142        }
1143 
1144 
1145        public ScanHandle openFlushedScan(DatabaseInstant start, int groupsIWant)
1146                 throws StandardException
1147        {
1148                return logFactory.openFlushedScan(start,groupsIWant);
1149        }
1150 
1151        public DaemonService getDaemon()
1152        {
1153                return rawStoreDaemon;
1154        }
1155 
1156        public void createFinished() throws StandardException
1157        {
1158                xactFactory.createFinished();
1159                dataFactory.createFinished();
1160        }
1161 
1162        /**
1163         * Get JBMS properties relavent to raw store
1164         * @exception StandardException Standard Cloudscape Error Policy
1165         */
1166        public void getRawStoreProperties(PersistentSet set)
1167                 throws StandardException
1168        {
1169                logFactory.getLogFactoryProperties(set);
1170        }
1171 
1172 
1173        /*
1174        ** backup restore
1175        */
1176        /**
1177                Freeze persistent store.  Reads can still happen, only cannot write.
1178                @exception StandardException Standard Cloudscape Error Policy
1179         */
1180        public void freezePersistentStore() throws StandardException
1181        {
1182                // do a checkpoint to get the persistent store up to date.
1183                logFactory.checkpoint(this, dataFactory, xactFactory,true);
1184                logFactory.freezePersistentStore();
1185 
1186        }
1187 
1188        /**
1189                Freeze persistent store.  Reads can still happen, only cannot write.
1190                @exception StandardException Standard Cloudscape Error Policy
1191         */
1192        public void unfreezePersistentStore() throws StandardException
1193        {
1194                logFactory.unfreezePersistentStore();
1195        }
1196 
1197 
1198        /*
1199        ** data encryption/decryption support
1200        */
1201 
1202 
1203    
1204 
1205        /**
1206                Encrypt cleartext into ciphertext.
1207 
1208                @see CipherProvider#encrypt
1209 
1210                @exception StandardException Standard Cloudscape Error Policy
1211         */
1212        public int encrypt(byte[] cleartext, int offset, int length,
1213                                           byte[] ciphertext, int outputOffset, 
1214                       boolean newEngine)
1215                 throws StandardException
1216        {
1217                if ((databaseEncrypted == false && encryptDatabase == false) || 
1218            (encryptionEngine == null && newEncryptionEngine == null))
1219        {
1220            throw StandardException.newException(
1221                        SQLState.STORE_FEATURE_NOT_IMPLEMENTED);
1222        }
1223 
1224                counter_encrypt++;
1225 
1226        if (newEngine) {
1227            return newEncryptionEngine.encrypt(cleartext, offset, length,
1228                                            ciphertext, outputOffset);
1229        } else {
1230            return encryptionEngine.encrypt(cleartext, offset, length,
1231                                            ciphertext, outputOffset);
1232        }
1233        }
1234 
1235        /**
1236                Decrypt cleartext from ciphertext.
1237 
1238                @see CipherProvider#decrypt
1239 
1240                @exception StandardException Standard Cloudscape Error Policy
1241         */
1242        public int decrypt(byte[] ciphertext, int offset, int length,
1243                                           byte[] cleartext, int outputOffset) 
1244                 throws StandardException
1245        {
1246                if (databaseEncrypted == false || decryptionEngine == null)
1247        {
1248            throw StandardException.newException(
1249                        SQLState.STORE_FEATURE_NOT_IMPLEMENTED);
1250        }
1251 
1252                counter_decrypt++;
1253        return decryptionEngine.decrypt(ciphertext, offset, length,
1254                                            cleartext, outputOffset);
1255        }
1256 
1257        /**
1258                Returns the encryption block size used by the algorithm at time of
1259                creation of an encrypted database
1260         */
1261        public int getEncryptionBlockSize()
1262        {
1263                return encryptionBlockSize;
1264        }
1265 
1266        public int random()
1267        {
1268                // don't synchronize it, the more random the better.
1269                return databaseEncrypted ? random.nextInt() : 0;
1270        }
1271 
1272        public Serializable changeBootPassword(Properties properties, Serializable changePassword)
1273                 throws StandardException
1274        {
1275                if (isReadOnly())
1276                        throw StandardException.newException(SQLState.DATABASE_READ_ONLY);
1277 
1278                if (!databaseEncrypted)
1279                        throw StandardException.newException(SQLState.DATABASE_NOT_ENCRYPTED);
1280 
1281                if (changePassword == null)
1282                        throw StandardException.newException(SQLState.NULL_BOOT_PASSWORD);
1283 
1284                if (!(changePassword instanceof String))
1285                        throw StandardException.newException(SQLState.NON_STRING_BP);
1286 
1287                // the new bootPassword is expected to be of the form
1288                // oldkey , newkey.
1289                String changeString = (String)changePassword;
1290 
1291                return currentCipherFactory.changeBootPassword((String)changePassword, properties, encryptionEngine);
1292 
1293        }
1294 
1295 
1296 
1297    /*
1298     * Configure the database for encryption, with the  specified 
1299     * encryption  properties.
1300     *
1301     * Basic idea is to encrypt all the containers with new password/key 
1302     * specified by the user and keep old versions of the data to 
1303     * rollback the database to the state before the configuration of database 
1304     * with new encryption attributes. Users can configure the database with 
1305     * new encryption  attributes at boot time only; advantage of this approach
1306     * is that there will not be any concurrency issues to handle because
1307     * no users will be modifying the data. 
1308 
1309     * First step is to encrypt the existing data with new encryption 
1310     * attributes  and then update the encryption properties for 
1311     * the database. Configuring  an un-encrypted database for 
1312     * encryption problem is a minor variation of  re-encrypting an 
1313     * encrypted database with new encryption key. The database 
1314     * reconfiguration with new encryption attributes is done under one
1315     * transaction, if there is a crash/error before it is committed, 
1316     * then it  is rolled back and the database will be brought back to the
1317     * state it was before the encryption.  
1318     * @param properties  properties related to this database.
1319     * @exception StandardException Standard Cloudscape Error Policy
1320     */
1321    public void configureDatabaseForEncryption(Properties properties,
1322                                               boolean reEncrypt, 
1323                                               CipherFactory newCipherFactory) 
1324        throws StandardException 
1325    {
1326 
1327        // check point the datase, so that encryption does not have
1328        // to encrypt the existing transactions logs. 
1329 
1330        logFactory.checkpoint(this, dataFactory, xactFactory, true);
1331 
1332        // start a transaction that is to be used for encryting the database
1333        RawTransaction transaction =
1334            xactFactory.startTransaction(
1335                   this,
1336                    ContextService.getFactory().getCurrentContextManager(),
1337                    AccessFactoryGlobals.USER_TRANS_NAME);
1338        boolean error = true;
1339        try {
1340            dataFactory.encryptAllContainers(transaction);
1341            error = false;
1342        }finally {
1343            
1344            // encryption is finished. close the transaction.
1345            if (error) { 
1346                transaction.abort();
1347            }
1348            else {
1349                transaction.commit();
1350 
1351                // TODO : handle the case where if engine crashes
1352                // after the commit but before the new database
1353                // encryption properties are made persistent. 
1354                
1355                // let log factory and data factory know that 
1356                // database is encrypted.
1357                logFactory.setDatabaseEncrypted();
1358                logFactory.setupLogEncryption();
1359                dataFactory.setDatabaseEncrypted();
1360                
1361                // mark in the raw store that the database is 
1362                // encrypted. 
1363                databaseEncrypted = true;
1364                encryptDatabase = false;
1365                //switch the encryption/decryption engine to the new ones.
1366                if (reEncrypt) {
1367                    decryptionEngine = newDecryptionEngine;  
1368                    encryptionEngine = newEncryptionEngine;
1369                    currentCipherFactory = newCipherFactory;
1370                }
1371 
1372                //force a checkpoint with new encryption algorithm
1373                logFactory.checkpoint(this, dataFactory, xactFactory, true);
1374                // store the encryption block size;
1375                properties.put(RawStoreFactory.ENCRYPTION_BLOCKSIZE,
1376                               String.valueOf(encryptionBlockSize));
1377                // save the encryption properties.
1378                currentCipherFactory.saveProperties(properties) ;
1379 
1380                // incase of rencrytion of database, save information needed 
1381                // to verify the new key on a next boot. 
1382                if (reEncrypt) {
1383                    currentCipherFactory.verifyKey(reEncrypt, 
1384                                               storageFactory, 
1385                                               properties);
1386                }
1387 
1388            }                
1389            newDecryptionEngine = null;   
1390            newEncryptionEngine = null;
1391            transaction.close(); 
1392        }
1393    }
1394 
1395 
1396        /*
1397        **
1398        */
1399 
1400        public StandardException markCorrupt(StandardException originalError) {
1401 
1402                logFactory.markCorrupt(originalError);
1403                dataFactory.markCorrupt(originalError);
1404                xactFactory.markCorrupt(originalError);
1405 
1406                return originalError;
1407        }
1408 
1409        /*
1410         * class specific methods
1411         */
1412 
1413        /* subclass can override this method to load different submodules */
1414        public String getTransactionFactoryModule()
1415        {
1416                return TransactionFactory.MODULE;
1417        }
1418 
1419        public String getDataFactoryModule()
1420        {
1421                return DataFactory.MODULE;
1422        }
1423 
1424        public String getLogFactoryModule()
1425        {
1426                return LogFactory.MODULE;
1427        }
1428 
1429 
1430        private void logHistory(OutputStreamWriter historyFile, String msg) throws IOException
1431        {
1432                Date d = new Date();
1433                historyFile.write(d.toString() + ":" + msg + "\n");
1434                historyFile.flush();
1435        }
1436 
1437    /*
1438     * Get the file path. If the canonical path can be obtained then return the 
1439     * canonical path, otherwise just return the abstract path. Typically if
1440     * there are no permission to read user.dir when  running under security
1441     * manager canonical path can not be obtained.
1442     *
1443     * This method is used to a write path name to error/status log file, where it
1444     * would be nice to print full paths but not esstential that the user 
1445     * grant permissions to read user.dir property.
1446     */
1447    private String getFilePath(StorageFile file) {
1448        String path = privGetCanonicalPath(file);
1449        if(path != null ) {
1450            return path;
1451        }else {
1452            //can not get the canoncal path, 
1453            // return the abstract path
1454            return file.getPath();
1455        }
1456    }
1457 
1458    /*
1459     * Get the file path.  If the canonical path can be obtained then return the 
1460     * canonical path, otherwise just return the abstract path. Typically if
1461     * there are no permission to read user.dir when  running under security
1462     * manager canonical path can not be obtained.
1463     *
1464     * This method is used to a write a file path name to error/status log file, 
1465     * where it would be nice to print full paths but not esstential that the user
1466     * grant permissions to read user.dir property.
1467     *
1468     */
1469    private String getFilePath(File file) {
1470        String path = privGetCanonicalPath(file);
1471        if(path != null ) {
1472            return path;
1473        }else {
1474            // can not get the canoncal path, 
1475            // return the abstract path
1476            return file.getPath();
1477        }
1478    }
1479 
1480        protected boolean privCopyDirectory(StorageFile from, File to)
1481        {
1482                return privCopyDirectory(from, to, (byte[])null, 
1483                                 (String[])null, true);
1484        }
1485 
1486        protected boolean privCopyDirectory(File from, StorageFile to)
1487        {
1488                return privCopyDirectory(from, to, (byte[])null, (String[])null);
1489        }
1490 
1491    /**
1492     * Return an id which can be used to create a container.
1493     * <p>
1494     * Return an id number with is greater than any existing container
1495     * in the current database.  Caller will use this to allocate future
1496     * container numbers - most likely caching the value and then incrementing
1497     * it as it is used.
1498     * <p>
1499     *
1500         * @return The an id which can be used to create a container.
1501     *
1502         * @exception  StandardException  Standard exception policy.
1503     **/
1504    public long getMaxContainerId()
1505                throws StandardException
1506    {
1507        return(dataFactory.getMaxContainerId());
1508    }
1509 
1510        
1511    /*
1512        These methods require Priv Blocks when run under a security manager.
1513    */
1514 
1515        private synchronized OutputStreamWriter privFileWriter( StorageFile fileName, boolean append) throws IOException
1516        {
1517        actionCode = FILE_WRITER_ACTION;
1518        actionStorageFile = fileName;
1519        actionAppend = append;
1520                try{
1521                        return (OutputStreamWriter) java.security.AccessController.doPrivileged( this);
1522                }catch (java.security.PrivilegedActionException pae)
1523        {
1524            throw (IOException) pae.getException();
1525        }
1526        finally
1527        {
1528            actionStorageFile = null;
1529        }
1530        }
1531 
1532        private synchronized boolean privExists( File file)
1533    {
1534        actionCode = REGULAR_FILE_EXISTS_ACTION;
1535        actionRegularFile = file;
1536 
1537        try
1538        {
1539            Object ret = AccessController.doPrivileged( this);
1540            return ((Boolean) ret).booleanValue();
1541        }
1542        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1543        finally
1544        {
1545            actionRegularFile = null;
1546        }
1547    }
1548 
1549        private synchronized boolean privExists(final StorageFile file)
1550    {
1551        actionCode = STORAGE_FILE_EXISTS_ACTION;
1552        actionStorageFile = file;
1553 
1554        try
1555        {
1556            Object ret = AccessController.doPrivileged( this);
1557            return ((Boolean) ret).booleanValue();
1558        }
1559        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1560        finally
1561        {
1562            actionStorageFile = null;
1563        }
1564    }
1565 
1566 
1567    private synchronized boolean privDelete( File file)
1568    {
1569        actionCode = REGULAR_FILE_DELETE_ACTION;
1570        actionRegularFile = file;
1571 
1572        try
1573        {
1574            Object ret = AccessController.doPrivileged( this);
1575            return ((Boolean) ret).booleanValue();
1576        }
1577        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1578        finally
1579        {
1580            actionRegularFile = null;
1581        }
1582    }
1583 
1584 
1585    private synchronized boolean privMkdirs( File file)
1586    {
1587        actionCode = REGULAR_FILE_MKDIRS_ACTION;
1588        actionRegularFile = file;
1589 
1590        try
1591        {
1592            Object ret = AccessController.doPrivileged( this);
1593            return ((Boolean) ret).booleanValue();
1594        }
1595        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1596        finally
1597        {
1598            actionRegularFile = null;
1599        }
1600    }
1601 
1602 
1603    private synchronized boolean privIsDirectory( File file)
1604    {
1605        actionCode = REGULAR_FILE_IS_DIRECTORY_ACTION;
1606        actionRegularFile = file;
1607 
1608        try
1609        {
1610            Object ret = AccessController.doPrivileged( this);
1611            return ((Boolean) ret).booleanValue();
1612        }
1613        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1614        finally
1615        {
1616            actionRegularFile = null;
1617        }
1618    }
1619 
1620    private synchronized boolean privRemoveDirectory( File file)
1621    {
1622        actionCode = REGULAR_FILE_REMOVE_DIRECTORY_ACTION;
1623        actionRegularFile = file;
1624 
1625        try
1626        {
1627            Object ret = AccessController.doPrivileged( this);
1628            return ((Boolean) ret).booleanValue();
1629        }
1630        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1631        finally
1632        {
1633            actionRegularFile = null;
1634        }
1635    }
1636 
1637    private synchronized boolean privRenameTo( File file1, File file2)
1638    {
1639        actionCode = REGULAR_FILE_RENAME_TO_ACTION;
1640        actionRegularFile = file1;
1641        actionRegularFile2 = file2;
1642 
1643        try
1644        {
1645            Object ret = AccessController.doPrivileged( this);
1646            return ((Boolean) ret).booleanValue();
1647        }
1648        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1649        finally
1650        {
1651            actionRegularFile = null;
1652            actionRegularFile2 = null;
1653        }
1654    }
1655 
1656    private synchronized boolean privCopyDirectory(StorageFile from, 
1657                                                   File to, 
1658                                                   byte[] buffer, 
1659                                                   String[] filter,
1660                                                   boolean copySubdirs)
1661    {
1662        actionCode = COPY_STORAGE_DIRECTORY_TO_REGULAR_ACTION;
1663        actionStorageFile = from;
1664        actionRegularFile = to;
1665        actionBuffer = buffer;
1666        actionFilter = filter;
1667        actionCopySubDirs = copySubdirs;
1668 
1669        try
1670        {
1671            Object ret = AccessController.doPrivileged( this);
1672            return ((Boolean) ret).booleanValue();
1673        }
1674        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1675        finally
1676        {
1677            actionStorageFile = null;
1678            actionRegularFile = null;
1679            actionBuffer = null;
1680            actionFilter = null;
1681        }
1682    }
1683 
1684 
1685    private synchronized boolean privCopyDirectory( File from, StorageFile to, byte[] buffer, String[] filter)
1686    {
1687        actionCode = COPY_REGULAR_DIRECTORY_TO_STORAGE_ACTION;
1688        actionStorageFile = to;
1689        actionRegularFile = from;
1690        actionBuffer = buffer;
1691        actionFilter = filter;
1692 
1693        try
1694        {
1695            Object ret = AccessController.doPrivileged( this);
1696            return ((Boolean) ret).booleanValue();
1697        }
1698        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1699        finally
1700        {
1701            actionStorageFile = null;
1702            actionRegularFile = null;
1703            actionBuffer = null;
1704            actionFilter = null;
1705        }
1706    }
1707 
1708        
1709    private synchronized boolean privCopyFile( File from, StorageFile to)
1710    {
1711        actionCode = COPY_REGULAR_FILE_TO_STORAGE_ACTION;
1712        actionStorageFile = to;
1713        actionRegularFile = from;
1714 
1715        try
1716        {
1717            Object ret = AccessController.doPrivileged( this);
1718            return ((Boolean) ret).booleanValue();
1719        }
1720        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1721        finally
1722        {
1723            actionStorageFile = null;
1724            actionRegularFile = null;
1725        }
1726    }
1727 
1728    private synchronized boolean privCopyFile( StorageFile from, File to)
1729    {
1730        actionCode = COPY_STORAGE_FILE_TO_REGULAR_ACTION;
1731        actionStorageFile = from;
1732        actionRegularFile = to;
1733 
1734        try
1735        {
1736            Object ret = AccessController.doPrivileged( this);
1737            return ((Boolean) ret).booleanValue();
1738        }
1739        catch( PrivilegedActionException pae) { return false;} // does not throw an exception
1740        finally
1741        {
1742            actionStorageFile = null;
1743            actionRegularFile = null;
1744        }
1745    }
1746 
1747 
1748    private synchronized String[] privList(final File file)
1749    {
1750        actionCode = REGULAR_FILE_LIST_DIRECTORY_ACTION;
1751        actionRegularFile = file;
1752 
1753        try
1754        {
1755            return (String[]) AccessController.doPrivileged( this);
1756        }
1757        catch( PrivilegedActionException pae) { return null;} // does not throw an exception
1758        finally
1759        {
1760            actionRegularFile = null;
1761        }
1762    }
1763 
1764    private synchronized String[] privList(final StorageFile file)
1765    {
1766        actionCode = STORAGE_FILE_LIST_DIRECTORY_ACTION;
1767        actionStorageFile = file;
1768 
1769        try
1770        {
1771            return (String[]) AccessController.doPrivileged( this);
1772        }
1773        catch( PrivilegedActionException pae) { return null;} // does not throw an exception
1774        finally
1775        {
1776            actionStorageFile = null;
1777        }
1778    }
1779 
1780 
1781    private synchronized String privGetCanonicalPath(final StorageFile file)
1782    {
1783        actionCode = STORAGE_FILE_GET_CANONICALPATH_ACTION;
1784        actionStorageFile = file;
1785 
1786        try
1787        {
1788            return (String) AccessController.doPrivileged( this);
1789        }
1790        catch( PrivilegedActionException pae) { 
1791            return null;
1792        } // does not throw an exception
1793        catch(SecurityException se) {
1794            // there are no permission to get canonical path 
1795            // just return null.
1796            return null;
1797        }
1798        finally
1799        {
1800            actionStorageFile = null;
1801        }
1802    }
1803 
1804 
1805    private synchronized String privGetCanonicalPath(final File file)
1806    {
1807        actionCode = REGULAR_FILE_GET_CANONICALPATH_ACTION;
1808        actionRegularFile = file;
1809 
1810        try
1811        {
1812            return (String) AccessController.doPrivileged( this);
1813        }
1814        catch( PrivilegedActionException pae) { 
1815            return null;
1816        } // does not throw an exception
1817        catch(SecurityException se) { 
1818            // there are no permission to get canonical path 
1819            // just return null.
1820            return null;
1821        }
1822        finally
1823        {
1824            actionRegularFile = null;
1825        }
1826    }
1827 
1828 
1829    // PrivilegedExceptionAction method
1830    public final Object run() throws IOException
1831    {
1832        switch(actionCode)
1833        {
1834        case FILE_WRITER_ACTION:
1835            // SECURITY PERMISSION - MP1
1836            return new OutputStreamWriter( actionStorageFile.getOutputStream( actionAppend));
1837 
1838        case REGULAR_FILE_EXISTS_ACTION:
1839            return ReuseFactory.getBoolean(actionRegularFile.exists());
1840 
1841        case STORAGE_FILE_EXISTS_ACTION:
1842            return ReuseFactory.getBoolean(actionStorageFile.exists());
1843 
1844        case REGULAR_FILE_DELETE_ACTION:
1845            return ReuseFactory.getBoolean(actionRegularFile.delete());
1846 
1847        case REGULAR_FILE_MKDIRS_ACTION:
1848            // SECURITY PERMISSION - OP4
1849            return ReuseFactory.getBoolean(actionRegularFile.mkdirs());
1850 
1851        case REGULAR_FILE_IS_DIRECTORY_ACTION:
1852            // SECURITY PERMISSION - MP1
1853            return ReuseFactory.getBoolean(actionRegularFile.isDirectory());
1854 
1855        case REGULAR_FILE_REMOVE_DIRECTORY_ACTION:
1856            // SECURITY PERMISSION - MP1, OP5
1857            return ReuseFactory.getBoolean(FileUtil.removeDirectory(actionRegularFile));
1858 
1859        case REGULAR_FILE_RENAME_TO_ACTION:
1860            // SECURITY PERMISSION - OP4
1861            return ReuseFactory.getBoolean(actionRegularFile.renameTo(actionRegularFile2));
1862 
1863        case COPY_STORAGE_DIRECTORY_TO_REGULAR_ACTION:
1864            // SECURITY PERMISSION - MP1, OP4
1865            return ReuseFactory.getBoolean(FileUtil.copyDirectory(storageFactory,
1866                                                                  actionStorageFile,
1867                                                                  actionRegularFile,
1868                                                                  actionBuffer,
1869                                                                  actionFilter,
1870                                                                  actionCopySubDirs));
1871 
1872        case COPY_REGULAR_DIRECTORY_TO_STORAGE_ACTION:
1873            // SECURITY PERMISSION - MP1, OP4
1874            return ReuseFactory.getBoolean(FileUtil.copyDirectory((WritableStorageFactory)storageFactory,
1875                                                                  actionRegularFile,
1876                                                                  actionStorageFile,
1877                                                                  actionBuffer,
1878                                                                  actionFilter));
1879 
1880        case COPY_REGULAR_FILE_TO_STORAGE_ACTION:
1881            // SECURITY PERMISSION - MP1, OP4
1882            return ReuseFactory.getBoolean(FileUtil.copyFile((WritableStorageFactory) storageFactory,
1883                                                             actionRegularFile,
1884                                                             actionStorageFile));
1885 
1886        case REGULAR_FILE_LIST_DIRECTORY_ACTION:
1887            // SECURITY PERMISSION - MP1
1888            return (String[])(actionRegularFile.list());
1889 
1890        case STORAGE_FILE_LIST_DIRECTORY_ACTION:
1891            // SECURITY PERMISSION - MP1
1892            return (String[])(actionStorageFile.list());
1893 
1894        case COPY_STORAGE_FILE_TO_REGULAR_ACTION:
1895            // SECURITY PERMISSION - MP1, OP4
1896            return ReuseFactory.getBoolean(FileUtil.copyFile(
1897                                           (WritableStorageFactory) storageFactory,
1898                                           actionStorageFile,
1899                                           actionRegularFile));
1900            
1901        case REGULAR_FILE_GET_CANONICALPATH_ACTION:
1902            // SECURITY PERMISSION - MP1
1903            return (String)(actionRegularFile.getCanonicalPath());
1904            
1905        case STORAGE_FILE_GET_CANONICALPATH_ACTION:
1906            // SECURITY PERMISSION - MP1
1907            return (String)(actionStorageFile.getCanonicalPath());
1908        }
1909        return null;
1910    } // end of run
1911}

[all classes][org.apache.derby.impl.store.raw]
EMMA 2.0.5312 (C) Vladimir Roubtsov