116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood/*
216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * you may not use this file except in compliance with the License.
616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * You may obtain a copy of the License at
716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
1016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Unless required by applicable law or agreed to in writing, software
1116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * See the License for the specific language governing permissions and
1416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * limitations under the License.
1516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood */
1616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
17b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#define LOG_TAG "MtpUtils"
18b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood
19708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <android-base/logging.h>
20708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <android-base/unique_fd.h>
21708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <dirent.h>
22708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <fcntl.h>
23e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang#include <string>
24708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <sys/sendfile.h>
25708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <sys/stat.h>
26708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <sys/types.h>
27335dd2be955607f2632eabc25045857f2cc8b674Mike Lockwood#include <stdio.h>
2816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <time.h>
29708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang#include <unistd.h>
3016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
3116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "MtpUtils.h"
3216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
33e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhangusing namespace std;
34e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang
357850ef999740f214a1990a9c090d3f3865d435aaMike Lockwoodnamespace android {
367850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood
37708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhangconstexpr unsigned long FILE_COPY_SIZE = 262144;
38708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
39dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhangstatic void access_ok(const char *path) {
40dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    if (access(path, F_OK) == -1) {
41dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang        // Ignore. Failure could be common in cases of delete where
42dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang        // the metadata was updated through other paths.
43dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    }
44dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang}
45dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang
4616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood/*
4716864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodDateTime strings follow a compatible subset of the definition found in ISO 8601, and
4816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodtake the form of a Unicode string formatted as: "YYYYMMDDThhmmss.s". In this
4916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodrepresentation, YYYY shall be replaced by the year, MM replaced by the month (01-12),
5016864bae0f51c32c456da2c43adf7a057c0c4882Mike LockwoodDD replaced by the day (01-31), T is a constant character 'T' delimiting time from date,
5116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodhh is replaced by the hour (00-23), mm is replaced by the minute (00-59), and ss by the
5216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodsecond (00-59). The ".s" is optional, and represents tenths of a second.
53d4b473884617987e02155cd1aae9e573e2f79a58Elliott HughesThis is followed by a UTC offset given as "[+-]zzzz" or the literal "Z", meaning UTC.
5416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood*/
5516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
5616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodbool parseDateTime(const char* dateTime, time_t& outSeconds) {
5716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    int year, month, day, hour, minute, second;
5816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    if (sscanf(dateTime, "%04d%02d%02dT%02d%02d%02d",
59d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes               &year, &month, &day, &hour, &minute, &second) != 6)
6016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood        return false;
61d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes
6216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    // skip optional tenth of second
63d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    const char* tail = dateTime + 15;
64d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    if (tail[0] == '.' && tail[1]) tail += 2;
6516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
66d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // FIXME: "Z" means UTC, but non-"Z" doesn't mean local time.
67d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // It might be that you're in Asia/Seoul on vacation and your Android
68d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // device has noticed this via the network, but your camera was set to
69d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // America/Los_Angeles once when you bought it and doesn't know where
70d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // it is right now, so the camera says "20160106T081700-0800" but we
71d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // just ignore the "-0800" and assume local time which is actually "+0900".
72d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // I think to support this (without switching to Java or using icu4c)
73d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // you'd want to always use timegm(3) and then manually add/subtract
74d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // the UTC offset parsed from the string (taking care of wrapping).
75d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    // mktime(3) ignores the tm_gmtoff field, so you can't let it do the work.
76d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    bool useUTC = (tail[0] == 'Z');
7716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
78d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    struct tm tm = {};
7916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    tm.tm_sec = second;
8016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    tm.tm_min = minute;
8116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    tm.tm_hour = hour;
8216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    tm.tm_mday = day;
83ea1db0a716cc937af5371153b959610baa2c6d52Mike Lockwood    tm.tm_mon = month - 1;  // mktime uses months in 0 - 11 range
8416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    tm.tm_year = year - 1900;
8516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    tm.tm_isdst = -1;
86d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes    outSeconds = useUTC ? timegm(&tm) : mktime(&tm);
8716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
8816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    return true;
8916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
9016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
9116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodvoid formatDateTime(time_t seconds, char* buffer, int bufferLength) {
9216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    struct tm tm;
9316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
9416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    localtime_r(&seconds, &tm);
9516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood    snprintf(buffer, bufferLength, "%04d%02d%02dT%02d%02d%02d",
96d4b473884617987e02155cd1aae9e573e2f79a58Elliott Hughes        tm.tm_year + 1900,
97ea1db0a716cc937af5371153b959610baa2c6d52Mike Lockwood        tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
98ea1db0a716cc937af5371153b959610baa2c6d52Mike Lockwood        tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
9916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
10016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
101e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhangint makeFolder(const char *path) {
102e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    mode_t mask = umask(0);
103e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    int ret = mkdir((const char *)path, DIR_PERM);
104e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    umask(mask);
105e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    if (ret && ret != -EEXIST) {
106e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        PLOG(ERROR) << "Failed to create folder " << path;
107e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        ret = -1;
108e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    } else {
109e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        chown((const char *)path, getuid(), FILE_GROUP);
110e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    }
111dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    access_ok(path);
112e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    return ret;
113e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang}
114e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang
115e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang/**
116e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang * Copies target path and all children to destination path.
117e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang *
118e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang * Returns 0 on success or a negative value indicating number of failures
119e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang */
120e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhangint copyRecursive(const char *fromPath, const char *toPath) {
121e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    int ret = 0;
122e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    string fromPathStr(fromPath);
123e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    string toPathStr(toPath);
124e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang
125e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    DIR* dir = opendir(fromPath);
126e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    if (!dir) {
127e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        PLOG(ERROR) << "opendir " << fromPath << " failed";
128e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        return -1;
129e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    }
130e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    if (fromPathStr[fromPathStr.size()-1] != '/')
131e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        fromPathStr += '/';
132e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    if (toPathStr[toPathStr.size()-1] != '/')
133e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        toPathStr += '/';
134e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang
135e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    struct dirent* entry;
136e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    while ((entry = readdir(dir))) {
137e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        const char* name = entry->d_name;
138e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang
139e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        // ignore "." and ".."
140e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
141e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang            continue;
142e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        }
143e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        string oldFile = fromPathStr + name;
144e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        string newFile = toPathStr + name;
145e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang
146e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        if (entry->d_type == DT_DIR) {
147e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang            ret += makeFolder(newFile.c_str());
148e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang            ret += copyRecursive(oldFile.c_str(), newFile.c_str());
149e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        } else {
150e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang            ret += copyFile(oldFile.c_str(), newFile.c_str());
151e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        }
152e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    }
153e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    return ret;
154e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang}
155e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang
156708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhangint copyFile(const char *fromPath, const char *toPath) {
157708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    auto start = std::chrono::steady_clock::now();
158708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
159708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    android::base::unique_fd fromFd(open(fromPath, O_RDONLY));
160708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    if (fromFd == -1) {
161708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        PLOG(ERROR) << "Failed to open copy from " << fromPath;
162708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        return -1;
163708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    }
164e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    android::base::unique_fd toFd(open(toPath, O_CREAT | O_WRONLY, FILE_PERM));
165708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    if (toFd == -1) {
166708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        PLOG(ERROR) << "Failed to open copy to " << toPath;
167708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        return -1;
168708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    }
169708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    off_t offset = 0;
170708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
171708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    struct stat sstat = {};
172708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    if (stat(fromPath, &sstat) == -1)
173708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        return -1;
174708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
175708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    off_t length = sstat.st_size;
176708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    int ret = 0;
177708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
178708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    while (offset < length) {
179708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        ssize_t transfer_length = std::min(length - offset, (off_t) FILE_COPY_SIZE);
180708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        ret = sendfile(toFd, fromFd, &offset, transfer_length);
181708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        if (ret != transfer_length) {
182708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang            ret = -1;
183708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang            PLOG(ERROR) << "Copying failed!";
184708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang            break;
185708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        }
186708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    }
187708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    auto end = std::chrono::steady_clock::now();
188708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    std::chrono::duration<double> diff = end - start;
189e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    LOG(DEBUG) << "Copied a file with MTP. Time: " << diff.count() << " s, Size: " << length <<
190708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        ", Rate: " << ((double) length) / diff.count() << " bytes/s";
191e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    chown(toPath, getuid(), FILE_GROUP);
192dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    access_ok(toPath);
193708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    return ret == -1 ? -1 : 0;
194708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang}
195708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
196708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhangvoid deleteRecursive(const char* path) {
197e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    string pathStr(path);
198e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang    if (pathStr[pathStr.size()-1] != '/') {
199e242f12c0f33518e0760fabfdad8cb93a1c8a2fbJerry Zhang        pathStr += '/';
200708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    }
201708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
202708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    DIR* dir = opendir(path);
203708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    if (!dir) {
204708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        PLOG(ERROR) << "opendir " << path << " failed";
205708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        return;
206708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    }
207708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
208708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    struct dirent* entry;
209708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    while ((entry = readdir(dir))) {
210708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        const char* name = entry->d_name;
211708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
212708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        // ignore "." and ".."
213708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
214708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang            continue;
215708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        }
216e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang        string childPath = pathStr + name;
217e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang        int success;
218708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        if (entry->d_type == DT_DIR) {
219e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            deleteRecursive(childPath.c_str());
220e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            success = rmdir(childPath.c_str());
221708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        } else {
222e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            success = unlink(childPath.c_str());
223708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        }
224dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang        access_ok(childPath.c_str());
225e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang        if (success == -1)
226e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            PLOG(ERROR) << "Deleting path " << childPath << " failed";
227708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    }
228708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    closedir(dir);
229708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang}
230708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
231e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhangbool deletePath(const char* path) {
232708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    struct stat statbuf;
233e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang    int success;
234708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    if (stat(path, &statbuf) == 0) {
235708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        if (S_ISDIR(statbuf.st_mode)) {
236e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            // rmdir will fail if the directory is non empty, so
237e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            // there is no need to keep errors from deleteRecursive
238708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang            deleteRecursive(path);
239e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            success = rmdir(path);
240708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        } else {
241e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang            success = unlink(path);
242708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang        }
243708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    } else {
244e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang        PLOG(ERROR) << "deletePath stat failed for " << path;
245e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang        return false;
246708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang    }
247e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang    if (success == -1)
248e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang        PLOG(ERROR) << "Deleting path " << path << " failed";
249dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    access_ok(path);
250e5aa05d12a48f7c5766a80d5bd2dc8cd068c1bcdJerry Zhang    return success == 0;
251708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang}
252708b3e0b72189d2d2e932459bd0391f98c9ff9a2Jerry Zhang
253dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhangint renameTo(const char *oldPath, const char *newPath) {
254dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    int ret = rename(oldPath, newPath);
255dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    access_ok(oldPath);
256dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    access_ok(newPath);
257dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    return ret;
258dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang}
259dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang
260dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang// Calls access(2) on the path to update underlying filesystems,
261dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang// then closes the fd.
262dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhangvoid closeObjFd(int fd, const char *path) {
263dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    close(fd);
264dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang    access_ok(path);
265dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang}
266dc148de23ea1437f0e9f9794c8977ad6cf70f361Jerry Zhang
2677850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood}  // namespace android
268