1 mike 1.2 //%/////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001 BMC Software, Hewlett-Packard Company, IBM,
4 // The Open Group, Tivoli Systems
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
14 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
15 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
16 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 mike 1.2 //==============================================================================
23 //
24 // Author: Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
25 //
26 // Modified By:
27 //
28 //%/////////////////////////////////////////////////////////////////////////////
29
30 #include <Pegasus/Common/Config.h>
31 #include <fstream>
32 #include <Pegasus/Common/Destroyer.h>
33 #include <Pegasus/Common/FileSystem.h>
34 #include <Pegasus/Common/XmlWriter.h>
35 #include "InstanceFile.h"
36
37 // Note: If the INDENT_XML_FILES option is set, the XmlWriter is called
38 // to parse the xml data to add indentations before saving the
39 // instance data to the instance file. It somewhat impacts the
40 // performance of a create or modify instance operation. In the
41 // future, this option should be made a configurable property to
42 // allow enabling and disabling without re-compilation.
43 mike 1.2
44 #define INDENT_XML_FILES
45
46 PEGASUS_USING_STD;
47
48 PEGASUS_NAMESPACE_BEGIN
49
50 /**
51 Loads an instance record in the instance file to memory.
52 */
53 Boolean InstanceFile::loadInstance(
54 const String& path,
55 Uint32 index,
56 Uint32 size,
57 Array<Sint8>& data)
58 {
59 //
60 // check for the existence of the instance file, and get the real path
61 // of the file
62 //
63 String realPath;
64 mike 1.2
65 if (!FileSystem::existsNoCase(path, realPath))
66 {
67 return false;
68 }
69
70 //
71 // load data from file
72 //
73 if (!_loadData(realPath, index, size, data))
74 {
75 return false;
76 }
77
78 return true;
79 }
80
81 /**
82 Loads all the instance records in the instance file to memory.
83 */
84 Boolean InstanceFile::loadAllInstances(
85 mike 1.2 const String& path,
86 Array<Sint8>& data)
87 {
88 //
89 // check for the existence of the instance file, and get the real path
90 // of the file
91 //
92 String realPath;
93
94 if (!FileSystem::existsNoCase(path, realPath))
95 {
96 return false;
97 }
98
99 //
100 // get the size of the instance file
101 //
102 Uint32 fileSize;
103 if (!FileSystem::getFileSizeNoCase(realPath, fileSize))
104 {
105 return false;
106 mike 1.2 }
107
108 //
109 // load all the instance data stored in the instance file
110 //
111 if (!_loadData(realPath, 0, fileSize, data))
112 {
113 return false;
114 }
115
116 return true;
117 }
118
119 /**
120 Inserts a new record into the instance file. Sets the byte position
121 and the size of the newly added instance record. Returns true on
122 success.
123
124 This method creates a temporary file, copies the contents of the original
125 instance file to the temporary file, and appends the new entry to the
126 temporary file. The caller must rename the temporary file back to the
127 mike 1.2 original file after the insert operation is successful on BOTH the
128 instance index file and the instance file.
129 */
130 Boolean InstanceFile::insertInstance(
131 Array<Sint8> out,
132 const String& path,
133 Uint32& index,
134 Uint32& size)
135 {
136 //
137 // Create a temporary instance file
138 //
139 // First make sure that there is not already a temporary file.
140 // If a temporary file already exists, remove it first.
141 //
142 String tempFilePath;
143 if (FileSystem::existsNoCase(path + ".tmp", tempFilePath))
144 {
145 if (!FileSystem::removeFileNoCase(tempFilePath))
146 {
147 return false;
148 mike 1.2 }
149 }
150
151 ArrayDestroyer<char> p(path.allocateCString(4));
152 strcat(p.getPointer(), ".tmp");
153 ofstream os(p.getPointer(), ios::app | ios::binary);
154
155 if (!os)
156 {
157 return false;
158 }
159
160 //
161 // Check for the existence of the instance file. If file exists, copy
162 // the contents of the file to the temporary file.
163 //
164 String realPath;
165 if (FileSystem::existsNoCase(path, realPath))
166 {
167 ArrayDestroyer<char> p(realPath.allocateCString());
168 ifstream is(p.getPointer(), ios::binary);
169 mike 1.2
170 if (!is)
171 {
172 return false;
173 }
174
175 //
176 // get the size of the instance file
177 //
178 Uint32 fileSize;
179 if (!FileSystem::getFileSizeNoCase(realPath, fileSize))
180 {
181 return false;
182 }
183
184 char* buffer = new char[fileSize];
185 is.clear();
186 is.seekg(0);
187 is.read(buffer, fileSize);
188
189 if (is.fail())
190 mike 1.2 return false;
191
192 os.write(buffer, fileSize);
193
194 delete [] buffer;
195
196 is.close();
197 }
198
199 //
200 // append the new instance to the end of the file
201 //
202 if (!_insertData(out, os, index, size))
203 {
204 return false;
205 }
206
207 os.close();
208
209 return true;
210 }
211 mike 1.2
212 /**
213 Removes an instance record from the instance file.
214
215 This method creates a temporary file, then calls removeData() to remove
216 the entry from the temporary file. The caller must rename the temporary
217 file back to the original file after the remove operation is successful
218 on BOTH the instance index file and the instance file.
219 */
220 Boolean InstanceFile::removeInstance(
221 const String& path,
222 Uint32 size,
223 Uint32 index)
224 {
225 //
226 // check for the existence of the instance file, and get the real path
227 // of the file
228 //
229 String realPath;
230
231 if (!FileSystem::existsNoCase(path, realPath))
232 mike 1.2 {
233 return false;
234 }
235
236 //
237 // Create a temporary instance index file
238 //
239 // First make sure that there is not already a temporary file.
240 // If a temporary file already exists, remove it first.
241 //
242 String tempFilePath;
243 if (FileSystem::existsNoCase(realPath + ".tmp", tempFilePath))
244 {
245 if (!FileSystem::removeFileNoCase(tempFilePath))
246 {
247 return false;
248 }
249 }
250
251 ArrayDestroyer<char> p(realPath.allocateCString(4));
252 strcat(p.getPointer(), ".tmp");
253 mike 1.2 ofstream os(p.getPointer(), ios::app | ios::binary);
254
255 if (!os)
256 {
257 return false;
258 }
259
260 //
261 // remove the entry from file
262 //
263 if (!_removeData(realPath, os, size, index))
264 {
265 return false;
266 }
267
268 os.close();
269
270 return true;
271 }
272
273 /**
274 mike 1.2 Modifies an instance record in the instance file by first removing the
275 the old instance record in the instance file, then appends the new
276 instance record to the instance file. Returns the byte position and the
277 size of the newly added instance record.
278
279 This method creates a temporary file. All updates are done to the
280 temporary file. The caller must rename the temporary file back to the
281 the original file after the modify operation is successful on BOTH the
282 instance index file and the instance file.
283 */
284 Boolean InstanceFile::modifyInstance(
285 Array<Sint8> out,
286 const String& path,
287 Uint32 oldIndex,
288 Uint32 oldSize,
289 Uint32& newIndex,
290 Uint32& newSize)
291 {
292 //
293 // check for the existence of the instance file, and get the real path
294 // of the file
295 mike 1.2 //
296 String realPath;
297
298 if (!FileSystem::existsNoCase(path, realPath))
299 {
300 return false;
301 }
302
303 //
304 // Open a temporary instance file
305 //
306 // First make sure that there is not already a temporary file.
307 // If a temporary file already exists, remove it first.
308 //
309 String tempFilePath;
310 if (FileSystem::existsNoCase(realPath + ".tmp", tempFilePath))
311 {
312 if (!FileSystem::removeFileNoCase(tempFilePath))
313 {
314 return false;
315 }
316 mike 1.2 }
317
318 ArrayDestroyer<char> p(realPath.allocateCString(4));
319 strcat(p.getPointer(), ".tmp");
320 ofstream os(p.getPointer(), ios::app | ios::binary);
321
322 if (!os)
323 {
324 return false;
325 }
326
327 //
328 // remove the old entry from the temporary file
329 //
330 if (!_removeData(realPath, os, oldSize, oldIndex))
331 {
332 return false;
333 }
334
335 //
336 // Append the new instance to the instance file
337 mike 1.2 //
338 if (!_insertData(out, os, newIndex, newSize))
339 {
340 return false;
341 }
342
343 os.close();
344
345 return true;
346 }
347
348 /**
349 Loads data from the instance file at the given byte positon for the
350 given size.
351 */
352 Boolean InstanceFile::_loadData(
353 const String& path,
354 Uint32 index,
355 Uint32 size,
356 Array<Sint8>& data)
357 {
358 mike 1.2 //
359 // open the instance file
360 //
361 ArrayDestroyer<char> p(path.allocateCString());
362 ifstream is(p.getPointer(), ios::in | ios::binary);
363
364 if (!is)
365 {
366 return false;
367 }
368
369 //
370 // position the file get pointer at the specified location
371 //
372 is.clear();
373 is.seekg(index);
374
375 //
376 // Load data from file into memory
377 //
378 char* buffer = new char[size];
379 mike 1.2 is.read( buffer, size);
380
381 if (is.fail())
382 return false;
383
384 data.clear();
385 data.reserve(size+1);
386 data.append(buffer, size);
387 data.append('\0');
388
389 is.close();
390
391 delete [] buffer;
392
393 return true;
394 }
395
396 /**
397 Removes a record in the instance file at the given byte position for
398 the given size.
399 */
400 mike 1.2 Boolean InstanceFile::_removeData(
401 const String& realPath,
402 ofstream& os,
403 Uint32 size,
404 Uint32 index)
405 {
406 //
407 // Open the instance file
408 //
409 ArrayDestroyer<char> q(realPath.allocateCString());
410 ifstream is(q.getPointer(), ios::in | ios::binary);
411
412 if (!is)
413 {
414 return false;
415 }
416
417 //
418 // get the size of the instance file
419 //
420 Uint32 fileSize;
421 mike 1.2 if (!FileSystem::getFileSizeNoCase(realPath, fileSize))
422 {
423 return false;
424 }
425
426 //
427 // Copy all the entries in the instance file up to the one to be deleted
428 //
429 Array<Sint8> data;
430 Uint32 copySize;
431 Uint32 sizeNeeded;
432
433 //
434 // determine the number of bytes to copy
435 //
436 sizeNeeded = fileSize - size;
437
438 //
439 // if the entry to be deleted is not the only entry in the instance file,
440 // copy the remaining entries
441 //
442 mike 1.2 if (sizeNeeded > 0)
443 {
444 char* buffer = new char[sizeNeeded];
445
446 data.clear();
447 data.reserve(sizeNeeded);
448
449 is.clear();
450
451 //
452 // copy from the beginning of the file if the entry to be deleted
453 // is not the first entry in the file
454 //
455 if (index != 0)
456 {
457 is.seekg(0);
458 is.read( buffer, index );
459
460 if (is.fail())
461 return false;
462
463 mike 1.2 data.append(buffer, index);
464 }
465
466 //
467 // skip the entry to be deleted and copy the remaining entries
468 //
469 Uint32 placeToCopy = index + size;
470
471 is.seekg(placeToCopy);
472 copySize = (fileSize - placeToCopy) - 1;
473
474 is.read( buffer, copySize );
475
476 if (is.fail())
477 return false;
478
479 data.append(buffer, copySize);
480 data.append('\0');
481
482 delete [] buffer;
483
484 mike 1.2 //
485 // write data to the temporary file
486 //
487 os << (char*)data.getData() << endl;
488
489 os.flush();
490 }
491
492 is.close();
493
494 return true;
495 }
496
497 /**
498 Inserts a new record into the instance file.
499
500 */
501 Boolean InstanceFile::_insertData(
502 Array<Sint8> out,
503 ofstream& os,
504 Uint32& index,
505 mike 1.2 Uint32& size)
506 {
507 Uint32 begPos; // file position before insertion
508 Uint32 endPos; // file position after insertion
509
510 //
511 // determine current position of file
512 //
513 begPos = os.tellp();
514 index = begPos;
515
516 //
517 // write the CIM/XML encoding of the instance to file
518 //
519 #ifdef INDENT_XML_FILES
520 out.append('\0');
521 XmlWriter::indentedPrint(os, out.getData(), 2);
522 #else
523 os.write((char*)out.getData(), out.size());
524 #endif
525
526 mike 1.2 //
527 // determine the size of the instance record written to file
528 //
529 endPos = os.tellp();
530 size = endPos - begPos;
531
532 os.flush();
533
534 return true;
535 }
536
537 PEGASUS_NAMESPACE_END
|