"Fossies" - the Fresh Open Source Software Archive 
Member "encfs-1.9.5/encfs/FileNode.cpp" (27 Apr 2018, 7051 Bytes) of package /linux/misc/encfs-1.9.5.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "FileNode.cpp" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.9.4_vs_1.9.5.
1 /*****************************************************************************
2 * Author: Valient Gough <vgough@pobox.com>
3 *
4 *****************************************************************************
5 * Copyright (c) 2003-2004, Valient Gough
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "FileNode.h"
22
23 #include <cerrno>
24 #include <cinttypes>
25 #include <cstring>
26 #include <fcntl.h>
27 #ifdef __linux__
28 #include <sys/fsuid.h>
29 #endif
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 #include "CipherFileIO.h"
35 #include "Error.h"
36 #include "FileIO.h"
37 #include "FileUtils.h"
38 #include "MACFileIO.h"
39 #include "Mutex.h"
40 #include "RawFileIO.h"
41
42 using namespace std;
43
44 namespace encfs {
45
46 /*
47 TODO: locking at the FileNode level is inefficient, since this precludes
48 multiple IO operations from going on concurrently within the same file.
49
50 There is no reason why simultainous reads cannot be satisfied, or why one
51 read has to wait for the decoding of the previous read before it can be
52 sent to the IO subsystem!
53 */
54
55 FileNode::FileNode(DirNode *parent_, const FSConfigPtr &cfg,
56 const char *plaintextName_, const char *cipherName_,
57 uint64_t fuseFh) {
58
59 pthread_mutex_init(&mutex, nullptr);
60
61 Lock _lock(mutex);
62
63 this->canary = CANARY_OK;
64
65 this->_pname = plaintextName_;
66 this->_cname = cipherName_;
67 this->parent = parent_;
68
69 this->fsConfig = cfg;
70
71 this->fuseFh = fuseFh;
72
73 // chain RawFileIO & CipherFileIO
74 std::shared_ptr<FileIO> rawIO(new RawFileIO(_cname));
75 io = std::shared_ptr<FileIO>(new CipherFileIO(rawIO, fsConfig));
76
77 if ((cfg->config->blockMACBytes != 0) ||
78 (cfg->config->blockMACRandBytes != 0)) {
79 io = std::shared_ptr<FileIO>(new MACFileIO(io, fsConfig));
80 }
81 }
82
83 FileNode::~FileNode() {
84 // FileNode mutex should be locked before the destructor is called
85 // pthread_mutex_lock( &mutex );
86
87 canary = CANARY_DESTROYED;
88 _pname.assign(_pname.length(), '\0');
89 _cname.assign(_cname.length(), '\0');
90 io.reset();
91
92 pthread_mutex_destroy(&mutex);
93 }
94
95 const char *FileNode::cipherName() const { return _cname.c_str(); }
96
97 const char *FileNode::plaintextName() const { return _pname.c_str(); }
98
99 string FileNode::plaintextParent() const { return parentDirectory(_pname); }
100
101 static bool setIV(const std::shared_ptr<FileIO> &io, uint64_t iv) {
102 struct stat stbuf;
103 if ((io->getAttr(&stbuf) < 0) || S_ISREG(stbuf.st_mode)) {
104 return io->setIV(iv);
105 }
106 return true;
107 }
108
109 bool FileNode::setName(const char *plaintextName_, const char *cipherName_,
110 uint64_t iv, bool setIVFirst) {
111 // Lock _lock( mutex );
112 if (cipherName_ != nullptr) {
113 VLOG(1) << "calling setIV on " << cipherName_;
114 }
115
116 if (setIVFirst) {
117 if (fsConfig->config->externalIVChaining && !setIV(io, iv)) {
118 return false;
119 }
120
121 // now change the name..
122 if (plaintextName_ != nullptr) {
123 this->_pname = plaintextName_;
124 }
125 if (cipherName_ != nullptr) {
126 this->_cname = cipherName_;
127 io->setFileName(cipherName_);
128 }
129 } else {
130 std::string oldPName = _pname;
131 std::string oldCName = _cname;
132
133 if (plaintextName_ != nullptr) {
134 this->_pname = plaintextName_;
135 }
136 if (cipherName_ != nullptr) {
137 this->_cname = cipherName_;
138 io->setFileName(cipherName_);
139 }
140
141 if (fsConfig->config->externalIVChaining && !setIV(io, iv)) {
142 _pname = oldPName;
143 _cname = oldCName;
144 return false;
145 }
146 }
147
148 return true;
149 }
150
151 int FileNode::mknod(mode_t mode, dev_t rdev, uid_t uid, gid_t gid) {
152 Lock _lock(mutex);
153
154 int res;
155 int olduid = -1;
156 int oldgid = -1;
157 if (gid != 0) {
158 oldgid = setfsgid(gid);
159 if (oldgid == -1) {
160 int eno = errno;
161 RLOG(DEBUG) << "setfsgid error: " << strerror(eno);
162 return -EPERM;
163 }
164 }
165 if (uid != 0) {
166 olduid = setfsuid(uid);
167 if (olduid == -1) {
168 int eno = errno;
169 RLOG(DEBUG) << "setfsuid error: " << strerror(eno);
170 return -EPERM;
171 }
172 }
173
174 /*
175 * cf. xmp_mknod() in fusexmp.c
176 * The regular file stuff could be stripped off if there
177 * were a create method (advised to have)
178 */
179 if (S_ISREG(mode)) {
180 res = ::open(_cname.c_str(), O_CREAT | O_EXCL | O_WRONLY, mode);
181 if (res >= 0) {
182 res = ::close(res);
183 }
184 } else if (S_ISFIFO(mode)) {
185 res = ::mkfifo(_cname.c_str(), mode);
186 } else {
187 res = ::mknod(_cname.c_str(), mode, rdev);
188 }
189
190 if (res == -1) {
191 int eno = errno;
192 VLOG(1) << "mknod error: " << strerror(eno);
193 res = -eno;
194 }
195
196 if (olduid >= 0) {
197 if(setfsuid(olduid) == -1) {
198 int eno = errno;
199 RLOG(DEBUG) << "setfsuid back error: " << strerror(eno);
200 // does not return error here as initial setfsuid worked
201 }
202 }
203 if (oldgid >= 0) {
204 if(setfsgid(oldgid) == -1) {
205 int eno = errno;
206 RLOG(DEBUG) << "setfsgid back error: " << strerror(eno);
207 // does not return error here as initial setfsgid worked
208 }
209 }
210
211 return res;
212 }
213
214 int FileNode::open(int flags) const {
215 Lock _lock(mutex);
216
217 int res = io->open(flags);
218 return res;
219 }
220
221 int FileNode::getAttr(struct stat *stbuf) const {
222 Lock _lock(mutex);
223
224 int res = io->getAttr(stbuf);
225 return res;
226 }
227
228 off_t FileNode::getSize() const {
229 Lock _lock(mutex);
230
231 off_t res = io->getSize();
232 return res;
233 }
234
235 ssize_t FileNode::read(off_t offset, unsigned char *data, size_t size) const {
236 IORequest req;
237 req.offset = offset;
238 req.dataLen = size;
239 req.data = data;
240
241 Lock _lock(mutex);
242
243 return io->read(req);
244 }
245
246 ssize_t FileNode::write(off_t offset, unsigned char *data, size_t size) {
247 VLOG(1) << "FileNode::write offset " << offset << ", data size " << size;
248
249 IORequest req;
250 req.offset = offset;
251 req.dataLen = size;
252 req.data = data;
253
254 Lock _lock(mutex);
255
256 ssize_t res = io->write(req);
257 // Of course due to encryption we genrally write more than requested
258 if (res < 0) {
259 return res;
260 }
261 return size;
262 }
263
264 int FileNode::truncate(off_t size) {
265 Lock _lock(mutex);
266
267 return io->truncate(size);
268 }
269
270 int FileNode::sync(bool datasync) {
271 Lock _lock(mutex);
272
273 int fh = io->open(O_RDONLY);
274 if (fh >= 0) {
275 int res = -EIO;
276 #if defined(HAVE_FDATASYNC)
277 if (datasync) {
278 res = fdatasync(fh);
279 } else {
280 res = fsync(fh);
281 }
282 #else
283 (void)datasync;
284 res = fsync(fh);
285 #endif
286
287 if (res == -1) {
288 res = -errno;
289 }
290
291 return res;
292 }
293 return fh;
294 }
295
296 } // namespace encfs