KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > raw > RawStore


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.RawStore
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.store.raw;
23
24 import org.apache.derby.iapi.services.daemon.DaemonFactory;
25 import org.apache.derby.iapi.services.daemon.DaemonService;
26 import org.apache.derby.iapi.services.context.ContextManager;
27 import org.apache.derby.iapi.services.context.ContextService;
28 import org.apache.derby.iapi.services.crypto.CipherFactoryBuilder;
29 import org.apache.derby.iapi.services.crypto.CipherFactory;
30 import org.apache.derby.iapi.services.crypto.CipherProvider;
31 import org.apache.derby.iapi.services.locks.LockFactory;
32 import org.apache.derby.iapi.services.monitor.Monitor;
33 import org.apache.derby.iapi.services.monitor.ModuleControl;
34 import org.apache.derby.iapi.services.monitor.ModuleSupportable;
35 import org.apache.derby.iapi.services.monitor.PersistentService;
36 import org.apache.derby.iapi.services.sanity.SanityManager;
37
38 import org.apache.derby.iapi.error.StandardException;
39 import org.apache.derby.iapi.services.i18n.MessageService;
40
41 import org.apache.derby.iapi.services.property.PersistentSet;
42 import org.apache.derby.iapi.store.access.TransactionInfo;
43 import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
44 import org.apache.derby.iapi.store.access.FileResource;
45 import org.apache.derby.iapi.store.raw.ScanHandle;
46 import org.apache.derby.iapi.store.raw.RawStoreFactory;
47 import org.apache.derby.iapi.store.raw.Transaction;
48 import org.apache.derby.iapi.store.raw.xact.RawTransaction;
49 import org.apache.derby.iapi.store.raw.xact.TransactionFactory;
50 import org.apache.derby.iapi.store.raw.data.DataFactory;
51 import org.apache.derby.iapi.store.raw.log.LogFactory;
52 import org.apache.derby.iapi.store.raw.log.LogInstant;
53 import org.apache.derby.impl.services.monitor.UpdateServiceProperties;
54
55 import org.apache.derby.io.StorageFactory;
56 import org.apache.derby.io.WritableStorageFactory;
57 import org.apache.derby.io.StorageFile;
58 import org.apache.derby.iapi.store.access.DatabaseInstant;
59 import org.apache.derby.catalog.UUID;
60 import org.apache.derby.iapi.services.property.PropertyUtil;
61 import org.apache.derby.iapi.services.io.FileUtil;
62 import org.apache.derby.iapi.util.ReuseFactory;
63 import org.apache.derby.iapi.util.StringUtil;
64 import org.apache.derby.iapi.reference.Attribute;
65 import org.apache.derby.iapi.reference.SQLState;
66 import org.apache.derby.iapi.reference.MessageId;
67 import org.apache.derby.iapi.reference.Property;
68
69 import java.security.AccessController JavaDoc;
70 import java.security.PrivilegedActionException JavaDoc;
71 import java.security.PrivilegedExceptionAction JavaDoc;
72 import java.security.SecureRandom JavaDoc;
73
74 import java.util.Date JavaDoc;
75 import java.util.Properties JavaDoc;
76 import java.io.Serializable JavaDoc;
77 import java.io.File JavaDoc;
78 import java.io.FileOutputStream JavaDoc;
79 import java.io.FileInputStream JavaDoc;
80 import java.io.IOException JavaDoc;
81 import java.io.FileNotFoundException JavaDoc;
82 import java.io.OutputStreamWriter JavaDoc;
83
84 import java.net.MalformedURLException JavaDoc;
85 import java.net.URL JavaDoc;
86
87 import java.security.PrivilegedExceptionAction JavaDoc;
88 import java.lang.SecurityException JavaDoc;
89
90
91 /**
92     A Raw store that implements the RawStoreFactory module by delegating all the
93     work to the lower modules TransactionFactory, LogFactory and DataFactory.
94     <PRE>
95     String TransactionFactoryId=<moduleIdentifier>
96     </PRE>
97     
98     <P>
99     Class is final as it has methods with privilege blocks
100     and implements PrivilegedExceptionAction.
101 */

102
103 public final class RawStore implements RawStoreFactory, ModuleControl, ModuleSupportable, PrivilegedExceptionAction JavaDoc
104 {
105     private static final String JavaDoc BACKUP_HISTORY = "BACKUP.HISTORY";
106     protected TransactionFactory xactFactory;
107     protected DataFactory dataFactory;
108     protected LogFactory logFactory;
109     private StorageFactory storageFactory;
110
111     private SecureRandom JavaDoc random;
112     private boolean databaseEncrypted;
113     private boolean encryptDatabase;
114     private CipherProvider encryptionEngine;
115     private CipherProvider decryptionEngine;
116     private CipherProvider newEncryptionEngine;
117     private CipherProvider newDecryptionEngine;
118     private CipherFactory currentCipherFactory;
119     private CipherFactory newCipherFactory = null;
120     private int counter_encrypt;
121     private int counter_decrypt;
122     private int encryptionBlockSize = RawStoreFactory.DEFAULT_ENCRYPTION_BLOCKSIZE;
123
124     String JavaDoc dataDirectory; // where files are stored
125

126     // this daemon takes care of all daemon work for this raw store
127
protected DaemonService rawStoreDaemon;
128
129     private int actionCode;
130     private static final int FILE_WRITER_ACTION = 1;
131     private StorageFile actionStorageFile;
132     private StorageFile actionToStorageFile;
133     private boolean actionAppend;
134     private static final int REGULAR_FILE_EXISTS_ACTION = 2;
135     private File actionRegularFile;
136     private static final int STORAGE_FILE_EXISTS_ACTION = 3;
137     private static final int REGULAR_FILE_DELETE_ACTION = 4;
138     private static final int REGULAR_FILE_MKDIRS_ACTION = 5;
139     private static final int REGULAR_FILE_IS_DIRECTORY_ACTION = 6;
140     private static final int REGULAR_FILE_REMOVE_DIRECTORY_ACTION = 7;
141     private static final int REGULAR_FILE_RENAME_TO_ACTION = 8;
142     private File actionRegularFile2;
143     private static final int COPY_STORAGE_DIRECTORY_TO_REGULAR_ACTION = 9;
144     private byte[] actionBuffer;
145     private String JavaDoc[] actionFilter;
146     private boolean actionCopySubDirs;
147     private static final int COPY_REGULAR_DIRECTORY_TO_STORAGE_ACTION = 10;
148     private static final int COPY_REGULAR_FILE_TO_STORAGE_ACTION = 11;
149     private static final int REGULAR_FILE_LIST_DIRECTORY_ACTION = 12;
150     private static final int STORAGE_FILE_LIST_DIRECTORY_ACTION = 13;
151     private static final int COPY_STORAGE_FILE_TO_REGULAR_ACTION = 14;
152     private static final int REGULAR_FILE_GET_CANONICALPATH_ACTION = 15;
153     private static final int STORAGE_FILE_GET_CANONICALPATH_ACTION = 16;
154     private static final int COPY_STORAGE_FILE_TO_STORAGE_ACTION = 17;
155     private static final int STORAGE_FILE_DELETE_ACTION = 18;
156
157     public RawStore() {
158     }
159
160     /*
161     ** Methods of ModuleControl
162     */

163
164     /**
165       We use this RawStore for all databases.
166       */

167     public boolean canSupport(Properties startParams) {
168         return true;
169     }
170
171     public void boot(boolean create, Properties properties)
172         throws StandardException
173     {
174         dataDirectory = properties.getProperty(PersistentService.ROOT);
175         DaemonFactory daemonFactory =
176             (DaemonFactory)Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.DaemonFactory);
177         rawStoreDaemon = daemonFactory.createNewDaemon("rawStoreDaemon");
178         xactFactory = (TransactionFactory)
179                     Monitor.bootServiceModule(
180                         create, this, getTransactionFactoryModule(), properties);
181
182         dataFactory = (DataFactory)
183                     Monitor.bootServiceModule(
184                       create, this, getDataFactoryModule(), properties);
185         storageFactory = dataFactory.getStorageFactory();
186
187         String JavaDoc restoreFromBackup = null;
188
189         if (properties != null)
190         {
191             // check if this is a restore from a backup copy.
192
restoreFromBackup = properties.getProperty(Attribute.CREATE_FROM);
193             if(restoreFromBackup == null)
194                 restoreFromBackup = properties.getProperty(Attribute.RESTORE_FROM);
195             if(restoreFromBackup == null)
196                 restoreFromBackup =
197                     properties.getProperty(Attribute.ROLL_FORWARD_RECOVERY_FROM);
198
199         }
200
201         // setup database encryption engines.
202
if (create)
203             setupEncryptionEngines(create, properties);
204
205
206         // let everyone knows who their rawStoreFactory is and they can use it
207
// to get to other modules
208
// pass in create and properties to dataFactory so it can boot the log
209
// factory
210

211         dataFactory.setRawStoreFactory(this, create, properties);
212         xactFactory.setRawStoreFactory(this);
213
214         if( properties instanceof UpdateServiceProperties)
215         {
216             if( storageFactory instanceof WritableStorageFactory)
217                 ((UpdateServiceProperties)properties).setStorageFactory( (WritableStorageFactory) storageFactory);
218         }
219         
220         // log factory is booted by the data factory
221
logFactory =(LogFactory) Monitor.findServiceModule(this, getLogFactoryModule());
222
223
224         //save the service properties to a file if we are doing a restore from
225
if(restoreFromBackup !=null)
226         {
227             //copy the jar files.etc from backup if they don't exist
228
restoreRemainingFromBackup(restoreFromBackup);
229             ((UpdateServiceProperties)properties).saveServiceProperties();
230         }
231
232         // If the log is at another location, make sure service.properties
233
// file has it.
234
String JavaDoc logDevice = properties.getProperty(Attribute.LOG_DEVICE);
235         if (logDevice !=null)
236         {
237             if (!isReadOnly() // We do not care about log location if read only
238
&& (create
239                     || !logDevice.equals(logFactory.getCanonicalLogPath())
240                     || restoreFromBackup!=null))
241             {
242                 // get the real location from the log factory
243
properties.put(Attribute.LOG_DEVICE, logFactory.getCanonicalLogPath());
244                 //make the log device param stored in backup is same as current log device.
245
properties.put(Property.LOG_DEVICE_AT_BACKUP, logFactory.getCanonicalLogPath());
246             }
247     
248         }else{
249             //when we restore from a backup logDevice param does not exists
250
//in service.properties to support restore using OS commands to work.
251
//Instead of logDevice, we user logDeviceWhenBackedUp parameter to
252
//identify the log location while restoring createFrom/restoreFrom/rollForwardRecoveryFrom
253
//attribute , following make sures the logDevice parameter gets
254
//into service.propertues in such cases.
255
if(restoreFromBackup!=null && logFactory.getCanonicalLogPath()!=null)
256             {
257                 //logdevice might have got changed because of backup restore.
258
properties.put(Attribute.LOG_DEVICE, logFactory.getCanonicalLogPath());
259             }
260             else{
261                 //might have been OS copy restore. We default log to db home
262
properties.remove(Property.LOG_DEVICE_AT_BACKUP);
263             }
264         }
265
266         
267         //save the service properties to a file if we are doing a restore from
268
if(restoreFromBackup !=null)
269         {
270             //copy the jar files.etc from backup if they don't exist
271
restoreRemainingFromBackup(restoreFromBackup);
272             ((UpdateServiceProperties)properties).saveServiceProperties();
273         }
274
275
276
277         /**
278          * Note: service.properties file acts as flags to indicate
279          * that the copy from backup is successful.
280          * If we reached so far while restoring from backup means
281          * we copied all the necessary data from backup. Only thing
282          * that remains is roll forwarding the logs. Incase if we crash at this
283          * point and user re boots the datbase again without any restore flags
284          * it shoud boot without any problem.
285          **/

286
287
288         // setup database encryption engine
289
if (!create)
290         {
291             // check if the engine crashed while re-encrypting an
292
// encrypted database or while encryption and
293
// existing database.
294
if(properties.getProperty(
295                               RawStoreFactory.DB_ENCRYPTION_STATUS) !=null)
296             {
297                 handleIncompleteDatabaseEncryption(properties);
298             }
299
300             setupEncryptionEngines(create, properties);
301         }
302
303         if (databaseEncrypted) {
304             // let log factory know if the database is encrypted .
305
logFactory.setDatabaseEncrypted(false);
306             // let data factory know if the database is encrypted.
307
dataFactory.setDatabaseEncrypted();
308         }
309
310         // no need to tell log factory which raw store factory it belongs to
311
// since this is passed into the log factory for recovery
312
// after the factories are loaded, recover the database
313
logFactory.recover(this, dataFactory, xactFactory);
314
315         // if user requested to encrpty an unecrypted database or encrypt with
316
// new alogorithm then do that now.
317
if (encryptDatabase) {
318             configureDatabaseForEncryption(properties,
319                                            newCipherFactory);
320         }
321     }
322
323     public void stop() {
324
325         if (SanityManager.DEBUG)
326         {
327             if (databaseEncrypted)
328                 SanityManager.DEBUG_PRINT("encryption statistics",
329                         "Encryption called " + counter_encrypt + " times, " +
330                         "decryption called " + counter_decrypt + " times");
331         }
332
333         if (rawStoreDaemon != null)
334             rawStoreDaemon.stop();
335
336         if (logFactory == null)
337             return;
338
339         try {
340
341             if (logFactory.checkpoint(this, dataFactory, xactFactory, false))
342             {
343                 if (dataFactory != null)
344                     dataFactory.removeStubsOK();
345             }
346
347         } catch (StandardException se) {
348             // checkpoint failed, stop all factory from shutting down normally
349
markCorrupt(se);
350         }
351     }
352
353     /*
354     ** Methods of RawStoreFactory
355     */

356
357     /**
358         Is the store read-only.
359         @see RawStoreFactory#isReadOnly
360     */

361     public boolean isReadOnly() {
362         return dataFactory.isReadOnly();
363     }
364
365     public LockFactory getLockFactory() {
366         return xactFactory.getLockFactory();
367     }
368
369     
370     /**
371         Get the Transaction Factory to use with this store.
372     */

373     public TransactionFactory getXactFactory() {
374         return xactFactory;
375     }
376
377     /*
378      * Return the module providing XAresource interface to the transaction
379      * table.
380      *
381      * @exception StandardException Standard cloudscape exception policy.
382      */

383     public /* XAResourceManager */ Object JavaDoc getXAResourceManager()
384         throws StandardException
385     {
386         return(xactFactory.getXAResourceManager());
387     }
388
389
390     public Transaction startGlobalTransaction(
391     ContextManager contextMgr,
392     int format_id,
393     byte[] global_id,
394     byte[] branch_id)
395         throws StandardException
396     {
397         return xactFactory.startGlobalTransaction(
398                     this, contextMgr, format_id, global_id, branch_id);
399     }
400
401     public Transaction startTransaction(ContextManager contextMgr, String JavaDoc transName)
402         throws StandardException
403     {
404         return xactFactory.startTransaction(this, contextMgr, transName);
405     }
406
407     public Transaction startNestedReadOnlyUserTransaction(
408     Object JavaDoc compatibilitySpace,
409     ContextManager contextMgr,
410     String JavaDoc transName)
411         throws StandardException
412     {
413         return(
414             xactFactory.startNestedReadOnlyUserTransaction(
415                 this, compatibilitySpace, contextMgr, transName));
416     }
417
418     public Transaction startNestedUpdateUserTransaction(
419     ContextManager contextMgr,
420     String JavaDoc transName)
421         throws StandardException
422     {
423         return(
424             xactFactory.startNestedUpdateUserTransaction(
425                 this, contextMgr, transName));
426     }
427
428     public Transaction findUserTransaction(
429         ContextManager contextMgr,
430         String JavaDoc transName)
431          throws StandardException
432     {
433         return xactFactory.findUserTransaction(this, contextMgr, transName);
434     }
435
436
437     public Transaction startInternalTransaction(ContextManager contextMgr) throws StandardException {
438
439         return xactFactory.startInternalTransaction(this, contextMgr);
440     }
441
442     public void checkpoint() throws StandardException
443     {
444         logFactory.checkpoint(this, dataFactory, xactFactory, false);
445     }
446
447     public void freeze() throws StandardException
448     {
449         logFactory.checkpoint(this, dataFactory, xactFactory, true);
450         dataFactory.freezePersistentStore();
451         logFactory.freezePersistentStore();
452     }
453
454     public void unfreeze() throws StandardException
455     {
456         logFactory.unfreezePersistentStore();
457         dataFactory.unfreezePersistentStore();
458     }
459
460     /**
461      * Backup the database to a backup directory.
462      *
463      * @param backupDir the name of the directory where the backup should be
464      * stored. This directory will be created if it
465      * does not exist.
466      * @param wait if <tt>true</tt>, waits for all the backup blocking
467      * operations in progress to finish.
468      * @exception StandardException thrown on error
469      */

470     public void backup(String JavaDoc backupDir, boolean wait)
471         throws StandardException
472     {
473         if (backupDir == null || backupDir.equals(""))
474         {
475             throw StandardException.newException(
476                 SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY, (File)null);
477         }
478
479         // in case this is an URL form
480
String JavaDoc backupDirURL = null;
481         try {
482             URL JavaDoc url = new URL JavaDoc(backupDir);
483             backupDirURL = url.getFile();
484         } catch (MalformedURLException JavaDoc ex) {}
485
486         if (backupDirURL != null)
487             backupDir = backupDirURL;
488
489
490         // find the user transaction, it is necessary for online backup
491
// to open the container through page cache
492
RawTransaction t =
493             xactFactory.findUserTransaction(this,
494                 ContextService.getFactory().getCurrentContextManager(),
495                 AccessFactoryGlobals.USER_TRANS_NAME);
496
497         try {
498
499             // check if any backup blocking operations are in progress
500
// in the same transaction backup is being executed? Backup is
501
// not allowed if the transaction has uncommitted
502
// unlogged operations that are blocking the backup.
503

504             if (t.isBlockingBackup())
505             {
506                 throw StandardException.newException(
507                       SQLState.BACKUP_OPERATIONS_NOT_ALLOWED);
508             }
509
510
511             // check if any backup blocking operations are in progress
512
// and stop new ones from starting until the backup is completed.
513
if (!xactFactory.blockBackupBlockingOperations(wait))
514             {
515                 throw StandardException.newException(
516                       SQLState.BACKUP_BLOCKING_OPERATIONS_IN_PROGRESS);
517             }
518
519             // perform backup
520
backup(t, new File(backupDir));
521         }finally {
522             // let the xactfatory know that backup is done, so that
523
// it can allow backup blocking operations.
524
xactFactory.unblockBackupBlockingOperations();
525         }
526     }
527
528
529     /*
530      * Backup the database.
531      * Online backup copies all the database files (log, seg0 ...Etc) to the
532      * specified backup location without blocking any user operation for the
533      * duration of the backup. Stable copy is made of each page using
534      * page level latches and in some cases with the help of monitors.
535      * Transaction log is also backed up, this is used to bring the database to
536      * the consistent state on restore.
537      *
538      * <P> MT- only one thread is allowed to perform backup at any given time.
539      * Synchronized on this. Parallel backups are not supported.
540      */

541     public synchronized void backup(Transaction t, File backupDir)
542         throws StandardException
543     {
544         if (!privExists(backupDir))
545         {
546             // if backup dir does not exist, go ahead and create it.
547

548             if (!privMkdirs(backupDir))
549             {
550                 throw StandardException.newException(
551                     SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
552                     (File) backupDir);
553             }
554         }
555         else
556         {
557             // entity with backup name exists, make sure it is a directory.
558

559             if (!privIsDirectory(backupDir))
560             {
561                 throw StandardException.newException(
562                     SQLState.RAWSTORE_CANNOT_BACKUP_TO_NONDIRECTORY,
563                     (File) backupDir);
564             }
565
566             // check if a user has given the backup as a database directory by
567
// mistake, backup path can not be a derby database directory.
568
// If a directory contains PersistentService.PROPERTIES_NAME, it
569
// is assumed to be a derby database directory because derby
570
// databases always have this file.
571

572             if (privExists(
573                     new File(backupDir, PersistentService.PROPERTIES_NAME)))
574             {
575                 throw StandardException.newException(
576                     SQLState.RAWSTORE_CANNOT_BACKUP_INTO_DATABASE_DIRECTORY,
577                     (File) backupDir);
578             }
579         }
580         
581         boolean error = true;
582         boolean renamed = false;
583         boolean renameFailed = false;
584         File oldbackup = null;
585         File backupcopy = null;
586         OutputStreamWriter JavaDoc historyFile = null;
587         StorageFile dbHistoryFile = null;
588         File backupHistoryFile = null;
589         LogInstant backupInstant = logFactory.getFirstUnflushedInstant();
590         
591         try
592         {
593             // get name of the current db, ie. database directory of current db.
594
StorageFile dbase = storageFactory.newStorageFile(null);
595             String JavaDoc canonicalDbName = storageFactory.getCanonicalName();
596             int lastSep =
597                 canonicalDbName.lastIndexOf(storageFactory.getSeparator());
598             String JavaDoc dbname =
599                 canonicalDbName.substring(lastSep + 1);
600
601             // append to end of history file
602
historyFile =
603                 privFileWriter(
604                     storageFactory.newStorageFile(BACKUP_HISTORY), true);
605             
606             backupcopy = new File(backupDir, dbname);
607
608             logHistory(
609                 historyFile,
610                 MessageService.getTextMessage(
611                     MessageId.STORE_BACKUP_STARTED,
612                     canonicalDbName,
613                     getFilePath(backupcopy)));
614
615             
616             // check if a backup copy of this database already exists,
617
if (privExists(backupcopy))
618             {
619                 // first make a backup of the backup
620
oldbackup = new File(backupDir, dbname+".OLD");
621                 if (privExists(oldbackup))
622                 {
623                     if (privIsDirectory(oldbackup))
624                         privRemoveDirectory(oldbackup);
625                     else
626                         privDelete(oldbackup);
627                 }
628
629                 if (!privRenameTo(backupcopy,oldbackup))
630                 {
631                     renameFailed = true;
632                     throw StandardException.
633                         newException(SQLState.RAWSTORE_ERROR_RENAMING_FILE,
634                                      backupcopy, oldbackup);
635                 }
636                 else
637                 {
638                     logHistory(
639                         historyFile,
640                         MessageService.getTextMessage(
641                             MessageId.STORE_MOVED_BACKUP,
642                             getFilePath(backupcopy),
643                             getFilePath(oldbackup)));
644                     renamed = true;
645                 }
646             }
647
648             // create the backup database directory
649
if (!privMkdirs(backupcopy))
650             {
651                 throw StandardException.newException(
652                     SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
653                     (File) backupcopy);
654             }
655
656             dbHistoryFile = storageFactory.newStorageFile(BACKUP_HISTORY);
657             backupHistoryFile = new File(backupcopy, BACKUP_HISTORY);
658
659             // copy the history file into the backup.
660
if(!privCopyFile(dbHistoryFile, backupHistoryFile))
661                 throw StandardException.
662                     newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
663                                  dbHistoryFile, backupHistoryFile);
664
665
666             // if they are any jar file stored in the database, copy them into
667
// the backup.
668
StorageFile jarDir =
669                 storageFactory.newStorageFile(FileResource.JAR_DIRECTORY_NAME);
670
671             if (privExists(jarDir))
672             {
673                 // find the list of schema directories under the jar dir and
674
// then copy only the plain files under those directories. One
675
// could just use the recursive copy of directory to copy all
676
// the files under the jar dir, but the problem with that is if
677
// a user gives jar directory as the backup path by mistake,
678
// copy will fail while copying the backup dir onto itself in
679
// recursion
680

681                 String JavaDoc [] jarSchemaList = privList(jarDir);
682                 File backupJarDir = new File(backupcopy,
683                                              FileResource.JAR_DIRECTORY_NAME);
684                 // Create the backup jar directory
685
if (!privMkdirs(backupJarDir))
686                 {
687                     throw StandardException.newException(
688                           SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
689                           (File) backupJarDir);
690                 }
691
692                 for (int i = 0; i < jarSchemaList.length; i++)
693                 {
694                     StorageFile jarSchemaDir =
695                         storageFactory.newStorageFile(jarDir, jarSchemaList[i]);
696                     File backupJarSchemaDir =
697                         new File(backupJarDir, jarSchemaList[i]);
698
699                     if (!privCopyDirectory(jarSchemaDir, backupJarSchemaDir,
700                                            (byte[])null, null, false))
701                     {
702                         throw StandardException.
703                             newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
704                                          jarSchemaDir, backupJarSchemaDir);
705                     }
706                 }
707             }
708
709
710             // save service properties into the backup, Read in property
711
// from service.properties file, remove logDevice from it,
712
// then write it to the backup.
713

714             StorageFile logdir = logFactory.getLogDirectory();
715             
716             try
717             {
718                 String JavaDoc name = Monitor.getMonitor().getServiceName(this);
719                 PersistentService ps =
720                     Monitor.getMonitor().getServiceType(this);
721                 String JavaDoc fullName = ps.getCanonicalServiceName(name);
722                 Properties prop =
723                     ps.getServiceProperties(fullName, (Properties)null);
724
725                 StorageFile defaultLogDir =
726                     storageFactory.newStorageFile(
727                         LogFactory.LOG_DIRECTORY_NAME);
728
729                 if (!logdir.equals(defaultLogDir))
730                 {
731                     prop.remove(Attribute.LOG_DEVICE);
732                     if (SanityManager.DEBUG)
733                     {
734                         SanityManager.ASSERT(
735                             prop.getProperty(Attribute.LOG_DEVICE) == null,
736                             "cannot get rid of logDevice property");
737                     }
738
739                     logHistory(historyFile,
740                                MessageService.getTextMessage(
741                                MessageId.STORE_EDITED_SERVICEPROPS));
742                 }
743             
744                 // save the service properties into the backup.
745
ps.saveServiceProperties(backupcopy.getPath(), prop, false);
746
747             }
748             catch(StandardException se)
749             {
750                 logHistory(
751                    historyFile,
752                    MessageService.getTextMessage(
753                        MessageId.STORE_ERROR_EDIT_SERVICEPROPS) + se);
754
755                 return; // skip the rest and let finally block clean up
756
}
757
758             // Incase of encrypted database and the key is an external
759
// encryption key, there is an extra file with name
760
// Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE, this file should be
761
// copied in to the backup.
762
StorageFile verifyKeyFile =
763                 storageFactory.newStorageFile(
764                                  Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
765             if (privExists(verifyKeyFile))
766             {
767                 File backupVerifyKeyFile =
768                     new File(
769                         backupcopy, Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
770
771                 if(!privCopyFile(verifyKeyFile, backupVerifyKeyFile))
772                    throw StandardException.
773                        newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
774                                     verifyKeyFile, backupVerifyKeyFile);
775             }
776                 
777             File logBackup =
778                 new File(backupcopy, LogFactory.LOG_DIRECTORY_NAME);
779
780             // this is wierd, delete it
781
if (privExists(logBackup))
782             {
783                 privRemoveDirectory(logBackup);
784             }
785
786             // Create the log directory
787
if (!privMkdirs(logBackup))
788             {
789                 throw StandardException.newException(
790                     SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
791                     (File) logBackup);
792             }
793
794             // do a checkpoint to get the persistent store up to date.
795
logFactory.checkpoint(this, dataFactory, xactFactory, true);
796             
797             // start the transaction log backup.
798
logFactory.startLogBackup(logBackup);
799
800             File segBackup = new File(backupcopy, "seg0");
801             
802             // Create the data segment directory
803
if (!privMkdirs(segBackup))
804             {
805                 throw StandardException.newException(
806                     SQLState.RAWSTORE_CANNOT_CREATE_BACKUP_DIRECTORY,
807                     (File) segBackup);
808             }
809
810             // backup all the information in the data segment.
811
dataFactory.backupDataFiles(t, segBackup);
812
813             logHistory(historyFile,
814                    MessageService.getTextMessage(
815                    MessageId.STORE_DATA_SEG_BACKUP_COMPLETED,
816                    getFilePath(segBackup)));
817
818
819             // copy the log that got generated after the backup started to
820
// backup location and tell the logfactory that backup has come
821
// to end.
822
logFactory.endLogBackup(logBackup);
823                                                                           
824             logHistory(historyFile,
825                 MessageService.getTextMessage(
826                     MessageId.STORE_COPIED_LOG,
827                     getFilePath(logdir),
828                     getFilePath(logBackup)));
829
830             error = false;
831         }
832         catch (IOException JavaDoc ioe)
833         {
834             throw StandardException.newException(
835                     SQLState.RAWSTORE_UNEXPECTED_EXCEPTION, ioe);
836         }
837         finally
838         {
839
840             try
841             {
842                 if (error)
843                 {
844                     
845                     // Abort all activity related to backup in the log factory.
846
logFactory.abortLogBackup();
847
848                     // remove the half backed up copy
849
// unless the error occured during rename process;
850
// inwhich case 'backupcopy' refers to the previous backup
851
// not an half backed one.
852
if(!renameFailed)
853                         privRemoveDirectory(backupcopy);
854
855                     if (renamed)
856                         // recover the old backup
857
privRenameTo(oldbackup,backupcopy);
858
859                     logHistory(historyFile,
860                         MessageService.getTextMessage(
861                             MessageId.STORE_BACKUP_ABORTED));
862
863                 }
864                 else
865                 {
866                     // success, remove the old backup copy
867
if (renamed && privExists(oldbackup))
868                     {
869                         // get rid of the old backup
870
privRemoveDirectory(oldbackup);
871                         logHistory(historyFile,
872                             MessageService.getTextMessage(
873                                 MessageId.STORE_REMOVED_BACKUP,
874                                 getFilePath(oldbackup)));
875                     }
876                     logHistory(historyFile,
877                         MessageService.getTextMessage(
878                             MessageId.STORE_BACKUP_COMPLETED,
879                             backupInstant));
880
881                     // copy the updated version of history file with current
882
// backup information into the backup.
883
if(!privCopyFile(dbHistoryFile, backupHistoryFile))
884                         throw StandardException.
885                             newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
886                                          dbHistoryFile, backupHistoryFile);
887                 }
888
889                 historyFile.close();
890             }
891             catch (IOException JavaDoc ioe)
892             {
893                 try
894                 {
895                     historyFile.close();
896                 }
897                 catch (IOException JavaDoc ioe2){};
898                 throw StandardException.newException(
899                         SQLState.RAWSTORE_UNEXPECTED_EXCEPTION, ioe);
900             }
901         }
902
903     }
904
905     /**
906      * Backup the database to a backup directory and enable the log archive
907      * mode that will keep the archived log files required for roll-forward
908      * from this version backup.
909      *
910      * @param backupDir the name of the directory where the backup should be
911      * stored. This directory will be created if it
912      * does not exist.
913      *
914      * @param deleteOnlineArchivedLogFiles
915      * If true deletes online archived
916      * log files that exist before this backup, delete
917      * will occur only after the backup is complete.
918      *
919      * @param wait if <tt>true</tt>, waits for all the backup blocking
920      * operations in progress to finish.
921      *
922      * @exception StandardException thrown on error.
923      */

924     public void backupAndEnableLogArchiveMode(
925     String JavaDoc backupDir,
926     boolean deleteOnlineArchivedLogFiles,
927     boolean wait)
928         throws StandardException
929     {
930         boolean enabledLogArchive = false;
931         try {
932             // Enable the log archive mode, if it is not already enabled.
933
if(!logFactory.logArchived()) {
934                 logFactory.enableLogArchiveMode();
935                 enabledLogArchive = true ;
936             }
937
938             backup(backupDir, wait);
939             
940             // After successful backup delete the archived log files
941
// that are not necessary to do a roll-forward recovery
942
// from this backup if requested.
943
if (deleteOnlineArchivedLogFiles)
944             {
945                 logFactory.deleteOnlineArchivedLogFiles();
946             }
947         }catch (Throwable JavaDoc error) {
948             // On any errors , disable the log archive, if it
949
// is enabled on this call.
950
if (enabledLogArchive)
951                 logFactory.disableLogArchiveMode();
952             throw StandardException.plainWrapException(error);
953         }
954     }
955
956
957     /*
958      * Disable the log archive mode and delete the archived log files
959      * if requested.
960      *
961      * @param deleteOnlineArchivedLogFiles
962      * If true deletes online archived
963      * log files that exist before this backup, delete
964      * will occur only after the backup is complete.
965      * @exception StandardException thrown on error.
966      */

967     public void disableLogArchiveMode(boolean deleteOnlineArchivedLogFiles)
968         throws StandardException
969     {
970         logFactory.disableLogArchiveMode();
971         if(deleteOnlineArchivedLogFiles)
972         {
973             logFactory.deleteOnlineArchivedLogFiles();
974         }
975     }
976
977     
978     //copies the files from the backup that does not need
979
//any special handling like jars.
980
private void restoreRemainingFromBackup(String JavaDoc backupPath) throws StandardException
981     {
982         /**
983          *copy the files from the backup except the ones that we already
984          *copied in the boot methods(like log directory and data segments)
985          *AND Service.properties file which we create last to
986          *indicate the end of copy from backup.
987          */

988
989         File backuploc = new File(backupPath);
990         String JavaDoc[] fromList = privList(backuploc);
991         for(int i =0 ; i < fromList.length ; i++)
992         {
993             StorageFile toFile = storageFactory.newStorageFile( fromList[i]);
994             if(privExists(toFile) ||
995                fromList[i].equals(PersistentService.PROPERTIES_NAME)){
996                 continue;
997             }
998
999             File fromFile = new File(backuploc, fromList[i]);
1000            if(privIsDirectory(fromFile))
1001            {
1002                if (!privCopyDirectory(fromFile, toFile)){
1003                    throw StandardException.newException(
1004                         SQLState.UNABLE_TO_COPY_FILE_FROM_BACKUP,
1005                         fromFile, toFile);
1006                }
1007            }else{
1008                if (!privCopyFile(fromFile, toFile)){
1009                    throw StandardException.newException(
1010                         SQLState.UNABLE_TO_COPY_FILE_FROM_BACKUP,
1011                         fromFile, toFile);
1012                }
1013            }
1014        }
1015    }
1016
1017    public void idle() throws StandardException {
1018        dataFactory.idle();
1019    }
1020
1021
1022    public TransactionInfo[] getTransactionInfo()
1023    {
1024        return xactFactory.getTransactionInfo();
1025    }
1026
1027
1028    public ScanHandle openFlushedScan(DatabaseInstant start, int groupsIWant)
1029         throws StandardException
1030    {
1031        return logFactory.openFlushedScan(start,groupsIWant);
1032    }
1033
1034    public DaemonService getDaemon()
1035    {
1036        return rawStoreDaemon;
1037    }
1038
1039    public void createFinished() throws StandardException
1040    {
1041        xactFactory.createFinished();
1042        dataFactory.createFinished();
1043    }
1044
1045    /**
1046     * Get JBMS properties relavent to raw store
1047     * @exception StandardException Standard Cloudscape Error Policy
1048     */

1049    public void getRawStoreProperties(PersistentSet set)
1050         throws StandardException
1051    {
1052        logFactory.getLogFactoryProperties(set);
1053    }
1054
1055
1056    /*
1057    ** backup restore
1058    */

1059    /**
1060        Freeze persistent store. Reads can still happen, only cannot write.
1061        @exception StandardException Standard Cloudscape Error Policy
1062     */

1063    public void freezePersistentStore() throws StandardException
1064    {
1065        // do a checkpoint to get the persistent store up to date.
1066
logFactory.checkpoint(this, dataFactory, xactFactory,true);
1067        logFactory.freezePersistentStore();
1068
1069    }
1070
1071    /**
1072        Freeze persistent store. Reads can still happen, only cannot write.
1073        @exception StandardException Standard Cloudscape Error Policy
1074     */

1075    public void unfreezePersistentStore() throws StandardException
1076    {
1077        logFactory.unfreezePersistentStore();
1078    }
1079
1080
1081    /*
1082    ** data encryption/decryption support
1083    */

1084
1085
1086    /*
1087     * Setup Encryption Engines.
1088     */

1089    private void setupEncryptionEngines(boolean create, Properties properties)
1090        throws StandardException
1091    {
1092                    
1093            // check if user has requested to encrypt the database or it is an
1094
// encrypted database.
1095

1096            String JavaDoc dataEncryption =
1097                properties.getProperty(Attribute.DATA_ENCRYPTION);
1098            databaseEncrypted = Boolean.valueOf(dataEncryption).booleanValue();
1099
1100            boolean reEncrypt = false;
1101
1102            if (!create) {
1103                // check if database is already encrypted, by directly peeking at the
1104
// database service propertes instead of the properties passed
1105
// to this method. By looking at properties to the boot method ,
1106
// one can not differentiate if user is requesting for database
1107
// encryption or the database is already encrypted because
1108
// Attribute.DATA_ENCRYPTION is used to store in the
1109
// service properties to indicate that database
1110
// is encrypted and also users can specify it as URL attribute
1111
// to encrypt and existing database.
1112

1113                String JavaDoc name = Monitor.getMonitor().getServiceName(this);
1114                PersistentService ps = Monitor.getMonitor().getServiceType(this);
1115                String JavaDoc canonicalName = ps.getCanonicalServiceName(name);
1116                Properties serviceprops = ps.getServiceProperties(canonicalName,
1117                                                                  (Properties)null);
1118                dataEncryption = serviceprops.getProperty(Attribute.DATA_ENCRYPTION);
1119                boolean encryptedDatabase = Boolean.valueOf(dataEncryption).booleanValue();
1120
1121                if (!encryptedDatabase && databaseEncrypted) {
1122                    // it it not an encrypted database, user is asking to
1123
// encrypt an un-encrypted database.
1124
encryptDatabase = true;
1125                    // set database as un-encrypted, we will set it as encrypted
1126
// after encrypting the existing data.
1127
databaseEncrypted = false;
1128                } else {
1129                    // check if the user has requested to renecrypt an
1130
// encrypted datbase with new encryption password/key.
1131
if (encryptedDatabase) {
1132                        if (properties.getProperty(
1133                                       Attribute.NEW_BOOT_PASSWORD) != null) {
1134                            reEncrypt = true;
1135                        }
1136                        else if (properties.getProperty(
1137                                       Attribute.NEW_CRYPTO_EXTERNAL_KEY) != null){
1138                            reEncrypt = true;
1139                        };
1140                        encryptDatabase = reEncrypt;
1141                    }
1142
1143                }
1144                
1145                
1146                // NOTE: if user specifies Attribute.DATA_ENCRYPTION on the
1147
// connection URL by mistake on an already encrypted database,
1148
// it is ignored.
1149

1150
1151                // prevent attempt to (re)encrypt of a read-only database
1152
if (encryptDatabase)
1153                {
1154                    if (isReadOnly())
1155                    {
1156                        if (reEncrypt)
1157                            throw StandardException.newException(
1158                                     SQLState.CANNOT_REENCRYPT_READONLY_DATABASE);
1159                        else
1160                            throw StandardException.newException(
1161                                     SQLState.CANNOT_ENCRYPT_READONLY_DATABASE);
1162                    }
1163                }
1164            }
1165
1166            // setup encryption engines.
1167
if (databaseEncrypted || encryptDatabase)
1168            {
1169                // check if database is configured for encryption, during
1170
// configuration some of the properties database; so that
1171
// user does not have to specify them on the URL everytime.
1172
// Incase of re-encryption of an already of encrypted database
1173
// only some information needs to updated; it is not treated
1174
// like the configuring the database for encryption first time.
1175
boolean setupEncryption = create || (encryptDatabase && !reEncrypt);
1176
1177                // start the cipher factory module, that is is used to create
1178
// instances of the cipher factory with specific enctyption
1179
// properties.
1180

1181                CipherFactoryBuilder cb = (CipherFactoryBuilder)
1182                    Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.CipherFactoryBuilder);
1183
1184                // create instance of the cipher factory with the
1185
// specified encryption properties.
1186
currentCipherFactory = cb.createCipherFactory(setupEncryption,
1187                                                              properties,
1188                                                              false);
1189
1190                // The database can be encrypted using an encryption key that is given at
1191
// connection url. For security reasons, this key is not made persistent
1192
// in the database. But it is necessary to verify the encryption key
1193
// whenever booting the database if it is similar to the key that was used
1194
// during creation time. This needs to happen before we access the data/logs to
1195
// avoid the risk of corrupting the database because of a wrong encryption key.
1196

1197                // Please note this verification process does not provide any added security
1198
// but is intended to allow to fail gracefully if a wrong encryption key
1199
// is used during boot time
1200

1201
1202                currentCipherFactory.verifyKey(setupEncryption, storageFactory, properties);
1203
1204                // Initializes the encryption and decryption engines
1205
encryptionEngine = currentCipherFactory.
1206                    createNewCipher(CipherFactory.ENCRYPT);
1207                
1208                // At creation time of an encrypted database, store the encryption block size
1209
// for the algorithm. Store this value as property given by
1210
// RawStoreFactory.ENCRYPTION_BLOCKSIZE. This value
1211
// is made persistent by storing it in service.properties
1212
// To connect to an existing database, retrieve the value and use it for
1213
// appropriate padding.
1214
// The default value of encryption block size is 8,
1215
// to allow for downgrade issues
1216
// Before support for AES (beetle6023), default encryption block size supported
1217
// was 8
1218

1219                if(setupEncryption)
1220                {
1221                    encryptionBlockSize = encryptionEngine.getEncryptionBlockSize();
1222                    // in case of database create, store the encryption block
1223
// size. Incase of reconfiguring the existing datbase, this
1224
// will be saved after encrypting the exisiting data.
1225
if (create)
1226                        properties.put(RawStoreFactory.ENCRYPTION_BLOCKSIZE,
1227                                       String.valueOf(encryptionBlockSize));
1228                }
1229                else
1230                {
1231                    if(properties.getProperty(RawStoreFactory.ENCRYPTION_BLOCKSIZE) != null)
1232                        encryptionBlockSize = Integer.parseInt(properties.getProperty
1233                                                               (RawStoreFactory.ENCRYPTION_BLOCKSIZE));
1234                    else
1235                        encryptionBlockSize = encryptionEngine.getEncryptionBlockSize();
1236                }
1237
1238                decryptionEngine = currentCipherFactory.
1239                    createNewCipher(CipherFactory.DECRYPT);
1240
1241                random = currentCipherFactory.getSecureRandom();
1242                    
1243                if (encryptDatabase) {
1244
1245                    if (reEncrypt) {
1246                        // create new cipher factory with the new encrytpion
1247
// properties specified by the user. This cipher factory
1248
// is used to create the new encryption/decryption
1249
// engines to reencrypt the database with the new
1250
// encryption keys.
1251
newCipherFactory =
1252                            cb.createCipherFactory(setupEncryption,
1253                                                   properties,
1254                                                   true);
1255                        newDecryptionEngine =
1256                            newCipherFactory.createNewCipher(CipherFactory.DECRYPT);
1257                        newEncryptionEngine =
1258                            newCipherFactory.createNewCipher(CipherFactory.ENCRYPT);
1259                    } else {
1260                        // there is only one engine when configuring an
1261
// unencrypted database for encryption
1262
newDecryptionEngine = decryptionEngine;
1263                        newEncryptionEngine = encryptionEngine;
1264
1265                    }
1266                }
1267
1268                // save the encryption properties if encryption is enabled
1269
// at database creation time.
1270
if(create)
1271                    currentCipherFactory.saveProperties(properties) ;
1272            }
1273    }
1274    
1275
1276    /**
1277        Encrypt cleartext into ciphertext.
1278
1279        @see CipherProvider#encrypt
1280
1281        @exception StandardException Standard Cloudscape Error Policy
1282     */

1283    public int encrypt(byte[] cleartext, int offset, int length,
1284                       byte[] ciphertext, int outputOffset,
1285                       boolean newEngine)
1286         throws StandardException
1287    {
1288        if ((databaseEncrypted == false && encryptDatabase == false) ||
1289            (encryptionEngine == null && newEncryptionEngine == null))
1290        {
1291            throw StandardException.newException(
1292                        SQLState.STORE_FEATURE_NOT_IMPLEMENTED);
1293        }
1294
1295        counter_encrypt++;
1296
1297        if (newEngine) {
1298            return newEncryptionEngine.encrypt(cleartext, offset, length,
1299                                            ciphertext, outputOffset);
1300        } else {
1301            return encryptionEngine.encrypt(cleartext, offset, length,
1302                                            ciphertext, outputOffset);
1303        }
1304    }
1305
1306    /**
1307        Decrypt cleartext from ciphertext.
1308
1309        @see CipherProvider#decrypt
1310
1311        @exception StandardException Standard Cloudscape Error Policy
1312     */

1313    public int decrypt(byte[] ciphertext, int offset, int length,
1314                       byte[] cleartext, int outputOffset)
1315         throws StandardException
1316    {
1317        if (databaseEncrypted == false || decryptionEngine == null)
1318        {
1319            throw StandardException.newException(
1320                        SQLState.STORE_FEATURE_NOT_IMPLEMENTED);
1321        }
1322
1323        counter_decrypt++;
1324        return decryptionEngine.decrypt(ciphertext, offset, length,
1325                                            cleartext, outputOffset);
1326    }
1327
1328    /**
1329        Returns the encryption block size used by the algorithm at time of
1330        creation of an encrypted database
1331     */

1332    public int getEncryptionBlockSize()
1333    {
1334        return encryptionBlockSize;
1335    }
1336
1337    public int random()
1338    {
1339        // don't synchronize it, the more random the better.
1340
return databaseEncrypted ? random.nextInt() : 0;
1341    }
1342
1343    public Serializable JavaDoc changeBootPassword(Properties properties, Serializable JavaDoc changePassword)
1344         throws StandardException
1345    {
1346        if (isReadOnly())
1347            throw StandardException.newException(SQLState.DATABASE_READ_ONLY);
1348
1349        if (!databaseEncrypted)
1350            throw StandardException.newException(SQLState.DATABASE_NOT_ENCRYPTED);
1351
1352        if (changePassword == null)
1353            throw StandardException.newException(SQLState.NULL_BOOT_PASSWORD);
1354
1355        if (!(changePassword instanceof String JavaDoc))
1356            throw StandardException.newException(SQLState.NON_STRING_BP);
1357
1358        // the new bootPassword is expected to be of the form
1359
// oldkey , newkey.
1360
String JavaDoc changeString = (String JavaDoc)changePassword;
1361
1362        return currentCipherFactory.changeBootPassword((String JavaDoc)changePassword, properties, encryptionEngine);
1363
1364    }
1365
1366
1367    /**
1368     * (re) encryption testing debug flags that are used to
1369     * simulate error/crash conditions for testing purposes.
1370     * When any one of the following flags are set to true
1371     * in the debug mode, re-encryption will fail at that point.
1372     */

1373
1374    public static final String JavaDoc TEST_REENCRYPT_CRASH_BEFORE_COMMT =
1375        SanityManager.DEBUG ? "TEST_REENCRYPT_CRASH_BEFORE_COMMT" : null ;
1376    public static final String JavaDoc TEST_REENCRYPT_CRASH_AFTER_COMMT =
1377        SanityManager.DEBUG ? "TEST_REENCRYPT_CRASH_AFTER_COMMT" : null ;
1378    public static final String JavaDoc TEST_REENCRYPT_CRASH_AFTER_SWITCH_TO_NEWKEY =
1379        SanityManager.DEBUG ? "TEST_REENCRYPT_CRASH_AFTER_SWITCH_TO_NEWKEY" : null ;
1380    public static final String JavaDoc TEST_REENCRYPT_CRASH_AFTER_CHECKPOINT =
1381        SanityManager.DEBUG ? "TEST_REENCRYPT_CRASH_AFTER_CHECKPOINT" : null ;
1382    public static final String JavaDoc
1383        TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_LOGFILE_DELETE =
1384        SanityManager.DEBUG ?
1385        "TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_LOGFILE_DELETE" : null;
1386    public static final String JavaDoc
1387        TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_REVERTING_KEY =
1388        SanityManager.DEBUG ?
1389        "TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_REVERTING_KEY" : null;
1390    public static final String JavaDoc
1391        TEST_REENCRYPT_CRASH_BEFORE_RECOVERY_FINAL_CLEANUP =
1392        SanityManager.DEBUG ?
1393        "TEST_REENCRYPT_CRASH_BEFORE_RECOVERY_FINAL_CLEANUP" : null;
1394    
1395    
1396
1397    /**
1398     * when the input debug flag is set, an expception
1399     * is throw when run in the debug mode.
1400     */

1401    private void crashOnDebugFlag(String JavaDoc debugFlag,
1402                                  boolean reEncrypt)
1403        throws StandardException
1404    {
1405        if (SanityManager.DEBUG)
1406        {
1407            // if the test debug flag is set, throw an
1408
// exception to simulate error cases.
1409
if (SanityManager.DEBUG_ON(debugFlag))
1410            {
1411               StandardException se = StandardException.newException(
1412                                      (reEncrypt ? SQLState.DATABASE_REENCRYPTION_FAILED :
1413                                      SQLState.DATABASE_ENCRYPTION_FAILED),
1414                                      debugFlag);
1415               markCorrupt(se);
1416               throw se;
1417            }
1418        }
1419    }
1420
1421    /*
1422     * Configure the database for encryption, with the specified
1423     * encryption properties.
1424     *
1425     * Basic idea is to encrypt all the containers with new password/key
1426     * specified by the user and keep old versions of the data to
1427     * rollback the database to the state before the configuration of database
1428     * with new encryption attributes. Users can configure the database with
1429     * new encryption attributes at boot time only; advantage of this approach
1430     * is that there will not be any concurrency issues to handle because
1431     * no users will be modifying the data.
1432     *
1433     * First step is to encrypt the existing data with new encryption
1434     * attributes and then update the encryption properties for
1435     * the database. Configuring an un-encrypted database for
1436     * encryption problem is a minor variation of re-encrypting an
1437     * encrypted database with new encryption key. The database
1438     * reconfiguration with new encryption attributes is done under one
1439     * transaction, if there is a crash/error before it is committed,
1440     * then it is rolled back and the database will be brought back to the
1441     * state it was before the encryption.
1442     *
1443     * One trickey case in (re) encrypion of database is
1444     * unlike standard protocol transaction commit means all done,
1445     * database (re) encryption process has to perform a checkpoint
1446     * with a newly generated key then only database (re) encrption
1447     * is complete, Otherwise the problem is recovery has to deal
1448     * with transaction log that is encrypted with old encryption key and
1449     * the new encryption key. This probelm is avoided writing COMMIT
1450     * and new CHECKPOINT log record to a new log file and encrypt the
1451     * with a new key, if there is crash before checkpoint records
1452     * are updated , then on next boot the log file after the checkpoint
1453     * is deleted before reovery, which will be the one that is
1454     * written with new encryption key and also contains COMMIT record,
1455     * so the COMMIT record is also gone when log file is deleted.
1456     * Recovery will not see the commit , so it will rollback the (re)
1457     * encryption and revert all the containers to the
1458     * original versions.
1459     *
1460     * Old container versions are deleted only when the check point
1461     * with new encryption key is successful, not on post-commit.
1462     *
1463     * @param properties properties related to this database.
1464     * @exception StandardException Standard Derby Error Policy
1465     */

1466    public void configureDatabaseForEncryption(Properties properties,
1467                                               CipherFactory newCipherFactory)
1468        throws StandardException
1469    {
1470
1471        boolean reEncrypt = (databaseEncrypted && encryptDatabase);
1472
1473        // check if the database can be encrypted.
1474
canEncryptDatabase(reEncrypt);
1475
1476        boolean externalKeyEncryption = false;
1477        if (properties.getProperty(Attribute.CRYPTO_EXTERNAL_KEY) != null)
1478        {
1479                externalKeyEncryption = true;
1480        }
1481
1482        // check point the datase, so that encryption does not have
1483
// to encrypt the existing transactions logs.
1484

1485        logFactory.checkpoint(this, dataFactory, xactFactory, true);
1486
1487        // start a transaction that is to be used for encryting the database
1488
RawTransaction transaction =
1489            xactFactory.startTransaction(
1490                   this,
1491                    ContextService.getFactory().getCurrentContextManager(),
1492                    AccessFactoryGlobals.USER_TRANS_NAME);
1493
1494        try
1495        {
1496            
1497            dataFactory.encryptAllContainers(transaction);
1498
1499            // all the containers are (re) encrypted, now mark the database as
1500
// encrypted if a plain database is getting configured for encryption
1501
// or update the encryption the properties, in the
1502
// service.properties ..etc.
1503

1504            
1505            if (SanityManager.DEBUG) {
1506                crashOnDebugFlag(TEST_REENCRYPT_CRASH_BEFORE_COMMT, reEncrypt);
1507            }
1508
1509            // check if the checkpoint is currently in the last log file,
1510
// otherwise force a checkpoint and then do a log switch,
1511
// after setting up a new encryption key
1512
if (!logFactory.isCheckpointInLastLogFile())
1513            {
1514                // perfrom a checkpoint, this is a reference checkpoint
1515
// to find if the re(encryption) is complete.
1516
logFactory.checkpoint(this, dataFactory, xactFactory, true);
1517            }
1518                
1519
1520            encryptDatabase = false;
1521
1522            // let the log factory know that database is
1523
// (re) encrypted and ask it to flush the log,
1524
// before enabling encryption of the log with
1525
// the new key.
1526
logFactory.setDatabaseEncrypted(true);
1527            
1528            // let the log factory and data factory know that
1529
// database is encrypted.
1530
if (!reEncrypt) {
1531                // mark in the raw store that the database is
1532
// encrypted.
1533
databaseEncrypted = true;
1534                dataFactory.setDatabaseEncrypted();
1535            } else {
1536                // switch the encryption/decryption engine to the new ones.
1537
decryptionEngine = newDecryptionEngine;
1538                encryptionEngine = newEncryptionEngine;
1539                currentCipherFactory = newCipherFactory;
1540            }
1541
1542            
1543            // make the log factory ready to encrypt
1544
// the transaction log with the new encryption
1545
// key by switching to a new log file.
1546
// If re-encryption is aborted for any reason,
1547
// this new log file will be deleted, during
1548
// recovery.
1549

1550            logFactory.startNewLogFile();
1551
1552            // mark that re-encryption is in progress in the
1553
// service.properties, so that (re) encryption
1554
// changes that can not be undone using the transaction
1555
// log can be un-done before recovery starts.
1556
// (like the changes to service.properties and
1557
// any log files the can not be understood by the
1558
// old encryption key), incase engine crashes
1559
// after this point.
1560

1561            // if the crash occurs before this point, recovery
1562
// will rollback the changes using the transaction
1563
// log.
1564

1565            properties.put(RawStoreFactory.DB_ENCRYPTION_STATUS,
1566                           String.valueOf(
1567                               RawStoreFactory.DB_ENCRYPTION_IN_PROGRESS));
1568
1569            if (reEncrypt)
1570            {
1571                // incase re-encryption, save the old
1572
// encryption related properties, before
1573
// doing updates with new values.
1574

1575                if (externalKeyEncryption)
1576                {
1577                    // save the current copy of verify key file.
1578
StorageFile verifyKeyFile =
1579                        storageFactory.newStorageFile(
1580                                 Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
1581                    StorageFile oldVerifyKeyFile =
1582                        storageFactory.newStorageFile(
1583                          RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
1584
1585                    if(!privCopyFile(verifyKeyFile, oldVerifyKeyFile))
1586                        throw StandardException.
1587                            newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
1588                                         verifyKeyFile, oldVerifyKeyFile);
1589
1590                    // update the verify key file with the new key info.
1591
currentCipherFactory.verifyKey(reEncrypt,
1592                                                   storageFactory,
1593                                                   properties);
1594                } else
1595                {
1596                    // save the current generated encryption key
1597
String JavaDoc keyString =
1598                        properties.getProperty(
1599                                               RawStoreFactory.ENCRYPTED_KEY);
1600                    if (keyString != null)
1601                        properties.put(RawStoreFactory.OLD_ENCRYPTED_KEY,
1602                                       keyString);
1603                }
1604            } else
1605            {
1606                // save the encryption block size;
1607
properties.put(RawStoreFactory.ENCRYPTION_BLOCKSIZE,
1608                               String.valueOf(encryptionBlockSize));
1609            }
1610
1611            // save the new encryption properties into service.properties
1612
currentCipherFactory.saveProperties(properties) ;
1613 
1614            if (SanityManager.DEBUG) {
1615                crashOnDebugFlag(
1616                                 TEST_REENCRYPT_CRASH_AFTER_SWITCH_TO_NEWKEY,
1617                                 reEncrypt);
1618            }
1619
1620            // commit the transaction that is used to
1621
// (re) encrypt the database. Note that
1622
// this will be logged with newly generated
1623
// encryption key in the new log file created
1624
// above.
1625
transaction.commit();
1626
1627            if (SanityManager.DEBUG) {
1628                crashOnDebugFlag(TEST_REENCRYPT_CRASH_AFTER_COMMT,
1629                                 reEncrypt);
1630            }
1631
1632            // force the checkpoint with new encryption key.
1633
logFactory.checkpoint(this, dataFactory, xactFactory, true);
1634
1635            if (SanityManager.DEBUG) {
1636                crashOnDebugFlag(TEST_REENCRYPT_CRASH_AFTER_CHECKPOINT,
1637                                 reEncrypt);
1638            }
1639
1640            // once the checkpont makes it to the log, re-encrption
1641
// is complete. only cleanup is remaining ; update the
1642
// re-encryption status flag to cleanup.
1643
properties.put(RawStoreFactory.DB_ENCRYPTION_STATUS,
1644                           String.valueOf(
1645                               RawStoreFactory.DB_ENCRYPTION_IN_CLEANUP));
1646
1647            // database is (re)encrypted successfuly,
1648
// remove the old version of the container files.
1649
dataFactory.removeOldVersionOfContainers(false);
1650                
1651            if (reEncrypt)
1652            {
1653                if (externalKeyEncryption)
1654                {
1655                    // remove the saved copy of the verify.key file
1656
StorageFile oldVerifyKeyFile =
1657                        storageFactory.newStorageFile(
1658                          RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
1659                    if (!privDelete(oldVerifyKeyFile))
1660                        throw StandardException.newException(
1661                                    SQLState.UNABLE_TO_DELETE_FILE,
1662                                    oldVerifyKeyFile);
1663                } else
1664                {
1665                    // remove the old encryption key property.
1666
properties.remove(RawStoreFactory.OLD_ENCRYPTED_KEY);
1667                }
1668            }
1669
1670            // (re) encrypion is done, remove the (re)
1671
// encryption status property.
1672

1673            properties.remove(RawStoreFactory.DB_ENCRYPTION_STATUS);
1674
1675            // close the transaction.
1676
transaction.close();
1677
1678        } catch (StandardException se) {
1679
1680            throw StandardException.newException(
1681                      (reEncrypt ? SQLState.DATABASE_REENCRYPTION_FAILED :
1682                      SQLState.DATABASE_ENCRYPTION_FAILED),
1683                      se,
1684                      se.getMessage());
1685        } finally {
1686            // clear the new encryption engines.
1687
newDecryptionEngine = null;
1688            newEncryptionEngine = null;
1689        }
1690    }
1691
1692
1693    /**
1694     * Engine might have crashed during encryption of un-encrypted datbase
1695     * or while re-encryptin an already encrypted database with a new key
1696     * after all the containers or (re) encrypted. If crash has occured
1697     * before all containers are encrypted, recovery wil un-do re-encryption
1698     * using the transaction log, nothing to be done here.
1699     *
1700     * If crash has occured after database encryption status flag
1701     * (RawStoreFactory.DB_ENCRYPTION_STATUS) is set, this method
1702     * will do any cleanup necessary for the recovery to correctly
1703     * perform the rollback if required.
1704     *
1705     *
1706     *
1707     * @param properties properties related to this database.
1708     * @exception StandardException Standard Derby Error Policy
1709     *
1710     */

1711    public void handleIncompleteDatabaseEncryption(Properties properties)
1712        throws StandardException
1713    {
1714        // find what was the encryption status before database crashed.
1715
int dbEncryptionStatus = 0;
1716        String JavaDoc dbEncryptionStatusStr =
1717            properties.getProperty(RawStoreFactory.DB_ENCRYPTION_STATUS);
1718        if ( dbEncryptionStatusStr != null)
1719            dbEncryptionStatus = Integer.parseInt(dbEncryptionStatusStr);
1720
1721        boolean reEncryption = false;
1722        // check if engine crashed when (re) encryption was in progress.
1723
if (dbEncryptionStatus == RawStoreFactory.DB_ENCRYPTION_IN_PROGRESS)
1724        {
1725
1726            // check if it crashed immediately after completion or
1727
// before. if the checkpoint is in the last log file
1728
// encrypted with new encryption key, it is as good
1729
// as complete. In this case just cleanup any uncleared
1730
// flags and mark that database is encrypted.
1731

1732            if(logFactory.isCheckpointInLastLogFile())
1733            {
1734                // database (re)encryption was successful, only
1735
// cleanup is remaining. change the status to cleanup.
1736
dbEncryptionStatus = RawStoreFactory.DB_ENCRYPTION_IN_CLEANUP;
1737            }else {
1738
1739                // crash occured before re-encrytion was completed.
1740
// update the db re-encryption status and write to
1741
// the service.properties that re-encryption
1742
// needs to be undone. The reason this status need
1743
// to be made persistent, it will help to correctly
1744
// handle a crash in this routine after the log file
1745
// encrypted with new key is deleted. If this flag
1746
// is not set, on next reboot, above check
1747
// will find checkpoint in the last log file and
1748
// incorrecly assume (re) encryption is
1749
// successful.
1750

1751                dbEncryptionStatus = RawStoreFactory.DB_ENCRYPTION_IN_UNDO;
1752                properties.put(RawStoreFactory.DB_ENCRYPTION_STATUS,
1753                               String.valueOf(dbEncryptionStatus));
1754            }
1755        }
1756
1757        
1758        if (dbEncryptionStatus == RawStoreFactory.DB_ENCRYPTION_IN_UNDO)
1759        {
1760            // delete the log file after the log file that has the checkpoint ,
1761
// it has the data encrypted with the new key, including the commit
1762
// record for the transaction that was used to (re)encrypt
1763
// the database. By Deleting the log file, we are forcing the
1764
// recovery to rollback the (re)encryption of the database.
1765

1766            logFactory.deleteLogFileAfterCheckpointLogFile();
1767                
1768            if (SanityManager.DEBUG) {
1769                crashOnDebugFlag(
1770                   TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_LOGFILE_DELETE,
1771                   reEncryption);
1772            }
1773
1774            // Note : If a crash occurs at this point, then on reboot
1775
// it will again be in the DB_ENRYPTION_IN__UNDO state,
1776
// there will not be a file after the checkpoint log file,
1777
// so no file will be deleted.
1778

1779            // check if this is a external key encryption and
1780
// if it replace the current verify key file with
1781
// the old copy.
1782

1783            StorageFile verifyKeyFile =
1784                storageFactory.newStorageFile(
1785                                 Attribute.CRYPTO_EXTERNAL_KEY_VERIFY_FILE);
1786            
1787            if (privExists(verifyKeyFile))
1788            {
1789                StorageFile oldVerifyKeyFile =
1790                    storageFactory.newStorageFile(
1791                      RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
1792            
1793                if (privExists(oldVerifyKeyFile))
1794                {
1795                    if(!privCopyFile(oldVerifyKeyFile, verifyKeyFile))
1796                        throw StandardException.
1797                            newException(SQLState.RAWSTORE_ERROR_COPYING_FILE,
1798                                         oldVerifyKeyFile, verifyKeyFile);
1799                    
1800                    // only incase of re-encryption there should
1801
// be old verify key file.
1802
reEncryption = true;
1803                }else
1804                {
1805                    // remove the verify key file.
1806
if (!privDelete(verifyKeyFile))
1807                        throw StandardException.newException(
1808                             SQLState.UNABLE_TO_DELETE_FILE,
1809                             verifyKeyFile);
1810                }
1811
1812            } else
1813            {
1814                // database enrypted with boot password.
1815

1816                // replace the current encryption key with the old key
1817
// in the service.properties file.
1818
// retreive the old encryption key
1819

1820                String JavaDoc OldKeyString =
1821                    properties.getProperty(RawStoreFactory.OLD_ENCRYPTED_KEY);
1822
1823                if (OldKeyString != null) {
1824                    // set the current encrypted key to the old one.
1825
properties.put(RawStoreFactory.ENCRYPTED_KEY,
1826                                   OldKeyString);
1827                    
1828                    // only incase of re-encryption there should
1829
// be old encryted key .
1830
reEncryption = true;
1831                }
1832            }
1833
1834            if (!reEncryption) {
1835                // crash occured when database was getting reconfigured
1836
// for encryption , all encryption properties should be
1837
// removed from service.properties
1838

1839                // common props for external key or password.
1840
properties.remove(Attribute.DATA_ENCRYPTION);
1841                properties.remove(RawStoreFactory.LOG_ENCRYPT_ALGORITHM_VERSION);
1842                properties.remove(RawStoreFactory.DATA_ENCRYPT_ALGORITHM_VERSION);
1843                properties.remove(RawStoreFactory.ENCRYPTION_BLOCKSIZE);
1844
1845                // properties specific to password based encryption.
1846
properties.remove(Attribute.CRYPTO_KEY_LENGTH);
1847                properties.remove(Attribute.CRYPTO_PROVIDER);
1848                properties.remove(Attribute.CRYPTO_ALGORITHM);
1849                properties.remove(RawStoreFactory.ENCRYPTED_KEY);
1850
1851            }
1852
1853            if (SanityManager.DEBUG) {
1854                crashOnDebugFlag(
1855                    TEST_REENCRYPT_CRASH_AFTER_RECOVERY_UNDO_REVERTING_KEY,
1856                    reEncryption);
1857            }
1858
1859        } // end of UNDO
1860

1861
1862        if (dbEncryptionStatus == RawStoreFactory.DB_ENCRYPTION_IN_CLEANUP)
1863        {
1864            // remove all the old versions of the containers.
1865
dataFactory.removeOldVersionOfContainers(true);
1866        }
1867        
1868        if (SanityManager.DEBUG) {
1869                crashOnDebugFlag(
1870                   TEST_REENCRYPT_CRASH_BEFORE_RECOVERY_FINAL_CLEANUP,
1871                   reEncryption);
1872        }
1873
1874        // either the (re) encryption was complete ,
1875
// or undone (except for rollback that needs to be
1876
// done by the recovery). Remove re-encryption specific
1877
// flags from the service.properties and old copy
1878
// of the verify key file.
1879

1880        // delete the old verify key file , if it exists.
1881
StorageFile oldVerifyKeyFile =
1882            storageFactory.newStorageFile(
1883                      RawStoreFactory.CRYPTO_OLD_EXTERNAL_KEY_VERIFY_FILE);
1884        if (privExists(oldVerifyKeyFile))
1885        {
1886            if (!privDelete(oldVerifyKeyFile))
1887                throw StandardException.newException(
1888                        SQLState.UNABLE_TO_DELETE_FILE,
1889                        oldVerifyKeyFile);
1890        } else
1891        {
1892            // remove the old encryption key property.
1893
properties.remove(RawStoreFactory.OLD_ENCRYPTED_KEY);
1894        }
1895
1896        // remove the re-encryptin status flag.
1897
properties.remove(RawStoreFactory.DB_ENCRYPTION_STATUS);
1898    }
1899
1900
1901
1902
1903    /**
1904     * checks if the database is in the right state to (re)encrypt it.
1905     *
1906     * @param reEncrypt true if the database getting encrypted
1907     * with new password/key.
1908     * @exception StandardException
1909     * if there is global transaction in the prepared state or
1910     * if the database is not at the version 10.2 or above, this
1911     * feature is not supported or
1912     * if the log is archived for the database.
1913     */

1914    private void canEncryptDatabase(boolean reEncrypt)
1915        throws StandardException
1916    {
1917
1918        String JavaDoc feature = (reEncrypt ?
1919                          "newBootPassword/newEncryptionKey attribute" :
1920                          "dataEncryption attribute on an existing database");
1921
1922        // check if the database version is at 10.2 or above.
1923
// encrytpion or re-encryption of the database
1924
// is supported only in version 10.2 or above.
1925
logFactory.checkVersion(
1926                       RawStoreFactory.DERBY_STORE_MAJOR_VERSION_10,
1927                       RawStoreFactory.DERBY_STORE_MINOR_VERSION_2,
1928                       feature);
1929
1930        // database can not be (re)encrypted if there
1931
// are any global transactions in the prepared state
1932
// after the recovery. The reason for this restriction
1933
// is that any transaction log before the encryption can not
1934
// be read once database is reconfigure with new encryption
1935
// key.
1936
if (xactFactory.hasPreparedXact()) {
1937            if(reEncrypt)
1938                throw StandardException.newException(
1939                       SQLState.REENCRYPTION_PREPARED_XACT_EXIST);
1940            else
1941                throw StandardException.newException(
1942                       SQLState.ENCRYPTION_PREPARED_XACT_EXIST);
1943        }
1944
1945
1946        // check if the database has the log archived.
1947
// database can not be congured of encryption or
1948
// or re-encrypt it with a new key when the database
1949
// log is being archived. The reason for this restriction is
1950
// it will create a scenarion where users will
1951
// have some logs encrypted with new key and some with old key
1952
// when rollforward recovery is performed.
1953

1954        if (logFactory.logArchived())
1955        {
1956            if(reEncrypt)
1957                throw StandardException.newException(
1958                       SQLState.CANNOT_REENCRYPT_LOG_ARCHIVED_DATABASE);
1959            else
1960                throw StandardException.newException(
1961                       SQLState.CANNOT_ENCRYPT_LOG_ARCHIVED_DATABASE);
1962            
1963        }
1964    }
1965
1966
1967    /*
1968    **
1969    */

1970
1971    public StandardException markCorrupt(StandardException originalError) {
1972
1973        logFactory.markCorrupt(originalError);
1974        dataFactory.markCorrupt(originalError);
1975        xactFactory.markCorrupt(originalError);
1976
1977        return originalError;
1978    }
1979
1980    /*
1981     * class specific methods
1982     */

1983
1984    /* subclass can override this method to load different submodules */
1985    public String JavaDoc getTransactionFactoryModule()
1986    {
1987        return TransactionFactory.MODULE;
1988    }
1989
1990    public String JavaDoc getDataFactoryModule()
1991    {
1992        return DataFactory.MODULE;
1993    }
1994
1995    public String JavaDoc getLogFactoryModule()
1996    {
1997        return LogFactory.MODULE;
1998    }
1999
2000
2001    private void logHistory(OutputStreamWriter JavaDoc historyFile, String JavaDoc msg) throws IOException JavaDoc
2002    {
2003        Date JavaDoc d = new Date JavaDoc();
2004        historyFile.write(d.toString() + ":" + msg + "\n");
2005        historyFile.flush();
2006    }
2007
2008    /*
2009     * Get the file path. If the canonical path can be obtained then return the
2010     * canonical path, otherwise just return the abstract path. Typically if
2011     * there are no permission to read user.dir when running under security
2012     * manager canonical path can not be obtained.
2013     *
2014     * This method is used to a write path name to error/status log file, where it
2015     * would be nice to print full paths but not esstential that the user
2016     * grant permissions to read user.dir property.
2017     */

2018    private String JavaDoc getFilePath(StorageFile file) {
2019        String JavaDoc path = privGetCanonicalPath(file);
2020        if(path != null ) {
2021            return path;
2022        }else {
2023            //can not get the canoncal path,
2024
// return the abstract path
2025
return file.getPath();
2026        }
2027    }
2028
2029    /*
2030     * Get the file path. If the canonical path can be obtained then return the
2031     * canonical path, otherwise just return the abstract path. Typically if
2032     * there are no permission to read user.dir when running under security
2033     * manager canonical path can not be obtained.
2034     *
2035     * This method is used to a write a file path name to error/status log file,
2036     * where it would be nice to print full paths but not esstential that the user
2037     * grant permissions to read user.dir property.
2038     *
2039     */

2040    private String JavaDoc getFilePath(File file) {
2041        String JavaDoc path = privGetCanonicalPath(file);
2042        if(path != null ) {
2043            return path;
2044        }else {
2045            // can not get the canoncal path,
2046
// return the abstract path
2047
return file.getPath();
2048        }
2049    }
2050
2051    protected boolean privCopyDirectory(StorageFile from, File to)
2052    {
2053        return privCopyDirectory(from, to, (byte[])null,
2054                                 (String JavaDoc[])null, true);
2055    }
2056
2057    protected boolean privCopyDirectory(File from, StorageFile to)
2058    {
2059        return privCopyDirectory(from, to, (byte[])null, (String JavaDoc[])null);
2060    }
2061
2062    /**
2063     * Return an id which can be used to create a container.
2064     * <p>
2065     * Return an id number with is greater than any existing container
2066     * in the current database. Caller will use this to allocate future
2067     * container numbers - most likely caching the value and then incrementing
2068     * it as it is used.
2069     * <p>
2070     *
2071     * @return The an id which can be used to create a container.
2072     *
2073     * @exception StandardException Standard exception policy.
2074     **/

2075    public long getMaxContainerId()
2076        throws StandardException
2077    {
2078        return(dataFactory.getMaxContainerId());
2079    }
2080
2081    
2082    /*
2083        These methods require Priv Blocks when run under a security manager.
2084    */

2085
2086    private synchronized OutputStreamWriter JavaDoc privFileWriter( StorageFile fileName, boolean append) throws IOException JavaDoc
2087    {
2088        actionCode = FILE_WRITER_ACTION;
2089        actionStorageFile = fileName;
2090        actionAppend = append;
2091        try{
2092            return (OutputStreamWriter JavaDoc) java.security.AccessController.doPrivileged( this);
2093        }catch (java.security.PrivilegedActionException JavaDoc pae)
2094        {
2095            throw (IOException JavaDoc) pae.getException();
2096        }
2097        finally
2098        {
2099            actionStorageFile = null;
2100        }
2101    }
2102
2103    private synchronized boolean privExists( File file)
2104    {
2105        actionCode = REGULAR_FILE_EXISTS_ACTION;
2106        actionRegularFile = file;
2107
2108        try
2109        {
2110            Object JavaDoc ret = AccessController.doPrivileged( this);
2111            return ((Boolean JavaDoc) ret).booleanValue();
2112        }
2113        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2114
finally
2115        {
2116            actionRegularFile = null;
2117        }
2118    }
2119
2120    private synchronized boolean privExists(final StorageFile file)
2121    {
2122        actionCode = STORAGE_FILE_EXISTS_ACTION;
2123        actionStorageFile = file;
2124
2125        try
2126        {
2127            Object JavaDoc ret = AccessController.doPrivileged( this);
2128            return ((Boolean JavaDoc) ret).booleanValue();
2129        }
2130        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2131
finally
2132        {
2133            actionStorageFile = null;
2134        }
2135    }
2136
2137
2138    private synchronized boolean privDelete( File file)
2139    {
2140        actionCode = REGULAR_FILE_DELETE_ACTION;
2141        actionRegularFile = file;
2142
2143        try
2144        {
2145            Object JavaDoc ret = AccessController.doPrivileged( this);
2146            return ((Boolean JavaDoc) ret).booleanValue();
2147        }
2148        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2149
finally
2150        {
2151            actionRegularFile = null;
2152        }
2153    }
2154
2155    private synchronized boolean privDelete(StorageFile file)
2156    {
2157        actionCode = STORAGE_FILE_DELETE_ACTION;
2158        actionStorageFile = file;
2159
2160        try
2161        {
2162            Object JavaDoc ret = AccessController.doPrivileged( this);
2163            return ((Boolean JavaDoc) ret).booleanValue();
2164        }
2165        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2166
finally
2167        {
2168            actionStorageFile = null;
2169        }
2170    }
2171
2172
2173
2174    private synchronized boolean privMkdirs( File file)
2175    {
2176        actionCode = REGULAR_FILE_MKDIRS_ACTION;
2177        actionRegularFile = file;
2178
2179        try
2180        {
2181            Object JavaDoc ret = AccessController.doPrivileged( this);
2182            return ((Boolean JavaDoc) ret).booleanValue();
2183        }
2184        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2185
finally
2186        {
2187            actionRegularFile = null;
2188        }
2189    }
2190
2191
2192    private synchronized boolean privIsDirectory( File file)
2193    {
2194        actionCode = REGULAR_FILE_IS_DIRECTORY_ACTION;
2195        actionRegularFile = file;
2196
2197        try
2198        {
2199            Object JavaDoc ret = AccessController.doPrivileged( this);
2200            return ((Boolean JavaDoc) ret).booleanValue();
2201        }
2202        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2203
finally
2204        {
2205            actionRegularFile = null;
2206        }
2207    }
2208
2209    private synchronized boolean privRemoveDirectory( File file)
2210    {
2211        actionCode = REGULAR_FILE_REMOVE_DIRECTORY_ACTION;
2212        actionRegularFile = file;
2213
2214        try
2215        {
2216            Object JavaDoc ret = AccessController.doPrivileged( this);
2217            return ((Boolean JavaDoc) ret).booleanValue();
2218        }
2219        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2220
finally
2221        {
2222            actionRegularFile = null;
2223        }
2224    }
2225
2226    private synchronized boolean privRenameTo( File file1, File file2)
2227    {
2228        actionCode = REGULAR_FILE_RENAME_TO_ACTION;
2229        actionRegularFile = file1;
2230        actionRegularFile2 = file2;
2231
2232        try
2233        {
2234            Object JavaDoc ret = AccessController.doPrivileged( this);
2235            return ((Boolean JavaDoc) ret).booleanValue();
2236        }
2237        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2238
finally
2239        {
2240            actionRegularFile = null;
2241            actionRegularFile2 = null;
2242        }
2243    }
2244
2245    private synchronized boolean privCopyDirectory(StorageFile from,
2246                                                   File to,
2247                                                   byte[] buffer,
2248                                                   String JavaDoc[] filter,
2249                                                   boolean copySubdirs)
2250    {
2251        actionCode = COPY_STORAGE_DIRECTORY_TO_REGULAR_ACTION;
2252        actionStorageFile = from;
2253        actionRegularFile = to;
2254        actionBuffer = buffer;
2255        actionFilter = filter;
2256        actionCopySubDirs = copySubdirs;
2257
2258        try
2259        {
2260            Object JavaDoc ret = AccessController.doPrivileged( this);
2261            return ((Boolean JavaDoc) ret).booleanValue();
2262        }
2263        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2264
finally
2265        {
2266            actionStorageFile = null;
2267            actionRegularFile = null;
2268            actionBuffer = null;
2269            actionFilter = null;
2270        }
2271    }
2272
2273
2274    private synchronized boolean privCopyDirectory( File from, StorageFile to, byte[] buffer, String JavaDoc[] filter)
2275    {
2276        actionCode = COPY_REGULAR_DIRECTORY_TO_STORAGE_ACTION;
2277        actionStorageFile = to;
2278        actionRegularFile = from;
2279        actionBuffer = buffer;
2280        actionFilter = filter;
2281
2282        try
2283        {
2284            Object JavaDoc ret = AccessController.doPrivileged( this);
2285            return ((Boolean JavaDoc) ret).booleanValue();
2286        }
2287        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2288
finally
2289        {
2290            actionStorageFile = null;
2291            actionRegularFile = null;
2292            actionBuffer = null;
2293            actionFilter = null;
2294        }
2295    }
2296
2297    
2298    private synchronized boolean privCopyFile( File from, StorageFile to)
2299    {
2300        actionCode = COPY_REGULAR_FILE_TO_STORAGE_ACTION;
2301        actionStorageFile = to;
2302        actionRegularFile = from;
2303
2304        try
2305        {
2306            Object JavaDoc ret = AccessController.doPrivileged( this);
2307            return ((Boolean JavaDoc) ret).booleanValue();
2308        }
2309        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2310
finally
2311        {
2312            actionStorageFile = null;
2313            actionRegularFile = null;
2314        }
2315    }
2316
2317    private synchronized boolean privCopyFile( StorageFile from, File to)
2318    {
2319        actionCode = COPY_STORAGE_FILE_TO_REGULAR_ACTION;
2320        actionStorageFile = from;
2321        actionRegularFile = to;
2322
2323        try
2324        {
2325            Object JavaDoc ret = AccessController.doPrivileged( this);
2326            return ((Boolean JavaDoc) ret).booleanValue();
2327        }
2328        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2329
finally
2330        {
2331            actionStorageFile = null;
2332            actionRegularFile = null;
2333        }
2334    }
2335
2336
2337    
2338    private synchronized boolean privCopyFile( StorageFile from, StorageFile to)
2339    {
2340        actionCode = COPY_STORAGE_FILE_TO_STORAGE_ACTION;
2341        actionStorageFile = from;
2342        actionToStorageFile = to;
2343
2344        try
2345        {
2346            Object JavaDoc ret = AccessController.doPrivileged( this);
2347            return ((Boolean JavaDoc) ret).booleanValue();
2348        }
2349        catch( PrivilegedActionException JavaDoc pae) { return false;} // does not throw an exception
2350
finally
2351        {
2352            actionStorageFile = null;
2353            actionToStorageFile = null;
2354        }
2355    }
2356
2357
2358    private synchronized String JavaDoc[] privList(final File file)
2359    {
2360        actionCode = REGULAR_FILE_LIST_DIRECTORY_ACTION;
2361        actionRegularFile = file;
2362
2363        try
2364        {
2365            return (String JavaDoc[]) AccessController.doPrivileged( this);
2366        }
2367        catch( PrivilegedActionException JavaDoc pae) { return null;} // does not throw an exception
2368
finally
2369        {
2370            actionRegularFile = null;
2371        }
2372    }
2373
2374    private synchronized String JavaDoc[] privList(final StorageFile file)
2375    {
2376        actionCode = STORAGE_FILE_LIST_DIRECTORY_ACTION;
2377        actionStorageFile = file;
2378
2379        try
2380        {
2381            return (String JavaDoc[]) AccessController.doPrivileged( this);
2382        }
2383        catch( PrivilegedActionException JavaDoc pae) { return null;} // does not throw an exception
2384
finally
2385        {
2386            actionStorageFile = null;
2387        }
2388    }
2389
2390
2391    private synchronized String JavaDoc privGetCanonicalPath(final StorageFile file)
2392    {
2393        actionCode = STORAGE_FILE_GET_CANONICALPATH_ACTION;
2394        actionStorageFile = file;
2395
2396        try
2397        {
2398            return (String JavaDoc) AccessController.doPrivileged( this);
2399        }
2400        catch( PrivilegedActionException JavaDoc pae) {
2401            return null;
2402        } // does not throw an exception
2403
catch(SecurityException JavaDoc se) {
2404            // there are no permission to get canonical path
2405
// just return null.
2406
return null;
2407        }
2408        finally
2409        {
2410            actionStorageFile = null;
2411        }
2412    }
2413
2414
2415    private synchronized String JavaDoc privGetCanonicalPath(final File file)
2416    {
2417        actionCode = REGULAR_FILE_GET_CANONICALPATH_ACTION;
2418        actionRegularFile = file;
2419
2420        try
2421        {
2422            return (String JavaDoc) AccessController.doPrivileged( this);
2423        }
2424        catch( PrivilegedActionException JavaDoc pae) {
2425            return null;
2426        } // does not throw an exception
2427
catch(SecurityException JavaDoc se) {
2428            // there are no permission to get canonical path
2429
// just return null.
2430
return null;
2431        }
2432        finally
2433        {
2434            actionRegularFile = null;
2435        }
2436    }
2437
2438
2439    // PrivilegedExceptionAction method
2440
public final Object JavaDoc run() throws IOException JavaDoc
2441    {
2442        switch(actionCode)
2443        {
2444        case FILE_WRITER_ACTION:
2445            // SECURITY PERMISSION - MP1
2446
return new OutputStreamWriter JavaDoc( actionStorageFile.getOutputStream( actionAppend));
2447
2448        case REGULAR_FILE_EXISTS_ACTION:
2449            return ReuseFactory.getBoolean(actionRegularFile.exists());
2450
2451        case STORAGE_FILE_EXISTS_ACTION:
2452            return ReuseFactory.getBoolean(actionStorageFile.exists());
2453
2454        case REGULAR_FILE_DELETE_ACTION:
2455            return ReuseFactory.getBoolean(actionRegularFile.delete());
2456
2457        case STORAGE_FILE_DELETE_ACTION:
2458            return ReuseFactory.getBoolean(actionStorageFile.delete());
2459
2460        case REGULAR_FILE_MKDIRS_ACTION:
2461            // SECURITY PERMISSION - OP4
2462
return ReuseFactory.getBoolean(actionRegularFile.mkdirs());
2463
2464        case REGULAR_FILE_IS_DIRECTORY_ACTION:
2465            // SECURITY PERMISSION - MP1
2466
return ReuseFactory.getBoolean(actionRegularFile.isDirectory());
2467
2468        case REGULAR_FILE_REMOVE_DIRECTORY_ACTION:
2469            // SECURITY PERMISSION - MP1, OP5
2470
return ReuseFactory.getBoolean(FileUtil.removeDirectory(actionRegularFile));
2471
2472        case REGULAR_FILE_RENAME_TO_ACTION:
2473            // SECURITY PERMISSION - OP4
2474
return ReuseFactory.getBoolean(actionRegularFile.renameTo(actionRegularFile2));
2475
2476        case COPY_STORAGE_DIRECTORY_TO_REGULAR_ACTION:
2477            // SECURITY PERMISSION - MP1, OP4
2478
return ReuseFactory.getBoolean(FileUtil.copyDirectory(storageFactory,
2479                                                                  actionStorageFile,
2480                                                                  actionRegularFile,
2481                                                                  actionBuffer,
2482                                                                  actionFilter,
2483                                                                  actionCopySubDirs));
2484
2485        case COPY_REGULAR_DIRECTORY_TO_STORAGE_ACTION:
2486            // SECURITY PERMISSION - MP1, OP4
2487
return ReuseFactory.getBoolean(FileUtil.copyDirectory((WritableStorageFactory)storageFactory,
2488                                                                  actionRegularFile,
2489                                                                  actionStorageFile,
2490                                                                  actionBuffer,
2491                                                                  actionFilter));
2492
2493        case COPY_REGULAR_FILE_TO_STORAGE_ACTION:
2494            // SECURITY PERMISSION - MP1, OP4
2495
return ReuseFactory.getBoolean(FileUtil.copyFile((WritableStorageFactory) storageFactory,
2496                                                             actionRegularFile,
2497                                                             actionStorageFile));
2498
2499        case REGULAR_FILE_LIST_DIRECTORY_ACTION:
2500            // SECURITY PERMISSION - MP1
2501
return (String JavaDoc[])(actionRegularFile.list());
2502
2503        case STORAGE_FILE_LIST_DIRECTORY_ACTION:
2504            // SECURITY PERMISSION - MP1
2505
return (String JavaDoc[])(actionStorageFile.list());
2506
2507        case COPY_STORAGE_FILE_TO_REGULAR_ACTION:
2508            // SECURITY PERMISSION - MP1, OP4
2509
return ReuseFactory.getBoolean(FileUtil.copyFile(
2510                                           (WritableStorageFactory) storageFactory,
2511                                           actionStorageFile,
2512                                           actionRegularFile));
2513
2514            
2515        case COPY_STORAGE_FILE_TO_STORAGE_ACTION:
2516            // SECURITY PERMISSION - MP1, OP4
2517
return ReuseFactory.getBoolean(FileUtil.copyFile(
2518                                           (WritableStorageFactory) storageFactory,
2519                                           actionStorageFile,
2520                                           actionToStorageFile));
2521
2522        case REGULAR_FILE_GET_CANONICALPATH_ACTION:
2523            // SECURITY PERMISSION - MP1
2524
return (String JavaDoc)(actionRegularFile.getCanonicalPath());
2525            
2526        case STORAGE_FILE_GET_CANONICALPATH_ACTION:
2527            // SECURITY PERMISSION - MP1
2528
return (String JavaDoc)(actionStorageFile.getCanonicalPath());
2529        }
2530        return null;
2531    } // end of run
2532
}
2533
Popular Tags