MediaScanResult MediaScanner::doProcessDirectory( char *path, int pathRemaining, MediaScannerClient &client, bool noMedia) { #ifndef ANDROID_DEFAULT_CODE LOGV("doProcessDirectory %s extensions: %s\n", path, extensions); #endif // place to copy file or directory name char* fileSpot = path + strlen(path); struct dirent* entry; if (shouldSkipDirectory(path)) { LOGD("Skipping: %s", path); return MEDIA_SCAN_RESULT_OK; } // Treat all files as non-media in directories that contain a ".nomedia" file if (pathRemaining >= 8 /* strlen(".nomedia") */ ) { strcpy(fileSpot, ".nomedia"); if (access(path, F_OK) == 0) { LOGV("found .nomedia, setting noMedia flag\n"); noMedia = true; } // restore path fileSpot[0] = 0; } DIR* dir = opendir(path); if (!dir) { LOGW("Error opening directory '%s', skipping: %s.", path, strerror(errno)); return MEDIA_SCAN_RESULT_SKIPPED; } #ifndef ANDROID_DEFAULT_CODE //--start--find the best file to set default ringtone. static bool isSetRingtone = false; static bool isSetNotification = false; static bool isSetAlarm = false; bool needFindFile = false; if (isSetRingtone == false) { if (strcmp(path, "/system/media/audio/ringtones/") == 0) { needFindFile = true; isSetRingtone = true; } } if (isSetNotification == false) { if (strcmp(path, "/system/media/audio/notifications/") == 0) { needFindFile = true; isSetNotification = true; } } if (isSetAlarm == false) { if (strcmp(path, "/system/media/audio/alarms/") == 0) { needFindFile = true; isSetAlarm = true; } } if (needFindFile) { char* findFile = 0; 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) { int nameLength = strlen(name); if (nameLength > pathRemaining) { // path too long! continue; } int pathLength = strlen(path); strcpy(fileSpot, name); //if (fileMatchesExtension(path, extensions)) { if (findFile == 0) { findFile = new char[pathLength + pathRemaining]; strcpy(findFile, path); } else { if (strcmp(path, findFile) < 0) { strcpy(findFile, path); } } // } } } if (findFile != 0) { struct stat statbuf; stat(findFile, &statbuf); if (statbuf.st_size > 0) { LOGD("find the default audio file = %s", findFile); // client.scanFile(findFile, statbuf.st_mtime, statbuf.st_size); //need audio owner check client.scanFile(findFile, statbuf.st_mtime, statbuf.st_size,false,false); } delete findFile; findFile = 0; // if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure; } else { LOGD("Can not get the best file for ringtone"); } closedir(dir); //restore the path fileSpot[0] = 0; //reopen the dir for android's default deal. dir = opendir(path); if (!dir) { LOGD("opendir %s failed, errno: %d", path, errno); return MEDIA_SCAN_RESULT_ERROR; } } //--end--find the best file to set default ringtone. #endif MediaScanResult result = MEDIA_SCAN_RESULT_OK; while ((entry = readdir(dir))) { if (doProcessDirectoryEntry(path, pathRemaining, client, noMedia, entry, fileSpot) == MEDIA_SCAN_RESULT_ERROR) { result = MEDIA_SCAN_RESULT_ERROR; break; } } closedir(dir); return result; }
MediaScanResult MediaScanner::doProcessDirectoryEntry( char *path, int pathRemaining, MediaScannerClient &client, bool noMedia, struct dirent* entry, char* fileSpot) { struct stat statbuf; const char* name = entry->d_name; #ifndef ANDROID_DEFAULT_CODE ALOGV("doProcessDirectoryEntry: %s \n", path); #endif // ignore "." and ".." if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { return MEDIA_SCAN_RESULT_SKIPPED; } int nameLength = strlen(name); if (nameLength + 1 > pathRemaining) { // path too long! return MEDIA_SCAN_RESULT_SKIPPED; } strcpy(fileSpot, name); 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. 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 { ALOGD("stat() failed for %s: %s", path, strerror(errno) ); } } if (type == DT_DIR) { bool childNoMedia = noMedia; // set noMedia flag on directories with a name that starts with '.' // for example, the Mac ".Trashes" directory if (name[0] == '.') childNoMedia = true; // report the directory to the client if (stat(path, &statbuf) == 0) { status_t status = client.scanFile(path, statbuf.st_mtime, 0, true /*isDirectory*/, childNoMedia); if (status) { return MEDIA_SCAN_RESULT_ERROR; } } // and now process its contents strcat(fileSpot, "/"); MediaScanResult result = doProcessDirectory(path, pathRemaining - nameLength - 1, client, childNoMedia); if (result == MEDIA_SCAN_RESULT_ERROR) { return MEDIA_SCAN_RESULT_ERROR; } } else if (type == DT_REG) { stat(path, &statbuf); status_t status = client.scanFile(path, statbuf.st_mtime, statbuf.st_size, false /*isDirectory*/, noMedia); if (status) { return MEDIA_SCAN_RESULT_ERROR; } } return MEDIA_SCAN_RESULT_OK; }
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; char* tempPathBuffer = NULL; char* pathBuffer = NULL; DIR* dir = NULL; int pathLength = strlen(path); if (pathLength >= PATH_MAX) { goto failure; } pathBuffer = (char *)malloc(PATH_MAX + 1); tempPathBuffer = (char *)malloc(PATH_MAX + 1); if (!pathBuffer || !tempPathBuffer) { goto failure; } strcpy(pathBuffer, path); // 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); goto success; } // restore path fileSpot[0] = 0; } dir = opendir(path); if (!dir) { LOGD("opendir %s failed, errno: %d", path, errno); goto failure; } 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; int tempPathLength = strlen(pathBuffer) + strlen(name); if (tempPathLength >= PATH_MAX) { goto failure; } strcpy(tempPathBuffer, pathBuffer); strcat(tempPathBuffer, name); if (stat(tempPathBuffer, &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: %s", path, name, 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); success: free(pathBuffer); free(tempPathBuffer); return OK; failure: free(pathBuffer); free(tempPathBuffer); closedir(dir); return -1; }