"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