Initialize Tizen 2.3
[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 #include <dpl/utils/wrt_utility.h>
24 #include <dpl/errno_string.h>
25 #include <dpl/file_input.h>
26 #include <dpl/file_output.h>
27 #include <dpl/copy.h>
28 #include <dpl/log/wrt_log.h>
29 #include <dpl/foreach.h>
30 #include <dpl/wrt-dao-ro/global_config.h>
31
32 #include <unistd.h>
33 #include <ftw.h>
34 #include <sys/time.h>
35 #include <dpl/free_deleter.h>
36 #include <memory>
37
38 namespace DPL {
39
40 namespace Utils {
41
42 namespace {
43 const char * const TEMPORARY_PATH_POSTFIX = "temp";
44 const mode_t TEMPORARY_PATH_MODE = 0775;
45 } // namespace
46
47 Path::Iterator::Iterator() //end iterator by default
48 {
49 }
50
51 Path::Iterator::Iterator(const char * str)
52 {
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)
56     {
57         ThrowMsg(NotDirectory, "Not directory");
58     }
59     ReadNext();
60 }
61
62 Path::Iterator& Path::Iterator::operator++()
63 {
64     ReadNext();
65     return *this;
66 }
67
68 Path::Iterator Path::Iterator::operator++(int)
69 {
70     Path::Iterator copy(*this);
71     ReadNext();
72     return copy;
73 }
74
75 void Path::Iterator::ReadNext()
76 {
77     struct dirent * entry = readdir(m_dir.get());
78     while(entry && (strcmp(entry->d_name, ".") == 0 ||
79           strcmp(entry->d_name, "..") == 0))
80     {
81         entry = readdir(m_dir.get());
82     }
83     if(entry)
84     {
85         m_path = std::shared_ptr<Path>(new Path(*m_root));
86         m_path->Append(entry->d_name);
87     }
88     else //transform into end iterator
89     {
90         m_path.reset();
91         m_dir.reset();
92     }
93 }
94
95 bool Path::Iterator::operator==(const Path::Iterator& rhs) const
96 {
97     if(m_dir.get() == NULL)
98     {
99         if(rhs.m_dir.get() == NULL) return true;
100         else return false;
101     }
102     else
103     {
104         if(rhs.m_dir.get() == NULL) return false;
105     }
106     return *m_path == *rhs.m_path;
107 }
108
109 bool Path::Iterator::operator!=(const Path::Iterator& rhs) const
110 {
111     return !this->operator==(rhs);
112 }
113
114 const Path & Path::Iterator::operator*()
115 {
116     return *m_path;
117 }
118
119 const Path * Path::Iterator::operator->()
120 {
121     return m_path.get();
122 }
123
124 Path::Path(const DPL::String & str)
125 {
126     Construct(ToUTF8String(str));
127 }
128
129 Path::Path(const std::string & str)
130 {
131     Construct(str);
132 }
133
134 Path::Path(const char * str)
135 {
136     Construct(std::string(str));
137 }
138
139 void Path::Construct(const std::string & src)
140 {
141     if(src.empty()) ThrowMsg(EmptyPath, "Path cannot be empty");
142     if(src[0] != '/')
143     {
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);
146     }
147     Tokenize(src, "\\/", std::inserter(m_parts, m_parts.end()), true);
148 }
149
150 Path::Path()
151 {
152 }
153
154 std::string Path::DirectoryName() const
155 {
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;
159 }
160
161 std::string Path::Filename() const
162 {
163     if(m_parts.empty()) return "";
164     else return m_parts.back();
165 }
166
167 std::string Path::Fullpath() const
168 {
169     std::string ret = Join(m_parts.begin(), m_parts.end(), "/");
170     return std::string ("/") + ret;
171 }
172
173 std::string Path::Extension() const
174 {
175     if(m_parts.empty()) return "";
176
177     const std::string& last = *--m_parts.end();
178
179     std::string::size_type pos = last.find_last_of(".");
180     if(pos != std::string::npos)
181     {
182         return last.substr(pos + 1);
183     }
184     else
185     {
186         return "";
187     }
188 }
189
190 //foreach
191 Path::Iterator Path::begin() const
192 {
193     if(IsDir())
194     {
195         return Iterator(Fullpath().c_str());
196     }
197     else
198     {
199         ThrowMsg(NotDirectory, "Cannot iterate not a directory");
200     }
201 }
202
203 Path::Iterator Path::end() const
204 {
205     return Iterator();
206 }
207
208 void Path::RootGuard() const
209 {
210     if(m_parts.empty()) Throw(RootDirectoryError);
211 }
212
213 bool Path::Exists() const
214 {
215     struct stat tmp;
216     memset(&tmp, 0, sizeof(struct stat));
217     return (0 == lstat(Fullpath().c_str(), &tmp));
218 }
219
220 bool Path::IsDir() const
221 {
222     struct stat tmp;
223     memset(&tmp, 0, sizeof(struct stat));
224     if (-1 == lstat(Fullpath().c_str(), &tmp))
225     {
226         ThrowMsg(NotExists, DPL::GetErrnoString());
227     }
228     return S_ISDIR(tmp.st_mode);
229 }
230
231 bool Path::IsFile() const
232 {
233     struct stat tmp;
234     memset(&tmp, 0, sizeof(struct stat));
235     if (-1 == lstat(Fullpath().c_str(), &tmp))
236     {
237         ThrowMsg(NotExists, DPL::GetErrnoString());
238     }
239     return S_ISREG(tmp.st_mode);
240 }
241
242 bool Path::ExistsAndIsFile() const
243 {
244     bool flag = false;
245     Try
246     {
247         flag = this->IsFile();
248     } Catch (Path::NotExists) {
249         WrtLogD("%s is not a file.", Fullpath().c_str());
250     }
251     return flag;
252 }
253
254 bool Path::ExistsAndIsDir() const
255 {
256     bool flag = false;
257     Try
258     {
259         flag = this->IsDir();
260     } Catch (Path::NotExists) {
261         WrtLogD("%s is not a directory.", Fullpath().c_str());
262     }
263     return flag;
264 }
265
266 bool Path::IsSymlink() const
267 {
268     struct stat tmp;
269     memset(&tmp, 0, sizeof(struct stat));
270     if (-1 == lstat(Fullpath().c_str(), &tmp))
271     {
272         ThrowMsg(NotExists, DPL::GetErrnoString());
273     }
274     return S_ISLNK(tmp.st_mode);
275 }
276
277 std::size_t Path::LastWriteTime() const
278 {
279     struct stat st;
280     memset(&st, 0, sizeof(struct stat));
281     if (-1 == stat(Fullpath().c_str(), &st)) {
282         ThrowMsg(NotExists, DPL::GetErrnoString());
283     }
284     return st.st_mtime;
285 }
286
287 bool Path::operator==(const Path & other) const
288 {
289     return m_parts == other.m_parts;
290 }
291
292 bool Path::operator!=(const Path & other) const
293 {
294     return m_parts != other.m_parts;
295 }
296
297 Path Path::operator/(const DPL::String& part) const
298 {
299     Path newOne(*this);
300     newOne.Append(ToUTF8String(part));
301     return newOne;
302 }
303
304 Path Path::operator/(const std::string& part) const
305 {
306     Path newOne(*this);
307     newOne.Append(part);
308     return newOne;
309 }
310
311 Path Path::operator/(const char * part) const
312 {
313     Path newOne(*this);
314     newOne.Append(std::string(part));
315     return newOne;
316 }
317
318 Path & Path::operator/=(const DPL::String& part)
319 {
320     Append(ToUTF8String(part));
321     return *this;
322 }
323
324 Path & Path::operator/=(const std::string& part)
325 {
326     Append(part);
327     return *this;
328 }
329
330 Path & Path::operator/=(const char * part)
331 {
332     Append(std::string(part));
333     return *this;
334 }
335
336 void Path::Append(const std::string& part)
337 {
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()));
341 }
342
343 Path Path::DirectoryPath() const
344 {
345     Path npath;
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));
348     return npath;
349 }
350
351 std::size_t Path::Size() const
352 {
353     struct stat tmp;
354     memset(&tmp, 0, sizeof(struct stat));
355     if (-1 == lstat(Fullpath().c_str(), &tmp))
356     {
357         ThrowMsg(NotExists, DPL::GetErrnoString());
358     }
359     return tmp.st_size;
360 }
361
362 bool Path::isSubPath(const Path & other) const
363 {
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++)
367     {
368         if(otherIter == other.m_parts.end()) return false;
369         if(*iter != *otherIter) return false;
370         otherIter++;
371     }
372     return true;
373 }
374
375 bool Path::hasExtension(const std::string& extension) const
376 {
377     WrtLogD("Looking for extension %s", extension.c_str());
378
379     if(Extension() == extension)
380     {
381         return true;
382     }
383     else
384     {
385         return false;
386     }
387 }
388
389 void MakeDir(const Path & path, mode_t mode)
390 {
391     path.RootGuard();
392     if(!WrtUtilMakeDir(path.Fullpath(), mode))
393         ThrowMsg(Path::OperationFailed, "Cannot make directory");
394 }
395
396 void MakeEmptyFile(const Path & path)
397 {
398     path.RootGuard();
399     int ret = 0;
400     ret = mknod(path.Fullpath().c_str(), S_IFREG, 0);
401     if(ret != 0)
402     {
403         if(errno == EEXIST)
404         {
405             ThrowMsg(Path::AlreadyExists, "File already exists: " << path);
406         }
407         else
408         {
409             ThrowMsg(Path::OperationFailed, "Operation failed");
410         }
411     }
412 }
413
414 void Remove(const Path & path)
415 {
416     path.RootGuard();
417     if(!WrtUtilRemove(path.Fullpath())) ThrowMsg(Path::OperationFailed, "Cannot remove path");
418 }
419
420 bool TryRemove(const Path & path)
421 {
422     path.RootGuard();
423     return WrtUtilRemove(path.Fullpath());
424 }
425
426 void Rename(const Path & from, const Path & to)
427 {
428     from.RootGuard();
429     to.RootGuard();
430     if(from == to)
431     {
432         return;
433     }
434     if(0 != rename(from.Fullpath().c_str(), to.Fullpath().c_str()))
435     {
436         if(errno == EXDEV)
437         {
438             if(from.IsDir())
439             {
440                 CopyDir(from, to);
441                 Remove(from);
442             }
443             else if(from.IsFile() || from.IsSymlink())
444             {
445                 CopyFile(from, to);
446                 Remove(from);
447             }
448             else
449             {
450                  ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
451             }
452         }
453         else
454         {
455             ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
456         }
457     }
458 }
459
460 void CopyFile(const Path & from, const Path & to)
461 {
462     from.RootGuard();
463     to.RootGuard();
464     Try
465     {
466         DPL::FileInput input(from.Fullpath());
467         DPL::FileOutput output(to.Fullpath());
468         DPL::Copy(&input, &output);
469     }
470     Catch(DPL::FileInput::Exception::Base)
471     {
472         WrtLogE("File input error");
473         ReThrowMsg(DPL::CopyFailed, std::string("File input error") + from.Fullpath());
474     }
475     Catch(DPL::FileOutput::Exception::Base)
476     {
477         WrtLogE("File output error");
478         ReThrowMsg(DPL::CopyFailed, std::string("File output error") + to.Fullpath());
479     }
480     Catch(DPL::CopyFailed)
481     {
482         WrtLogE("File copy error");
483         ReThrowMsg(DPL::CopyFailed, std::string("File copy error") + from.Fullpath());
484     }
485 }
486
487 void CopyDir(const Path & from, const Path & to)
488 {
489     from.RootGuard();
490     to.RootGuard();
491     if(from.isSubPath(to))
492     {
493         ThrowMsg(Path::CannotCopy, "Cannot copy content of directory to it's sub directory");
494     }
495     MakeDir(to);
496     FOREACH(item, from)
497     {
498         if(item->IsDir())
499         {
500             CopyDir(*item, to / item->Filename());
501         }
502         else if(item->IsFile() || item->IsSymlink())
503         {
504             CopyFile(*item, to / item->Filename());
505         }
506         else
507         {
508             Throw(Path::OperationFailed);
509         }
510     }
511 }
512
513 Path CreateTempPath(const Path & basePath)
514 {
515     WrtLogD("Step: Creating temporary path");
516
517     // Temporary path
518     Path tempPath = basePath;
519     tempPath /= WrtDB::GlobalConfig::GetTmpDirPath();
520
521     timeval tv;
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();
527
528     MakeDir(tempPath, TEMPORARY_PATH_MODE);
529     return tempPath;
530 }
531
532 bool Exists(const Path & path)
533 {
534     return path.Exists();
535 }
536
537 }
538
539 }
540
541 std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path)
542 {
543     str << path.Fullpath();
544     return str;
545 }
546
547 //TODO: uncomment when used defiend literals are supported
548 ///DPL::Utils::Path operator""p(const char * str, size_t)
549 //{
550 //    return DPL::Utils::Path(str);
551 //}