summaryrefslogtreecommitdiffstats
path: root/media/libmedia/MediaScanner.cpp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2009-12-03 11:31:19 -0800
committerAndreas Huber <andih@google.com>2009-12-03 13:21:54 -0800
commit413f523afe96aff02d2b0a7459127b8f67b2b43c (patch)
tree395251a728a780bf6d46e4ef4a721e0cf4a77f3a /media/libmedia/MediaScanner.cpp
parent8908d616cc9d74f9fe2c17f1d8d9335ee28c290d (diff)
downloadframeworks_av-413f523afe96aff02d2b0a7459127b8f67b2b43c.zip
frameworks_av-413f523afe96aff02d2b0a7459127b8f67b2b43c.tar.gz
frameworks_av-413f523afe96aff02d2b0a7459127b8f67b2b43c.tar.bz2
Refactor MediaScanner. Some steps on the way towards being able to build the tree without OpenCore.
Diffstat (limited to 'media/libmedia/MediaScanner.cpp')
-rw-r--r--media/libmedia/MediaScanner.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
new file mode 100644
index 0000000..f201667
--- /dev/null
+++ b/media/libmedia/MediaScanner.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/mediascanner.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+
+namespace android {
+
+MediaScanner::MediaScanner()
+ : mLocale(NULL) {
+}
+
+MediaScanner::~MediaScanner() {
+ setLocale(NULL);
+}
+
+void MediaScanner::setLocale(const char *locale) {
+ if (mLocale) {
+ free(mLocale);
+ mLocale = NULL;
+ }
+ if (locale) {
+ mLocale = strdup(locale);
+ }
+}
+
+const char *MediaScanner::locale() const {
+ return mLocale;
+}
+
+status_t MediaScanner::processDirectory(
+ const char *path, const char *extensions,
+ MediaScannerClient &client,
+ ExceptionCheck exceptionCheck, void *exceptionEnv) {
+ int pathLength = strlen(path);
+ if (pathLength >= PATH_MAX) {
+ return UNKNOWN_ERROR;
+ }
+ char* pathBuffer = (char *)malloc(PATH_MAX + 1);
+ if (!pathBuffer) {
+ return UNKNOWN_ERROR;
+ }
+
+ int pathRemaining = PATH_MAX - pathLength;
+ strcpy(pathBuffer, path);
+ if (pathBuffer[pathLength - 1] != '/') {
+ pathBuffer[pathLength] = '/';
+ pathBuffer[pathLength + 1] = 0;
+ --pathRemaining;
+ }
+
+ client.setLocale(locale());
+
+ status_t result =
+ doProcessDirectory(
+ pathBuffer, pathRemaining, extensions, client,
+ exceptionCheck, exceptionEnv);
+
+ free(pathBuffer);
+
+ return result;
+}
+
+static bool fileMatchesExtension(const char* path, const char* extensions) {
+ char* extension = strrchr(path, '.');
+ if (!extension) return false;
+ ++extension; // skip the dot
+ if (extension[0] == 0) return false;
+
+ while (extensions[0]) {
+ char* comma = strchr(extensions, ',');
+ size_t length = (comma ? comma - extensions : strlen(extensions));
+ if (length == strlen(extension) && strncasecmp(extension, extensions, length) == 0) return true;
+ extensions += length;
+ if (extensions[0] == ',') ++extensions;
+ }
+
+ return false;
+}
+
+status_t MediaScanner::doProcessDirectory(
+ char *path, int pathRemaining, const char *extensions,
+ MediaScannerClient &client, ExceptionCheck exceptionCheck,
+ void *exceptionEnv) {
+ // place to copy file or directory name
+ char* fileSpot = path + strlen(path);
+ struct dirent* entry;
+
+ // ignore directories that contain a ".nomedia" file
+ if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
+ strcpy(fileSpot, ".nomedia");
+ if (access(path, F_OK) == 0) {
+ LOGD("found .nomedia, skipping directory\n");
+ fileSpot[0] = 0;
+ client.addNoMediaFolder(path);
+ return OK;
+ }
+
+ // restore path
+ fileSpot[0] = 0;
+ }
+
+ DIR* dir = opendir(path);
+ if (!dir) {
+ LOGD("opendir %s failed, errno: %d", path, errno);
+ return UNKNOWN_ERROR;
+ }
+
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+
+ int type = entry->d_type;
+ if (type == DT_UNKNOWN) {
+ // If the type is unknown, stat() the file instead.
+ // This is sometimes necessary when accessing NFS mounted filesystems, but
+ // could be needed in other cases well.
+ struct stat statbuf;
+ if (stat(path, &statbuf) == 0) {
+ if (S_ISREG(statbuf.st_mode)) {
+ type = DT_REG;
+ } else if (S_ISDIR(statbuf.st_mode)) {
+ type = DT_DIR;
+ }
+ } else {
+ LOGD("stat() failed for %s: %s", path, strerror(errno) );
+ }
+ }
+ if (type == DT_REG || type == DT_DIR) {
+ int nameLength = strlen(name);
+ bool isDirectory = (type == DT_DIR);
+
+ if (nameLength > pathRemaining || (isDirectory && nameLength + 1 > pathRemaining)) {
+ // path too long!
+ continue;
+ }
+
+ strcpy(fileSpot, name);
+ if (isDirectory) {
+ // ignore directories with a name that starts with '.'
+ // for example, the Mac ".Trashes" directory
+ if (name[0] == '.') continue;
+
+ strcat(fileSpot, "/");
+ int err = doProcessDirectory(path, pathRemaining - nameLength - 1, extensions, client, exceptionCheck, exceptionEnv);
+ if (err) {
+ // pass exceptions up - ignore other errors
+ if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
+ LOGE("Error processing '%s' - skipping\n", path);
+ continue;
+ }
+ } else if (fileMatchesExtension(path, extensions)) {
+ struct stat statbuf;
+ stat(path, &statbuf);
+ if (statbuf.st_size > 0) {
+ client.scanFile(path, statbuf.st_mtime, statbuf.st_size);
+ }
+ if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
+ }
+ }
+ }
+
+ closedir(dir);
+ return OK;
+failure:
+ closedir(dir);
+ return -1;
+}
+
+} // namespace android