Path class for DPL + tests
[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
32 #include <sys/stat.h>
33
34 namespace DPL {
35
36 namespace Utils {
37
38 Path::Iterator::Iterator() //end iterator by default
39 {
40 }
41
42 Path::Iterator::Iterator(const char * str)
43 {
44     m_root = std::shared_ptr<Path>(new Path(str));
45     m_dir = std::shared_ptr<DIR>(opendir(str), [](DIR * d){ if(d)closedir(d); }); //custom delete
46     if(m_dir.get() == NULL)
47     {
48         ThrowMsg(NotDirectory, "Not directory");
49     }
50     ReadNext();
51 }
52
53 Path::Iterator& Path::Iterator::operator++()
54 {
55     ReadNext();
56     return *this;
57 }
58
59 Path::Iterator Path::Iterator::operator++(int)
60 {
61     Path::Iterator copy(*this);
62     ReadNext();
63     return copy;
64 }
65
66 void Path::Iterator::ReadNext()
67 {
68     struct dirent * entry = readdir(m_dir.get());
69     while(entry && (strcmp(entry->d_name, ".") == 0 ||
70           strcmp(entry->d_name, "..") == 0))
71     {
72         entry = readdir(m_dir.get());
73     }
74     if(entry)
75     {
76         m_path = std::shared_ptr<Path>(new Path(*m_root));
77         m_path->Append(entry->d_name);
78     }
79     else //transform into end iterator
80     {
81         m_path.reset();
82         m_dir.reset();
83     }
84 }
85
86 bool Path::Iterator::operator==(const Path::Iterator& rhs) const
87 {
88     if(m_dir.get() == NULL)
89     {
90         if(rhs.m_dir.get() == NULL) return true;
91         else return false;
92     }
93     else
94     {
95         if(rhs.m_dir.get() == NULL) return false;
96     }
97     return *m_path == *rhs.m_path;
98 }
99
100 bool Path::Iterator::operator!=(const Path::Iterator& rhs) const
101 {
102     return !this->operator==(rhs);
103 }
104
105 const Path & Path::Iterator::operator*()
106 {
107     return *m_path;
108 }
109
110 const Path * Path::Iterator::operator->()
111 {
112     return m_path.get();
113 }
114
115 Path::Path(const DPL::String & str)
116 {
117     Construct(ToUTF8String(str));
118 }
119
120 Path::Path(const std::string & str)
121 {
122     Construct(str);
123 }
124
125 Path::Path(const char * str)
126 {
127     Construct(std::string(str));
128 }
129
130 void Path::Construct(const std::string & src)
131 {
132     if(src.empty()) ThrowMsg(EmptyPath, "Path cannot be empty");
133     if(src[0] != '/')
134     {
135         DPL::ScopedFree<char> root(getcwd(NULL,0));
136         Tokenize(std::string(root.Get()), "\\/", std::inserter(m_parts, m_parts.begin()), true);
137     }
138     Tokenize(src, "\\/", std::inserter(m_parts, m_parts.end()), true);
139 }
140
141 Path::Path() //for private usage
142 {
143 }
144
145 std::string Path::DirectoryName() const
146 {
147     if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryName for root directory");
148     std::string ret = Join(m_parts.begin(), --m_parts.end(), "/");
149     return std::string("/") + ret;
150 }
151
152 std::string Path::Basename() const
153 {
154     if(m_parts.empty()) return "";
155     else return m_parts.back();
156 }
157
158 std::string Path::Fullpath() const
159 {
160     std::string ret = Join(m_parts.begin(), m_parts.end(), "/");
161     return std::string ("/") + ret;
162 }
163
164 //foreach
165 Path::Iterator Path::begin() const
166 {
167     if(IsDir())
168     {
169         return Iterator(Fullpath().c_str());
170     }
171     else
172     {
173         ThrowMsg(NotDirectory, "Cannot iterate not a directory");
174     }
175 }
176
177 Path::Iterator Path::end() const
178 {
179     return Iterator();
180 }
181
182
183 bool Path::Exists() const
184 {
185     struct stat tmp;
186     return (0 == lstat(Fullpath().c_str(), &tmp));
187 }
188
189 bool Path::IsDir() const
190 {
191     struct stat tmp;
192     if (-1 == lstat(Fullpath().c_str(), &tmp))
193     {
194         ThrowMsg(NotExists, DPL::GetErrnoString());
195     }
196     return S_ISDIR(tmp.st_mode);
197 }
198
199 bool Path::IsFile() const
200 {
201     struct stat tmp;
202     if (-1 == lstat(Fullpath().c_str(), &tmp))
203     {
204         ThrowMsg(NotExists, DPL::GetErrnoString());
205     }
206     return S_ISREG(tmp.st_mode);
207 }
208
209 bool Path::IsSymlink() const
210 {
211     struct stat tmp;
212     if (-1 == lstat(Fullpath().c_str(), &tmp))
213     {
214         ThrowMsg(NotExists, DPL::GetErrnoString());
215     }
216     return S_ISLNK(tmp.st_mode);
217 }
218
219 bool Path::operator==(const Path & other) const
220 {
221     return m_parts == other.m_parts;
222 }
223
224 bool Path::operator!=(const Path & other) const
225 {
226     return m_parts != other.m_parts;
227 }
228
229 Path Path::operator/(const DPL::String& part) const
230 {
231     Path newOne;
232     newOne.Append(ToUTF8String(part));
233     return newOne;
234 }
235
236 Path Path::operator/(const std::string& part) const
237 {
238     Path newOne;
239     newOne.Append(part);
240     return newOne;
241 }
242
243 Path Path::operator/(const char * part) const
244 {
245     Path newOne(*this);
246     newOne.Append(std::string(part));
247     return newOne;
248 }
249
250 Path & Path::operator/=(const DPL::String& part)
251 {
252     Append(ToUTF8String(part));
253 }
254
255 Path & Path::operator/=(const std::string& part)
256 {
257     Append(part);
258 }
259
260 Path & Path::operator/=(const char * part)
261 {
262     Append(std::string(part));
263 }
264
265 void Path::Append(const std::string& part)
266 {
267     std::vector<std::string> tokens;
268     Tokenize(part, "\\/", std::inserter(tokens, tokens.end()), true);
269     std::copy(tokens.begin(), tokens.end(), std::inserter(m_parts, m_parts.end()));
270 }
271
272 void MakeDir(const Path & path, mode_t mode)
273 {
274     if(!WrtUtilMakeDir(path.Fullpath(), mode)) ThrowMsg(Path::OperationFailed, "Cannot make directory");
275 }
276
277 void MakeEmptyFile(const Path & path)
278 {
279     std::string fp = path.Fullpath();
280     FILE* fd = fopen(fp.c_str(), "wx");
281     if(!fd)
282     {
283         struct stat st;
284         if(lstat(fp.c_str(), &st) == 0)
285         {
286             ThrowMsg(Path::AlreadyExists, "File already exists");
287         }
288         else
289         {
290             ThrowMsg(Path::OperationFailed, "Operation failed");
291         }
292     }
293     fclose(fd);
294 }
295
296 void Remove(const Path & path)
297 {
298     if(!WrtUtilRemove(path.Fullpath())) ThrowMsg(Path::OperationFailed, "Cannot remove path");
299 }
300
301 void Rename(const Path & from, const Path & to)
302 {
303     if(from == to)
304     {
305         return;
306     }
307     int code = 0;
308     if( (code = rename(from.Fullpath().c_str(), to.Fullpath().c_str())) )
309     {
310         if(code == EXDEV)
311         {
312             Try
313             {
314                 DPL::FileInput in(from.Fullpath());
315                 DPL::FileOutput out(to.Fullpath());
316                 DPL::Copy(&in, &out);
317             }
318             Catch(DPL::FileInput::Exception::Base)
319             {
320                 ThrowMsg(Path::OperationFailed, "Cannot open input file " << from.Fullpath());
321             }
322             Catch(DPL::FileOutput::Exception::Base)
323             {
324                 ThrowMsg(Path::OperationFailed, "Cannot open output file " << to.Fullpath());
325             }
326         }
327         else
328         {
329             ThrowMsg(Path::OperationFailed, DPL::GetErrnoString());
330         }
331     }
332 }
333
334 bool Exists(const Path & path)
335 {
336     return path.Exists();
337 }
338
339 }
340
341 }
342
343 std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path)
344 {
345     str << path.Fullpath();
346     return str;
347 }
348
349 //TODO: uncomment when used defiend literals are supported
350 ///DPL::Utils::Path operator""p(const char * str, size_t)
351 //{
352 //    return DPL::Utils::Path(str);
353 //}