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/errno_string.h>
25 #include <dpl/file_input.h>
26 #include <dpl/file_output.h>
28 #include <dpl/log/wrt_log.h>
29 #include <dpl/foreach.h>
30 #include <dpl/wrt-dao-ro/global_config.h>
35 #include <dpl/free_deleter.h>
43 const char * const TEMPORARY_PATH_POSTFIX = "temp";
44 const mode_t TEMPORARY_PATH_MODE = 0775;
47 Path::Iterator::Iterator() //end iterator by default
51 Path::Iterator::Iterator(const char * str)
53 m_root = std::shared_ptr<Path>(new Path(str));
54 m_dir = std::shared_ptr<DIR>(opendir(str), [](DIR * d){ if(d)closedir(d); }); //custom delete
55 if(m_dir.get() == NULL)
57 ThrowMsg(NotDirectory, "Not directory");
62 Path::Iterator& Path::Iterator::operator++()
68 Path::Iterator Path::Iterator::operator++(int)
70 Path::Iterator copy(*this);
75 void Path::Iterator::ReadNext()
77 struct dirent * entry = readdir(m_dir.get());
78 while(entry && (strcmp(entry->d_name, ".") == 0 ||
79 strcmp(entry->d_name, "..") == 0))
81 entry = readdir(m_dir.get());
85 m_path = std::shared_ptr<Path>(new Path(*m_root));
86 m_path->Append(entry->d_name);
88 else //transform into end iterator
95 bool Path::Iterator::operator==(const Path::Iterator& rhs) const
97 if(m_dir.get() == NULL)
99 if(rhs.m_dir.get() == NULL) return true;
104 if(rhs.m_dir.get() == NULL) return false;
106 return *m_path == *rhs.m_path;
109 bool Path::Iterator::operator!=(const Path::Iterator& rhs) const
111 return !this->operator==(rhs);
114 const Path & Path::Iterator::operator*()
119 const Path * Path::Iterator::operator->()
124 Path::Path(const DPL::String & str)
126 Construct(ToUTF8String(str));
129 Path::Path(const std::string & str)
134 Path::Path(const char * str)
136 Construct(std::string(str));
139 void Path::Construct(const std::string & src)
141 if(src.empty()) ThrowMsg(EmptyPath, "Path cannot be empty");
144 std::unique_ptr<char[],free_deleter> root(getcwd(NULL,0));
145 Tokenize(std::string(root.get()), "\\/", std::inserter(m_parts, m_parts.begin()), true);
147 Tokenize(src, "\\/", std::inserter(m_parts, m_parts.end()), true);
154 std::string Path::DirectoryName() const
156 if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryName for root directory");
157 std::string ret = Join(m_parts.begin(), --m_parts.end(), "/");
158 return std::string("/") + ret;
161 std::string Path::Filename() const
163 if(m_parts.empty()) return "";
164 else return m_parts.back();
167 std::string Path::Fullpath() const
169 std::string ret = Join(m_parts.begin(), m_parts.end(), "/");
170 return std::string ("/") + ret;
173 std::string Path::Extension() const
175 if(m_parts.empty()) return "";
177 const std::string& last = *--m_parts.end();
179 std::string::size_type pos = last.find_last_of(".");
180 if(pos != std::string::npos)
182 return last.substr(pos + 1);
191 Path::Iterator Path::begin() const
195 return Iterator(Fullpath().c_str());
199 ThrowMsg(NotDirectory, "Cannot iterate not a directory");
203 Path::Iterator Path::end() const
208 void Path::RootGuard() const
210 if(m_parts.empty()) Throw(RootDirectoryError);
213 bool Path::Exists() const
216 memset(&tmp, 0, sizeof(struct stat));
217 return (0 == lstat(Fullpath().c_str(), &tmp));
220 bool Path::IsDir() const
223 memset(&tmp, 0, sizeof(struct stat));
224 if (-1 == lstat(Fullpath().c_str(), &tmp))
226 ThrowMsg(NotExists, DPL::GetErrnoString());
228 return S_ISDIR(tmp.st_mode);
231 bool Path::IsFile() const
234 memset(&tmp, 0, sizeof(struct stat));
235 if (-1 == lstat(Fullpath().c_str(), &tmp))
237 ThrowMsg(NotExists, DPL::GetErrnoString());
239 return S_ISREG(tmp.st_mode);
242 bool Path::ExistsAndIsFile() const
247 flag = this->IsFile();
248 } Catch (Path::NotExists) {
249 WrtLogD("%s is not a file.", Fullpath().c_str());
254 bool Path::ExistsAndIsDir() const
259 flag = this->IsDir();
260 } Catch (Path::NotExists) {
261 WrtLogD("%s is not a directory.", Fullpath().c_str());
266 bool Path::IsSymlink() const
269 memset(&tmp, 0, sizeof(struct stat));
270 if (-1 == lstat(Fullpath().c_str(), &tmp))
272 ThrowMsg(NotExists, DPL::GetErrnoString());
274 return S_ISLNK(tmp.st_mode);
277 std::size_t Path::LastWriteTime() const
280 memset(&st, 0, sizeof(struct stat));
281 if (-1 == stat(Fullpath().c_str(), &st)) {
282 ThrowMsg(NotExists, DPL::GetErrnoString());
287 bool Path::operator==(const Path & other) const
289 return m_parts == other.m_parts;
292 bool Path::operator!=(const Path & other) const
294 return m_parts != other.m_parts;
297 Path Path::operator/(const DPL::String& part) const
300 newOne.Append(ToUTF8String(part));
304 Path Path::operator/(const std::string& part) const
311 Path Path::operator/(const char * part) const
314 newOne.Append(std::string(part));
318 Path & Path::operator/=(const DPL::String& part)
320 Append(ToUTF8String(part));
324 Path & Path::operator/=(const std::string& part)
330 Path & Path::operator/=(const char * part)
332 Append(std::string(part));
336 void Path::Append(const std::string& part)
338 std::vector<std::string> tokens;
339 Tokenize(part, "\\/", std::inserter(tokens, tokens.end()), true);
340 std::copy(tokens.begin(), tokens.end(), std::inserter(m_parts, m_parts.end()));
343 Path Path::DirectoryPath() const
346 if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryPath for root directory");
347 std::copy(m_parts.begin(), --m_parts.end(), std::back_inserter(npath.m_parts));
351 std::size_t Path::Size() const
354 memset(&tmp, 0, sizeof(struct stat));
355 if (-1 == lstat(Fullpath().c_str(), &tmp))
357 ThrowMsg(NotExists, DPL::GetErrnoString());
362 bool Path::isSubPath(const Path & other) const
364 typedef std::vector<std::string>::const_iterator Iter;
365 Iter otherIter = other.m_parts.begin();
366 for(Iter iter = m_parts.begin(); iter != m_parts.end(); iter++)
368 if(otherIter == other.m_parts.end()) return false;
369 if(*iter != *otherIter) return false;
375 bool Path::hasExtension(const std::string& extension) const
377 WrtLogD("Looking for extension %s", extension.c_str());
379 if(Extension() == extension)
389 void MakeDir(const Path & path, mode_t mode)
392 if(!WrtUtilMakeDir(path.Fullpath(), mode))
393 ThrowMsg(Path::OperationFailed, "Cannot make directory");
396 void MakeEmptyFile(const Path & path)
400 ret = mknod(path.Fullpath().c_str(), S_IFREG, 0);
405 ThrowMsg(Path::AlreadyExists, "File already exists: " << path);
409 ThrowMsg(Path::OperationFailed, "Operation failed");
414 void Remove(const Path & path)
417 if(!WrtUtilRemove(path.Fullpath())) ThrowMsg(Path::OperationFailed, "Cannot remove path");
420 bool TryRemove(const Path & path)
423 return WrtUtilRemove(path.Fullpath());
426 void Rename(const Path & from, const Path & to)
434 if(0 != rename(from.Fullpath().c_str(), to.Fullpath().c_str()))
443 else if(from.IsFile() || from.IsSymlink())
450 ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
455 ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
460 void CopyFile(const Path & from, const Path & to)
466 DPL::FileInput input(from.Fullpath());
467 DPL::FileOutput output(to.Fullpath());
468 DPL::Copy(&input, &output);
470 Catch(DPL::FileInput::Exception::Base)
472 WrtLogE("File input error");
473 ReThrowMsg(DPL::CopyFailed, std::string("File input error") + from.Fullpath());
475 Catch(DPL::FileOutput::Exception::Base)
477 WrtLogE("File output error");
478 ReThrowMsg(DPL::CopyFailed, std::string("File output error") + to.Fullpath());
480 Catch(DPL::CopyFailed)
482 WrtLogE("File copy error");
483 ReThrowMsg(DPL::CopyFailed, std::string("File copy error") + from.Fullpath());
487 void CopyDir(const Path & from, const Path & to)
491 if(from.isSubPath(to))
493 ThrowMsg(Path::CannotCopy, "Cannot copy content of directory to it's sub directory");
500 CopyDir(*item, to / item->Filename());
502 else if(item->IsFile() || item->IsSymlink())
504 CopyFile(*item, to / item->Filename());
508 Throw(Path::OperationFailed);
513 Path CreateTempPath(const Path & basePath)
515 WrtLogD("Step: Creating temporary path");
518 Path tempPath = basePath;
519 tempPath /= WrtDB::GlobalConfig::GetTmpDirPath();
522 gettimeofday(&tv, NULL);
523 unsigned long long nr = (static_cast<unsigned long long>(tv.tv_sec) * 1000000ULL + static_cast<unsigned long long>(tv.tv_usec));
524 std::stringstream relPath;
525 relPath << TEMPORARY_PATH_POSTFIX << "_" << nr;
526 tempPath /= relPath.str();
528 MakeDir(tempPath, TEMPORARY_PATH_MODE);
532 bool Exists(const Path & path)
534 return path.Exists();
541 std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path)
543 str << path.Fullpath();
547 //TODO: uncomment when used defiend literals are supported
548 ///DPL::Utils::Path operator""p(const char * str, size_t)
550 // return DPL::Utils::Path(str);