/* walk a directory and check all entries if a .talk file exists */ static void check_file_thumbnails(struct tree_context* c) { int i; struct dirent *entry; struct entry* entries; DIR *dir; dir = opendir(c->currdir); if(!dir) return; /* mark all files as non talking, except the .talk ones */ entries = tree_get_entries(c); tree_lock_cache(c); for (i=0; i < c->filesindir; i++) { if (entries[i].attr & ATTR_DIRECTORY) continue; /* we're not touching directories */ if (strcasecmp(file_thumbnail_ext, &entries[i].name[strlen(entries[i].name) - strlen(file_thumbnail_ext)])) { /* no .talk file */ entries[i].attr &= ~FILE_ATTR_THUMBNAIL; /* clear */ } else { /* .talk file, we later let them speak themselves */ entries[i].attr |= FILE_ATTR_THUMBNAIL; /* set */ } } while((entry = readdir(dir)) != 0) /* walk directory */ { int ext_pos; struct dirinfo info = dir_get_info(dir, entry); ext_pos = strlen((char *)entry->d_name) - strlen(file_thumbnail_ext); if (ext_pos <= 0 /* too short to carry ".talk" */ || (info.attribute & ATTR_DIRECTORY) /* no file */ || strcasecmp((char *)&entry->d_name[ext_pos], file_thumbnail_ext)) { /* or doesn't end with ".talk", no candidate */ continue; } /* terminate the (disposable) name in dir buffer, this truncates off the ".talk" without needing an extra buffer */ entry->d_name[ext_pos] = '\0'; /* search corresponding file in dir cache */ for (i=0; i < c->filesindir; i++) { if (!strcasecmp(entries[i].name, (char *)entry->d_name)) { /* match */ entries[i].attr |= FILE_ATTR_THUMBNAIL; /* set the flag */ break; /* exit search loop, because we found it */ } } } tree_unlock_cache(c); closedir(dir); }
/* helper function to remove a non-empty directory */ static int remove_dir(char* dirname, int len) { int result = 0; DIR* dir; int dirlen = strlen(dirname); dir = opendir(dirname); if (!dir) return -1; /* open error */ while(true) { struct dirent* entry; /* walk through the directory content */ entry = readdir(dir); if (!entry) break; struct dirinfo info = dir_get_info(dir, entry); dirname[dirlen] ='\0'; /* inform the user which dir we're deleting */ splash(0, dirname); /* append name to current directory */ snprintf(dirname+dirlen, len-dirlen, "/%s", entry->d_name); if (info.attribute & ATTR_DIRECTORY) { /* remove a subdirectory */ if (!strcmp((char *)entry->d_name, ".") || !strcmp((char *)entry->d_name, "..")) continue; /* skip these */ result = remove_dir(dirname, len); /* recursion */ if (result) break; /* or better continue, delete what we can? */ } else { /* remove a file */ draw_slider(); result = remove(dirname); } if(ACTION_STD_CANCEL == get_action(CONTEXT_STD,TIMEOUT_NOBLOCK)) { splash(HZ, ID2P(LANG_CANCEL)); result = -1; break; } } closedir(dir); if (!result) { /* remove the now empty directory */ dirname[dirlen] = '\0'; /* terminate to original length */ result = rmdir(dirname); } return result; }
/* Paste a directory to a new location. Designed to be called by clipboard_paste */ static bool clipboard_pastedirectory(char *src, int srclen, char *target, int targetlen, bool copy) { DIR *srcdir; int srcdirlen = strlen(src); int targetdirlen = strlen(target); bool result = true; if (!file_exists(target)) { if (!copy) { /* Just move the directory */ result = rename(src, target) == 0; #ifdef HAVE_MULTIVOLUME if (!result && errno == EXDEV) { /* Try a copy as we're going across devices */ result = clipboard_pastedirectory(src, srclen, target, targetlen, true); /* If it worked, remove the source directory */ if (result) { remove_dir(src, srclen); } } #endif return result; } else { /* Make a directory to copy things to */ result = mkdir(target) == 0; } } /* Check if something went wrong already */ if (!result) { return result; } srcdir = opendir(src); if (!srcdir) { return false; } /* This loop will exit as soon as there's a problem */ while(result) { struct dirent* entry; /* walk through the directory content */ entry = readdir(srcdir); if (!entry) break; struct dirinfo info = dir_get_info(srcdir, entry); /* append name to current directory */ snprintf(src+srcdirlen, srclen-srcdirlen, "/%s", entry->d_name); snprintf(target+targetdirlen, targetlen-targetdirlen, "/%s", entry->d_name); DEBUGF("Copy %s to %s\n", src, target); if (info.attribute & ATTR_DIRECTORY) { /* copy/move a subdirectory */ if (!strcmp((char *)entry->d_name, ".") || !strcmp((char *)entry->d_name, "..")) continue; /* skip these */ result = clipboard_pastedirectory(src, srclen, target, targetlen, copy); /* recursion */ } else { /* copy/move a file */ draw_slider(); result = clipboard_pastefile(src, target, copy); } } closedir(srcdir); if (result) { src[srcdirlen] = '\0'; /* terminate to original length */ target[targetdirlen] = '\0'; /* terminate to original length */ } return result; }
/* load and sort directory into the tree's cache. returns NULL on failure. */ int ft_load(struct tree_context* c, const char* tempdir) { int files_in_dir = 0; int name_buffer_used = 0; struct dirent *entry; bool (*callback_show_item)(char *, int, struct tree_context *) = NULL; DIR *dir; if (tempdir) dir = opendir(tempdir); else { dir = opendir(c->currdir); callback_show_item = c->browse? c->browse->callback_show_item: NULL; } if(!dir) return -1; /* not a directory */ c->dirsindir = 0; c->dirfull = false; while ((entry = readdir(dir))) { int len; struct dirinfo info; struct entry* table = c->cache.entries; struct entry* dptr = &table[files_in_dir]; if (!entry) break; info = dir_get_info(dir, entry); len = strlen((char *)entry->d_name); /* skip directories . and .. */ if ((info.attribute & ATTR_DIRECTORY) && (((len == 1) && (!strncmp((char *)entry->d_name, ".", 1))) || ((len == 2) && (!strncmp((char *)entry->d_name, "..", 2))))) { continue; } /* Skip FAT volume ID */ if (info.attribute & ATTR_VOLUME_ID) { continue; } /* filter out dotfiles and hidden files */ if (*c->dirfilter != SHOW_ALL && ((entry->d_name[0]=='.') || (info.attribute & ATTR_HIDDEN))) { continue; } dptr->attr = info.attribute; /* check for known file types */ if ( !(dptr->attr & ATTR_DIRECTORY) ) dptr->attr |= filetype_get_attr((char *)entry->d_name); /* filter out non-visible files */ if ((!(dptr->attr & ATTR_DIRECTORY) && ( (*c->dirfilter == SHOW_PLAYLIST && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) || ((*c->dirfilter == SHOW_MUSIC && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) || (*c->dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)))) || (*c->dirfilter == SHOW_WPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_WPS) || #ifdef HAVE_LCD_BITMAP (*c->dirfilter == SHOW_FONT && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FONT) || (*c->dirfilter == SHOW_SBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_SBS) || #if CONFIG_TUNER (*c->dirfilter == SHOW_FMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMS) || #endif #endif #ifdef HAVE_REMOTE_LCD (*c->dirfilter == SHOW_RWPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RWPS) || (*c->dirfilter == SHOW_RSBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RSBS) || #if CONFIG_TUNER (*c->dirfilter == SHOW_RFMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RFMS) || #endif #endif #if CONFIG_TUNER (*c->dirfilter == SHOW_FMR && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMR) || #endif (*c->dirfilter == SHOW_M3U && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) || (*c->dirfilter == SHOW_CFG && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_CFG) || (*c->dirfilter == SHOW_LNG && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LNG) || (*c->dirfilter == SHOW_MOD && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_MOD) || (*c->dirfilter == SHOW_PLUGINS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_ROCK && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LUA) || (callback_show_item && !callback_show_item(entry->d_name, dptr->attr, c))) { continue; } if ((len > c->cache.name_buffer_size - name_buffer_used - 1) || (files_in_dir >= c->cache.max_entries)) { /* Tell the world that we ran out of buffer space */ c->dirfull = true; break; } ++files_in_dir; dptr->name = &c->cache.name_buffer[name_buffer_used]; dptr->time_write = (long)info.wrtdate<<16 | (long)info.wrttime; /* in one # */ strcpy(dptr->name, (char *)entry->d_name); name_buffer_used += len + 1; if (dptr->attr & ATTR_DIRECTORY) /* count the remaining dirs */ c->dirsindir++; } c->filesindir = files_in_dir; c->dirlength = files_in_dir; closedir(dir); compare_sort_dir = c->sort_dir; qsort(c->cache.entries, files_in_dir, sizeof(struct entry), compare); /* If thumbnail talking is enabled, make an extra run to mark files with associated thumbnails, so we don't do unsuccessful spinups later. */ if (global_settings.talk_file_clip) check_file_thumbnails(c); /* map .talk to ours */ return 0; }
static struct folder* load_folder(struct folder* parent, char *folder) { DIR *dir; char* path = get_full_path(parent); char fullpath[MAX_PATH]; struct dirent *entry; struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder)); int child_count = 0; char *first_child = NULL; if (!strcmp(folder,"/")) strlcpy(fullpath, folder, 2); else snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder); if (!this) return NULL; dir = opendir(fullpath); if (!dir) return NULL; this->previous = parent; this->name = folder; this->children = NULL; this->children_count = 0; this->depth = parent ? parent->depth + 1 : 0; while ((entry = readdir(dir))) { int len = strlen((char *)entry->d_name); struct dirinfo info; info = dir_get_info(dir, entry); /* skip anything not a directory */ if ((info.attribute & ATTR_DIRECTORY) == 0) { continue; } /* skip directories . and .. */ if ((!strcmp((char *)entry->d_name, ".")) || (!strcmp((char *)entry->d_name, ".."))) { continue; } char *name = folder_alloc_from_end(len+1); if (!name) return NULL; memcpy(name, (char *)entry->d_name, len+1); child_count++; first_child = name; } closedir(dir); /* now put the names in the array */ this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count); if (!this->children) return NULL; while (child_count) { this->children[this->children_count].name = first_child; this->children[this->children_count].folder = NULL; this->children[this->children_count].state = COLLAPSED; this->children_count++; first_child += strlen(first_child) + 1; child_count--; } qsort(this->children, this->children_count, sizeof(struct child), compare); return this; }