d663831fdfad45f1da460cd38e28a33804aeb02b
[platform/core/security/vasum.git] / common / utils / fs.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Lukasz Pawelczyk <l.pawelczyk@partner.samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Lukasz Pawelczyk (l.pawelczyk@partner.samsung.com)
22  * @brief   File utility functions
23  */
24
25 #include "config.hpp"
26 #include "logger/logger.hpp"
27 #include "utils/fs.hpp"
28 #include "utils/paths.hpp"
29 #include "utils/exception.hpp"
30
31 #include <boost/filesystem.hpp>
32 #include <dirent.h>
33 #include <fstream>
34 #include <streambuf>
35 #include <cstring>
36 #include <cerrno>
37 #include <sys/stat.h>
38 #include <sys/mount.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41
42
43 namespace security_containers {
44 namespace utils {
45
46
47 std::string readFileContent(const std::string& path)
48 {
49     std::string result;
50     if (!readFileContent(path, result)) {
51         throw UtilsException();
52     }
53     return result;
54 }
55
56 bool readFileContent(const std::string& path, std::string& result)
57 {
58     std::ifstream file(path);
59
60     if (!file) {
61         LOGD(path << ": could not open for reading");
62         return false;
63     }
64
65     file.seekg(0, std::ios::end);
66     std::streampos length = file.tellg();
67     if (length < 0) {
68         LOGD(path << ": tellg failed");
69         return false;
70     }
71     result.resize(static_cast<size_t>(length));
72     file.seekg(0, std::ios::beg);
73
74     file.read(&result[0], length);
75     if (!file) {
76         LOGD(path << ": read error");
77         result.clear();
78         return false;
79     }
80
81     return true;
82 }
83
84 bool saveFileContent(const std::string& path, const std::string& content)
85 {
86     std::ofstream file(path);
87     if (!file) {
88         LOGD(path << ": could not open for writing");
89         return false;
90     }
91     file.write(content.data(), static_cast<std::streamsize>(content.size()));
92     if (!file) {
93         LOGD(path << ": could not write to");
94         return false;
95     }
96     return true;
97 }
98
99 bool isCharDevice(const std::string& path)
100 {
101     struct stat s;
102     return ::stat(path.c_str(), &s) == 0 && S_IFCHR == (s.st_mode & S_IFMT);
103 }
104
105 namespace {
106 // NOTE: Should be the same as in systemd/src/core/mount-setup.c
107 const std::string RUN_MOUNT_POINT_OPTIONS = "mode=755,smackfstransmute=System::Run";
108 const std::string RUN_MOUNT_POINT_OPTIONS_NO_SMACK = "mode=755";
109 const unsigned long RUN_MOUNT_POINT_FLAGS = MS_NOSUID | MS_NODEV | MS_STRICTATIME;
110
111 bool mountTmpfs(const std::string& path, unsigned long flags, const std::string& options)
112 {
113     if (::mount("tmpfs", path.c_str(), "tmpfs", flags, options.c_str()) != 0) {
114         LOGD("Mount failed for '" << path << "', options=" << options << ": " << strerror(errno));
115         return false;
116     }
117     return true;
118 }
119
120 } // namespace
121
122 bool mountRun(const std::string& path)
123 {
124     return utils::mountTmpfs(path, RUN_MOUNT_POINT_FLAGS, RUN_MOUNT_POINT_OPTIONS)
125            || utils::mountTmpfs(path, RUN_MOUNT_POINT_FLAGS, RUN_MOUNT_POINT_OPTIONS_NO_SMACK);
126 }
127
128 bool umount(const std::string& path)
129 {
130     if (::umount(path.c_str()) != 0) {
131         LOGD("Umount failed for '" << path << "': " << strerror(errno));
132         return false;
133     }
134     return true;
135 }
136
137 bool isMountPoint(const std::string& path, bool& result)
138 {
139     std::string parentPath = dirName(path);
140     bool newResult;
141     bool ret = hasSameMountPoint(path, parentPath, newResult);
142
143     result = !newResult;
144     return ret;
145 }
146
147 bool hasSameMountPoint(const std::string& path1, const std::string& path2, bool& result)
148 {
149     struct stat s1, s2;
150
151     if (::stat(path1.c_str(), &s1)) {
152         LOGD("Failed to get stat of " << path1 << ": " << strerror(errno));
153         return false;
154     }
155
156     if (::stat(path2.c_str(), &s2)) {
157         LOGD("Failed to get stat of " << path2 << ": " << strerror(errno));
158         return false;
159     }
160
161     result = (s1.st_dev == s2.st_dev);
162     return true;
163 }
164
165 bool moveFile(const std::string& src, const std::string& dst)
166 {
167     bool bResult;
168
169     namespace fs = boost::filesystem;
170     boost::system::error_code error;
171
172     // The destination has to be a full path (including a file name)
173     // so it doesn't exist yet, we need to check upper level dir instead.
174     if (!hasSameMountPoint(src, dirName(dst), bResult)) {
175         LOGE("Failed to check the files' mount points");
176         return false;
177     }
178
179     if (bResult) {
180         fs::rename(src, dst, error);
181         if (error) {
182             LOGE("Failed to rename the file: " << error);
183             return false;
184         }
185     } else {
186         fs::copy_file(src, dst, error);
187         if (error) {
188             LOGE("Failed to copy the file: " << error);
189             return false;
190         }
191         fs::remove(src, error);
192         if (error) {
193             LOGE("Failed to remove the file: " << error);
194             fs::remove(dst, error);
195             return false;
196         }
197     }
198
199     return true;
200 }
201
202 bool createDir(const std::string& path, uid_t uid, uid_t gid, boost::filesystem::perms mode)
203 {
204     namespace fs = boost::filesystem;
205
206     fs::path dirPath(path);
207     boost::system::error_code ec;
208     bool runDirCreated = false;
209     if (!fs::exists(dirPath)) {
210         if (!fs::create_directory(dirPath, ec)) {
211             LOGE("Failed to create directory '" << path << "': "
212                  << ec.message());
213             return false;
214         }
215         runDirCreated = true;
216     } else if (!fs::is_directory(dirPath)) {
217         LOGE("Path '" << path << " already exists");
218         return false;
219     }
220
221     // set permissions
222     fs::permissions(dirPath, mode, ec);
223     if (fs::status(dirPath).permissions() != mode) {
224         LOGE("Failed to set permissions to '" << path << "': "
225              << ec.message());
226         return false;
227     }
228
229     // set owner
230     if (::chown(path.c_str(), uid, gid) != 0) {
231         // remove the directory only if it hadn't existed before
232         if (runDirCreated) {
233             fs::remove(dirPath);
234         }
235         LOGE("chown() failed for path '" << path << "': " << strerror(errno));
236         return false;
237     }
238
239     return true;
240 }
241
242 } // namespace utils
243 } // namespace security_containers