root/trunk/whisperlib/common/io/file/file.cc

Revision 7, 6.9 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Cosmin Tudorache
31
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include "common/base/log.h"
36 #include "common/base/common.h"
37 #include "common/base/errno.h"
38
39 #include "common/io/file/file.h"
40 #include "common/io/file/fd.h"
41
42 namespace io {
43
44 const char* File::AccessName(Access access) {
45   switch ( access ) {
46     CONSIDER(GENERIC_READ);
47     CONSIDER(GENERIC_WRITE);
48     CONSIDER(GENERIC_READ_WRITE);
49   }
50   return "UnknownAccess";
51 }
52
53 const char* File::CreationDispositionName(CreationDisposition cd) {
54   switch ( cd ) {
55     CONSIDER(CREATE_ALWAYS);
56     CONSIDER(CREATE_NEW);
57     CONSIDER(OPEN_ALWAYS);
58     CONSIDER(OPEN_EXISTING);
59     CONSIDER(TRUNCATE_EXISTING);
60   }
61   return "UnknownCreationDisposition";
62 }
63
64 const char* File::MoveMethodName(MoveMethod mm) {
65   switch ( mm ) {
66     CONSIDER(FILE_SET);
67     CONSIDER(FILE_CUR);
68     CONSIDER(FILE_END);
69   }
70   return "UnknownMoveMethod";
71 }
72
73 File::File()
74   : filename_(""),
75     fd_(INVALID_FD_VALUE),
76     size_(-1),
77     position_(-1) {
78 }
79
80 File::~File() {
81   if ( is_open() )
82     Close();
83 }
84
85 File* File::OpenFileOrDie(const char* filename) {
86   File* const f = new File();
87   CHECK(f->Open(filename, GENERIC_READ, OPEN_EXISTING));
88   return f;
89 }
90
91 File* File::TryOpenFile(const char* filename) {
92   File* const f = new File();
93   if ( !f->Open(filename, GENERIC_READ, OPEN_EXISTING) ) {
94     delete f;
95     return NULL;
96   }
97   return f;
98 }
99
100 File* File::CreateFileOrDie(const char* filename) {
101   File* const f = new File();
102   CHECK(f->Open(filename, GENERIC_READ_WRITE, CREATE_ALWAYS));
103   return f;
104 }
105 File* File::TryCreateFile(const char* filename) {
106   File* const f = new File();
107   if ( !f->Open(filename, GENERIC_READ_WRITE, CREATE_ALWAYS) ) {
108     delete f;
109     return NULL;
110   }
111   return f;
112 }
113
114
115 bool File::Open(const char* filename,  Access access, CreationDisposition cd) {
116   CHECK(!is_open());
117
118   int flags = O_NOCTTY | O_LARGEFILE;
119   switch ( cd ) {
120   case CREATE_ALWAYS:     flags |= O_CREAT | O_TRUNC; break;
121   case CREATE_NEW:        flags |= O_CREAT | O_EXCL; break;
122   case OPEN_ALWAYS:       flags |= O_CREAT; break;
123   case OPEN_EXISTING:     flags |= 0; break;
124   case TRUNCATE_EXISTING: flags |= O_TRUNC; break;
125   default:
126     LOG_FATAL << filename << " - Invalid Disposition: " << cd;
127   };
128
129   mode_t mode = 0;
130   switch (access)  {
131   case GENERIC_READ:       flags |= O_RDONLY; mode = 00444; break;
132   case GENERIC_WRITE:      flags |= O_WRONLY; mode = 00200; break;
133   case GENERIC_READ_WRITE: flags |= O_RDWR;   mode = 00644; break;
134   default:
135     LOG_FATAL << filename << " Invalid Access: " << access;
136   };
137   flags |= O_LARGEFILE;
138
139   const int fd = ::open(filename, flags, mode);
140   if ( fd == INVALID_FD_VALUE ) {
141     LOG_ERROR << "Cannot open file " << filename
142               << " using access: " << AccessName(access)
143               << " creationDisposition: " << CreationDispositionName(cd)
144               << " reason: " << GetLastSystemErrorDescription();
145     return false;
146   }
147
148   filename_ = filename;
149   fd_ = fd;
150   UpdateSize();
151   UpdatePosition();
152
153   return true;
154 }
155
156 void File::Close() {
157   CHECK(is_open());
158   if ( ::close(fd_) < 0 ) {
159     LOG_ERROR << filename_ << " - Error closing file."
160               << " Reason: " << GetLastSystemErrorDescription();
161   }
162   fd_ = INVALID_FD_VALUE;
163   filename_.clear();
164 }
165
166 int64 File::Size() const {
167   CHECK(is_open());
168   return size_;
169 }
170
171 int64 File::Position() const {
172   CHECK(is_open());
173   return position_;
174 }
175
176 int64 File::SetPosition(int64 distance,
177                         MoveMethod move_method) {
178   CHECK(is_open());
179   int whence = SEEK_SET;
180   switch ( move_method ) {
181   case FILE_SET: whence = SEEK_SET; break;
182   case FILE_CUR: whence = SEEK_CUR; break;
183   case FILE_END: whence = SEEK_END; break;
184   default:
185     LOG_FATAL << filename_ << " Invalid MoveMethod : " << move_method;
186   }
187
188   const int64 crt = ::lseek64(fd_, distance, whence);
189   if ( crt == -1 ) {
190     LOG_ERROR << filename_ << " lseek64 failed "
191               << GetLastSystemErrorDescription();
192     return -1;
193   }
194   // update cached position_
195   position_ = crt;
196   return position_;
197 }
198
199 int32 File::Read(void* buf, int32 len) {
200   CHECK(is_open()) << filename_;
201   FileDescriptor fdesc;
202   CHECK(fdesc.OpenFD(fd()));
203   const int32 cb = fdesc.Read(buf, len);
204   if ( cb < 0 ) {
205     LOG_ERROR << filename_ << " Read Error encountered.";
206     return cb;
207   } else {
208     position_ += cb;
209     CHECK_LE(position_, size_);
210   }
211   return cb;
212 }
213
214 int32 File::Write(const void* buf, int32 len) {
215   CHECK(is_open()) << filename_;
216   FileDescriptor fdesc;
217   CHECK(fdesc.OpenFD(fd()));
218   const int32 cb = fdesc.Write(buf, len);
219   if ( cb < 0 ) {
220     LOG_ERROR << filename_ << " Write Error encountered.";
221     UpdatePosition();  // don't know where the file pointer ended-up
222   }
223   return cb;
224 }
225
226 void File::Flush() {
227   CHECK(is_open()) << filename_;
228   // Well this should not happen - we are screwed otherwise
229   CHECK_NE(::fdatasync(fd()), -1) << filename_ << " Failed on Flush. "
230                                   << GetLastSystemErrorDescription();
231 }
232
233
234 int64 File::UpdateSize() {
235   const int64 crt = ::lseek64(fd_, 0, SEEK_CUR);
236   CHECK_NE(crt, -1) << GetLastSystemErrorDescription();
237   size_ =  ::lseek64(fd_, 0, SEEK_END);
238   CHECK_NE(size_, -1) << GetLastSystemErrorDescription();
239   CHECK_EQ(::lseek64(fd_, crt, SEEK_SET), crt)
240     << GetLastSystemErrorDescription();
241   return size_;
242 }
243
244 int64 File::UpdatePosition() {
245   position_ = ::lseek64(fd_, 0, SEEK_CUR);
246   CHECK_NE(position_, -1) << GetLastSystemErrorDescription();
247   return position_;
248 }
249 }
Note: See TracBrowser for help on using the browser.