1 kumpf 1.1 //%2006////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
11 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 kumpf 1.1 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include <Pegasus/Common/Config.h>
35 #include <cctype>
36 #include <cstdio>
37 #include <fstream>
38
39 #include <Pegasus/Common/InternalException.h>
40 #include <Pegasus/Common/DeclContext.h>
41 #include <Pegasus/Common/Resolver.h>
42 #include <Pegasus/Common/System.h>
43 kumpf 1.1 #include <Pegasus/Common/Tracer.h>
44 #include <Pegasus/Common/MessageLoader.h>
45 #include <Pegasus/Common/FileSystem.h>
46 #include <Pegasus/Common/Dir.h>
47 #include <Pegasus/Common/CommonUTF.h>
48 #include "InstanceIndexFile.h"
49 #include "InstanceDataFile.h"
50 #include "AssocInstTable.h"
51 #include "AssocClassTable.h"
52 #include "FileBasedStore.h"
53
54 #ifdef PEGASUS_ENABLE_COMPRESSED_REPOSITORY
55 // #define win32
56 # include <zlib.h>
57 # include <sstream>
58 #endif
59
60 PEGASUS_NAMESPACE_BEGIN
61
62 static const char _CLASSES_DIR[] = "classes";
63 static const char _INSTANCES_DIR[] = "instances";
64 kumpf 1.1 static const char _QUALIFIERS_DIR[] = "qualifiers";
65
66 static const char _CLASSES_SUFFIX[] = "/classes";
67 static const char _INSTANCES_SUFFIX[] = "/instances";
68 static const char _QUALIFIERS_SUFFIX[] = "/qualifiers";
69 static const char _ASSOCIATIONS_SUFFIX[] = "/associations";
70
71 static const Uint32 _MAX_FREE_COUNT = 16;
72
73 static inline String _escapeUtf8FileNameCharacters(const String& fileName)
74 {
75 #ifdef PEGASUS_REPOSITORY_ESCAPE_UTF8
76 // All chars above 0x7F will be escape.
77 return escapeStringEncoder(fileName);
78 #else
79 return fileName;
80 #endif
81 }
82
83 static inline String _unescapeUtf8FileNameCharacters(const String& fileName)
84 {
85 kumpf 1.1 #ifdef PEGASUS_REPOSITORY_ESCAPE_UTF8
86 return escapeStringDecoder(fileName);
87 #else
88 return fileName;
89 #endif
90 }
91
92 ////////////////////////////////////////////////////////////////////////////////
93 //
94 // _namespaceNameToDirName()
95 //
96 ////////////////////////////////////////////////////////////////////////////////
97
98 static String _namespaceNameToDirName(const CIMNamespaceName& namespaceName)
99 {
100 String nameSpaceDirName = namespaceName.getString();
101
102 for (Uint32 i = 0; i < nameSpaceDirName.size(); i++)
103 {
104 if (nameSpaceDirName[i] == '/')
105 {
106 kumpf 1.1 nameSpaceDirName[i] = '#';
107 }
108 }
109
110 return _escapeUtf8FileNameCharacters(nameSpaceDirName);
111 }
112
113 ////////////////////////////////////////////////////////////////////////////////
114 //
115 // _dirNameToNamespaceName()
116 //
117 ////////////////////////////////////////////////////////////////////////////////
118
119 static String _dirNameToNamespaceName(const String& nameSpaceDirName)
120 {
121 String namespaceName = nameSpaceDirName;
122
123 for (Uint32 i = 0; i < namespaceName.size(); i++)
124 {
125 if (namespaceName[i] == '#')
126 {
127 kumpf 1.1 namespaceName[i] = '/';
128 }
129 }
130 #ifdef PEGASUS_REPOSITORY_ESCAPE_UTF8
131 // All chars above 0x7F will be escape.
132 return escapeStringDecoder(namespaceName);
133 #else
134 return namespaceName;
135 #endif
136 }
137
138 ////////////////////////////////////////////////////////////////////////////////
139 //
140 // _LoadFileToMemory() PEP214
141 //
142 // The gzxxxx functions read both compresed and non-compresed files.
143 //
144 // There is no conditional flag on reading of files since gzread()
145 // (from zlib) is capable of reading compressed and non-compressed
146 // files (so it contains the logic that examines the header
147 // and magic number). Everything will work properly if the repository
148 kumpf 1.1 // has some compressed and some non-compressed files.
149 //
150 //
151 ////////////////////////////////////////////////////////////////////////////////
152
153 static void _LoadFileToMemory(Buffer& data, const String& path)
154 {
155
156 #ifdef PEGASUS_ENABLE_COMPRESSED_REPOSITORY
157
158 Uint32 fileSize;
159
160 if (!FileSystem::getFileSize(path, fileSize))
161 throw CannotOpenFile(path);
162
163 gzFile fp = gzopen(path.getCString(), "rb");
164
165 if (fp == NULL)
166 throw CannotOpenFile(path);
167
168 data.reserveCapacity(fileSize);
169 kumpf 1.1 char buffer[4096];
170 int n;
171
172 while ((n = gzread(fp, buffer, sizeof(buffer))) > 0)
173 data.append(buffer, n);
174
175 gzclose(fp);
176
177 #else
178
179 FileSystem::loadFileToMemory(data, path);
180
181 #endif /* PEGASUS_ENABLE_COMPRESSED_REPOSITORY */
182 }
183
184 ////////////////////////////////////////////////////////////////////////////////
185 //
186 // _LoadObject()
187 //
188 // Loads objects (classes and qualifiers) from disk to
189 // memory objects.
190 kumpf 1.1 //
191 ////////////////////////////////////////////////////////////////////////////////
192
193 template<class Object>
194 void _LoadObject(
195 const String& path,
196 Object& object,
197 ObjectStreamer* streamer)
198 {
199 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::_LoadObject");
200
201 // Get the real path of the file:
202
203 String realPath;
204
205 if (!FileSystem::existsNoCase(path, realPath))
206 {
207 PEG_TRACE_STRING(TRC_REPOSITORY, Tracer::LEVEL1,
208 path + " does not exist.");
209 PEG_METHOD_EXIT();
210 throw CannotOpenFile(path);
211 kumpf 1.1 }
212
213 PEG_TRACE_STRING(TRC_REPOSITORY, Tracer::LEVEL4, "realpath = " + realPath);
214
215 // Load file into memory:
216
217 Buffer data;
218
219 _LoadFileToMemory(data, realPath);
220
221 streamer->decode(data, 0, object);
222
223 PEG_METHOD_EXIT();
224 }
225
226 ////////////////////////////////////////////////////////////////////////////////
227 //
228 // _SaveObject()
229 //
230 // Saves objects (classes and qualifiers) from memory to
231 // disk files.
232 kumpf 1.1 //
233 ////////////////////////////////////////////////////////////////////////////////
234
235 static void _SaveObject(
236 const String& path,
237 Buffer& objectXml,
238 ObjectStreamer* streamer)
239 {
240 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::_SaveObject");
241
242 #ifdef PEGASUS_ENABLE_COMPRESSED_REPOSITORY
243 if (_compressMode) // PEP214
244 {
245 PEGASUS_STD(ostringstream) os;
246 streamer->write(os, objectXml);
247 string str = os.str();
248
249 gzFile fp = gzopen(path.getCString(), "wb");
250
251 if (fp == NULL)
252 throw CannotOpenFile(path);
253 kumpf 1.1
254 const char* ptr = str.data();
255 size_t rem = str.size();
256 int n;
257
258 while (rem > 0 && (n = gzwrite(fp, (char*)ptr, rem)) > 0)
259 {
260 ptr += n;
261 rem -= n;
262 }
263
264 gzclose(fp);
265 }
266 else
267 #endif /* PEGASUS_ENABLE_COMPRESSED_REPOSITORY */
268 {
269 PEGASUS_STD(ofstream) os(path.getCString() PEGASUS_IOS_BINARY);
270
271 if (!os)
272 {
273 PEG_METHOD_EXIT();
274 kumpf 1.1 throw CannotOpenFile(path);
275 }
276
277 streamer->write(os, objectXml);
278 }
279 PEG_METHOD_EXIT();
280 }
281
282 ////////////////////////////////////////////////////////////////////////////////
283 //
284 // _beginInstanceTransaction()
285 //
286 // Creates rollback files to allow an incomplete transaction to be voided.
287 //
288 ////////////////////////////////////////////////////////////////////////////////
289
290 static void _beginInstanceTransaction(
291 const String& indexFilePath,
292 const String& dataFilePath)
293 {
294 PEG_METHOD_ENTER(TRC_REPOSITORY, "_beginInstanceTransaction");
295 kumpf 1.1
296 //
297 // Begin the transaction (an incomplete transaction will cause
298 // a rollback the next time an instance-oriented routine is invoked).
299 //
300
301 if (!InstanceIndexFile::beginTransaction(indexFilePath))
302 {
303 PEG_METHOD_EXIT();
304 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
305 MessageLoaderParms("Repository.CIMRepository.BEGIN_FAILED",
306 "begin failed"));
307 }
308
309 if (!InstanceDataFile::beginTransaction(dataFilePath))
310 {
311 PEG_METHOD_EXIT();
312 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
313 MessageLoaderParms("Repository.CIMRepository.BEGIN_FAILED",
314 "begin failed"));
315 }
316 kumpf 1.1
317 PEG_METHOD_EXIT();
318 }
319
320 ////////////////////////////////////////////////////////////////////////////////
321 //
322 // _commitInstanceTransaction()
323 //
324 // Removes the rollback files to complete the transaction.
325 //
326 ////////////////////////////////////////////////////////////////////////////////
327
328 static void _commitInstanceTransaction(
329 const String& indexFilePath,
330 const String& dataFilePath)
331 {
332 PEG_METHOD_ENTER(TRC_REPOSITORY, "_commitInstanceTransaction");
333
334 //
335 // Commit the transaction by removing the rollback files.
336 //
337 kumpf 1.1
338 if (!InstanceIndexFile::commitTransaction(indexFilePath))
339 {
340 PEG_METHOD_EXIT();
341 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
342 MessageLoaderParms("Repository.CIMRepository.COMMIT_FAILED",
343 "commit failed"));
344 }
345
346 if (!InstanceDataFile::commitTransaction(dataFilePath))
347 {
348 PEG_METHOD_EXIT();
349 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
350 MessageLoaderParms("Repository.CIMRepository.COMMIT_FAILED",
351 "commit failed"));
352 }
353
354 PEG_METHOD_EXIT();
355 }
356
357 ////////////////////////////////////////////////////////////////////////////////
358 kumpf 1.1 //
359 // _rollbackInstanceTransaction()
360 //
361 // Restores instance index and data files to void an incomplete operation.
362 // If there are no rollback files, this method has no effect.
363 //
364 ////////////////////////////////////////////////////////////////////////////////
365
366 static String _dirName(const String& path)
367 {
368 Uint32 n = path.size();
369
370 for (Uint32 i = n; i != 0; )
371 {
372 if (path[--i] == '/')
373 return path.subString(0, i);
374 }
375
376 return String(".");
377 }
378
379 kumpf 1.1 static void _rollbackInstanceTransaction(
380 const String& indexFilePath,
381 const String& dataFilePath)
382 {
383 PEG_METHOD_ENTER(TRC_REPOSITORY, "_rollbackInstanceTransaction");
384
385 // Avoid rollback logic if directory has no .rollback files.
386
387 String path = _dirName(indexFilePath);
388 Array<String> rollbackFiles;
389
390 if (FileSystem::glob(path, "*.rollback", rollbackFiles))
391 {
392 if (rollbackFiles.size() == 0)
393 return;
394 }
395
396 // Proceed to rollback logic.
397
398 if (!InstanceIndexFile::rollbackTransaction(indexFilePath))
399 {
400 kumpf 1.1 PEG_METHOD_EXIT();
401 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
402 MessageLoaderParms("Repository.CIMRepository.ROLLBACK_FAILED",
403 "rollback failed"));
404 }
405
406 if (!InstanceDataFile::rollbackTransaction(dataFilePath))
407 {
408 PEG_METHOD_EXIT();
409 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
410 MessageLoaderParms(
411 "Repository.CIMRepository.ROLLBACK_FAILED",
412 "rollback failed"));
413 }
414
415 PEG_METHOD_EXIT();
416 }
417
418 ////////////////////////////////////////////////////////////////////////////////
419 //
420 // InstanceTransactionHandler
421 kumpf 1.1 //
422 // This class is used to manage a repository instance transaction. The
423 // transaction is started when the class is instantiated, committed when
424 // the complete() method is called, and rolled back if the destructor is
425 // called without a prior call to complete().
426 //
427 // The appropriate repository write locks must be owned while an
428 // InstanceTransactionHandler instance exists.
429 //
430 ////////////////////////////////////////////////////////////////////////////////
431
432 class InstanceTransactionHandler
433 {
434 public:
435 InstanceTransactionHandler(
436 const String& indexFilePath,
437 const String& dataFilePath)
438 : _indexFilePath(indexFilePath),
439 _dataFilePath(dataFilePath),
440 _isComplete(false)
441 {
442 kumpf 1.1 _rollbackInstanceTransaction(_indexFilePath, _dataFilePath);
443 _beginInstanceTransaction(_indexFilePath, _dataFilePath);
444 }
445
446 ~InstanceTransactionHandler()
447 {
448 if (!_isComplete)
449 {
450 _rollbackInstanceTransaction(_indexFilePath, _dataFilePath);
451 }
452 }
453
454 void complete()
455 {
456 _commitInstanceTransaction(_indexFilePath, _dataFilePath);
457 _isComplete = true;
458 }
459
460 private:
461 String _indexFilePath;
462 String _dataFilePath;
463 kumpf 1.1 Boolean _isComplete;
464 };
465
466
467 ////////////////////////////////////////////////////////////////////////////////
468 //
469 // FileBasedStore
470 //
471 ////////////////////////////////////////////////////////////////////////////////
472
473 FileBasedStore::FileBasedStore(
474 const String& repositoryPath,
475 ObjectStreamer* streamer,
476 Boolean compressMode)
477 : _repositoryPath(repositoryPath),
478 _streamer(streamer),
479 _compressMode(compressMode)
480 {
481 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::FileBasedStore");
482
483 // Create the repository directory if it does not already exist.
484 kumpf 1.1
485 if (!FileSystem::isDirectory(_repositoryPath))
486 {
487 if (!FileSystem::makeDirectory(_repositoryPath))
488 {
489 PEG_METHOD_EXIT();
490 throw CannotCreateDirectory(_repositoryPath);
491 }
492 }
493
494 _rollbackIncompleteTransactions();
495
496 PEG_METHOD_EXIT();
497 }
498
499 FileBasedStore::~FileBasedStore()
500 {
501 AssocClassTable::removeCaches();
502 }
503
504 ////////////////////////////////////////////////////////////////////////////////
505 kumpf 1.1 //
506 // FileBasedStore::_rollbackIncompleteTransactions()
507 //
508 // Searches for incomplete instance transactions for all classes in all
509 // namespaces. Restores instance index and data files to void an
510 // incomplete operation. If no incomplete instance transactions are
511 // outstanding, this method has no effect.
512 //
513 ////////////////////////////////////////////////////////////////////////////////
514
515 static Boolean _containsNoCase(const Array<String>& array, const String& str)
516 {
517 for (Uint32 i = 0; i < array.size(); i++)
518 {
519 if (String::equalNoCase(array[i], str))
520 return true;
521 }
522
523 return false;
524 }
525
526 kumpf 1.1 void FileBasedStore::_rollbackIncompleteTransactions()
527 {
528 PEG_METHOD_ENTER(TRC_REPOSITORY,
529 "FileBasedStore::_rollbackIncompleteTransactions");
530
531 for (Dir dir(_repositoryPath); dir.more(); dir.next())
532 {
533 String nameSpaceDirName = dir.getName();
534 if (nameSpaceDirName == ".." || nameSpaceDirName == ".")
535 {
536 continue;
537 }
538
539 String instanceDirPath =
540 _repositoryPath + "/" + nameSpaceDirName + _INSTANCES_SUFFIX;
541
542 // Form a list of .rollback files.
543
544 Array<String> rollbackFiles;
545 FileSystem::glob(instanceDirPath, "*.rollback", rollbackFiles);
546
547 kumpf 1.1 // Perform a rollback operation for each class for which a rollback
548 // file was found. A rollback may be performed twice for the same
549 // class if index and instance rollback files exist, but that will
550 // not cause a problem.
551
552 for (Uint32 i = 0; i < rollbackFiles.size(); i++)
553 {
554 // Parse the class name out of the file name. (We know the
555 // file name contains a '.', since it matched the pattern above.)
556 String className =
557 rollbackFiles[i].subString(0, rollbackFiles[i].find('.'));
558
559 _rollbackInstanceTransaction(
560 instanceDirPath + "/" + className + ".idx",
561 instanceDirPath + "/" + className + ".instances");
562 }
563 }
564
565 PEG_METHOD_EXIT();
566 }
567
568 kumpf 1.1 // This function needs to be called from within a transaction scope for
569 // proper error handling in compacting index and data files.
570 static void _CompactInstanceRepository(
571 const String& indexFilePath,
572 const String& dataFilePath)
573 {
574 PEG_METHOD_ENTER(TRC_REPOSITORY,
575 "FileBasedStore::_CompactInstanceRepository");
576
577 //
578 // Compact the data file first:
579 //
580
581 Array<Uint32> freeFlags;
582 Array<Uint32> indices;
583 Array<Uint32> sizes;
584 Array<CIMObjectPath> instanceNames;
585
586 if (!InstanceIndexFile::enumerateEntries(
587 indexFilePath, freeFlags, indices, sizes, instanceNames, true))
588 {
589 kumpf 1.1 PEG_METHOD_EXIT();
590 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
591 MessageLoaderParms(
592 "Repository.CIMRepository.INDEX_ENUM_ENTRIES_FAILED",
593 "Failed to obtain the entries from the Repository Instance"
594 " Index file."));
595 }
596
597 if (!InstanceDataFile::compact(dataFilePath, freeFlags, indices, sizes))
598 {
599 PEG_METHOD_EXIT();
600 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
601 MessageLoaderParms(
602 "Repository.CIMRepository.COMPACT_FAILED",
603 "Failed to compact the Repository Instance Data file."));
604 }
605
606 //
607 // Now compact the index file:
608 //
609
610 kumpf 1.1 if (!InstanceIndexFile::compact(indexFilePath))
611 {
612 PEG_METHOD_EXIT();
613 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
614 MessageLoaderParms(
615 "Repository.CIMRepository.INDEX_COMPACT_FAILED",
616 "Failed to compact the Repository Instance Index file."));
617 }
618
619 PEG_METHOD_EXIT();
620 }
621
622 //----------------------------------------------------------------------
623 //
624 // _getNameSpaceDirPath()
625 //
626 // returns the path of a namespace directory.
627 //
628 //----------------------------------------------------------------------
629
630 String FileBasedStore::_getNameSpaceDirPath(
631 kumpf 1.1 const CIMNamespaceName& nameSpace) const
632 {
633 String path;
634 Boolean found = _nameSpacePathTable.lookup(nameSpace.getString(), path);
635 PEGASUS_ASSERT(found);
636 return path;
637 }
638
639 //----------------------------------------------------------------------
640 //
641 // _getQualifierFilePath()
642 //
643 // returns the path of the qualifier file.
644 //
645 //----------------------------------------------------------------------
646
647 String FileBasedStore::_getQualifierFilePath(
648 const CIMNamespaceName& nameSpace,
649 const CIMName& qualifierName) const
650 {
651 String tmp = _getNameSpaceDirPath(nameSpace);
652 kumpf 1.1 tmp.append(_QUALIFIERS_SUFFIX);
653 tmp.append('/');
654 tmp.append(_escapeUtf8FileNameCharacters(qualifierName.getString()));
655 return tmp;
656 }
657
658 //----------------------------------------------------------------------
659 //
660 // _getClassFilePath()
661 //
662 // returns the path of the class file.
663 //
664 //----------------------------------------------------------------------
665
666 String FileBasedStore::_getClassFilePath(
667 const CIMNamespaceName& nameSpace,
668 const CIMName& className,
669 const CIMName& superClassName) const
670 {
671 String tmp = _getNameSpaceDirPath(nameSpace);
672 tmp.append(_CLASSES_SUFFIX);
673 kumpf 1.1 tmp.append('/');
674 tmp.append(_escapeUtf8FileNameCharacters(className.getString()));
675
676 if (superClassName.isNull())
677 {
678 tmp.append(".#");
679 }
680 else
681 {
682 tmp.append('.');
683 tmp.append(_escapeUtf8FileNameCharacters(superClassName.getString()));
684 }
685
686 return tmp;
687 }
688
689 //----------------------------------------------------------------------
690 //
691 // _getInstanceIndexFilePath()
692 //
693 // returns the path of the instance index file.
694 kumpf 1.1 //
695 //----------------------------------------------------------------------
696
697 String FileBasedStore::_getInstanceIndexFilePath(
698 const CIMNamespaceName& nameSpace,
699 const CIMName& className) const
700 {
701 String tmp = _getNameSpaceDirPath(nameSpace);
702 tmp.append(_INSTANCES_SUFFIX);
703 tmp.append('/');
704 tmp.append(_escapeUtf8FileNameCharacters(className.getString()));
705 tmp.append(".idx");
706 return tmp;
707 }
708
709 //----------------------------------------------------------------------
710 //
711 // _getInstanceDataFilePath()
712 //
713 // returns the path of the instance file.
714 //
715 kumpf 1.1 //----------------------------------------------------------------------
716
717 String FileBasedStore::_getInstanceDataFilePath(
718 const CIMNamespaceName& nameSpace,
719 const CIMName& className) const
720 {
721 String tmp = _getNameSpaceDirPath(nameSpace);
722 tmp.append(_INSTANCES_SUFFIX);
723 tmp.append('/');
724 tmp.append(_escapeUtf8FileNameCharacters(className.getString()));
725 tmp.append(".instances");
726 return tmp;
727 }
728
729 //----------------------------------------------------------------------
730 //
731 // _getAssocClassPath()
732 //
733 // returns the path of the class association file.
734 //
735 //----------------------------------------------------------------------
736 kumpf 1.1
737 String FileBasedStore::_getAssocClassPath(
738 const CIMNamespaceName& nameSpace) const
739 {
740 String tmp = _getNameSpaceDirPath(nameSpace);
741 tmp.append(_CLASSES_SUFFIX);
742 tmp.append(_ASSOCIATIONS_SUFFIX);
743 return tmp;
744 }
745
746 //----------------------------------------------------------------------
747 //
748 // _getAssocInstPath()
749 //
750 // returns the path of the instance association file.
751 //
752 //----------------------------------------------------------------------
753
754 String FileBasedStore::_getAssocInstPath(
755 const CIMNamespaceName& nameSpace) const
756 {
757 kumpf 1.1 String tmp = _getNameSpaceDirPath(nameSpace);
758 tmp.append(_INSTANCES_SUFFIX);
759 tmp.append(_ASSOCIATIONS_SUFFIX);
760 return tmp;
761 }
762
763 Boolean FileBasedStore::_loadInstance(
764 const String& path,
765 CIMInstance& object,
766 Uint32 index,
767 Uint32 size)
768 {
769 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::_loadInstance");
770
771 //
772 // Load instance (in XML) from instance file into memory:
773 //
774
775 Buffer data;
776
777 if (!InstanceDataFile::loadInstance(path, index, size, data))
778 kumpf 1.1 {
779 PEG_METHOD_EXIT();
780 return false;
781 }
782
783 //
784 // Convert XML into an actual object:
785 //
786
787 _streamer->decode(data, 0, object);
788
789 PEG_METHOD_EXIT();
790 return true;
791 }
792
793 Boolean FileBasedStore::_loadAllInstances(
794 const CIMNamespaceName& nameSpace,
795 const CIMName& className,
796 Array<CIMInstance>& namedInstances)
797 {
798 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::_loadAllInstances");
799 kumpf 1.1
800 Array<CIMObjectPath> instanceNames;
801 Buffer data;
802 Array<Uint32> indices;
803 Array<Uint32> sizes;
804
805 //
806 // Form the names of the instance index and data files
807 //
808
809 String indexFilePath = _getInstanceIndexFilePath(nameSpace, className);
810 String dataFilePath = _getInstanceDataFilePath(nameSpace, className);
811
812 //
813 // Enumerate the index file:
814 //
815
816 Array<Uint32> freeFlags;
817
818 if (!InstanceIndexFile::enumerateEntries(
819 indexFilePath, freeFlags, indices, sizes, instanceNames, true))
820 kumpf 1.1 {
821 PEG_METHOD_EXIT();
822 return false;
823 }
824
825 //
826 // Form the array of instances result:
827 //
828
829 if (instanceNames.size() > 0)
830 {
831 //
832 // Load all instances from the data file:
833 //
834
835 if (!InstanceDataFile::loadAllInstances(dataFilePath, data))
836 {
837 PEG_METHOD_EXIT();
838 return false;
839 }
840
841 kumpf 1.1 //
842 // for each instance loaded, call XML parser to parse the XML
843 // data and create a CIMInstance object.
844 //
845
846 CIMInstance tmpInstance;
847
848 char* buffer = (char*)data.getData();
849
850 for (Uint32 i = 0; i < instanceNames.size(); i++)
851 {
852 if (!freeFlags[i])
853 {
854 Uint32 pos= (Uint32)((&(buffer[indices[i]]))-buffer);
855 _streamer->decode(data, pos, tmpInstance);
856
857 tmpInstance.setPath(instanceNames[i]);
858
859 namedInstances.append(tmpInstance);
860 }
861 }
862 kumpf 1.1 }
863
864 PEG_METHOD_EXIT();
865 return true;
866 }
867
868 Array<NamespaceDefinition> FileBasedStore::enumerateNameSpaces()
869 {
870 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::enumerateNameSpaces");
871
872 Array<NamespaceDefinition> nameSpaces;
873
874 for (Dir dir(_repositoryPath); dir.more(); dir.next())
875 {
876 String nameSpaceDirName = dir.getName();
877 if (nameSpaceDirName == ".." || nameSpaceDirName == ".")
878 {
879 continue;
880 }
881
882 String nameSpacePath = _repositoryPath + "/" + nameSpaceDirName;
883 kumpf 1.1
884 if (!FileSystem::isDirectory(nameSpacePath + _CLASSES_SUFFIX) ||
885 !FileSystem::isDirectory(nameSpacePath + _INSTANCES_SUFFIX) ||
886 !FileSystem::isDirectory(nameSpacePath + _QUALIFIERS_SUFFIX))
887 {
888 PEG_TRACE_STRING(TRC_REPOSITORY, Tracer::LEVEL2,
889 "Namespace: " + nameSpaceDirName +
890 " ignored -- subdirectories are not correctly formed");
891 continue;
892 }
893
894 NamespaceDefinition nsdef(_dirNameToNamespaceName(nameSpaceDirName));
895
896 Boolean skipThisNamespace = false;
897
898 for (Dir subdir(nameSpacePath); subdir.more(); subdir.next())
899 {
900 String nameSpaceSubDirName = subdir.getName();
901 if (nameSpaceSubDirName == ".." || nameSpaceSubDirName == ".")
902 {
903 continue;
904 kumpf 1.1 }
905
906 String tmp = nameSpaceSubDirName;
907 tmp.toLower();
908
909 if (tmp[0] == 's')
910 {
911 if ((tmp[1]=='w' || tmp[1]=='r') &&
912 (tmp[2]=='f' || tmp[2]=='s'))
913 {
914 nsdef.shareable = tmp[2]=='s';
915 nsdef.updatesAllowed = tmp[1]=='w';
916 String parent = nameSpaceSubDirName.subString(3);
917 if (parent.size())
918 {
919 nsdef.parentNameSpace = _dirNameToNamespaceName(parent);
920 }
921
922 #ifdef PEGASUS_ENABLE_REMOTE_CMPI
923 nsdef.shared = true;
924 #endif
925 kumpf 1.1 }
926 else
927 {
928 PEG_TRACE_STRING(TRC_REPOSITORY, Tracer::LEVEL2,
929 "Namespace " + nameSpaceDirName +
930 " ignored - using incorrect parent namespace "
931 "specification: " +
932 nameSpaceSubDirName);
933 skipThisNamespace = true;
934 }
935 #ifndef PEGASUS_ENABLE_REMOTE_CMPI
936 break;
937 #endif
938 }
939 #ifdef PEGASUS_ENABLE_REMOTE_CMPI
940 else if (tmp[0] == 'r')
941 {
942 nsdef.remote = true;
943 nsdef.remoteId = tmp.subString(1, 2);
944
945 Uint32 pos = nameSpaceSubDirName.find('@');
946 kumpf 1.1 if (pos != PEG_NOT_FOUND)
947 {
948 nsdef.remoteHost = nameSpaceSubDirName.subString(3, pos-3);
949 nsdef.remotePort = nameSpaceSubDirName.subString(pos+1);
950 }
951 else
952 {
953 nsdef.remoteHost = nameSpaceSubDirName.subString(3);
954 }
955
956 nsdef.remoteInfo = nameSpaceSubDirName;
957 PEG_TRACE_STRING(TRC_REPOSITORY, Tracer::LEVEL4,
958 "Remote namespace: " + nameSpaceDirName + " >" +
959 nameSpaceSubDirName);
960 }
961 #endif
962 }
963
964 if (!skipThisNamespace)
965 {
966 _nameSpacePathTable.insert(
967 kumpf 1.1 nsdef.name.getString(),
968 _repositoryPath + "/" + nameSpaceDirName);
969 nameSpaces.append(nsdef);
970 }
971 }
972
973 PEG_METHOD_EXIT();
974 return nameSpaces;
975 }
976
977 void FileBasedStore::createNameSpace(
978 const CIMNamespaceName& nameSpace,
979 Boolean shareable,
980 Boolean updatesAllowed,
981 const String& parentNameSpace)
982 {
983 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::createNameSpace");
984
985 #ifndef PEGASUS_SUPPORT_UTF8_FILENAME
986 // Do not allow file names to contain characters outside of 7-bit ASCII.
987 String nameSpaceNameString = nameSpace.getString();
988 kumpf 1.1 Uint32 len = nameSpaceNameString.size();
989 for (Uint32 i = 0; i < len; ++i)
990 {
991 if ((Uint16)nameSpaceNameString[i] > 0x007F)
992 {
993 PEG_METHOD_EXIT();
994 throw PEGASUS_CIM_EXCEPTION(
995 CIM_ERR_INVALID_PARAMETER, nameSpaceNameString);
996 }
997 }
998 #endif
999
1000 // Attempt to create all the namespace directories:
1001
1002 String nameSpacePath =
1003 _repositoryPath + "/" + _namespaceNameToDirName(nameSpace);
1004
1005 if (!FileSystem::makeDirectory(nameSpacePath))
1006 {
1007 throw CannotCreateDirectory(nameSpacePath);
1008 }
1009 kumpf 1.1
1010 String classesPath = nameSpacePath + _CLASSES_SUFFIX;
1011 String instancesPath = nameSpacePath + _INSTANCES_SUFFIX;
1012 String qualifiersPath = nameSpacePath + _QUALIFIERS_SUFFIX;
1013
1014 if (!FileSystem::makeDirectory(classesPath))
1015 {
1016 throw CannotCreateDirectory(classesPath);
1017 }
1018
1019 if (!FileSystem::makeDirectory(instancesPath))
1020 {
1021 throw CannotCreateDirectory(instancesPath);
1022 }
1023
1024 if (!FileSystem::makeDirectory(qualifiersPath))
1025 {
1026 throw CannotCreateDirectory(qualifiersPath);
1027 }
1028
1029 if (shareable || !updatesAllowed || parentNameSpace.size())
1030 kumpf 1.1 {
1031 String path = nameSpacePath + "/S" + (updatesAllowed ? "W" : "R") +
1032 (shareable ? "S" : "F");
1033 if (parentNameSpace.size())
1034 {
1035 path.append(_namespaceNameToDirName(parentNameSpace));
1036 }
1037
1038 if (!FileSystem::makeDirectory(path))
1039 {
1040 throw CannotCreateDirectory(path);
1041 }
1042 }
1043
1044 _nameSpacePathTable.insert(nameSpace.getString(), nameSpacePath);
1045
1046 PEG_METHOD_EXIT();
1047 }
1048
1049 void FileBasedStore::modifyNameSpace(
1050 const CIMNamespaceName& nameSpace,
1051 kumpf 1.1 Boolean shareable,
1052 Boolean updatesAllowed)
1053 {
1054 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::modifyNameSpace");
1055
1056 String nameSpacePath = _getNameSpaceDirPath(nameSpace);
1057 String oldSpecialDirName;
1058
1059 for (Dir subdir(nameSpacePath); subdir.more(); subdir.next())
1060 {
1061 String dirName = subdir.getName();
1062
1063 if ((dirName[0] == 's') || (dirName[0] == 'S'))
1064 {
1065 oldSpecialDirName = dirName;
1066 break;
1067 }
1068 }
1069
1070 String newSpecialDirName = oldSpecialDirName;
1071
1072 kumpf 1.1 if (newSpecialDirName.size() == 0)
1073 {
1074 newSpecialDirName = "SWF";
1075 }
1076
1077 newSpecialDirName[0] = 'S';
1078 newSpecialDirName[1] = updatesAllowed ? 'W' : 'R';
1079 newSpecialDirName[2] = shareable ? 'S' : 'F';
1080
1081 if (newSpecialDirName != oldSpecialDirName)
1082 {
1083 if (oldSpecialDirName.size())
1084 {
1085 FileSystem::removeDirectoryHier(
1086 nameSpacePath + "/" + oldSpecialDirName);
1087 }
1088
1089 if (newSpecialDirName != "SWF")
1090 {
1091 String newPath = nameSpacePath + "/" + newSpecialDirName;
1092 if (!FileSystem::makeDirectory(newPath))
1093 kumpf 1.1 {
1094 PEG_METHOD_EXIT();
1095 throw CannotCreateDirectory(newPath);
1096 }
1097 }
1098 }
1099
1100 PEG_METHOD_EXIT();
1101 }
1102
1103 void FileBasedStore::deleteNameSpace(const CIMNamespaceName& nameSpace)
1104 {
1105 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::deleteNameSpace");
1106
1107 String nameSpacePath = _getNameSpaceDirPath(nameSpace);
1108
1109 if (!FileSystem::removeDirectoryHier(nameSpacePath))
1110 {
1111 PEG_METHOD_EXIT();
1112 throw CannotRemoveDirectory(nameSpacePath);
1113 }
1114 kumpf 1.1
1115 _nameSpacePathTable.remove(nameSpace.getString());
1116
1117 PEG_METHOD_EXIT();
1118 }
1119
1120 Boolean FileBasedStore::isNameSpaceEmpty(const CIMNamespaceName& nameSpace)
1121 {
1122 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::isNameSpaceEmpty");
1123
1124 String nameSpacePath = _getNameSpaceDirPath(nameSpace);
1125
1126 for (Dir dir(nameSpacePath); dir.more(); dir.next())
1127 {
1128 const char* name = dir.getName();
1129
1130 if (strcmp(name, ".") != 0 &&
1131 strcmp(name, "..") != 0 &&
1132 System::strcasecmp(name, _CLASSES_DIR) != 0 &&
1133 System::strcasecmp(name, _INSTANCES_DIR) != 0 &&
1134 System::strcasecmp(name, _QUALIFIERS_DIR) != 0)
1135 kumpf 1.1 {
1136 // ATTN: Is it assumed that dependent namespaces are empty?
1137 return true;
1138 }
1139 }
1140
1141 String classesPath = nameSpacePath + _CLASSES_SUFFIX;
1142 String instancesPath = nameSpacePath + _INSTANCES_SUFFIX;
1143 String qualifiersPath = nameSpacePath + _QUALIFIERS_SUFFIX;
1144
1145 PEG_METHOD_EXIT();
1146 return
1147 FileSystem::isDirectoryEmpty(classesPath) &&
1148 FileSystem::isDirectoryEmpty(instancesPath) &&
1149 FileSystem::isDirectoryEmpty(qualifiersPath);
1150 }
1151
1152 Array<CIMQualifierDecl> FileBasedStore::enumerateQualifiers(
1153 const CIMNamespaceName& nameSpace)
1154 {
1155 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::enumerateQualifiers");
1156 kumpf 1.1
1157 String qualifiersRoot =
1158 _getNameSpaceDirPath(nameSpace) + _QUALIFIERS_SUFFIX;
1159
1160 Array<String> qualifierNames;
1161
1162 if (!FileSystem::getDirectoryContents(qualifiersRoot, qualifierNames))
1163 {
1164 PEG_METHOD_EXIT();
1165 String str ="enumerateQualifiers()";
1166 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1167 MessageLoaderParms("Repository.CIMRepository.INTERNAL_ERROR",
1168 "$0: internal error",
1169 str));
1170 }
1171
1172 Array<CIMQualifierDecl> qualifiers;
1173
1174 for (Uint32 i = 0; i < qualifierNames.size(); i++)
1175 {
1176 CIMQualifierDecl qualifier = getQualifier(
1177 kumpf 1.1 nameSpace, _unescapeUtf8FileNameCharacters(qualifierNames[i]));
1178 qualifiers.append(qualifier);
1179 }
1180
1181 PEG_METHOD_EXIT();
1182 return qualifiers;
1183 }
1184
1185 CIMQualifierDecl FileBasedStore::getQualifier(
1186 const CIMNamespaceName& nameSpace,
1187 const CIMName& qualifierName)
1188 {
1189 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::getQualifier");
1190
1191 CIMQualifierDecl qualifierDecl;
1192
1193 //
1194 // Get path of qualifier file:
1195 //
1196
1197 String qualifierFilePath = _getQualifierFilePath(nameSpace, qualifierName);
1198 kumpf 1.1
1199 try
1200 {
1201 _LoadObject(qualifierFilePath, qualifierDecl, _streamer);
1202 }
1203 catch (const CannotOpenFile&)
1204 {
1205 // Qualifier not found
1206 PEG_METHOD_EXIT();
1207 return CIMQualifierDecl();
1208 }
1209
1210 PEG_METHOD_EXIT();
1211 return qualifierDecl;
1212 }
1213
1214 void FileBasedStore::setQualifier(
1215 const CIMNamespaceName& nameSpace,
1216 const CIMQualifierDecl& qualifierDecl)
1217 {
1218 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::setQualifier");
1219 kumpf 1.1
1220 // -- Get path of qualifier file:
1221
1222 String qualifierFilePath =
1223 _getQualifierFilePath(nameSpace, qualifierDecl.getName());
1224
1225 // -- If qualifier already exists, throw exception:
1226
1227 if (FileSystem::existsNoCase(qualifierFilePath))
1228 {
1229 PEG_METHOD_EXIT();
1230 throw PEGASUS_CIM_EXCEPTION(
1231 CIM_ERR_NOT_SUPPORTED, qualifierDecl.getName().getString());
1232 }
1233
1234 // -- Save qualifier:
1235
1236 Buffer qualifierDeclXml;
1237 _streamer->encode(qualifierDeclXml, qualifierDecl);
1238 _SaveObject(qualifierFilePath, qualifierDeclXml, _streamer);
1239
1240 kumpf 1.1 PEG_METHOD_EXIT();
1241 }
1242
1243 void FileBasedStore::deleteQualifier(
1244 const CIMNamespaceName& nameSpace,
1245 const CIMName& qualifierName)
1246 {
1247 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::deleteQualifier");
1248
1249 // -- Get path of qualifier file:
1250
1251 String qualifierFilePath = _getQualifierFilePath(nameSpace, qualifierName);
1252
1253 // -- Delete qualifier:
1254
1255 if (!FileSystem::removeFileNoCase(qualifierFilePath))
1256 {
1257 PEG_METHOD_EXIT();
1258 throw PEGASUS_CIM_EXCEPTION(
1259 CIM_ERR_NOT_FOUND, qualifierName.getString());
1260 }
1261 kumpf 1.1
1262 PEG_METHOD_EXIT();
1263 }
1264
1265 Array<Pair<String, String> > FileBasedStore::enumerateClassNames(
1266 const CIMNamespaceName& nameSpace)
1267 {
1268 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::enumerateClassNames");
1269
1270 Array<Pair<String, String> > classList;
1271
1272 String classesPath = _getNameSpaceDirPath(nameSpace) + _CLASSES_SUFFIX;
1273
1274 for (Dir dir(classesPath); dir.more(); dir.next())
1275 {
1276 String fileName = dir.getName();
1277
1278 // Ignore the current and parent directories.
1279
1280 if (fileName == "." || fileName == "..")
1281 continue;
1282 kumpf 1.1
1283 Uint32 dot = fileName.find('.');
1284
1285 // Ignore files without dots in them:
1286
1287 if (dot == PEG_NOT_FOUND)
1288 continue;
1289
1290 String className =
1291 _unescapeUtf8FileNameCharacters(fileName.subString(0, dot));
1292 String superClassName =
1293 _unescapeUtf8FileNameCharacters(fileName.subString(dot + 1));
1294
1295 if (superClassName == "#")
1296 superClassName.clear();
1297
1298 classList.append(Pair<String, String>(className, superClassName));
1299 }
1300
1301 PEG_METHOD_EXIT();
1302 return classList;
1303 kumpf 1.1 }
1304
1305 CIMClass FileBasedStore::getClass(
1306 const CIMNamespaceName& nameSpace,
1307 const CIMName& className,
1308 const CIMName& superClassName)
1309 {
1310 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::getClass");
1311
1312 String classFilePath =
1313 _getClassFilePath(nameSpace, className, superClassName);
1314 CIMClass cimClass;
1315 _LoadObject(classFilePath, cimClass, _streamer);
1316
1317 PEG_METHOD_EXIT();
1318 return cimClass;
1319 }
1320
1321 void FileBasedStore::createClass(
1322 const CIMNamespaceName& nameSpace,
1323 const CIMClass& newClass)
1324 kumpf 1.1 {
1325 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::createClass");
1326
1327 #ifndef PEGASUS_SUPPORT_UTF8_FILENAME
1328 // Do not allow file names to contain characters outside of 7-bit ASCII.
1329 String classNameString = newClass.getClassName().getString();
1330 Uint32 len = classNameString.size();
1331 for (Uint32 i = 0; i < len; ++i)
1332 {
1333 if ((Uint16)classNameString[i] > 0x007F)
1334 {
1335 PEG_METHOD_EXIT();
1336 throw PEGASUS_CIM_EXCEPTION(
1337 CIM_ERR_INVALID_PARAMETER, classNameString);
1338 }
1339 }
1340 #endif
1341
1342 String classFilePath = _getClassFilePath(
1343 nameSpace, newClass.getClassName(), newClass.getSuperClassName());
1344 Buffer classXml;
1345 kumpf 1.1 _streamer->encode(classXml, newClass);
1346 _SaveObject(classFilePath, classXml, _streamer);
1347
1348 PEG_METHOD_EXIT();
1349 }
1350
1351 void FileBasedStore::modifyClass(
1352 const CIMNamespaceName& nameSpace,
1353 const CIMClass& modifiedClass)
1354 {
1355 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::modifyClass");
1356
1357 String classFilePath = _getClassFilePath(
1358 nameSpace,
1359 modifiedClass.getClassName(),
1360 modifiedClass.getSuperClassName());
1361
1362 //
1363 // Delete the old file containing the class:
1364 //
1365
1366 kumpf 1.1 if (!FileSystem::removeFileNoCase(classFilePath))
1367 {
1368 PEG_METHOD_EXIT();
1369 // ATTN: Parameter should be file name, not method name.
1370 String str = "FileBasedStore::modifyClass()";
1371 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1372 MessageLoaderParms(
1373 "Repository.CIMRepository.FAILED_TO_REMOVE_FILE",
1374 "failed to remove file in $0", str));
1375 }
1376
1377 //
1378 // Create new class file:
1379 //
1380
1381 Buffer classXml;
1382 _streamer->encode(classXml, modifiedClass);
1383 _SaveObject(classFilePath, classXml, _streamer);
1384
1385 PEG_METHOD_EXIT();
1386 }
1387 kumpf 1.1
1388 void FileBasedStore::deleteClass(
1389 const CIMNamespaceName& nameSpace,
1390 const CIMName& className,
1391 const CIMName& superClassName)
1392 {
1393 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::deleteClass");
1394
1395 // Remove class file
1396
1397 String classFilePath =
1398 _getClassFilePath(nameSpace, className, superClassName);
1399
1400 if (!FileSystem::removeFileNoCase(classFilePath))
1401 {
1402 PEG_METHOD_EXIT();
1403 throw CannotRemoveFile(classFilePath);
1404 }
1405
1406 PEG_METHOD_EXIT();
1407 }
1408 kumpf 1.1
1409 Array<CIMObjectPath> FileBasedStore::enumerateInstanceNamesForClass(
1410 const CIMNamespaceName& nameSpace,
1411 const CIMName& className)
1412 {
1413 PEG_METHOD_ENTER(TRC_REPOSITORY,
1414 "FileBasedStore::enumerateInstanceNamesForClass");
1415
1416 //
1417 // Get instance names from the instance index file for the class:
1418 //
1419 Array<Uint32> indices;
1420 Array<Uint32> sizes;
1421
1422 //
1423 // Form the names of the instance index and data files
1424 //
1425
1426 String indexFilePath = _getInstanceIndexFilePath(nameSpace, className);
1427 String dataFilePath = _getInstanceDataFilePath(nameSpace, className);
1428
1429 kumpf 1.1 //
1430 // Get all instances for the class:
1431 //
1432
1433 Array<CIMObjectPath> instanceNames;
1434 Array<Uint32> freeFlags;
1435
1436 if (!InstanceIndexFile::enumerateEntries(
1437 indexFilePath, freeFlags, indices, sizes, instanceNames, false))
1438 {
1439 PEG_METHOD_EXIT();
1440 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1441 MessageLoaderParms(
1442 "Repository.CIMRepository.FAILED_TO_LOAD_INSTANCE_NAMES",
1443 "Failed to load instance names in class $0",
1444 className.getString()));
1445 }
1446
1447 PEG_METHOD_EXIT();
1448 return instanceNames;
1449 }
1450 kumpf 1.1
1451 Array<CIMInstance> FileBasedStore::enumerateInstancesForClass(
1452 const CIMNamespaceName& nameSpace,
1453 const CIMName& className)
1454 {
1455 PEG_METHOD_ENTER(TRC_REPOSITORY,
1456 "FileBasedStore::enumerateInstancesForClass");
1457
1458 Array<CIMInstance> cimInstances;
1459
1460 if (!_loadAllInstances(nameSpace, className, cimInstances))
1461 {
1462 PEG_METHOD_EXIT();
1463 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1464 MessageLoaderParms(
1465 "Repository.CIMRepository.FAILED_TO_LOAD_INSTANCES",
1466 "Failed to load instances in class $0",
1467 className.getString()));
1468 }
1469
1470 PEG_METHOD_EXIT();
1471 kumpf 1.1 return cimInstances;
1472 }
1473
1474 CIMInstance FileBasedStore::getInstance(
1475 const CIMNamespaceName& nameSpace,
1476 const CIMObjectPath& instanceName)
1477 {
1478 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::getInstance");
1479
1480 //
1481 // Get paths of index and data files:
1482 //
1483
1484 String indexFilePath = _getInstanceIndexFilePath(
1485 nameSpace, instanceName.getClassName());
1486
1487 String dataFilePath = _getInstanceDataFilePath(
1488 nameSpace, instanceName.getClassName());
1489
1490 //
1491 // Get the index for this instance:
1492 kumpf 1.1 //
1493
1494 Uint32 index;
1495 Uint32 size;
1496
1497 if (!InstanceIndexFile::lookupEntry(
1498 indexFilePath, instanceName, index, size))
1499 {
1500 PEG_METHOD_EXIT();
1501 throw PEGASUS_CIM_EXCEPTION(CIM_ERR_NOT_FOUND, instanceName.toString());
1502 }
1503
1504 //
1505 // Load the instance from file:
1506 //
1507
1508 CIMInstance cimInstance;
1509
1510 if (!_loadInstance(dataFilePath, cimInstance, index, size))
1511 {
1512 PEG_METHOD_EXIT();
1513 kumpf 1.1 throw CannotOpenFile(dataFilePath);
1514 }
1515
1516 PEG_METHOD_EXIT();
1517 return cimInstance;
1518 }
1519
1520 void FileBasedStore::createInstance(
1521 const CIMNamespaceName& nameSpace,
1522 const CIMObjectPath& instanceName,
1523 const CIMInstance& cimInstance)
1524 {
1525 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::createInstance");
1526
1527 //
1528 // Get paths to data and index files:
1529 //
1530
1531 String indexFilePath = _getInstanceIndexFilePath(
1532 nameSpace, cimInstance.getClassName());
1533
1534 kumpf 1.1 String dataFilePath = _getInstanceDataFilePath(
1535 nameSpace, cimInstance.getClassName());
1536
1537 //
1538 // Perform the operation in a transaction scope to enable rollback on
1539 // failure.
1540 //
1541
1542 InstanceTransactionHandler transaction(indexFilePath, dataFilePath);
1543
1544 //
1545 // Save instance to file:
1546 //
1547
1548 Uint32 index;
1549 Uint32 size;
1550
1551 {
1552 Buffer data;
1553 _streamer->encode(data, cimInstance);
1554 size = data.size();
1555 kumpf 1.1
1556 if (!InstanceDataFile::appendInstance(dataFilePath, data, index))
1557 {
1558 PEG_METHOD_EXIT();
1559 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1560 MessageLoaderParms(
1561 "Repository.CIMRepository.FAILED_TO_CREATE_INSTANCE",
1562 "Failed to create instance: $0",
1563 instanceName.toString()));
1564 }
1565 }
1566
1567 //
1568 // Create entry in index file:
1569 //
1570
1571 if (!InstanceIndexFile::createEntry(
1572 indexFilePath, instanceName, index, size))
1573 {
1574 PEG_METHOD_EXIT();
1575 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1576 kumpf 1.1 MessageLoaderParms(
1577 "Repository.CIMRepository.FAILED_TO_CREATE_INSTANCE",
1578 "Failed to create instance: $0",
1579 instanceName.toString()));
1580 }
1581
1582 transaction.complete();
1583
1584 PEG_METHOD_EXIT();
1585 }
1586
1587 void FileBasedStore::modifyInstance(
1588 const CIMNamespaceName& nameSpace,
1589 const CIMObjectPath& instanceName,
1590 const CIMInstance& cimInstance)
1591 {
1592 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::modifyInstance");
1593
1594 //
1595 // Get paths of index and data files:
1596 //
1597 kumpf 1.1
1598 String indexFilePath = _getInstanceIndexFilePath(
1599 nameSpace, cimInstance.getClassName());
1600
1601 String dataFilePath = _getInstanceDataFilePath(
1602 nameSpace, cimInstance.getClassName());
1603
1604 //
1605 // Look up the specified instance
1606 //
1607
1608 Uint32 oldSize;
1609 Uint32 oldIndex;
1610 Uint32 newSize;
1611 Uint32 newIndex;
1612
1613 if (!InstanceIndexFile::lookupEntry(
1614 indexFilePath, instanceName, oldIndex, oldSize))
1615 {
1616 PEG_METHOD_EXIT();
1617 throw PEGASUS_CIM_EXCEPTION(CIM_ERR_NOT_FOUND, instanceName.toString());
1618 kumpf 1.1 }
1619
1620 //
1621 // Perform the operation in a transaction scope to enable rollback on
1622 // failure.
1623 //
1624
1625 InstanceTransactionHandler transaction(indexFilePath, dataFilePath);
1626
1627 //
1628 // Modify the data file:
1629 //
1630
1631 {
1632 Buffer out;
1633 _streamer->encode(out, cimInstance);
1634
1635 newSize = out.size();
1636
1637 if (!InstanceDataFile::appendInstance(dataFilePath, out, newIndex))
1638 {
1639 kumpf 1.1 PEG_METHOD_EXIT();
1640 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1641 MessageLoaderParms(
1642 "Repository.CIMRepository.FAILED_TO_MODIFY_INSTANCE",
1643 "Failed to modify instance $0",
1644 instanceName.toString()));
1645 }
1646 }
1647
1648 //
1649 // Modify the index file:
1650 //
1651
1652 Uint32 freeCount;
1653
1654 if (!InstanceIndexFile::modifyEntry(indexFilePath, instanceName, newIndex,
1655 newSize, freeCount))
1656 {
1657 PEG_METHOD_EXIT();
1658 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1659 MessageLoaderParms(
1660 kumpf 1.1 "Repository.CIMRepository.FAILED_TO_MODIFY_INSTANCE",
1661 "Failed to modify instance $0",
1662 instanceName.toString()));
1663 }
1664
1665 //
1666 // Compact the index and data files if the free count max was
1667 // reached.
1668 //
1669
1670 if (freeCount >= _MAX_FREE_COUNT)
1671 {
1672 _CompactInstanceRepository(indexFilePath, dataFilePath);
1673 }
1674
1675 transaction.complete();
1676
1677 PEG_METHOD_EXIT();
1678 }
1679
1680 void FileBasedStore::deleteInstance(
1681 kumpf 1.1 const CIMNamespaceName& nameSpace,
1682 const CIMObjectPath& instanceName)
1683 {
1684 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::deleteInstance");
1685
1686 //
1687 // Get paths of index and data files:
1688 //
1689
1690 String indexFilePath = _getInstanceIndexFilePath(
1691 nameSpace, instanceName.getClassName());
1692
1693 String dataFilePath = _getInstanceDataFilePath(
1694 nameSpace, instanceName.getClassName());
1695
1696 //
1697 // Perform the operation in a transaction scope to enable rollback on
1698 // failure.
1699 //
1700
1701 InstanceTransactionHandler transaction(indexFilePath, dataFilePath);
1702 kumpf 1.1
1703 //
1704 // Lookup instance from the index file (raise error if not found).
1705 //
1706
1707 Uint32 index;
1708 Uint32 size;
1709
1710 if (!InstanceIndexFile::lookupEntry(
1711 indexFilePath, instanceName, index, size))
1712 {
1713 PEG_METHOD_EXIT();
1714 throw PEGASUS_CIM_EXCEPTION(CIM_ERR_NOT_FOUND, instanceName.toString());
1715 }
1716
1717 //
1718 // Remove entry from index file.
1719 //
1720
1721 Uint32 freeCount;
1722
1723 kumpf 1.1 if (!InstanceIndexFile::deleteEntry(indexFilePath, instanceName, freeCount))
1724 {
1725 PEG_METHOD_EXIT();
1726 throw PEGASUS_CIM_EXCEPTION_L(CIM_ERR_FAILED,
1727 MessageLoaderParms(
1728 "Repository.CIMRepository.FAILED_TO_DELETE_INSTANCE",
1729 "Failed to delete instance: $0",
1730 instanceName.toString()));
1731 }
1732
1733 //
1734 // Compact the index and data files if the free count max was
1735 // reached.
1736 //
1737
1738 if (freeCount >= _MAX_FREE_COUNT)
1739 {
1740 _CompactInstanceRepository(indexFilePath, dataFilePath);
1741 }
1742
1743 transaction.complete();
1744 kumpf 1.1
1745 PEG_METHOD_EXIT();
1746 }
1747
1748 void FileBasedStore::deleteAllInstances(
1749 const CIMNamespaceName& nameSpace,
1750 const CIMName& className)
1751 {
1752 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::deleteAllInstances");
1753
1754 String indexFilePath =
1755 _getInstanceIndexFilePath(nameSpace, className);
1756 String dataFilePath =
1757 _getInstanceDataFilePath(nameSpace, className);
1758
1759 FileSystem::removeFileNoCase(indexFilePath);
1760 FileSystem::removeFileNoCase(dataFilePath);
1761
1762 PEG_METHOD_EXIT();
1763 }
1764
1765 kumpf 1.1 Boolean FileBasedStore::instanceExists(
1766 const CIMNamespaceName& nameSpace,
1767 const CIMObjectPath& instanceName)
1768 {
1769 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::instanceExists");
1770
1771 String path =
1772 _getInstanceIndexFilePath(nameSpace, instanceName.getClassName());
1773
1774 Uint32 index;
1775 Uint32 size;
1776 if (InstanceIndexFile::lookupEntry(path, instanceName, index, size))
1777 {
1778 PEG_METHOD_EXIT();
1779 return true;
1780 }
1781
1782 PEG_METHOD_EXIT();
1783 return false;
1784 }
1785
1786 kumpf 1.1 void FileBasedStore::addClassAssociations(
1787 const CIMNamespaceName& nameSpace,
1788 const Array<ClassAssociation>& classAssocEntries)
1789 {
1790 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::addClassAssociations");
1791
1792 String assocFileName = _getAssocClassPath(nameSpace);
1793 PEGASUS_STD(ofstream) os;
1794
1795 if (!OpenAppend(os, assocFileName))
1796 {
1797 PEG_METHOD_EXIT();
1798 throw CannotOpenFile(assocFileName);
1799 }
1800
1801 for (Uint32 i = 0; i < classAssocEntries.size(); i++)
1802 {
1803 AssocClassTable::append(
1804 os,
1805 assocFileName,
1806 classAssocEntries[i].assocClassName,
1807 kumpf 1.1 classAssocEntries[i].fromClassName,
1808 classAssocEntries[i].fromPropertyName,
1809 classAssocEntries[i].toClassName,
1810 classAssocEntries[i].toPropertyName);
1811 }
1812
1813 PEG_METHOD_EXIT();
1814 }
1815
1816 Boolean FileBasedStore::removeClassAssociation(
1817 const CIMNamespaceName& nameSpace,
1818 const CIMName& assocClassName)
1819 {
1820 PEG_METHOD_ENTER(TRC_REPOSITORY, "FileBasedStore::removeClassAssociation");
1821
1822 String assocFileName = _getAssocClassPath(nameSpace);
1823
1824 Boolean returnStatus =
1825 AssocClassTable::deleteAssociation(assocFileName, assocClassName);
1826
1827 PEG_METHOD_EXIT();
1828 kumpf 1.1 return returnStatus;
1829 }
1830
1831 void FileBasedStore::getClassAssociatorNames(
1832 const CIMNamespaceName& nameSpace,
1833 const Array<CIMName>& classList,
1834 const Array<CIMName>& assocClassList,
1835 const Array<CIMName>& resultClassList,
1836 const String& role,
1837 const String& resultRole,
1838 Array<String>& associatorNames)
1839 {
1840 PEG_METHOD_ENTER(TRC_REPOSITORY,
1841 "FileBasedStore::getClassAssociatorNames");
1842
1843 String assocFileName = _getAssocClassPath(nameSpace);
1844
|