static int iterate_subdirs(const MEDIADB_DESCR_T *pMediaDb, const char *pathDb, const char *pathMedia, int level, unsigned int iterIdx) { DIR *pdir; FILE_LIST_T fileList; FILE_LIST_ENTRY_T *pFileListEntry; struct dirent *direntry; char bufMedia[VSX_MAX_PATH_LEN]; char bufDb[VSX_MAX_PATH_LEN]; char tmpfile[VSX_MAX_PATH_LEN]; int rc = 0; int rcsub = 0; int fileListChanged = 0; int numTnCreated = 0; int highestTn; struct stat st; //fprintf(stdout, "%d dir:'%s' '%s'\n", level, pathDb, pathMedia); // // TODO: escape invalid chars in pathnames ' , & # $ ' // if(level >= SRVMEDIA_MAX_LEVELS) { LOG(X_WARNING("Path '%s' exceeded max number of subdirs under %s"), pathMedia, pMediaDb->mediaDir); return -1; } if(!(pdir = fileops_OpenDir(pathMedia))) { return -1; } memset(&fileList, 0, sizeof(fileList)); file_list_read(pathDb, &fileList); strncpy(fileList.pathmedia, pathMedia, sizeof(fileList.pathmedia) - 1); while((direntry = fileops_ReadDir(pdir)) && g_proc_exit == 0) { //fprintf(stdout, "- %d %s\n", level, direntry->d_name); if(direntry->d_type & DT_DIR) { if(mediadb_isvalidDirName(pMediaDb, direntry->d_name)) { if(mediadb_prepend_dir(pathDb, direntry->d_name, bufDb, sizeof(bufDb)) < 0) { LOG(X_WARNING("Unable to concatenate subdir %s %s"), bufDb, direntry->d_name); } else if(mediadb_prepend_dir(pathMedia, direntry->d_name, bufMedia, sizeof(bufMedia)) < 0) { LOG(X_WARNING("Unable to concatenate subdir %s %s"), bufMedia, direntry->d_name); } else { if(numTnCreated > 1) { file_list_write(pathDb, &fileList); } if((rcsub = iterate_subdirs(pMediaDb, bufDb, bufMedia, level+1, iterIdx)) < 0) { rc = rcsub; } if(g_proc_exit != 0) { break; } } } else if(direntry->d_name[0] != '.') { //fprintf(stderr, "skipping directory '%s'\n", direntry->d_name); } } else if(mediadb_isvalidFileName(pMediaDb, direntry->d_name, 1, 0)) { //fprintf(stdout, "%d media file %s '%s'\n", level, pathMedia, direntry->d_name); if(fileops_stat(pathDb, &st) != 0 && mediadb_mkdirfull(pMediaDb->dbDir, pathDb) < 0) { continue; } if(mediadb_prepend_dir(pathDb, direntry->d_name, bufDb, sizeof(bufDb)) < 0) { LOG(X_ERROR("Unable to concatenate subdir %s %s"), bufDb, direntry->d_name); continue; } else if(mediadb_prepend_dir(pathMedia, direntry->d_name, bufMedia, sizeof(bufMedia)) < 0) { LOG(X_ERROR("Unable to concatenate subdir %s %s"), bufMedia, direntry->d_name); continue; } if(update_fileentry(&fileList, direntry->d_name, bufMedia, &pFileListEntry) > 0) { LOG(X_DEBUG("'%s' changed ('%s')"), direntry->d_name, pFileListEntry->name); fileListChanged = 1; if(pFileListEntry->numTn < 0) { pFileListEntry->numTn = 0; } } if(pMediaDb->avcthumb && pFileListEntry && pFileListEntry->vstr[0] != '\0' && pFileListEntry->numTn != -1) { // // On very first iteration, check all thumbnails // snprintf(tmpfile, sizeof(tmpfile), "%s%s."NOTN_EXT, bufDb, pMediaDb->tn_suffix); if(fileops_stat(tmpfile, &st) == 0 && iterIdx > 0) { // // Ignore thumbnail creation if the .notn file has been // previously created on an error condition // } else // // Update thumbnail info // if((highestTn = createTn(pMediaDb, pFileListEntry, bufMedia, bufDb, pFileListEntry->numTn, 1)) > pFileListEntry->numTn || highestTn == -1) { pFileListEntry->numTn = highestTn; fileListChanged = 1; // Periodically update the db file if(numTnCreated > 10) { file_list_write(pathDb, &fileList); numTnCreated = 0; } } } } else { //fprintf(stdout, "skipping %s '%s'\n", pathMedia, direntry->d_name); } } fileops_CloseDir(pdir); if(g_proc_exit == 0) { if(file_list_removeunmarked(&fileList) || fileListChanged) { LOG(X_DEBUG("Writing file index in %s"), pathDb); //fprintf(stdout, "level:%u\n", level); file_list_write(pathDb, &fileList); } // //Remove thumbnails which are not included in the fileList // clearTn(pathMedia, pathDb, &fileList); } file_list_close(&fileList); return rc; }
DIR_ENTRY_LIST_T *direntry_getentries(const MEDIADB_DESCR_T *pMediaDb, const char *dir, const char *fidxdir, const char *searchstr, int includedirs, unsigned int startidx, unsigned int max, enum DIR_SORT sort) { DIR *pdir; int rc = 0; struct dirent *direntry; char path[VSX_MAX_PATH_LEN]; struct stat st; int addEntry; FILE_LIST_T fileList; FILE_LIST_ENTRY_T *pFileEntry = NULL; META_FILE_T metaFile; DIR_ENTRY_LIST_T *pEntryList = NULL; DIR_ENTRY_T entry; DIR_ENTRY_T *pEntry; const char *pdispname; unsigned int idx = 0; unsigned int cnt = 0; unsigned int cntInDir = 0; COMPARE_DIR_ENTRY compareFunc = direntry_getcompfunc(sort); VSX_DEBUG_MGR( LOG(X_DEBUG("MGR - direntry_getentries dir: '%s', fidxdir: '%s', searchstr: '%s', " "includedirs: %d, startidx: %d, max: %d"), dir, fidxdir, searchstr, includedirs, startidx, max)); if(!(pdir = fileops_OpenDir(dir))) { return NULL; } memset(&fileList, 0, sizeof(fileList)); if(fidxdir) { file_list_read(fidxdir, &fileList); } // // Read the directory wide metafile to get a list of 'ignore' entries // memset(&metaFile, 0, sizeof(metaFile)); mediadb_prepend_dir(dir, METAFILE_DEFAULT, path, sizeof(path)); if(fileops_stat(path, &st) == 0) { metafile_open(path, &metaFile, 1, 1); } while((direntry = fileops_ReadDir(pdir))) { VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries d_name: '%s', isdir: %d"), direntry->d_name, (direntry->d_type & DT_DIR)) ); if(is_entry_ignored(metaFile.pignoreList, direntry->d_name)) { continue; } if(!(pdispname = find_entry_description(metaFile.pDescriptionList, direntry->d_name))) { pdispname = direntry->d_name; } if(searchstr && !is_match_search(pdispname, NULL, searchstr)) { continue; } memset(&entry, 0, sizeof(entry)); strncpy(entry.d_name, direntry->d_name, sizeof(entry.d_name) - 1); if(pdispname != direntry->d_name) { strncpy(entry.displayname, pdispname, sizeof(entry.displayname) - 1); } entry.d_type = direntry->d_type; addEntry = 0; if(direntry->d_type & DT_DIR) { if(includedirs && mediadb_isvalidDirName(pMediaDb, direntry->d_name)) { addEntry = 1; } } else if(mediadb_isvalidFileName(pMediaDb, direntry->d_name, 1, 1)) { mediadb_prepend_dir(dir, direntry->d_name, path, sizeof(path)); if(fileops_stat(path, &st) == 0) { entry.size = st.st_size; //entry.tm = st.st_mtime; entry.tm = st.st_ctime; if(fidxdir && (pFileEntry = file_list_find(&fileList, direntry->d_name))) { entry.numTn = pFileEntry->numTn; entry.duration = pFileEntry->duration; } addEntry = 1; } } if(addEntry) { VSX_DEBUG_MGR( LOG(X_DEBUGV("MGR - direntry_getentries add d_name: '%s', isdir: %d"), direntry->d_name, (direntry->d_type & DT_DIR)) ); if(compareFunc || (idx >= startidx && (max == 0 || cnt < max))) { if(cnt >= DIR_ENTRY_LIST_BUFNUM) { LOG(X_WARNING("Not showing more than %d entries in %s"), cnt, dir); break; } else if(!(pEntry = direntry_addsorted(&pEntryList, &entry, compareFunc))) { LOG(X_ERROR("Failed to add directory entry '%s' to list"), direntry->d_name); rc = -1; break; } cnt++; } idx++; cntInDir++; } } // // Since when a sort is requested we have to sort every entry in the directory. Now we can move the head pointer // to the first desired entry // if(pEntryList && compareFunc && startidx > 0) { pEntry = pEntryList->pHead; for(idx = 0; idx < startidx; idx++) { pEntry = pEntry->pnext; cnt--; } pEntryList->pHead = pEntry; if(cnt > max) { cnt = max; } //fprintf(stderr, "moved phead to %s, cnt:%d, cntInDir:%d\n", pEntryList->pHead ? pEntryList->pHead->d_name : NULL, cnt, cntInDir); } fileops_CloseDir(pdir); if(fidxdir) { file_list_close(&fileList); } metafile_close(&metaFile); if(rc == 0 && !pEntryList) { // If the user requested an index out of bounds, return an empty list with // a valid cntTotalInDir pEntryList = (DIR_ENTRY_LIST_T *) avc_calloc(1, sizeof(DIR_ENTRY_LIST_T)); } if(pEntryList) { pEntryList->cntTotal = cnt; pEntryList->cntTotalInDir = cntInDir; } //if(pEntryList) fprintf(stderr, "DIR '%s' num:%d numAlloc:%d pnext:0x%x TOTAL:%d/%d\n", dir, pEntryList->num, pEntryList->numAlloc, pEntryList->pnext, pEntryList->cntTotal, pEntryList->cntTotalInDir); return pEntryList; }