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