1 karl 1.47 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.17 //
|
3 karl 1.40 // 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 karl 1.36 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.40 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.42 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.47 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.17 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 kumpf 1.26 // 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 mike 1.17 // 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 karl 1.56 //
|
21 kumpf 1.26 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
22 mike 1.17 // 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 kumpf 1.26 // 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 mike 1.17 // 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 mike 1.18 #include <Pegasus/Common/Config.h>
|
35 mike 1.17 #include <fstream>
36 #include <cctype>
37 #include <cstdio>
|
38 mike 1.20 #include <cstring>
|
39 mike 1.17 #include <cstdlib>
40 #include <Pegasus/Common/FileSystem.h>
|
41 kumpf 1.22 #include <Pegasus/Common/Tracer.h>
|
42 mike 1.17 #include "InstanceIndexFile.h"
43
44 PEGASUS_USING_STD;
45
46 PEGASUS_NAMESPACE_BEGIN
47
|
48 mike 1.20 ////////////////////////////////////////////////////////////////////////////////
49 //
50 // Local routines:
|
51 mike 1.17 //
|
52 mike 1.20 ////////////////////////////////////////////////////////////////////////////////
|
53 kumpf 1.57
|
54 marek 1.32 #ifdef PEGASUS_OS_ZOS
|
55 mike 1.20
|
56 marek 1.32 static Uint32 getOffset( streampos sp )
57 {
58 Uint32 result = (streamoff)sp;
59
60 fpos_t posArray = sp.seekpos();
61
62
63 result += posArray.__fpos_elem[1];
64
65 return result;
66 }
|
67 kumpf 1.57
|
68 marek 1.32 #endif
|
69 kumpf 1.57
70 //
71 // Converts a CIMObjectPath to a form that can be used as a key in the index
72 // file. Newline and carriage return characters are escaped to prevent
73 // problems with the line-based file format.
74 //
75
76 static String _convertInstanceNameToKey(const CIMObjectPath& instanceName)
77 {
78 String instanceNameString(instanceName.toString());
79 const Uint32 stringLength = instanceNameString.size();
80 String keyString;
81 keyString.reserveCapacity(stringLength);
82
83 for (Uint32 i = 0; i < stringLength; i++)
84 {
85 Char16 instanceNameChar = instanceNameString[i];
86
87 if (instanceNameChar == '\n')
88 {
89 keyString.append("\\n");
90 kumpf 1.57 }
91 else if (instanceNameChar == '\r')
92 {
93 keyString.append("\\r");
94 }
95 else
96 {
97 keyString.append(instanceNameChar);
98 }
99 }
100
101 return keyString;
102 }
103
104 //
105 // Converts an index file key to a CIMObjectPath object. Newline and
106 // carriage return characters are un-escaped.
107 //
108
109 static CIMObjectPath _convertKeyToInstanceName(const char* key)
110 {
111 kumpf 1.57 String keyString(key);
112
113 for (Uint32 i = 0; i < keyString.size() - 1; i++)
114 {
115 if (keyString[i] == '\\')
116 {
117 if (keyString[i+1] == 'n')
118 {
119 keyString[i] = '\n';
120 keyString.remove(i+1, 1);
121 }
122 else if (keyString[i+1] == 'r')
123 {
124 keyString[i] = '\r';
125 keyString.remove(i+1, 1);
126 }
127 else
128 {
129 i++;
130 }
131 }
132 kumpf 1.57 }
133
134 return CIMObjectPath(keyString);
135 }
136
|
137 mike 1.17 //
|
138 mike 1.20 // Gets one line from the given file.
|
139 mike 1.17 //
140
|
141 mike 1.44 static Boolean _GetLine(fstream& fs, Buffer& x)
|
142 mike 1.17 {
|
143 marek 1.48 const Uint32 buffersize = 1023 + 1;
144 Uint32 xcount = 0;
145 Uint32 gcount = 0;
146
|
147 mike 1.17 x.clear();
|
148 marek 1.48 x.reserveCapacity(buffersize);
149
150 // The general idea is, we will read the stream at buffersize each time.
151 // if we get exactly buffersize-1, that means we didn't hit a \n
|
152 kumpf 1.50 // so we loop again to read more,
|
153 marek 1.48 // until we get a buffer that's not completely full.
154 // That means we hit a \n so we exit the loop.
155 do
156 {
157 char input[buffersize];
158
|
159 kumpf 1.50 // This will read up to buffersize-1 char,
|
160 marek 1.48 // but stop as soon as it hit \n.
161 // This will NOT consume the \n at the end.
162 fs.get(input, buffersize, '\n');
163
|
164 a.dunfey 1.51 gcount = (Uint32)fs.gcount();
|
165 marek 1.48 x.append(input, gcount);
166 xcount += gcount;
|
167 mike 1.17
|
168 marek 1.48 } while (gcount == buffersize-1 && fs.rdstate() != istream::failbit);
|
169 mike 1.17
|
170 marek 1.48 // if we read 0 byte in the last call, that's because the read buffer is
171 // exactly multiple of the input line.
172 // So the 2nd last get() read everything up to the \n and
173 // the last get() read 0 char and set the failbit on the
174 // stream. The clear() call will set the stream to ready state.
175 if (gcount == 0)
176 {
177 fs.clear();
178 }
|
179 mike 1.17
|
180 marek 1.48 if (!fs.eof())
181 {
|
182 kumpf 1.50 // we need to consume the '\n', because get() doesn't
183 char c = 0;
184 fs.get(c);
|
185 marek 1.48 }
|
186 mike 1.17
|
187 marek 1.48 // if xcount is non zero, then we have read something from the buffer.
188 return (xcount != 0);
|
189 mike 1.20 }
190
191 inline void _SkipWhitespace(char*& p)
192 {
193 while (*p && isspace(*p))
194 p++;
|
195 mike 1.17 }
196
197 //
|
198 mike 1.20 // Get an integer field from the character pointer and advance the
199 // pointer past the field.
|
200 mike 1.17 //
201
|
202 mike 1.20 Boolean _GetIntField(
203 char*& ptr,
204 Boolean& error,
205 Uint32& value,
206 int base)
|
207 mike 1.17 {
|
208 mike 1.20 char* end = 0;
209 value = strtoul(ptr, &end, base);
210
|
211 mike 1.17 error = false;
212
213 if (!end)
214 {
|
215 mike 1.18 error = true;
216 return false;
|
217 mike 1.17 }
218
|
219 mike 1.20 _SkipWhitespace(end);
|
220 mike 1.17
|
221 mike 1.20 if (*end == '\0')
|
222 mike 1.18 {
223 error = true;
224 return false;
225 }
|
226 mike 1.17
|
227 mike 1.20 ptr = end;
228 return true;
229 }
|
230 mike 1.18
|
231 mike 1.20 //
232 // Gets the next record in the index file.
233 //
|
234 mike 1.17
|
235 mike 1.20 static Boolean _GetNextRecord(
|
236 r.kieninger 1.39 fstream& fs,
|
237 mike 1.44 Buffer& line,
|
238 mike 1.20 Uint32& freeFlag,
239 Uint32& hashCode,
240 Uint32& index,
241 Uint32& size,
242 const char*& instanceName,
243 Boolean& error)
244 {
245 error = false;
|
246 mike 1.17
|
247 mike 1.20 //
248 // Get next line:
249 //
250
251 if (!_GetLine(fs, line))
|
252 mike 1.18 return false;
|
253 mike 1.17
|
254 mike 1.20 //
255 // Get the free flag field:
256 //
257
258 char* end = (char*)line.getData();
|
259 mike 1.18
|
260 mike 1.20 if (!_GetIntField(end, error, freeFlag, 10))
|
261 kumpf 1.50 return false;
|
262 mike 1.17
|
263 mike 1.20 if (freeFlag != 0 && freeFlag != 1)
|
264 mike 1.18 {
|
265 kumpf 1.50 error = true;
266 return false;
|
267 mike 1.18 }
|
268 mike 1.17
|
269 mike 1.20 //
270 // Get the hash-code field:
271 //
|
272 mike 1.17
|
273 mike 1.20 if (!_GetIntField(end, error, hashCode, 16))
|
274 kumpf 1.50 return false;
|
275 mike 1.18
|
276 mike 1.20 //
277 // Get index field:
278 //
|
279 mike 1.18
|
280 mike 1.20 if (!_GetIntField(end, error, index, 10))
|
281 kumpf 1.50 return false;
|
282 mike 1.18
|
283 mike 1.20 //
284 // Get size field:
285 //
|
286 mike 1.17
|
287 mike 1.20 if (!_GetIntField(end, error, size, 10))
|
288 kumpf 1.50 return false;
|
289 mike 1.17
|
290 mike 1.20 //
291 // Get instance name:
292 //
|
293 mike 1.18
|
294 mike 1.20 instanceName = end;
|
295 mike 1.18
|
296 mike 1.17 return true;
297 }
298
|
299 mike 1.20 ////////////////////////////////////////////////////////////////////////////////
|
300 mike 1.17 //
|
301 mike 1.20 // InstanceIndexFile:
|
302 mike 1.17 //
|
303 mike 1.20 ////////////////////////////////////////////////////////////////////////////////
|
304 mike 1.17
|
305 mike 1.20 Boolean InstanceIndexFile::lookupEntry(
|
306 r.kieninger 1.39 const String& path,
|
307 kumpf 1.24 const CIMObjectPath& instanceName,
|
308 mike 1.20 Uint32& indexOut,
309 Uint32& sizeOut)
|
310 mike 1.17 {
|
311 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::lookupEntry()");
312
|
313 mike 1.20 fstream fs;
|
314 mike 1.17
|
315 mike 1.20 if (!_openFile(path, fs))
|
316 kumpf 1.22 {
317 PEG_METHOD_EXIT();
|
318 kumpf 1.50 return false;
|
319 kumpf 1.22 }
|
320 mike 1.17
|
321 mike 1.20 Uint32 entryOffset = 0;
|
322 mike 1.17
|
323 mike 1.20 Boolean result = _lookupEntry(
|
324 kumpf 1.50 fs, instanceName, indexOut, sizeOut, entryOffset);
|
325 mike 1.18
|
326 mike 1.20 fs.close();
|
327 kumpf 1.22
328 PEG_METHOD_EXIT();
|
329 mike 1.20 return result;
|
330 mike 1.17 }
331
|
332 mike 1.20 Boolean InstanceIndexFile::createEntry(
|
333 r.kieninger 1.39 const String& path,
|
334 kumpf 1.24 const CIMObjectPath& instanceName,
|
335 mike 1.20 Uint32 indexIn,
336 Uint32 sizeIn)
|
337 mike 1.17 {
|
338 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::createEntry()");
339
|
340 mike 1.18 //
|
341 mike 1.20 // Open the file:
342 //
343
344 fstream fs;
345
|
346 kumpf 1.22 if (!_openFile(path, fs, true))
347 {
348 PEG_METHOD_EXIT();
|
349 kumpf 1.50 return false;
|
350 kumpf 1.22 }
|
351 mike 1.20
|
352 mike 1.18 //
|
353 mike 1.20 // Return false if entry already exists:
|
354 mike 1.18 //
355
|
356 mike 1.20 Uint32 tmpIndex;
357 Uint32 tmpSize;
358 Uint32 tmpEntryOffset;
359
360 if (InstanceIndexFile::_lookupEntry(
|
361 kumpf 1.50 fs, instanceName, tmpIndex, tmpSize, tmpEntryOffset))
|
362 kumpf 1.22 {
363 PEG_METHOD_EXIT();
|
364 kumpf 1.50 return false;
|
365 kumpf 1.22 }
|
366 mike 1.20
367 //
368 // Append the new entry to the end of the file:
369 //
|
370 mike 1.18
|
371 mike 1.20 if (!_appendEntry(fs, instanceName, indexIn, sizeIn))
|
372 kumpf 1.22 {
373 PEG_METHOD_EXIT();
|
374 kumpf 1.50 return false;
|
375 kumpf 1.22 }
|
376 mike 1.17
|
377 mike 1.18 //
|
378 mike 1.20 // Close the file:
|
379 mike 1.18 //
|
380 mike 1.17
|
381 mike 1.20 fs.close();
|
382 kumpf 1.22
383 PEG_METHOD_EXIT();
|
384 mike 1.20 return true;
385 }
|
386 mike 1.17
|
387 mike 1.20 Boolean InstanceIndexFile::deleteEntry(
|
388 r.kieninger 1.39 const String& path,
|
389 kumpf 1.24 const CIMObjectPath& instanceName,
|
390 mike 1.20 Uint32& freeCount)
391 {
|
392 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::deleteEntry()");
393
|
394 mike 1.20 freeCount = 0;
|
395 mike 1.17
|
396 mike 1.20 //
397 // Open the file:
398 //
|
399 mike 1.18
|
400 mike 1.20 fstream fs;
|
401 mike 1.18
|
402 mike 1.20 if (!_openFile(path, fs))
403 {
|
404 kumpf 1.22 PEG_METHOD_EXIT();
|
405 kumpf 1.50 return false;
|
406 mike 1.20 }
|
407 mike 1.17
|
408 mike 1.20 //
409 // Mark the entry as free:
410 //
|
411 mike 1.17
|
412 mike 1.20 if (!_markEntryFree(fs, instanceName))
413 {
|
414 kumpf 1.22 PEG_METHOD_EXIT();
|
415 kumpf 1.50 return false;
|
416 mike 1.18 }
|
417 mike 1.17
|
418 mike 1.18 //
|
419 mike 1.20 // Increment the free count:
420 //
421
422 freeCount = 0;
423
424 if (!_incrementFreeCount(fs, freeCount))
|
425 kumpf 1.22 {
426 PEG_METHOD_EXIT();
|
427 kumpf 1.50 return false;
|
428 kumpf 1.22 }
|
429 mike 1.20
430 //
431 // Close the file:
|
432 mike 1.18 //
|
433 mike 1.17
|
434 mike 1.20 fs.close();
|
435 mike 1.17
|
436 kumpf 1.22 PEG_METHOD_EXIT();
|
437 mike 1.17 return true;
438 }
439
|
440 mike 1.20 Boolean InstanceIndexFile::modifyEntry(
|
441 r.kieninger 1.39 const String& path,
|
442 kumpf 1.24 const CIMObjectPath& instanceName,
|
443 mike 1.20 Uint32 indexIn,
444 Uint32 sizeIn,
445 Uint32& freeCount)
446 {
|
447 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::modifyEntry()");
448
|
449 mike 1.20 //
450 // Open the file:
451 //
452
453 fstream fs;
454
455 if (!_openFile(path, fs))
|
456 kumpf 1.22 {
457 PEG_METHOD_EXIT();
|
458 kumpf 1.50 return false;
|
459 kumpf 1.22 }
|
460 mike 1.17
|
461 mike 1.18 //
|
462 mike 1.20 // Mark the entry as free:
|
463 mike 1.18 //
|
464 mike 1.17
|
465 mike 1.20 if (!_markEntryFree(fs, instanceName))
|
466 kumpf 1.22 {
467 PEG_METHOD_EXIT();
|
468 kumpf 1.50 return false;
|
469 kumpf 1.22 }
|
470 mike 1.17
|
471 mike 1.18 //
|
472 mike 1.20 // Append new entry:
473 //
474
475 if (!_appendEntry(fs, instanceName, indexIn, sizeIn))
|
476 kumpf 1.22 {
477 PEG_METHOD_EXIT();
|
478 kumpf 1.50 return false;
|
479 kumpf 1.22 }
|
480 mike 1.20
|
481 mike 1.18 //
|
482 mike 1.20 // Increment the free count:
|
483 mike 1.18 //
|
484 mike 1.17
|
485 mike 1.20 freeCount = 0;
|
486 mike 1.17
|
487 mike 1.20 if (!_incrementFreeCount(fs, freeCount))
|
488 kumpf 1.22 {
489 PEG_METHOD_EXIT();
|
490 kumpf 1.50 return false;
|
491 kumpf 1.22 }
|
492 mike 1.17
|
493 mike 1.18 //
|
494 mike 1.20 // Close the file:
|
495 mike 1.18 //
|
496 mike 1.17
|
497 mike 1.20 fs.close();
|
498 mike 1.17
|
499 kumpf 1.22 PEG_METHOD_EXIT();
|
500 mike 1.18 return true;
501 }
|
502 mike 1.17
|
503 mike 1.20 Boolean InstanceIndexFile::enumerateEntries(
504 const String& path,
505 Array<Uint32>& freeFlags,
506 Array<Uint32>& indices,
507 Array<Uint32>& sizes,
|
508 kumpf 1.24 Array<CIMObjectPath>& instanceNames,
|
509 mike 1.20 Boolean includeFreeEntries)
|
510 mike 1.18 {
|
511 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::enumerateEntries()");
512
|
513 mike 1.18 //
|
514 mike 1.20 // Reserve space for at least COUNT entries:
|
515 mike 1.18 //
|
516 mike 1.17
|
517 mike 1.20 const Uint32 COUNT = 1024;
518
|
519 kumpf 1.27 freeFlags.reserveCapacity(COUNT);
520 indices.reserveCapacity(COUNT);
521 sizes.reserveCapacity(COUNT);
522 instanceNames.reserveCapacity(COUNT);
|
523 mike 1.17
|
524 mike 1.18 //
|
525 mike 1.20 // Open input file:
|
526 mike 1.18 //
|
527 mike 1.20
528 fstream fs;
529
530 if (!_openFile(path, fs))
|
531 kumpf 1.22 {
532 // file does not exist, just return with no instanceNames
533 PEG_METHOD_EXIT();
534 return true;
535 }
|
536 mike 1.20
537 //
538 // Iterate over all instances to build output arrays:
|
539 mike 1.18 //
|
540 mike 1.20
|
541 mike 1.44 Buffer line;
|
542 mike 1.20 Uint32 freeFlag;
543 Uint32 hashCode;
544 const char* instanceName;
545 Uint32 index;
546 Uint32 size;
547 Boolean error;
548
549 while (_GetNextRecord(
|
550 kumpf 1.50 fs, line, freeFlag, hashCode, index, size, instanceName, error))
|
551 mike 1.17 {
|
552 kumpf 1.50 if (!freeFlag || includeFreeEntries)
553 {
554 freeFlags.append(freeFlag);
555 indices.append(index);
556 sizes.append(size);
|
557 kumpf 1.57 instanceNames.append(_convertKeyToInstanceName(instanceName));
|
558 kumpf 1.50 }
|
559 mike 1.17 }
560
|
561 mike 1.20 if (error)
|
562 kumpf 1.22 {
563 PEG_METHOD_EXIT();
|
564 kumpf 1.50 return false;
|
565 kumpf 1.22 }
|
566 mike 1.20
|
567 kumpf 1.22 PEG_METHOD_EXIT();
|
568 mike 1.20 return true;
569 }
570
571 Boolean InstanceIndexFile::_incrementFreeCount(
572 PEGASUS_STD(fstream)& fs,
573 Uint32& freeCount)
574 {
|
575 kumpf 1.50 PEG_METHOD_ENTER(TRC_REPOSITORY,
576 "InstanceIndexFile::_incrementFreeCount()");
|
577 kumpf 1.22
|
578 mike 1.20 //
579 // Position file pointer to beginning of file (where free count is
580 // located) and read the current free count.
581 //
582
583 fs.seekg(0);
584 char hexString[9];
585 fs.read(hexString, 8);
586
587 if (!fs)
|
588 kumpf 1.22 {
589 PEG_METHOD_EXIT();
|
590 kumpf 1.50 return false;
|
591 kumpf 1.22 }
|
592 mike 1.17
|
593 mike 1.20 hexString[8] = '\0';
|
594 mike 1.17
|
595 mike 1.18 //
|
596 mike 1.20 // Convert hex string to integer:
|
597 mike 1.18 //
|
598 mike 1.20
599 char* end = 0;
600 long tmp = strtol(hexString, &end, 16);
601
602 if (!end || *end != '\0' || tmp < 0)
|
603 kumpf 1.22 {
604 PEG_METHOD_EXIT();
|
605 kumpf 1.50 return false;
|
606 kumpf 1.22 }
|
607 mike 1.20
608 freeCount = Uint32(tmp);
|
609 mike 1.17
|
610 mike 1.18 //
|
611 mike 1.20 // Increment and rewrite the free count:
|
612 mike 1.18 //
|
613 mike 1.17
|
614 mike 1.20 sprintf(hexString, "%08X", ++freeCount);
615 fs.seekg(0);
616 fs.write(hexString, 8);
|
617 mike 1.17
|
618 kumpf 1.22 PEG_METHOD_EXIT();
|
619 mike 1.20 return !!fs;
|
620 mike 1.17 }
621
|
622 mike 1.20 Boolean InstanceIndexFile::_openFile(
|
623 r.kieninger 1.39 const String& path,
|
624 kumpf 1.22 PEGASUS_STD(fstream)& fs,
625 Boolean create)
|
626 mike 1.17 {
|
627 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::_openFile()");
628
|
629 mike 1.20 const char ZERO_FREE_COUNT[] = "00000000\n";
|
630 mike 1.17
|
631 mike 1.20 //
632 // Open the file:
633 //
|
634 mike 1.17
|
635 kumpf 1.50 if (!FileSystem::openNoCase(
636 fs, path, ios::in | ios::out PEGASUS_OR_IOS_BINARY))
|
637 mike 1.18 {
|
638 kumpf 1.22 if (create)
639 {
|
640 kumpf 1.50 //
641 // File does not exist so create it:
642 //
|
643 david 1.38 fs.open(path.getCString(), ios::out PEGASUS_OR_IOS_BINARY);
|
644 kumpf 1.22
645 if (!fs)
646 {
647 PEG_METHOD_EXIT();
|
648 kumpf 1.50 return false;
|
649 kumpf 1.22 }
650
|
651 kumpf 1.50 fs.write(ZERO_FREE_COUNT, sizeof(ZERO_FREE_COUNT) - 1);
652 fs.close();
|
653 kumpf 1.22
|
654 kumpf 1.50 //
655 // Reopen the file:
|
656 kumpf 1.22 //
657
|
658 kumpf 1.50 if (!FileSystem::openNoCase(
659 fs, path, ios::in | ios::out PEGASUS_OR_IOS_BINARY))
|
660 kumpf 1.22 {
661 PEG_METHOD_EXIT();
|
662 kumpf 1.50 return false;
|
663 kumpf 1.22 }
664 }
665 else
666 {
667 PEG_METHOD_EXIT();
668 return false;
669 }
|
670 mike 1.20 }
|
671 mike 1.18
|
672 mike 1.20 //
673 // Position the file pointer beyond the free count:
674 //
675
676 fs.seekg(sizeof(ZERO_FREE_COUNT) - 1);
|
677 mike 1.18
|
678 kumpf 1.22 PEG_METHOD_EXIT();
|
679 mike 1.18 return true;
680 }
681
|
682 mike 1.20 Boolean InstanceIndexFile::_appendEntry(
683 PEGASUS_STD(fstream)& fs,
|
684 kumpf 1.24 const CIMObjectPath& instanceName,
|
685 mike 1.20 Uint32 indexIn,
686 Uint32 sizeIn)
|
687 mike 1.18 {
|
688 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::_appendEntry()");
689
|
690 mike 1.18 //
|
691 mike 1.20 // Position the file at the end:
692 //
693
694 fs.seekg(0, ios::end);
695
696 if (!fs)
|
697 kumpf 1.22 {
698 PEG_METHOD_EXIT();
|
699 kumpf 1.50 return false;
|
700 kumpf 1.22 }
|
701 mike 1.20
702 //
703 // Write the entry:
|
704 mike 1.18 //
|
705 mike 1.20
|
706 mike 1.18 Uint32 targetHashCode = instanceName.makeHashCode();
707
708 char buffer[32];
709 sprintf(buffer, "%08X", targetHashCode);
|
710 mike 1.20
711 fs << "0 " << buffer << ' ' << indexIn << ' ' << sizeIn << ' ';
|
712 chuck 1.43
713 // Calling getCString to ensure that utf-8 goes to the file
714 // Calling write to ensure no data conversion by the stream
|
715 kumpf 1.57 CString name = _convertInstanceNameToKey(instanceName).getCString();
|
716 kumpf 1.46 fs.write((const char *)name,
717 static_cast<streamsize>(strlen((const char *)name)));
|
718 chuck 1.43 fs << endl;
|
719 mike 1.20
|
720 kumpf 1.22 PEG_METHOD_EXIT();
|
721 mike 1.20 return !!fs;
|
722 mike 1.18 }
|
723 mike 1.17
|
724 mike 1.20 Boolean InstanceIndexFile::_markEntryFree(
725 PEGASUS_STD(fstream)& fs,
|
726 kumpf 1.24 const CIMObjectPath& instanceName)
|
727 mike 1.18 {
|
728 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::_markEntryFree()");
729
|
730 mike 1.18 //
|
731 mike 1.20 // First look up the entry:
|
732 mike 1.18 //
|
733 mike 1.17
|
734 mike 1.20 Uint32 index = 0;
735 Uint32 size = 0;
736 Uint32 entryOffset = 0;
737
738 if (!InstanceIndexFile::_lookupEntry(
|
739 kumpf 1.50 fs, instanceName, index, size, entryOffset))
|
740 mike 1.18 {
|
741 kumpf 1.22 PEG_METHOD_EXIT();
|
742 kumpf 1.50 return false;
|
743 mike 1.18 }
|
744 mike 1.17
|
745 mike 1.18 //
|
746 mike 1.20 // Now mark the entry as free (change the first character of the entry
747 // from a '0' to a '1').
|
748 mike 1.18 //
|
749 mike 1.20
750 fs.seekg(entryOffset);
751
752 if (!fs)
753 {
|
754 kumpf 1.22 PEG_METHOD_EXIT();
|
755 kumpf 1.50 return false;
|
756 mike 1.20 }
757
758 fs.write("1", 1);
759
|
760 kumpf 1.22 PEG_METHOD_EXIT();
|
761 mike 1.20 return !!fs;
762 }
763
764 Boolean InstanceIndexFile::_lookupEntry(
765 PEGASUS_STD(fstream)& fs,
|
766 kumpf 1.24 const CIMObjectPath& instanceName,
|
767 mike 1.20 Uint32& indexOut,
768 Uint32& sizeOut,
769 Uint32& entryOffset)
770 {
|
771 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::_lookupEntry()");
772
|
773 mike 1.20 indexOut = 0;
774 sizeOut = 0;
775 entryOffset = 0;
776
|
777 r.kieninger 1.39 // For for bugzilla 1508. Hostname and namespace are not included
778 // in the comparison here. Instances in the repository index file
779 // are generally stored without hostname and namespace. If the hostname
780 // and namespace of the instance to look up would not match, we would have
781 // not gotten here at all.
782 CIMObjectPath shortInstanceName = instanceName;
783 shortInstanceName.setNameSpace(CIMNamespaceName());
784 shortInstanceName.setHost(String::EMPTY);
785
786 Uint32 targetHashCode = shortInstanceName.makeHashCode();
|
787 mike 1.44 Buffer line;
|
788 mike 1.20 Uint32 freeFlag;
789 Uint32 hashCode;
790 const char* instanceNameTmp;
791 Uint32 index;
792 Uint32 size;
793 Boolean error;
|
794 kumpf 1.50 #ifndef PEGASUS_OS_ZOS
|
795 a.dunfey 1.51 entryOffset = (Uint32)fs.tellp();
|
796 kumpf 1.50 #else
|
797 marek 1.32 entryOffset = getOffset(fs.tellp());
|
798 kumpf 1.50 #endif
|
799 mike 1.20
800 while (_GetNextRecord(
|
801 kumpf 1.50 fs, line, freeFlag, hashCode, index, size, instanceNameTmp, error))
|
802 mike 1.20 {
|
803 r.kieninger 1.39
|
804 chuck 1.37 #ifdef PEGASUS_REPOSITORY_NOT_NORMALIZED
805 // See bugzilla 1207. If the object paths in the repository
806 // are not normalized, then the hashcodes cannot be used for
807 // the look up (because the hash is based on the normalized path).
808 if (freeFlag == 0 &&
|
809 kumpf 1.57 _convertKeyToInstanceName(instanceNameTmp) == shortInstanceName)
|
810 chuck 1.37 #else
|
811 kumpf 1.50 if (freeFlag == 0 &&
812 hashCode == targetHashCode &&
|
813 kumpf 1.57 _convertKeyToInstanceName(instanceNameTmp) == shortInstanceName)
|
814 chuck 1.37 #endif
|
815 kumpf 1.50 {
816 indexOut = index;
817 sizeOut = size;
|
818 kumpf 1.22 PEG_METHOD_EXIT();
|
819 kumpf 1.50 return true;
820 }
|
821 mike 1.20
|
822 kumpf 1.50 #ifndef PEGASUS_OS_ZOS
|
823 a.dunfey 1.51 entryOffset = (Uint32)fs.tellp();
|
824 kumpf 1.50 #else
|
825 marek 1.32 entryOffset = getOffset(fs.tellp());
|
826 kumpf 1.50 #endif
|
827 mike 1.20 }
828
829 fs.clear();
830
|
831 kumpf 1.22 PEG_METHOD_EXIT();
|
832 mike 1.20 return false;
833 }
834
835 Boolean InstanceIndexFile::compact(
836 const String& path)
837 {
|
838 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::compact()");
839
|
840 mike 1.20 //
841 // Open input file:
842 //
843
844 fstream fs;
845
846 if (!_openFile(path, fs))
|
847 kumpf 1.22 {
848 PEG_METHOD_EXIT();
|
849 kumpf 1.50 return false;
|
850 kumpf 1.22 }
|
851 mike 1.20
852 //
853 // Open temporary file (delete it first):
854 //
855
856 fstream tmpFs;
857 String tmpPath = path;
|
858 kumpf 1.29 tmpPath.append(".tmp");
|
859 mike 1.20
|
860 kumpf 1.22 FileSystem::removeFileNoCase(tmpPath);
|
861 mike 1.20
|
862 kumpf 1.22 if (!_openFile(tmpPath, tmpFs, true))
863 {
864 PEG_METHOD_EXIT();
|
865 kumpf 1.50 return false;
|
866 kumpf 1.22 }
|
867 mike 1.20
868 //
869 // Iterate over all instances to build output arrays:
870 //
|
871 mike 1.17
|
872 mike 1.44 Buffer line;
|
873 mike 1.20 Uint32 freeFlag;
|
874 mike 1.17 Uint32 hashCode;
|
875 mike 1.20 const char* instanceName;
876 Uint32 index;
|
877 mike 1.18 Uint32 size;
|
878 mike 1.17 Boolean error;
|
879 mike 1.20 Uint32 adjust = 0;
|
880 mike 1.17
|
881 mike 1.20 while (_GetNextRecord(
|
882 kumpf 1.50 fs, line, freeFlag, hashCode, index, size, instanceName, error))
|
883 mike 1.17 {
|
884 kumpf 1.50 //
885 // Copy the entry over to the temporary file if it is not free.
886 // Otherwise, discard the entry and update subsequent indices to
887 // compensate for removal of this block.
888 //
889
890 if (freeFlag)
891 {
892 adjust += size;
893 }
894 else
895 {
|
896 kumpf 1.57 if (!_appendEntry(tmpFs, _convertKeyToInstanceName(instanceName),
|
897 kumpf 1.28 index - adjust, size))
|
898 kumpf 1.50 {
899 error = true;
900 break;
901 }
902 }
|
903 mike 1.17 }
904
|
905 mike 1.20 //
906 // Close both files:
907
908 fs.close();
|
909 mateus.baur 1.54
910 FileSystem::syncWithDirectoryUpdates(tmpFs);
|
911 mike 1.20 tmpFs.close();
912
913 //
914 // If an error occurred, remove the temporary file and
915 // return false.
916 //
|
917 mike 1.18
918 if (error)
919 {
|
920 kumpf 1.50 FileSystem::removeFileNoCase(tmpPath);
|
921 kumpf 1.22 PEG_METHOD_EXIT();
|
922 kumpf 1.50 return false;
|
923 mike 1.20 }
924
925 //
926 // Replace index file with temporary file:
927 //
928
|
929 kumpf 1.22 if (!FileSystem::removeFileNoCase(path))
930 {
931 PEG_METHOD_EXIT();
|
932 kumpf 1.50 return false;
|
933 kumpf 1.22 }
|
934 mike 1.20
935 if (!FileSystem::renameFile(tmpPath, path))
|
936 kumpf 1.22 {
937 PEG_METHOD_EXIT();
|
938 kumpf 1.50 return false;
|
939 kumpf 1.22 }
|
940 mike 1.20
|
941 kumpf 1.22 PEG_METHOD_EXIT();
|
942 mike 1.20 return true;
943 }
944
945 Boolean InstanceIndexFile::hasNonFreeEntries(const String& path)
946 {
947 //
948 // If file does not exist, there are no instances:
949 //
950
951 if (!FileSystem::existsNoCase(path))
|
952 kumpf 1.50 return false;
|
953 mike 1.20
954 //
955 // We must iterate all the entries looking for a non-free one:
956 //
957
958 Array<Uint32> freeFlags;
959 Array<Uint32> indices;
960 Array<Uint32> sizes;
|
961 kumpf 1.24 Array<CIMObjectPath> instanceNames;
|
962 mike 1.20
963 if (!InstanceIndexFile::enumerateEntries(
|
964 kumpf 1.50 path, freeFlags, indices, sizes, instanceNames, false))
|
965 mike 1.20 {
|
966 kumpf 1.50 // This won't happen!
967 return false;
|
968 mike 1.18 }
969
|
970 mike 1.20 return freeFlags.size() != 0;
971 }
972
973 Boolean InstanceIndexFile::beginTransaction(const String& path)
974 {
|
975 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::beginTransaction()");
976
|
977 chuck 1.45 String rollbackPath = path;
978 rollbackPath.append(".rollback");
979
980 //
981 // If the index file does not exist, then create a rollback file with
982 // freecount of 0.
983 //
984 if (!FileSystem::existsNoCase(path))
985 {
986 // Make sure the rollback file does not exist.
987 if (FileSystem::existsNoCase(rollbackPath))
988 {
989 if (!FileSystem::removeFileNoCase(rollbackPath))
990 {
991 PEG_METHOD_EXIT();
992 return false;
993 }
994 }
995
|
996 kumpf 1.50 // Create the rollback file, and write the freecount of 0.
|
997 chuck 1.45 fstream fs;
998 if (!_openFile(rollbackPath, fs, true))
999 {
1000 // Make sure no rollback file is left over.
1001 FileSystem::removeFileNoCase(rollbackPath);
1002
1003 PEG_METHOD_EXIT();
|
1004 kumpf 1.50 return false;
|
1005 chuck 1.45 }
1006 fs.close();
1007
1008 PEG_METHOD_EXIT();
1009 return true;
1010 }
1011
|
1012 mike 1.20 //
1013 // Create a rollback file which is a copy of the index file. The
1014 // new filename is formed by appending ".rollback" to the name of
|
1015 kumpf 1.49 // the index file. The rollback file, if it exists, is considered
1016 // the "master" copy of the data. To ensure its completeness, the
1017 // index file is renamed to the rollback file and the data is then
1018 // copied back to the index file.
|
1019 mike 1.20 //
|
1020 kumpf 1.49
1021 if (!FileSystem::renameFileNoCase(path, rollbackPath))
1022 {
1023 PEG_METHOD_EXIT();
|
1024 kumpf 1.50 return false;
|
1025 kumpf 1.49 }
1026
1027 if (!FileSystem::copyFile(rollbackPath, path))
|
1028 kumpf 1.22 {
|
1029 kumpf 1.49 // Try to restore the initial state
1030 FileSystem::removeFileNoCase(path);
1031 FileSystem::renameFileNoCase(rollbackPath, path);
|
1032 chuck 1.45
|
1033 kumpf 1.22 PEG_METHOD_EXIT();
|
1034 kumpf 1.50 return false;
|
1035 kumpf 1.22 }
|
1036 mike 1.20
|
1037 kumpf 1.22 PEG_METHOD_EXIT();
|
1038 mike 1.20 return true;
1039 }
1040
1041 Boolean InstanceIndexFile::rollbackTransaction(const String& path)
1042 {
|
1043 kumpf 1.50 PEG_METHOD_ENTER(TRC_REPOSITORY,
1044 "InstanceIndexFile::rollbackTransaction()");
|
1045 kumpf 1.22
|
1046 mike 1.20 //
1047 // If the rollback file does not exist, then everything is fine (nothing
1048 // to roll back).
1049 //
1050
|
1051 kumpf 1.23 if (!FileSystem::existsNoCase(path + ".rollback"))
|
1052 kumpf 1.22 {
1053 PEG_METHOD_EXIT();
|
1054 kumpf 1.50 return true;
|
1055 kumpf 1.22 }
|
1056 mike 1.20
1057 //
1058 // To roll back, simply delete the index file and rename
1059 // the rollback file over it.
1060 //
1061
|
1062 kumpf 1.25 if (FileSystem::existsNoCase(path))
|
1063 kumpf 1.22 {
|
1064 kumpf 1.25 if (!FileSystem::removeFileNoCase(path))
1065 {
1066 PEG_METHOD_EXIT();
|
1067 kumpf 1.50 return false;
|
1068 kumpf 1.25 }
|
1069 kumpf 1.22 }
|
1070 mike 1.20
|
1071 kumpf 1.22 PEG_METHOD_EXIT();
|
1072 kumpf 1.23 return FileSystem::renameFileNoCase(path + ".rollback", path);
|
1073 mike 1.20 }
1074
1075 Boolean InstanceIndexFile::commitTransaction(const String& path)
1076 {
|
1077 kumpf 1.22 PEG_METHOD_ENTER(TRC_REPOSITORY, "InstanceIndexFile::commitTransaction()");
1078
|
1079 mike 1.20 //
1080 // To commit, simply remove the rollback file:
1081 //
1082
1083 String rollbackPath = path;
|
1084 kumpf 1.29 rollbackPath.append(".rollback");
|
1085 mike 1.20
|
1086 kumpf 1.22 PEG_METHOD_EXIT();
|
1087 mike 1.20 return FileSystem::removeFileNoCase(rollbackPath);
|
1088 mike 1.17 }
1089
1090 PEGASUS_NAMESPACE_END
|