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"
24 #include <dpl/utils/wrt_utility.h>
26 #include <dpl/scoped_free.h>
27 #include <dpl/errno_string.h>
28 #include <dpl/file_input.h>
29 #include <dpl/file_output.h>
31 #include <dpl/log/log.h>
32 #include <dpl/foreach.h>
40 Path::Iterator::Iterator() //end iterator by default
44 Path::Iterator::Iterator(const char * str)
46 m_root = std::shared_ptr<Path>(new Path(str));
47 m_dir = std::shared_ptr<DIR>(opendir(str), [](DIR * d){ if(d)closedir(d); }); //custom delete
48 if(m_dir.get() == NULL)
50 ThrowMsg(NotDirectory, "Not directory");
55 Path::Iterator& Path::Iterator::operator++()
61 Path::Iterator Path::Iterator::operator++(int)
63 Path::Iterator copy(*this);
68 void Path::Iterator::ReadNext()
70 struct dirent * entry = readdir(m_dir.get());
71 while(entry && (strcmp(entry->d_name, ".") == 0 ||
72 strcmp(entry->d_name, "..") == 0))
74 entry = readdir(m_dir.get());
78 m_path = std::shared_ptr<Path>(new Path(*m_root));
79 m_path->Append(entry->d_name);
81 else //transform into end iterator
88 bool Path::Iterator::operator==(const Path::Iterator& rhs) const
90 if(m_dir.get() == NULL)
92 if(rhs.m_dir.get() == NULL) return true;
97 if(rhs.m_dir.get() == NULL) return false;
99 return *m_path == *rhs.m_path;
102 bool Path::Iterator::operator!=(const Path::Iterator& rhs) const
104 return !this->operator==(rhs);
107 const Path & Path::Iterator::operator*()
112 const Path * Path::Iterator::operator->()
117 Path::Path(const DPL::String & str)
119 Construct(ToUTF8String(str));
122 Path::Path(const std::string & str)
127 Path::Path(const char * str)
129 Construct(std::string(str));
132 void Path::Construct(const std::string & src)
134 if(src.empty()) ThrowMsg(EmptyPath, "Path cannot be empty");
137 DPL::ScopedFree<char> root(getcwd(NULL,0));
138 Tokenize(std::string(root.Get()), "\\/", std::inserter(m_parts, m_parts.begin()), true);
140 Tokenize(src, "\\/", std::inserter(m_parts, m_parts.end()), true);
147 std::string Path::DirectoryName() const
149 if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryName for root directory");
150 std::string ret = Join(m_parts.begin(), --m_parts.end(), "/");
151 return std::string("/") + ret;
154 std::string Path::Filename() const
156 if(m_parts.empty()) return "";
157 else return m_parts.back();
160 std::string Path::Fullpath() const
162 std::string ret = Join(m_parts.begin(), m_parts.end(), "/");
163 return std::string ("/") + ret;
167 Path::Iterator Path::begin() const
171 return Iterator(Fullpath().c_str());
175 ThrowMsg(NotDirectory, "Cannot iterate not a directory");
179 Path::Iterator Path::end() const
184 void Path::RootGuard() const
186 if(m_parts.empty()) Throw(RootDirectoryError);
189 bool Path::Exists() const
192 memset(&tmp, 0, sizeof(struct stat));
193 return (0 == lstat(Fullpath().c_str(), &tmp));
196 bool Path::IsDir() const
199 memset(&tmp, 0, sizeof(struct stat));
200 if (-1 == lstat(Fullpath().c_str(), &tmp))
202 ThrowMsg(NotExists, DPL::GetErrnoString());
204 return S_ISDIR(tmp.st_mode);
207 bool Path::IsFile() const
210 memset(&tmp, 0, sizeof(struct stat));
211 if (-1 == lstat(Fullpath().c_str(), &tmp))
213 ThrowMsg(NotExists, DPL::GetErrnoString());
215 return S_ISREG(tmp.st_mode);
218 bool Path::IsSymlink() const
221 memset(&tmp, 0, sizeof(struct stat));
222 if (-1 == lstat(Fullpath().c_str(), &tmp))
224 ThrowMsg(NotExists, DPL::GetErrnoString());
226 return S_ISLNK(tmp.st_mode);
229 bool Path::operator==(const Path & other) const
231 return m_parts == other.m_parts;
234 bool Path::operator!=(const Path & other) const
236 return m_parts != other.m_parts;
239 Path Path::operator/(const DPL::String& part) const
242 newOne.Append(ToUTF8String(part));
246 Path Path::operator/(const std::string& part) const
253 Path Path::operator/(const char * part) const
256 newOne.Append(std::string(part));
260 Path & Path::operator/=(const DPL::String& part)
262 Append(ToUTF8String(part));
266 Path & Path::operator/=(const std::string& part)
272 Path & Path::operator/=(const char * part)
274 Append(std::string(part));
278 void Path::Append(const std::string& part)
280 std::vector<std::string> tokens;
281 Tokenize(part, "\\/", std::inserter(tokens, tokens.end()), true);
282 std::copy(tokens.begin(), tokens.end(), std::inserter(m_parts, m_parts.end()));
285 Path Path::DirectoryPath() const
288 if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryPath for root directory");
289 std::copy(m_parts.begin(), --m_parts.end(), std::back_inserter(npath.m_parts));
293 std::size_t Path::Size() const
296 memset(&tmp, 0, sizeof(struct stat));
297 if (-1 == lstat(Fullpath().c_str(), &tmp))
299 ThrowMsg(NotExists, DPL::GetErrnoString());
304 bool Path::isSubPath(const Path & other) const
306 typedef std::vector<std::string>::const_iterator Iter;
307 Iter otherIter = other.m_parts.begin();
308 for(Iter iter = m_parts.begin(); iter != m_parts.end(); iter++)
310 if(otherIter == other.m_parts.end()) return false;
311 if(*iter != *otherIter) return false;
317 bool Path::hasExtension(const std::string& extension) const
319 LogDebug("Looking for extension " << extension << " in: " << this->Filename());
321 size_t extLen = extension.length();
323 if(m_parts.empty()) return false;
324 if(extLen == 0) return false;
326 const std::string& last = *--m_parts.end();
327 size_t lastLen = last.length();
329 if(lastLen < (1 + extLen)) return false;
331 const char last_tmp = last[ lastLen - (1 + extLen) ];
332 if(last_tmp != '.') return false;
334 if(last.substr(lastLen - extLen) != extension) return false;
338 void MakeDir(const Path & path, mode_t mode)
341 if(!WrtUtilMakeDir(path.Fullpath(), mode)) ThrowMsg(Path::OperationFailed, "Cannot make directory");
344 void MakeEmptyFile(const Path & path)
347 std::string fp = path.Fullpath();
348 FILE* fd = fopen(fp.c_str(), "wx");
352 memset(&st, 0, sizeof(struct stat));
353 if(lstat(fp.c_str(), &st) == 0)
355 ThrowMsg(Path::AlreadyExists, "File already exists");
359 ThrowMsg(Path::OperationFailed, "Operation failed");
365 void Remove(const Path & path)
368 if(!WrtUtilRemove(path.Fullpath())) ThrowMsg(Path::OperationFailed, "Cannot remove path");
371 bool TryRemove(const Path & path)
374 if(!WrtUtilRemove(path.Fullpath())) return false;
378 void Rename(const Path & from, const Path & to)
386 if(0 != rename(from.Fullpath().c_str(), to.Fullpath().c_str()))
395 else if(from.IsFile() || from.IsSymlink())
402 ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
407 ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
412 void CopyFile(const Path & from, const Path & to)
418 DPL::FileInput input(from.Fullpath());
419 DPL::FileOutput output(to.Fullpath());
420 DPL::Copy(&input, &output);
422 Catch(DPL::FileInput::Exception::Base)
424 LogError("File input error");
425 ReThrowMsg(DPL::CopyFailed, std::string("File input error") + from.Fullpath());
427 Catch(DPL::FileOutput::Exception::Base)
429 LogError("File output error");
430 ReThrowMsg(DPL::CopyFailed, std::string("File output error") + to.Fullpath());
432 Catch(DPL::CopyFailed)
434 LogError("File copy error");
435 ReThrowMsg(DPL::CopyFailed, std::string("File copy error") + from.Fullpath());
439 void CopyDir(const Path & from, const Path & to)
443 if(from.isSubPath(to))
445 ThrowMsg(Path::CannotCopy, "Cannot copy content of directory to it's sub directory");
452 CopyDir(*item, to / item->Filename());
454 else if(item->IsFile() || item->IsSymlink())
456 CopyFile(*item, to / item->Filename());
460 Throw(Path::OperationFailed);
465 bool Exists(const Path & path)
467 return path.Exists();
474 std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path)
476 str << path.Fullpath();
480 //TODO: uncomment when used defiend literals are supported
481 ///DPL::Utils::Path operator""p(const char * str, size_t)
483 // return DPL::Utils::Path(str);