1 /*
2 * Copyright (c) 2024 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 "mtpfs_util.h"
17
18 #include <config.h>
19 #include <cstdio>
20 #include <cstring>
21 #include <iomanip>
22 #include <sstream>
23
24 #include <dirent.h>
25 #include <libgen.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <climits>
30 #include <libmtp.h>
31 #include <libusb.h>
32
33 #include "file_utils.h"
34 #include "storage_service_log.h"
35
36 constexpr const char *DEV_NULL = "/dev/null";
37 constexpr int32_t MAX_INT = 255;
38 constexpr int32_t SCANF_NUM = 2;
39
40 bool MtpFsUtil::enabled_ = false;
41 int MtpFsUtil::stdOut_ = -1;
42 int MtpFsUtil::stdErr_ = -1;
43
On()44 void MtpFsUtil::On()
45 {
46 if (!enabled_) {
47 return;
48 }
49 if (freopen(DEV_NULL, "w", stdout) == nullptr) {
50 LOGE("freopen stdout fail");
51 }
52 if (freopen(DEV_NULL, "w", stderr) == nullptr) {
53 LOGE("freopen stderr fail");
54 }
55 dup2(stdOut_, fileno(stdout));
56 dup2(stdErr_, fileno(stderr));
57 close(stdOut_);
58 close(stdErr_);
59 if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) {
60 LOGE("setvbuf stdout fail");
61 }
62 if (setvbuf(stderr, NULL, _IOLBF, 0) != 0) {
63 LOGE("setvbuf stderr fail");
64 }
65 enabled_ = false;
66 }
67
Off()68 void MtpFsUtil::Off()
69 {
70 if (enabled_) {
71 return;
72 }
73 fflush(stdout);
74 fflush(stderr);
75 stdOut_ = dup(fileno(stdout));
76 stdErr_ = dup(fileno(stderr));
77 if (freopen(DEV_NULL, "w", stdout) == nullptr) {
78 LOGE("freopen stdout fail");
79 }
80 if (freopen(DEV_NULL, "w", stderr) == nullptr) {
81 LOGE("freopen stderr fail");
82 }
83 enabled_ = true;
84 }
85
SmtpfsDirName(const std::string & path)86 std::string SmtpfsDirName(const std::string &path)
87 {
88 char *str = strdup(path.c_str());
89 if (!str) {
90 return -ENOMEM;
91 }
92 std::string result(dirname(str));
93 free(static_cast<void *>(str));
94 return result;
95 }
96
SmtpfsBaseName(const std::string & path)97 std::string SmtpfsBaseName(const std::string &path)
98 {
99 char *str = strdup(path.c_str());
100 if (!str) {
101 return -ENOMEM;
102 }
103 std::string result(basename(str));
104 free(static_cast<void *>(str));
105 return result;
106 }
107
SmtpfsRealPath(const std::string & path)108 std::string SmtpfsRealPath(const std::string &path)
109 {
110 if (path.length() > PATH_MAX) {
111 return "";
112 }
113 char buf[PATH_MAX + 1];
114 char *realPath = realpath(path.c_str(), buf);
115 return std::string(realPath ? buf : "");
116 }
117
SmtpfsGetTmpDir()118 std::string SmtpfsGetTmpDir()
119 {
120 const char *cTmp = "/data/local/mtp_tmp";
121 OHOS::StorageDaemon::DelTemp(cTmp);
122 std::string tmpDir = SmtpfsRealPath(cTmp) + "/simple-mtpfs-XXXXXX";
123 char *cTempDir = ::strdup(tmpDir.c_str());
124 if (cTempDir == nullptr) {
125 return "";
126 }
127 char *cTmpDir = ::mkdtemp(cTempDir);
128 if (cTmpDir == nullptr) {
129 ::free(cTempDir);
130 return "";
131 }
132 tmpDir.assign(cTmpDir);
133 ::free(static_cast<void *>(cTempDir));
134 return tmpDir;
135 }
136
SmtpfsCreateDir(const std::string & dirName)137 bool SmtpfsCreateDir(const std::string &dirName)
138 {
139 return ::mkdir(dirName.c_str(), S_IRWXU) == 0;
140 }
141
SmtpfsRemoveDir(const std::string & dirName)142 bool SmtpfsRemoveDir(const std::string &dirName)
143 {
144 DIR *dir;
145 struct dirent *entry;
146 std::string path;
147
148 dir = ::opendir(dirName.c_str());
149 if (dir == nullptr) {
150 return false;
151 }
152 while ((entry = ::readdir(dir))) {
153 if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
154 path = dirName + "/" + entry->d_name;
155 if (entry->d_type == DT_DIR) {
156 ::closedir(dir);
157 return SmtpfsRemoveDir(path);
158 }
159 ::unlink(path.c_str());
160 }
161 }
162 ::closedir(dir);
163 ::remove(dirName.c_str());
164 return true;
165 }
166
SmtpfsUsbDevPath(const std::string & path,uint8_t * bnum,uint8_t * dnum)167 bool SmtpfsUsbDevPath(const std::string &path, uint8_t *bnum, uint8_t *dnum)
168 {
169 unsigned int bus;
170 unsigned int dev;
171 #ifdef USB_DEVPATH
172 std::string realPath(SmtpfsRealPath(path));
173 if (realPath.empty() || sscanf_s(realPath.c_str(), USB_DEVPATH, &bus, &dev) != SCANF_NUM) {
174 #endif
175 if (sscanf_s(path.c_str(), "%u/%u", &bus, &dev) != SCANF_NUM) {
176 return false;
177 }
178 }
179 if (bus > MAX_INT || dev > MAX_INT) {
180 return false;
181 }
182
183 *bnum = bus;
184 *dnum = dev;
185 return true;
186 }
187
smtpfs_raw_device_new_priv(libusb_device * usb_device)188 LIBMTP_raw_device_t *smtpfs_raw_device_new_priv(libusb_device *usb_device)
189 {
190 if (!usb_device) {
191 return nullptr;
192 }
193
194 LIBMTP_raw_device_t *device = static_cast<LIBMTP_raw_device_t *>(malloc(sizeof(LIBMTP_raw_device_t)));
195
196 if (device == nullptr) {
197 return nullptr;
198 }
199
200 struct libusb_device_descriptor desc;
201 int err = libusb_get_device_descriptor(usb_device, &desc);
202 if (err != LIBUSB_SUCCESS) {
203 free(static_cast<void *>(device));
204 return nullptr;
205 }
206
207 device->device_entry.vendor = nullptr;
208 device->device_entry.vendor_id = desc.idVendor;
209 device->device_entry.product = nullptr;
210 device->device_entry.product_id = desc.idProduct;
211 device->device_entry.device_flags = 0;
212
213 device->bus_location = static_cast<uint32_t>(libusb_get_bus_number(usb_device));
214 device->devnum = libusb_get_device_address(usb_device);
215
216 return device;
217 }
218
SmtpfsRawDeviceNew(const std::string & path)219 LIBMTP_raw_device_t *SmtpfsRawDeviceNew(const std::string &path)
220 {
221 uint8_t bnum;
222 uint8_t dnum;
223 if (!SmtpfsUsbDevPath(path, &bnum, &dnum)) {
224 return nullptr;
225 }
226
227 if (libusb_init(NULL) != 0) {
228 return nullptr;
229 }
230
231 libusb_device **devList;
232 ssize_t numDevs = libusb_get_device_list(NULL, &devList);
233 if (!numDevs) {
234 libusb_exit(NULL);
235 return nullptr;
236 }
237
238 libusb_device *dev = nullptr;
239 for (auto i = 0; i < numDevs; ++i) {
240 dev = devList[i];
241 if (bnum == libusb_get_bus_number(devList[i]) && dnum == libusb_get_device_address(devList[i])) {
242 break;
243 }
244 dev = nullptr;
245 }
246
247 LIBMTP_raw_device_t *rawDevice = smtpfs_raw_device_new_priv(dev);
248
249 libusb_free_device_list(devList, 0);
250 libusb_exit(NULL);
251
252 return rawDevice;
253 }
254
SmtpfsResetDevice(LIBMTP_raw_device_t * device)255 bool SmtpfsResetDevice(LIBMTP_raw_device_t *device)
256 {
257 if (device == nullptr) {
258 LOGE("device is null");
259 return false;
260 }
261
262 if (libusb_init(NULL) != 0) {
263 return false;
264 }
265
266 libusb_device **devList;
267 ssize_t numDevs = libusb_get_device_list(NULL, &devList);
268 if (!numDevs) {
269 libusb_exit(NULL);
270 return false;
271 }
272
273 libusb_device_handle *devHandle = nullptr;
274 for (auto i = 0; i < numDevs; ++i) {
275 uint8_t bnum = libusb_get_bus_number(devList[i]);
276 uint8_t dnum = libusb_get_device_address(devList[i]);
277 if (static_cast<uint32_t>(bnum) == device->bus_location && dnum == device->devnum) {
278 libusb_open(devList[i], &devHandle);
279 libusb_reset_device(devHandle);
280 libusb_close(devHandle);
281 break;
282 }
283 }
284
285 libusb_free_device_list(devList, 0);
286 libusb_exit(NULL);
287
288 return true;
289 }
290
SmtpfsRawDeviceFree(LIBMTP_raw_device_t * device)291 void SmtpfsRawDeviceFree(LIBMTP_raw_device_t *device)
292 {
293 if (device == nullptr) {
294 return;
295 }
296
297 free(static_cast<void *>(device->device_entry.vendor));
298 free(static_cast<void *>(device->device_entry.product));
299 free(static_cast<void *>(device));
300 }
301
SmtpfsCheckDir(const std::string & path)302 bool SmtpfsCheckDir(const std::string &path)
303 {
304 struct stat buf;
305 if (::stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode) && ::access(path.c_str(), R_OK | W_OK | X_OK) == 0) {
306 return true;
307 }
308
309 return false;
310 }
311