MediaScanner.cpp revision 413f523afe96aff02d2b0a7459127b8f67b2b43c
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 17413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber#include <media/mediascanner.h> 18413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 19413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber#include <sys/stat.h> 20413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber#include <dirent.h> 21413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 22413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Hubernamespace android { 23413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 24413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas HuberMediaScanner::MediaScanner() 25413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber : mLocale(NULL) { 26413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} 27413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 28413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas HuberMediaScanner::~MediaScanner() { 29413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber setLocale(NULL); 30413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} 31413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 32413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Hubervoid MediaScanner::setLocale(const char *locale) { 33413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (mLocale) { 34413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber free(mLocale); 35413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber mLocale = NULL; 36413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 37413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (locale) { 38413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber mLocale = strdup(locale); 39413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 40413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} 41413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 42413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberconst char *MediaScanner::locale() const { 43413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return mLocale; 44413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} 45413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 46413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberstatus_t MediaScanner::processDirectory( 47413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber const char *path, const char *extensions, 48413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber MediaScannerClient &client, 49413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber ExceptionCheck exceptionCheck, void *exceptionEnv) { 50413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber int pathLength = strlen(path); 51413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (pathLength >= PATH_MAX) { 52413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return UNKNOWN_ERROR; 53413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 54413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber char* pathBuffer = (char *)malloc(PATH_MAX + 1); 55413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (!pathBuffer) { 56413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return UNKNOWN_ERROR; 57413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 58413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 59413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber int pathRemaining = PATH_MAX - pathLength; 60413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber strcpy(pathBuffer, path); 61413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (pathBuffer[pathLength - 1] != '/') { 62413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber pathBuffer[pathLength] = '/'; 63413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber pathBuffer[pathLength + 1] = 0; 64413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber --pathRemaining; 65413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 66413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 67413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber client.setLocale(locale()); 68413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 69413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber status_t result = 70413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber doProcessDirectory( 71413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber pathBuffer, pathRemaining, extensions, client, 72413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber exceptionCheck, exceptionEnv); 73413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 74413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber free(pathBuffer); 75413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 76413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return result; 77413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} 78413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 79413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberstatic bool fileMatchesExtension(const char* path, const char* extensions) { 80413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber char* extension = strrchr(path, '.'); 81413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (!extension) return false; 82413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber ++extension; // skip the dot 83413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (extension[0] == 0) return false; 84413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 85413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber while (extensions[0]) { 86413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber char* comma = strchr(extensions, ','); 87413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber size_t length = (comma ? comma - extensions : strlen(extensions)); 88413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (length == strlen(extension) && strncasecmp(extension, extensions, length) == 0) return true; 89413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber extensions += length; 90413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (extensions[0] == ',') ++extensions; 91413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 92413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 93413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return false; 94413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} 95413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 96413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberstatus_t MediaScanner::doProcessDirectory( 97413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber char *path, int pathRemaining, const char *extensions, 98413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber MediaScannerClient &client, ExceptionCheck exceptionCheck, 99413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber void *exceptionEnv) { 100413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // place to copy file or directory name 101413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber char* fileSpot = path + strlen(path); 102413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber struct dirent* entry; 103413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 104413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // ignore directories that contain a ".nomedia" file 105413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (pathRemaining >= 8 /* strlen(".nomedia") */ ) { 106413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber strcpy(fileSpot, ".nomedia"); 107413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (access(path, F_OK) == 0) { 108413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber LOGD("found .nomedia, skipping directory\n"); 109413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber fileSpot[0] = 0; 110413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber client.addNoMediaFolder(path); 111413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return OK; 112413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 113413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 114413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // restore path 115413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber fileSpot[0] = 0; 116413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 117413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 118413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber DIR* dir = opendir(path); 119413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (!dir) { 120413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber LOGD("opendir %s failed, errno: %d", path, errno); 121413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return UNKNOWN_ERROR; 122413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 123413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 124413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber while ((entry = readdir(dir))) { 125413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber const char* name = entry->d_name; 126413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 127413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // ignore "." and ".." 128413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { 129413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber continue; 130413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 131413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 132413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber int type = entry->d_type; 133413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (type == DT_UNKNOWN) { 134413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // If the type is unknown, stat() the file instead. 135413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // This is sometimes necessary when accessing NFS mounted filesystems, but 136413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // could be needed in other cases well. 137413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber struct stat statbuf; 138413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (stat(path, &statbuf) == 0) { 139413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (S_ISREG(statbuf.st_mode)) { 140413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber type = DT_REG; 141413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } else if (S_ISDIR(statbuf.st_mode)) { 142413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber type = DT_DIR; 143413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 144413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } else { 145413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber LOGD("stat() failed for %s: %s", path, strerror(errno) ); 146413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 147413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 148413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (type == DT_REG || type == DT_DIR) { 149413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber int nameLength = strlen(name); 150413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber bool isDirectory = (type == DT_DIR); 151413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 152413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (nameLength > pathRemaining || (isDirectory && nameLength + 1 > pathRemaining)) { 153413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // path too long! 154413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber continue; 155413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 156413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 157413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber strcpy(fileSpot, name); 158413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (isDirectory) { 159413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // ignore directories with a name that starts with '.' 160413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // for example, the Mac ".Trashes" directory 161413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (name[0] == '.') continue; 162413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 163413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber strcat(fileSpot, "/"); 164413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber int err = doProcessDirectory(path, pathRemaining - nameLength - 1, extensions, client, exceptionCheck, exceptionEnv); 165413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (err) { 166413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber // pass exceptions up - ignore other errors 167413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure; 168413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber LOGE("Error processing '%s' - skipping\n", path); 169413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber continue; 170413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 171413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } else if (fileMatchesExtension(path, extensions)) { 172413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber struct stat statbuf; 173413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber stat(path, &statbuf); 174413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (statbuf.st_size > 0) { 175413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber client.scanFile(path, statbuf.st_mtime, statbuf.st_size); 176413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 177413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure; 178413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 179413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 180413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber } 181413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 182413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber closedir(dir); 183413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return OK; 184413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huberfailure: 185413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber closedir(dir); 186413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber return -1; 187413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} 188413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber 189413f523afe96aff02d2b0a7459127b8f67b2b43cAndreas Huber} // namespace android 190