MongoDB  2.0.3
paths.h
00001 // @file paths.h
00002 // file paths and directory handling
00003 
00004 /*    Copyright 2010 10gen Inc.
00005  *
00006  *    Licensed under the Apache License, Version 2.0 (the "License");
00007  *    you may not use this file except in compliance with the License.
00008  *    You may obtain a copy of the License at
00009  *
00010  *    http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  *    Unless required by applicable law or agreed to in writing, software
00013  *    distributed under the License is distributed on an "AS IS" BASIS,
00014  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  *    See the License for the specific language governing permissions and
00016  *    limitations under the License.
00017  */
00018 
00019 #pragma once
00020 
00021 #include "mongoutils/str.h"
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024 #include <fcntl.h>
00025 
00026 namespace mongo {
00027     
00028     using namespace mongoutils;
00029 
00030     extern string dbpath;
00031 
00035     struct RelativePath {
00036         string _p;
00037 
00038         bool empty() const { return _p.empty(); }
00039 
00040         static RelativePath fromRelativePath(string f) {
00041             RelativePath rp;
00042             rp._p = f;
00043             return rp;
00044         }
00045 
00047         static RelativePath fromFullPath(path f) {
00048             path dbp(dbpath); // normalizes / and backslash
00049             string fullpath = f.string();
00050             string relative = str::after(fullpath, dbp.string());
00051             if( relative.empty() ) {
00052                 log() << "warning file is not under db path? " << fullpath << ' ' << dbp.string() << endl;
00053                 RelativePath rp;
00054                 rp._p = fullpath;
00055                 return rp;
00056             }
00057             /*uassert(13600,
00058                     str::stream() << "file path is not under the db path? " << fullpath << ' ' << dbpath,
00059                     relative != fullpath);*/
00060             if( str::startsWith(relative, "/") || str::startsWith(relative, "\\") ) {
00061                 relative.erase(0, 1);
00062             }
00063             RelativePath rp;
00064             rp._p = relative;
00065             return rp;
00066         }
00067 
00068         string toString() const { return _p; }
00069 
00070         bool operator!=(const RelativePath& r) const { return _p != r._p; }
00071         bool operator==(const RelativePath& r) const { return _p == r._p; }
00072         bool operator<(const RelativePath& r) const { return _p < r._p; }
00073 
00074         string asFullPath() const {
00075             path x(dbpath);
00076             x /= _p;
00077             return x.string();
00078         }
00079 
00080     };
00081 
00082     inline dev_t getPartition(const string& path){
00083         struct stat stats;
00084 
00085         if (stat(path.c_str(), &stats) != 0){
00086             uasserted(13646, str::stream() << "stat() failed for file: " << path << " " << errnoWithDescription());
00087         }
00088 
00089         return stats.st_dev;
00090     }
00091     
00092     inline bool onSamePartition(const string& path1, const string& path2){
00093         dev_t dev1 = getPartition(path1);
00094         dev_t dev2 = getPartition(path2);
00095 
00096         return dev1 == dev2;
00097     }
00098 
00099     inline void flushMyDirectory(const boost::filesystem::path& file){
00100 #ifdef __linux__ // this isn't needed elsewhere
00101         massert(13652, str::stream() << "Couldn't find parent dir for file: " << file.string(), file.has_branch_path());
00102         boost::filesystem::path dir = file.branch_path(); // parent_path in new boosts
00103 
00104         log(1) << "flushing directory " << dir.string() << endl;
00105 
00106         int fd = ::open(dir.string().c_str(), O_RDONLY); // DO NOT THROW OR ASSERT BEFORE CLOSING
00107         massert(13650, str::stream() << "Couldn't open directory '" << dir.string() << "' for flushing: " << errnoWithDescription(), fd >= 0);
00108         if (fsync(fd) != 0){
00109             int e = errno;
00110             close(fd);
00111             massert(13651, str::stream() << "Couldn't fsync directory '" << dir.string() << "': " << errnoWithDescription(e), false);
00112         }
00113         close(fd);
00114 #endif
00115     }
00116 
00117 }