|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU Lesser General Public License as published by |
|
7 * the Free Software Foundation, either version 3 of the License, or |
|
8 * (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU Lesser General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU Lesser General Public License |
|
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 */ |
|
18 |
|
19 #include <sys/types.h> |
|
20 #include <sys/stat.h> |
|
21 #include <fcntl.h> |
|
22 #include <cstdio> |
|
23 #include <cstdlib> |
|
24 #include <unistd.h> |
|
25 #include <cassert> |
|
26 |
|
27 #include "outputfile.h" |
|
28 |
|
29 static const size_t NumReservedFileFragments = 100; |
|
30 |
|
31 OutputFile::OutputFile(PathName aFileName) : |
|
32 iFileName(aFileName), iOpened(false), iFd(-1), iCurrentOffset(0) |
|
33 { |
|
34 assert(iFileName.size() != 0); |
|
35 // reserve space for file fragments |
|
36 iFileFragments.reserve(NumReservedFileFragments); |
|
37 } |
|
38 |
|
39 OutputFile::~OutputFile(){ |
|
40 iFileFragments.clear(); |
|
41 if (iOpened) |
|
42 Close(); |
|
43 } |
|
44 |
|
45 |
|
46 void OutputFile::Close(){ |
|
47 if (iOpened) { |
|
48 close(iFd); |
|
49 iOpened = false; |
|
50 } |
|
51 } |
|
52 |
|
53 void OutputFile::Flush(){ |
|
54 if (!iOpened) |
|
55 Open(); |
|
56 if (iFileFragments.size() > 0) { |
|
57 FragmentList::iterator aFrag = iFileFragments.begin(); |
|
58 FragmentList::iterator end = iFileFragments.end(); |
|
59 while (aFrag != end) { |
|
60 aFrag->Write(this); |
|
61 aFrag++; |
|
62 } |
|
63 iFileFragments.clear(); |
|
64 } |
|
65 } |
|
66 |
|
67 void OutputFile::Dump(){ |
|
68 Flush(); |
|
69 Close(); |
|
70 } |
|
71 |
|
72 const FileFragment & OutputFile::GetFileFragment(FileFragmentOwner * aOwner){ |
|
73 size_t aSize = aOwner->Size(); |
|
74 FileFragment aFragment(iCurrentOffset, aSize, aOwner); |
|
75 iFileFragments.push_back(aFragment); |
|
76 iCurrentOffset += ALIGN4(aSize); |
|
77 return iFileFragments.back(); |
|
78 } |
|
79 |
|
80 void OutputFile::Open(){ |
|
81 if (!iOpened) { |
|
82 if ((iFd = open(iFileName.c_str(), O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) { |
|
83 char msg[1000]; |
|
84 sprintf(msg, "Output file %s", iFileName.c_str()); |
|
85 perror(msg); |
|
86 exit(EXIT_FAILURE); |
|
87 } |
|
88 iOpened = true; |
|
89 } |
|
90 } |
|
91 |
|
92 void OutputFile::Write(size_t aOffset, size_t aSize, char * aData){ |
|
93 assert(((aSize==0) && (aData==NULL)) || ((aSize>0) && (aData!=NULL))); |
|
94 if (aSize == 0) return; |
|
95 char msg[1000]; |
|
96 #ifndef USE_PWRITE |
|
97 if (lseek(iFd, aOffset, SEEK_SET) != (int)aOffset) { |
|
98 sprintf(msg, "Failed to seek to offset %d in output file %s", aOffset, iFileName.c_str()); |
|
99 goto error; |
|
100 } |
|
101 for (size_t n = 0; n < aSize;) { |
|
102 if ((int)(n += write(iFd, aData+n, aSize - n)) == -1) { |
|
103 sprintf(msg, "Failed to write to output file %s", iFileName.c_str()); |
|
104 goto error; |
|
105 } |
|
106 } |
|
107 #else |
|
108 for (size_t n = 0; n < aSize;) { |
|
109 if ((n += pwrite(iFd, aData+n, aSize - n, aOffset + n)) == -1) { |
|
110 sprintf(msg, "Failed to write to output file %s", iFileName.c_str()); |
|
111 goto error; |
|
112 } |
|
113 } |
|
114 #endif |
|
115 return; |
|
116 |
|
117 error: |
|
118 perror(msg); |
|
119 // should we close the file and delete it?? |
|
120 #ifdef DELETE_OUTPUT_ON_ERROR |
|
121 Close(); |
|
122 unlink(iFileName); |
|
123 #endif |
|
124 exit(EXIT_FAILURE); |
|
125 } |