• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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