1413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber/*
2413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * Copyright (C) 2009 The Android Open Source Project
3413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber *
4413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * you may not use this file except in compliance with the License.
6413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * You may obtain a copy of the License at
7413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber *
8413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber *
10413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * Unless required by applicable law or agreed to in writing, software
11413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * See the License for the specific language governing permissions and
14413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber * limitations under the License.
15413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber */
16413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
171629399bb578fc176613ccaf134d1be6e3047638Andreas Huber//#define LOG_NDEBUG 0
181629399bb578fc176613ccaf134d1be6e3047638Andreas Huber#define LOG_TAG "MediaScanner"
19fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu#include <cutils/properties.h>
201629399bb578fc176613ccaf134d1be6e3047638Andreas Huber#include <utils/Log.h>
211629399bb578fc176613ccaf134d1be6e3047638Andreas Huber
22413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber#include <media/mediascanner.h>
23413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
24413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber#include <sys/stat.h>
25413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber#include <dirent.h>
26413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
27413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Hubernamespace android {
28413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
29413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas HuberMediaScanner::MediaScanner()
30fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    : mLocale(NULL), mSkipList(NULL), mSkipIndex(NULL) {
31fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    loadSkipList();
32413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber}
33413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
34413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas HuberMediaScanner::~MediaScanner() {
35413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    setLocale(NULL);
36fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    free(mSkipList);
37fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    free(mSkipIndex);
38413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber}
39413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
40413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Hubervoid MediaScanner::setLocale(const char *locale) {
41413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    if (mLocale) {
42413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        free(mLocale);
43413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        mLocale = NULL;
44413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
45413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    if (locale) {
46413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        mLocale = strdup(locale);
47413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
48413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber}
49413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
50413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberconst char *MediaScanner::locale() const {
51413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    return mLocale;
52413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber}
53413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
54fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhuvoid MediaScanner::loadSkipList() {
55fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    mSkipList = (char *)malloc(PROPERTY_VALUE_MAX * sizeof(char));
56fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    if (mSkipList) {
57e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten        property_get("testing.mediascanner.skiplist", mSkipList, "");
58fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    }
59fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    if (!mSkipList || (strlen(mSkipList) == 0)) {
60fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        free(mSkipList);
61fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        mSkipList = NULL;
62fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        return;
63fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    }
64fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    mSkipIndex = (int *)malloc(PROPERTY_VALUE_MAX * sizeof(int));
65fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    if (mSkipIndex) {
66fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        // dup it because strtok will modify the string
67fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        char *skipList = strdup(mSkipList);
68fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        if (skipList) {
69fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            char * path = strtok(skipList, ",");
70fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            int i = 0;
71fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            while (path) {
72fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu                mSkipIndex[i++] = strlen(path);
73fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu                path = strtok(NULL, ",");
74fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            }
75fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            mSkipIndex[i] = -1;
76fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            free(skipList);
77fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        }
78fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    }
79fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu}
80fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu
817188e55f54a43c55fd6b96454720c447f1dc454eJeff BrownMediaScanResult MediaScanner::processDirectory(
827188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        const char *path, MediaScannerClient &client) {
83413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    int pathLength = strlen(path);
84413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    if (pathLength >= PATH_MAX) {
857188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        return MEDIA_SCAN_RESULT_SKIPPED;
86413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
87413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    char* pathBuffer = (char *)malloc(PATH_MAX + 1);
88413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    if (!pathBuffer) {
897188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        return MEDIA_SCAN_RESULT_ERROR;
90413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
91413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
92413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    int pathRemaining = PATH_MAX - pathLength;
93413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    strcpy(pathBuffer, path);
943e42b4491529975f771f8d71f931e24e120a7856Kenny Root    if (pathLength > 0 && pathBuffer[pathLength - 1] != '/') {
95413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        pathBuffer[pathLength] = '/';
96413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        pathBuffer[pathLength + 1] = 0;
97413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        --pathRemaining;
98413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
99413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
100413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    client.setLocale(locale());
101413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
1027188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    MediaScanResult result = doProcessDirectory(pathBuffer, pathRemaining, client, false);
103413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
104413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    free(pathBuffer);
105413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
106413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    return result;
107413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber}
108413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
109fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhubool MediaScanner::shouldSkipDirectory(char *path) {
110fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    if (path && mSkipList && mSkipIndex) {
111fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        int len = strlen(path);
112fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        int idx = 0;
113fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        // track the start position of next path in the comma
114fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        // separated list obtained from getprop
115fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        int startPos = 0;
116fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        while (mSkipIndex[idx] != -1) {
117fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            // no point to match path name if strlen mismatch
118fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            if ((len == mSkipIndex[idx])
119fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu                // pick out the path segment from comma separated list
120fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu                // to compare against current path parameter
121fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu                && (strncmp(path, &mSkipList[startPos], len) == 0)) {
122fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu                return true;
123fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            }
124fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            startPos += mSkipIndex[idx] + 1; // extra char for the delimiter
125fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu            idx++;
126fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu        }
127fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    }
128fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    return false;
129fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu}
130fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu
1317188e55f54a43c55fd6b96454720c447f1dc454eJeff BrownMediaScanResult MediaScanner::doProcessDirectory(
1327188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        char *path, int pathRemaining, MediaScannerClient &client, bool noMedia) {
133413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    // place to copy file or directory name
134413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    char* fileSpot = path + strlen(path);
135413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    struct dirent* entry;
136413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
137fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    if (shouldSkipDirectory(path)) {
138e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten        ALOGD("Skipping: %s", path);
139e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten        return MEDIA_SCAN_RESULT_OK;
140fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu    }
141fb6f03425a791dcc4188462c860becf6ca6be4eaGuang Zhu
142462accab9dbcf8d1597de999328fa74337b3b88cMike Lockwood    // Treat all files as non-media in directories that contain a  ".nomedia" file
143413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
144413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        strcpy(fileSpot, ".nomedia");
145413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        if (access(path, F_OK) == 0) {
14690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten            ALOGV("found .nomedia, setting noMedia flag");
147462accab9dbcf8d1597de999328fa74337b3b88cMike Lockwood            noMedia = true;
148413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        }
149413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
150413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        // restore path
151413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        fileSpot[0] = 0;
152413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
153413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
154413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    DIR* dir = opendir(path);
155413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    if (!dir) {
1565ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("Error opening directory '%s', skipping: %s.", path, strerror(errno));
1577188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        return MEDIA_SCAN_RESULT_SKIPPED;
158413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
159413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
1607188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    MediaScanResult result = MEDIA_SCAN_RESULT_OK;
161413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    while ((entry = readdir(dir))) {
1627188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        if (doProcessDirectoryEntry(path, pathRemaining, client, noMedia, entry, fileSpot)
1637188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown                == MEDIA_SCAN_RESULT_ERROR) {
1647188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            result = MEDIA_SCAN_RESULT_ERROR;
1657188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            break;
166413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        }
1677188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    }
1687188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    closedir(dir);
1697188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    return result;
1707188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown}
171413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
1727188e55f54a43c55fd6b96454720c447f1dc454eJeff BrownMediaScanResult MediaScanner::doProcessDirectoryEntry(
1737188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        char *path, int pathRemaining, MediaScannerClient &client, bool noMedia,
1747188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        struct dirent* entry, char* fileSpot) {
1757188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    struct stat statbuf;
1767188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    const char* name = entry->d_name;
1777188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown
1787188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    // ignore "." and ".."
1797188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
1807188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        return MEDIA_SCAN_RESULT_SKIPPED;
1817188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    }
1827188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown
1837188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    int nameLength = strlen(name);
1847188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    if (nameLength + 1 > pathRemaining) {
1857188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // path too long!
1867188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        return MEDIA_SCAN_RESULT_SKIPPED;
1877188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    }
1887188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    strcpy(fileSpot, name);
1897188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown
1907188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    int type = entry->d_type;
1917188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    if (type == DT_UNKNOWN) {
1927188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // If the type is unknown, stat() the file instead.
1937188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // This is sometimes necessary when accessing NFS mounted filesystems, but
1947188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // could be needed in other cases well.
1957188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        if (stat(path, &statbuf) == 0) {
1967188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            if (S_ISREG(statbuf.st_mode)) {
1977188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown                type = DT_REG;
1987188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            } else if (S_ISDIR(statbuf.st_mode)) {
1997188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown                type = DT_DIR;
200413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber            }
2017188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        } else {
202b8a805261bf0282e992d3608035e47d05a898710Steve Block            ALOGD("stat() failed for %s: %s", path, strerror(errno) );
203413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        }
2047188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    }
2057188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    if (type == DT_DIR) {
2067188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        bool childNoMedia = noMedia;
2077188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // set noMedia flag on directories with a name that starts with '.'
2087188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // for example, the Mac ".Trashes" directory
2097188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        if (name[0] == '.')
2107188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            childNoMedia = true;
2117188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown
2127188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // report the directory to the client
2137188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        if (stat(path, &statbuf) == 0) {
2147188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            status_t status = client.scanFile(path, statbuf.st_mtime, 0,
2157188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown                    true /*isDirectory*/, childNoMedia);
2167188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            if (status) {
2177188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown                return MEDIA_SCAN_RESULT_ERROR;
218413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber            }
219413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber        }
2207188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown
2217188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        // and now process its contents
2227188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        strcat(fileSpot, "/");
2237188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        MediaScanResult result = doProcessDirectory(path, pathRemaining - nameLength - 1,
2247188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown                client, childNoMedia);
2257188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        if (result == MEDIA_SCAN_RESULT_ERROR) {
2267188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            return MEDIA_SCAN_RESULT_ERROR;
2277188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        }
2287188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    } else if (type == DT_REG) {
2297188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        stat(path, &statbuf);
2307188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        status_t status = client.scanFile(path, statbuf.st_mtime, statbuf.st_size,
2317188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown                false /*isDirectory*/, noMedia);
2327188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        if (status) {
2337188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown            return MEDIA_SCAN_RESULT_ERROR;
2347188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown        }
235413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber    }
236413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
2377188e55f54a43c55fd6b96454720c447f1dc454eJeff Brown    return MEDIA_SCAN_RESULT_OK;
238413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber}
239413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber
240f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott HughesMediaAlbumArt *MediaAlbumArt::clone() {
241f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    size_t byte_size = this->size() + sizeof(MediaAlbumArt);
242f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    MediaAlbumArt *result = reinterpret_cast<MediaAlbumArt *>(malloc(byte_size));
243f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    result->mSize = this->size();
244f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    memcpy(&result->mData[0], &this->mData[0], this->size());
245f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    return result;
246f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes}
247f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes
248f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughesvoid MediaAlbumArt::init(MediaAlbumArt *instance, int32_t dataSize, const void *data) {
249f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    instance->mSize = dataSize;
250f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    memcpy(&instance->mData[0], data, dataSize);
251f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes}
252f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes
253f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott HughesMediaAlbumArt *MediaAlbumArt::fromData(int32_t dataSize, const void* data) {
254f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    size_t byte_size = sizeof(MediaAlbumArt) + dataSize;
255f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    MediaAlbumArt *result = reinterpret_cast<MediaAlbumArt *>(malloc(byte_size));
256f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    init(result, dataSize, data);
257f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes    return result;
258f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes}
259f3e80dddd7376aa9deeb27de25e1d50030a2ad98Elliott Hughes
260413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber}  // namespace android
261