[Release] wrt-commons_0.2.135
[framework/web/wrt-commons.git] / modules / utils / src / path.cpp
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file    path.h
18  * @author  Tomasz Iwanek (t.iwanek@samsung.com)
19  * @version 1.0
20  */
21
22 #include "dpl/utils/path.h"
23
24 #include <dpl/utils/wrt_utility.h>
25
26 #include <dpl/scoped_free.h>
27 #include <dpl/errno_string.h>
28 #include <dpl/file_input.h>
29 #include <dpl/file_output.h>
30 #include <dpl/copy.h>
31 #include <dpl/log/log.h>
32 #include <dpl/foreach.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35
36 namespace DPL {
37
38 namespace Utils {
39
40 Path::Iterator::Iterator() //end iterator by default
41 {
42 }
43
44 Path::Iterator::Iterator(const char * str)
45 {
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)
49     {
50         ThrowMsg(NotDirectory, "Not directory");
51     }
52     ReadNext();
53 }
54
55 Path::Iterator& Path::Iterator::operator++()
56 {
57     ReadNext();
58     return *this;
59 }
60
61 Path::Iterator Path::Iterator::operator++(int)
62 {
63     Path::Iterator copy(*this);
64     ReadNext();
65     return copy;
66 }
67
68 void Path::Iterator::ReadNext()
69 {
70     struct dirent * entry = readdir(m_dir.get());
71     while(entry && (strcmp(entry->d_name, ".") == 0 ||
72           strcmp(entry->d_name, "..") == 0))
73     {
74         entry = readdir(m_dir.get());
75     }
76     if(entry)
77     {
78         m_path = std::shared_ptr<Path>(new Path(*m_root));
79         m_path->Append(entry->d_name);
80     }
81     else //transform into end iterator
82     {
83         m_path.reset();
84         m_dir.reset();
85     }
86 }
87
88 bool Path::Iterator::operator==(const Path::Iterator& rhs) const
89 {
90     if(m_dir.get() == NULL)
91     {
92         if(rhs.m_dir.get() == NULL) return true;
93         else return false;
94     }
95     else
96     {
97         if(rhs.m_dir.get() == NULL) return false;
98     }
99     return *m_path == *rhs.m_path;
100 }
101
102 bool Path::Iterator::operator!=(const Path::Iterator& rhs) const
103 {
104     return !this->operator==(rhs);
105 }
106
107 const Path & Path::Iterator::operator*()
108 {
109     return *m_path;
110 }
111
112 const Path * Path::Iterator::operator->()
113 {
114     return m_path.get();
115 }
116
117 Path::Path(const DPL::String & str)
118 {
119     Construct(ToUTF8String(str));
120 }
121
122 Path::Path(const std::string & str)
123 {
124     Construct(str);
125 }
126
127 Path::Path(const char * str)
128 {
129     Construct(std::string(str));
130 }
131
132 void Path::Construct(const std::string & src)
133 {
134     if(src.empty()) ThrowMsg(EmptyPath, "Path cannot be empty");
135     if(src[0] != '/')
136     {
137         DPL::ScopedFree<char> root(getcwd(NULL,0));
138         Tokenize(std::string(root.Get()), "\\/", std::inserter(m_parts, m_parts.begin()), true);
139     }
140     Tokenize(src, "\\/", std::inserter(m_parts, m_parts.end()), true);
141 }
142
143 Path::Path()
144 {
145 }
146
147 std::string Path::DirectoryName() const
148 {
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;
152 }
153
154 std::string Path::Filename() const
155 {
156     if(m_parts.empty()) return "";
157     else return m_parts.back();
158 }
159
160 std::string Path::Fullpath() const
161 {
162     std::string ret = Join(m_parts.begin(), m_parts.end(), "/");
163     return std::string ("/") + ret;
164 }
165
166 //foreach
167 Path::Iterator Path::begin() const
168 {
169     if(IsDir())
170     {
171         return Iterator(Fullpath().c_str());
172     }
173     else
174     {
175         ThrowMsg(NotDirectory, "Cannot iterate not a directory");
176     }
177 }
178
179 Path::Iterator Path::end() const
180 {
181     return Iterator();
182 }
183
184 void Path::RootGuard() const
185 {
186     if(m_parts.empty()) Throw(RootDirectoryError);
187 }
188
189 bool Path::Exists() const
190 {
191     struct stat tmp;
192     memset(&tmp, 0, sizeof(struct stat));
193     return (0 == lstat(Fullpath().c_str(), &tmp));
194 }
195
196 bool Path::IsDir() const
197 {
198     struct stat tmp;
199     memset(&tmp, 0, sizeof(struct stat));
200     if (-1 == lstat(Fullpath().c_str(), &tmp))
201     {
202         ThrowMsg(NotExists, DPL::GetErrnoString());
203     }
204     return S_ISDIR(tmp.st_mode);
205 }
206
207 bool Path::IsFile() const
208 {
209     struct stat tmp;
210     memset(&tmp, 0, sizeof(struct stat));
211     if (-1 == lstat(Fullpath().c_str(), &tmp))
212     {
213         ThrowMsg(NotExists, DPL::GetErrnoString());
214     }
215     return S_ISREG(tmp.st_mode);
216 }
217
218 bool Path::IsSymlink() const
219 {
220     struct stat tmp;
221     memset(&tmp, 0, sizeof(struct stat));
222     if (-1 == lstat(Fullpath().c_str(), &tmp))
223     {
224         ThrowMsg(NotExists, DPL::GetErrnoString());
225     }
226     return S_ISLNK(tmp.st_mode);
227 }
228
229 bool Path::operator==(const Path & other) const
230 {
231     return m_parts == other.m_parts;
232 }
233
234 bool Path::operator!=(const Path & other) const
235 {
236     return m_parts != other.m_parts;
237 }
238
239 Path Path::operator/(const DPL::String& part) const
240 {
241     Path newOne(*this);
242     newOne.Append(ToUTF8String(part));
243     return newOne;
244 }
245
246 Path Path::operator/(const std::string& part) const
247 {
248     Path newOne(*this);
249     newOne.Append(part);
250     return newOne;
251 }
252
253 Path Path::operator/(const char * part) const
254 {
255     Path newOne(*this);
256     newOne.Append(std::string(part));
257     return newOne;
258 }
259
260 Path & Path::operator/=(const DPL::String& part)
261 {
262     Append(ToUTF8String(part));
263     return *this;
264 }
265
266 Path & Path::operator/=(const std::string& part)
267 {
268     Append(part);
269     return *this;
270 }
271
272 Path & Path::operator/=(const char * part)
273 {
274     Append(std::string(part));
275     return *this;
276 }
277
278 void Path::Append(const std::string& part)
279 {
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()));
283 }
284
285 Path Path::DirectoryPath() const
286 {
287     Path npath;
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));
290     return npath;
291 }
292
293 std::size_t Path::Size() const
294 {
295     struct stat tmp;
296     memset(&tmp, 0, sizeof(struct stat));
297     if (-1 == lstat(Fullpath().c_str(), &tmp))
298     {
299         ThrowMsg(NotExists, DPL::GetErrnoString());
300     }
301     return tmp.st_size;
302 }
303
304 bool Path::isSubPath(const Path & other) const
305 {
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++)
309     {
310         if(otherIter == other.m_parts.end()) return false;
311         if(*iter != *otherIter) return false;
312         otherIter++;
313     }
314     return true;
315 }
316
317 bool Path::hasExtension(const std::string& extension) const
318 {
319     LogDebug("Looking for extension " << extension << " in: " << this->Filename());
320
321     size_t extLen = extension.length();
322
323     if(m_parts.empty()) return false;
324     if(extLen == 0) return false;
325
326     const std::string& last = *--m_parts.end();
327     size_t lastLen = last.length();
328
329     if(lastLen < (1 + extLen)) return false;
330
331     const char last_tmp = last[ lastLen - (1 + extLen) ];
332     if(last_tmp != '.') return false;
333
334     if(last.substr(lastLen - extLen) != extension) return false;
335     return true;
336 }
337
338 void MakeDir(const Path & path, mode_t mode)
339 {
340     path.RootGuard();
341     if(!WrtUtilMakeDir(path.Fullpath(), mode)) ThrowMsg(Path::OperationFailed, "Cannot make directory");
342 }
343
344 void MakeEmptyFile(const Path & path)
345 {
346     path.RootGuard();
347     std::string fp = path.Fullpath();
348     FILE* fd = fopen(fp.c_str(), "wx");
349     if(!fd)
350     {
351         struct stat st;
352         memset(&st, 0, sizeof(struct stat));
353         if(lstat(fp.c_str(), &st) == 0)
354         {
355             ThrowMsg(Path::AlreadyExists, "File already exists");
356         }
357         else
358         {
359             ThrowMsg(Path::OperationFailed, "Operation failed");
360         }
361     }
362     fclose(fd);
363 }
364
365 void Remove(const Path & path)
366 {
367     path.RootGuard();
368     if(!WrtUtilRemove(path.Fullpath())) ThrowMsg(Path::OperationFailed, "Cannot remove path");
369 }
370
371 bool TryRemove(const Path & path)
372 {
373     path.RootGuard();
374     if(!WrtUtilRemove(path.Fullpath())) return false;
375     return true;
376 }
377
378 void Rename(const Path & from, const Path & to)
379 {
380     from.RootGuard();
381     to.RootGuard();
382     if(from == to)
383     {
384         return;
385     }
386     if(0 != rename(from.Fullpath().c_str(), to.Fullpath().c_str()))
387     {
388         if(errno == EXDEV)
389         {
390             if(from.IsDir())
391             {
392                 CopyDir(from, to);
393                 Remove(from);
394             }
395             else if(from.IsFile() || from.IsSymlink())
396             {
397                 CopyFile(from, to);
398                 Remove(from);
399             }
400             else
401             {
402                  ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
403             }
404         }
405         else
406         {
407             ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
408         }
409     }
410 }
411
412 void CopyFile(const Path & from, const Path & to)
413 {
414     from.RootGuard();
415     to.RootGuard();
416     Try
417     {
418         DPL::FileInput input(from.Fullpath());
419         DPL::FileOutput output(to.Fullpath());
420         DPL::Copy(&input, &output);
421     }
422     Catch(DPL::FileInput::Exception::Base)
423     {
424         LogError("File input error");
425         ReThrowMsg(DPL::CopyFailed, std::string("File input error") + from.Fullpath());
426     }
427     Catch(DPL::FileOutput::Exception::Base)
428     {
429         LogError("File output error");
430         ReThrowMsg(DPL::CopyFailed, std::string("File output error") + to.Fullpath());
431     }
432     Catch(DPL::CopyFailed)
433     {
434         LogError("File copy error");
435         ReThrowMsg(DPL::CopyFailed, std::string("File copy error") + from.Fullpath());
436     }
437 }
438
439 void CopyDir(const Path & from, const Path & to)
440 {
441     from.RootGuard();
442     to.RootGuard();
443     if(from.isSubPath(to))
444     {
445         ThrowMsg(Path::CannotCopy, "Cannot copy content of directory to it's sub directory");
446     }
447     MakeDir(to);
448     FOREACH(item, from)
449     {
450         if(item->IsDir())
451         {
452             CopyDir(*item, to / item->Filename());
453         }
454         else if(item->IsFile() || item->IsSymlink())
455         {
456             CopyFile(*item, to / item->Filename());
457         }
458         else
459         {
460             Throw(Path::OperationFailed);
461         }
462     }
463 }
464
465 bool Exists(const Path & path)
466 {
467     return path.Exists();
468 }
469
470 }
471
472 }
473
474 std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path)
475 {
476     str << path.Fullpath();
477     return str;
478 }
479
480 //TODO: uncomment when used defiend literals are supported
481 ///DPL::Utils::Path operator""p(const char * str, size_t)
482 //{
483 //    return DPL::Utils::Path(str);
484 //}