1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "volume/external_volume_info.h"
17
18 #include <sys/stat.h>
19 #include <sys/wait.h>
20 #include <future>
21
22 #include "storage_service_errno.h"
23 #include "storage_service_log.h"
24 #include "utils/disk_utils.h"
25 #include "utils/file_utils.h"
26 #include "utils/storage_radar.h"
27 #include "utils/string_utils.h"
28 #include "volume/process.h"
29
30 using namespace std;
31 using namespace OHOS::StorageService;
32 namespace OHOS {
33 namespace StorageDaemon {
34 constexpr int32_t WAIT_THREAD_TIMEOUT_S = 15;
35 constexpr int32_t FILE_NOT_EXIST = 2;
36 constexpr int UID_FILE_MANAGER = 1006;
ReadMetadata()37 int32_t ExternalVolumeInfo::ReadMetadata()
38 {
39 int32_t ret = OHOS::StorageDaemon::ReadMetadata(devPath_, fsUuid_, fsType_, fsLabel_);
40 if (fsType_ == "ntfs" && (fsLabel_.find('?') != std::string::npos || fsLabel_ == "")) {
41 std::vector<std::string> cmd;
42 cmd = {
43 "ntfslabel",
44 devPath_
45 };
46 fsLabel_ = GetBlkidDataByCmd(cmd);
47 }
48 return ret;
49 }
50
GetFsType()51 int32_t ExternalVolumeInfo::GetFsType()
52 {
53 for (uint32_t i = 0; i < supportMountType_.size(); i++) {
54 if (supportMountType_[i].compare(fsType_) == 0) {
55 return i;
56 }
57 }
58 return -1;
59 }
60
GetFsUuid()61 std::string ExternalVolumeInfo::GetFsUuid()
62 {
63 return fsUuid_;
64 }
65
GetFsLabel()66 std::string ExternalVolumeInfo::GetFsLabel()
67 {
68 return fsLabel_;
69 }
70
GetMountPath()71 std::string ExternalVolumeInfo::GetMountPath()
72 {
73 return mountPath_;
74 }
75
DoCreate(dev_t dev)76 int32_t ExternalVolumeInfo::DoCreate(dev_t dev)
77 {
78 int32_t ret = 0;
79 string id = VolumeInfo::GetVolumeId();
80
81 device_ = dev;
82 devPath_ = StringPrintf(devPathDir_.c_str(), (id).c_str());
83
84 ret = mknod(devPath_.c_str(), S_IFBLK, dev);
85 if (ret) {
86 LOGE("External volume DoCreate error.");
87 return E_ERR;
88 }
89 return E_OK;
90 }
91
DoDestroy()92 int32_t ExternalVolumeInfo::DoDestroy()
93 {
94 int err = remove(devPath_.c_str());
95 if (err) {
96 LOGE("External volume DoDestroy error.");
97 return E_ERR;
98 }
99 return E_OK;
100 }
101
DoMount4Ext(uint32_t mountFlags)102 int32_t ExternalVolumeInfo::DoMount4Ext(uint32_t mountFlags)
103 {
104 mode_t mode = 0777;
105 int32_t ret = mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, "");
106 if (ret) {
107 return E_EXT_MOUNT;
108 }
109 TravelChmod(mountPath_, mode);
110 return ret;
111 }
112
DoMount4Hmfs(uint32_t mountFlags)113 int32_t ExternalVolumeInfo::DoMount4Hmfs(uint32_t mountFlags)
114 {
115 mode_t mode = 0777;
116 const char *fsType = "hmfs";
117 auto mountData = StringPrintf("context=u:object_r:mnt_external_file:s0");
118 int32_t ret = mount(devPath_.c_str(), mountPath_.c_str(), fsType, mountFlags, mountData.c_str());
119 if (!ret) {
120 TravelChmod(mountPath_, mode);
121 StorageRadar::ReportVolumeOperation("ExternalVolumeInfo::DoMount4Hmfs", ret);
122 }
123 return ret;
124 }
125
DoMount4Ntfs(uint32_t mountFlags)126 int32_t ExternalVolumeInfo::DoMount4Ntfs(uint32_t mountFlags)
127 {
128 #ifdef EXTERNAL_STORAGE_QOS_TRANS
129 auto mountData = StringPrintf("rw,big_writes,uid=%d,gid=%d,dmask=0007,fmask=0007",
130 UID_FILE_MANAGER, UID_FILE_MANAGER);
131 #else
132 auto mountData = StringPrintf("rw,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
133 #endif
134 if (mountFlags & MS_RDONLY) {
135 mountData = StringPrintf("ro,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
136 }
137
138 std::vector<std::string> cmd = {
139 "mount.ntfs",
140 devPath_,
141 mountPath_,
142 "-o",
143 mountData.c_str()
144 };
145 #ifdef EXTERNAL_STORAGE_QOS_TRANS
146 if (ExtStorageMountForkExec(cmd) != E_OK) {
147 return E_NTFS_MOUNT;
148 }
149 return E_OK;
150 #else
151 if (ForkExec(cmd) != E_OK) {
152 return E_NTFS_MOUNT;
153 }
154 return E_OK;
155 #endif
156 }
157
DoMount4Exfat(uint32_t mountFlags)158 int32_t ExternalVolumeInfo::DoMount4Exfat(uint32_t mountFlags)
159 {
160 auto mountData = StringPrintf("rw,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
161 if (mountFlags & MS_RDONLY) {
162 mountData = StringPrintf("ro,uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
163 }
164
165 std::vector<std::string> cmd = {
166 "mount.exfat",
167 "-o",
168 mountData.c_str(),
169 devPath_,
170 mountPath_,
171 };
172 #ifdef EXTERNAL_STORAGE_QOS_TRANS
173 if (ExtStorageMountForkExec(cmd) != E_OK) {
174 return E_EXFAT_MOUNT;
175 }
176 return E_OK;
177 #else
178 if (ForkExec(cmd) != E_OK) {
179 return E_EXFAT_MOUNT;
180 }
181 return E_OK;
182 #endif
183 }
184
DoMount4OtherType(uint32_t mountFlags)185 int32_t ExternalVolumeInfo::DoMount4OtherType(uint32_t mountFlags)
186 {
187 mountFlags |= MS_MGC_VAL;
188 auto mountData = StringPrintf("uid=%d,gid=%d,dmask=0007,fmask=0007", UID_FILE_MANAGER, UID_FILE_MANAGER);
189 int32_t ret = mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, mountData.c_str());
190 if (ret) {
191 return E_OTHER_MOUNT;
192 }
193 return ret;
194 }
195
DoMount4Vfat(uint32_t mountFlags)196 int32_t ExternalVolumeInfo::DoMount4Vfat(uint32_t mountFlags)
197 {
198 mountFlags |= MS_MGC_VAL;
199 auto mountData = StringPrintf("uid=%d,gid=%d,dmask=0007,fmask=0007,utf8", UID_FILE_MANAGER, UID_FILE_MANAGER);
200 int32_t ret = mount(devPath_.c_str(), mountPath_.c_str(), fsType_.c_str(), mountFlags, mountData.c_str());
201 if (ret) {
202 return E_FAT_MOUNT;
203 }
204 return ret;
205 }
206
DoMount(uint32_t mountFlags)207 int32_t ExternalVolumeInfo::DoMount(uint32_t mountFlags)
208 {
209 int32_t ret = DoCheck();
210 if (ret != E_OK) {
211 LOGE("External volume uuid=%{public}s check failed.", GetAnonyString(GetFsUuid()).c_str());
212 return E_DOCHECK_MOUNT;
213 }
214
215 struct stat statbuf;
216 mountPath_ = StringPrintf(mountPathDir_.c_str(), fsUuid_.c_str());
217 if (!lstat(mountPath_.c_str(), &statbuf)) {
218 LOGE("volume mount path %{public}s exists, please remove first", GetMountPath().c_str());
219 remove(mountPath_.c_str());
220 return E_SYS_KERNEL_ERR;
221 }
222
223 if (mkdir(mountPath_.c_str(), S_IRWXU | S_IRWXG | S_IXOTH)) {
224 LOGE("the volume %{public}s create path %{public}s failed", GetVolumeId().c_str(), GetMountPath().c_str());
225 return E_MKDIR_MOUNT;
226 }
227
228 if (fsType_ == "hmfs" || fsType_ == "f2fs") ret = DoMount4Hmfs(mountFlags);
229 if (ret) {
230 LOGE("External volume DoMount error, errno = %{public}d", errno);
231 remove(mountPath_.c_str());
232 return E_HMFS_MOUNT;
233 }
234
235 std::promise<int32_t> promise;
236 std::future<int32_t> future = promise.get_future();
237 std::thread mountThread ([this, mountFlags, p = std::move(promise)]() mutable {
238 LOGI("Ready to mount: volume fstype is %{public}s, mountflag is %{public}d", fsType_.c_str(), mountFlags);
239 int retValue = E_OK;
240 if (fsType_ == "ext2" || fsType_ == "ext3" || fsType_ == "ext4") retValue = DoMount4Ext(mountFlags);
241 else if (fsType_ == "ntfs") retValue = DoMount4Ntfs(mountFlags);
242 else if (fsType_ == "exfat") retValue = DoMount4Exfat(mountFlags);
243 else if (fsType_ == "vfat" || fsType_ == "fat32") retValue = DoMount4Vfat(mountFlags);
244 else if (fsType_ != "hmfs" && fsType_ != "f2fs") retValue = DoMount4OtherType(mountFlags);
245 p.set_value(retValue);
246 });
247
248 if (future.wait_for(std::chrono::seconds(WAIT_THREAD_TIMEOUT_S)) == std::future_status::timeout) {
249 LOGE("Mount timed out");
250 remove(mountPath_.c_str());
251 mountThread.detach();
252 return E_TIMEOUT_MOUNT;
253 }
254 ret = future.get();
255 mountThread.join();
256
257 if (ret) {
258 LOGE("External volume DoMount error, errno = %{public}d", errno);
259 remove(mountPath_.c_str());
260 return ret;
261 }
262 LOGI("external volume mount success");
263 return E_OK;
264 }
265
DoUMount(bool force)266 int32_t ExternalVolumeInfo::DoUMount(bool force)
267 {
268 if (force) {
269 LOGI("External volume start force to unmount.");
270 Process ps(mountPath_);
271 ps.UpdatePidByPath();
272 ps.KillProcess(SIGKILL);
273 umount2(mountPath_.c_str(), MNT_DETACH);
274 remove(mountPath_.c_str());
275 LOGI("External volume force to unmount success.");
276 return E_OK;
277 }
278 LOGI("External volume start to unmount.");
279 int ret = umount(mountPath_.c_str());
280 int err = remove(mountPath_.c_str());
281 if (err && ret) {
282 LOGE("External volume DoUmount error.");
283 return E_VOL_UMOUNT_ERR;
284 }
285
286 if (err && errno != FILE_NOT_EXIST) {
287 LOGE("failed to call remove(%{public}s) error, errno = %{public}d", mountPath_.c_str(), errno);
288 return E_RMDIR_MOUNT;
289 }
290 LOGI("External volume unmount success.");
291 return E_OK;
292 }
293
DoCheck()294 int32_t ExternalVolumeInfo::DoCheck()
295 {
296 int32_t ret = ExternalVolumeInfo::ReadMetadata();
297 if (ret) {
298 LOGE("External volume uuid=%{public}s DoCheck failed.", GetAnonyString(GetFsUuid()).c_str());
299 return E_CHECK;
300 }
301
302 // check fstype
303 if (GetFsType() == -1) {
304 LOGE("External Volume type not support.");
305 return E_NOT_SUPPORT;
306 }
307 return E_OK;
308 }
309
DoFormat(std::string type)310 int32_t ExternalVolumeInfo::DoFormat(std::string type)
311 {
312 int32_t err = 0;
313 std::map<std::string, std::string>::iterator iter = supportFormatType_.find(type);
314 if (iter == supportFormatType_.end()) {
315 LOGE("External volume format not support.");
316 return E_NOT_SUPPORT;
317 }
318
319 if (type == "vfat") {
320 std::vector<std::string> cmd = {
321 iter->second,
322 "-A",
323 devPath_
324 };
325 err = ForkExec(cmd);
326 } else {
327 std::vector<std::string> cmd = {
328 iter->second,
329 devPath_
330 };
331 err = ForkExec(cmd);
332 }
333
334 if (err == E_NO_CHILD) {
335 err = E_OK;
336 }
337
338 ReadMetadata();
339 return err;
340 }
341
DoSetVolDesc(std::string description)342 int32_t ExternalVolumeInfo::DoSetVolDesc(std::string description)
343 {
344 int32_t err = 0;
345 if (fsType_ == "ntfs") {
346 std::vector<std::string> fixCmd = {
347 "ntfsfix",
348 "-d",
349 devPath_
350 };
351 err = ForkExec(fixCmd);
352 std::vector<std::string> labelCmd = {
353 "ntfslabel",
354 devPath_,
355 description
356 };
357 err = ForkExec(labelCmd);
358 } else if (fsType_ == "exfat") {
359 std::vector<std::string> cmd = {
360 "exfatlabel",
361 devPath_,
362 description
363 };
364 err = ForkExec(cmd);
365 } else if (fsType_ == "hmfs") {
366 std::vector<std::string> cmd = {
367 "hmfslabel",
368 devPath_,
369 description
370 };
371 err = ForkExec(cmd);
372 } else {
373 LOGE("SetVolumeDescription fsType not support.");
374 return E_NOT_SUPPORT;
375 }
376
377 ReadMetadata();
378 return err;
379 }
380 } // StorageDaemon
381 } // OHOS
382