2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * @author Tomasz Iwanek (t.iwanek@samsung.com)
22 #include "dpl/utils/path.h"
23 #include <dpl/utils/wrt_utility.h>
24 #include <dpl/scoped_free.h>
25 #include <dpl/errno_string.h>
26 #include <dpl/file_input.h>
27 #include <dpl/file_output.h>
29 #include <dpl/log/log.h>
30 #include <dpl/foreach.h>
31 #include <dpl/wrt-dao-ro/global_config.h>
42 const char * const TEMPORARY_PATH_POSTFIX = "temp";
43 const mode_t TEMPORARY_PATH_MODE = 0775;
46 Path::Iterator::Iterator() //end iterator by default
50 Path::Iterator::Iterator(const char * str)
52 m_root = std::shared_ptr<Path>(new Path(str));
53 m_dir = std::shared_ptr<DIR>(opendir(str), [](DIR * d){ if(d)closedir(d); }); //custom delete
54 if(m_dir.get() == NULL)
56 ThrowMsg(NotDirectory, "Not directory");
61 Path::Iterator& Path::Iterator::operator++()
67 Path::Iterator Path::Iterator::operator++(int)
69 Path::Iterator copy(*this);
74 void Path::Iterator::ReadNext()
76 struct dirent * entry = readdir(m_dir.get());
77 while(entry && (strcmp(entry->d_name, ".") == 0 ||
78 strcmp(entry->d_name, "..") == 0))
80 entry = readdir(m_dir.get());
84 m_path = std::shared_ptr<Path>(new Path(*m_root));
85 m_path->Append(entry->d_name);
87 else //transform into end iterator
94 bool Path::Iterator::operator==(const Path::Iterator& rhs) const
96 if(m_dir.get() == NULL)
98 if(rhs.m_dir.get() == NULL) return true;
103 if(rhs.m_dir.get() == NULL) return false;
105 return *m_path == *rhs.m_path;
108 bool Path::Iterator::operator!=(const Path::Iterator& rhs) const
110 return !this->operator==(rhs);
113 const Path & Path::Iterator::operator*()
118 const Path * Path::Iterator::operator->()
123 Path::Path(const DPL::String & str)
125 Construct(ToUTF8String(str));
128 Path::Path(const std::string & str)
133 Path::Path(const char * str)
135 Construct(std::string(str));
138 void Path::Construct(const std::string & src)
140 if(src.empty()) ThrowMsg(EmptyPath, "Path cannot be empty");
143 DPL::ScopedFree<char> root(getcwd(NULL,0));
144 Tokenize(std::string(root.Get()), "\\/", std::inserter(m_parts, m_parts.begin()), true);
146 Tokenize(src, "\\/", std::inserter(m_parts, m_parts.end()), true);
153 std::string Path::DirectoryName() const
155 if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryName for root directory");
156 std::string ret = Join(m_parts.begin(), --m_parts.end(), "/");
157 return std::string("/") + ret;
160 std::string Path::Filename() const
162 if(m_parts.empty()) return "";
163 else return m_parts.back();
166 std::string Path::Fullpath() const
168 std::string ret = Join(m_parts.begin(), m_parts.end(), "/");
169 return std::string ("/") + ret;
172 std::string Path::Extension() const
174 if(m_parts.empty()) return "";
176 const std::string& last = *--m_parts.end();
178 std::string::size_type pos = last.find_last_of(".");
179 if(pos != std::string::npos)
181 return last.substr(pos + 1);
190 Path::Iterator Path::begin() const
194 return Iterator(Fullpath().c_str());
198 ThrowMsg(NotDirectory, "Cannot iterate not a directory");
202 Path::Iterator Path::end() const
207 void Path::RootGuard() const
209 if(m_parts.empty()) Throw(RootDirectoryError);
212 bool Path::Exists() const
215 memset(&tmp, 0, sizeof(struct stat));
216 return (0 == lstat(Fullpath().c_str(), &tmp));
219 bool Path::IsDir() const
222 memset(&tmp, 0, sizeof(struct stat));
223 if (-1 == lstat(Fullpath().c_str(), &tmp))
225 ThrowMsg(NotExists, DPL::GetErrnoString());
227 return S_ISDIR(tmp.st_mode);
230 bool Path::IsFile() const
233 memset(&tmp, 0, sizeof(struct stat));
234 if (-1 == lstat(Fullpath().c_str(), &tmp))
236 ThrowMsg(NotExists, DPL::GetErrnoString());
238 return S_ISREG(tmp.st_mode);
241 bool Path::ExistsAndIsFile() const
246 flag = this->IsFile();
247 } Catch (Path::NotExists) {
248 LogPedantic(*this << "is not a file.");
253 bool Path::ExistsAndIsDir() const
258 flag = this->IsDir();
259 } Catch (Path::NotExists) {
260 LogPedantic(*this << "is not a directory.");
265 bool Path::IsSymlink() const
268 memset(&tmp, 0, sizeof(struct stat));
269 if (-1 == lstat(Fullpath().c_str(), &tmp))
271 ThrowMsg(NotExists, DPL::GetErrnoString());
273 return S_ISLNK(tmp.st_mode);
276 bool Path::operator==(const Path & other) const
278 return m_parts == other.m_parts;
281 bool Path::operator!=(const Path & other) const
283 return m_parts != other.m_parts;
286 Path Path::operator/(const DPL::String& part) const
289 newOne.Append(ToUTF8String(part));
293 Path Path::operator/(const std::string& part) const
300 Path Path::operator/(const char * part) const
303 newOne.Append(std::string(part));
307 Path & Path::operator/=(const DPL::String& part)
309 Append(ToUTF8String(part));
313 Path & Path::operator/=(const std::string& part)
319 Path & Path::operator/=(const char * part)
321 Append(std::string(part));
325 void Path::Append(const std::string& part)
327 std::vector<std::string> tokens;
328 Tokenize(part, "\\/", std::inserter(tokens, tokens.end()), true);
329 std::copy(tokens.begin(), tokens.end(), std::inserter(m_parts, m_parts.end()));
332 Path Path::DirectoryPath() const
335 if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryPath for root directory");
336 std::copy(m_parts.begin(), --m_parts.end(), std::back_inserter(npath.m_parts));
340 std::size_t Path::Size() const
343 memset(&tmp, 0, sizeof(struct stat));
344 if (-1 == lstat(Fullpath().c_str(), &tmp))
346 ThrowMsg(NotExists, DPL::GetErrnoString());
351 bool Path::isSubPath(const Path & other) const
353 typedef std::vector<std::string>::const_iterator Iter;
354 Iter otherIter = other.m_parts.begin();
355 for(Iter iter = m_parts.begin(); iter != m_parts.end(); iter++)
357 if(otherIter == other.m_parts.end()) return false;
358 if(*iter != *otherIter) return false;
364 bool Path::hasExtension(const std::string& extension) const
366 LogPedantic("Looking for extension " << extension);
368 if(Extension() == extension)
378 void MakeDir(const Path & path, mode_t mode)
381 if(!WrtUtilMakeDir(path.Fullpath(), mode))
382 ThrowMsg(Path::OperationFailed, "Cannot make directory");
385 void MakeEmptyFile(const Path & path)
389 ret = mknod(path.Fullpath().c_str(), S_IFREG, 0);
394 ThrowMsg(Path::AlreadyExists, "File already exists: " << path);
398 ThrowMsg(Path::OperationFailed, "Operation failed");
403 void Remove(const Path & path)
406 if(!WrtUtilRemove(path.Fullpath())) ThrowMsg(Path::OperationFailed, "Cannot remove path");
409 bool TryRemove(const Path & path)
412 return WrtUtilRemove(path.Fullpath());
415 void Rename(const Path & from, const Path & to)
423 if(0 != rename(from.Fullpath().c_str(), to.Fullpath().c_str()))
432 else if(from.IsFile() || from.IsSymlink())
439 ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
444 ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
449 void CopyFile(const Path & from, const Path & to)
455 DPL::FileInput input(from.Fullpath());
456 DPL::FileOutput output(to.Fullpath());
457 DPL::Copy(&input, &output);
459 Catch(DPL::FileInput::Exception::Base)
461 LogError("File input error");
462 ReThrowMsg(DPL::CopyFailed, std::string("File input error") + from.Fullpath());
464 Catch(DPL::FileOutput::Exception::Base)
466 LogError("File output error");
467 ReThrowMsg(DPL::CopyFailed, std::string("File output error") + to.Fullpath());
469 Catch(DPL::CopyFailed)
471 LogError("File copy error");
472 ReThrowMsg(DPL::CopyFailed, std::string("File copy error") + from.Fullpath());
476 void CopyDir(const Path & from, const Path & to)
480 if(from.isSubPath(to))
482 ThrowMsg(Path::CannotCopy, "Cannot copy content of directory to it's sub directory");
489 CopyDir(*item, to / item->Filename());
491 else if(item->IsFile() || item->IsSymlink())
493 CopyFile(*item, to / item->Filename());
497 Throw(Path::OperationFailed);
502 Path CreateTempPath(const Path & basePath)
504 LogDebug("Step: Creating temporary path");
507 Path tempPath = basePath;
508 tempPath /= WrtDB::GlobalConfig::GetTmpDirPath();
511 gettimeofday(&tv, NULL);
512 unsigned long long nr = (static_cast<unsigned long long>(tv.tv_sec) * 1000000ULL + static_cast<unsigned long long>(tv.tv_usec));
513 std::stringstream relPath;
514 relPath << TEMPORARY_PATH_POSTFIX << "_" << nr;
515 tempPath /= relPath.str();
517 MakeDir(tempPath, TEMPORARY_PATH_MODE);
521 bool Exists(const Path & path)
523 return path.Exists();
530 std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path)
532 str << path.Fullpath();
536 //TODO: uncomment when used defiend literals are supported
537 ///DPL::Utils::Path operator""p(const char * str, size_t)
539 // return DPL::Utils::Path(str);