From 735f4537309d4a66e16dd020fa99149a9d5f8d29 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Thu, 17 Nov 2005 19:31:29 +0000 Subject: [PATCH] Added dircache support to playlist. Now playlist filename pointers are automatically accuired from dircache. WPS UI response with dircache enabled should be instant. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7931 a1c6a512-1295-4272-9138-f99709370657 --- apps/filetree.c | 1 + apps/lang/english.lang | 6 + apps/playback.c | 137 ++++++++++++++--------- apps/playlist.c | 216 +++++++++++++++++++++++++++++++++--- apps/playlist.h | 3 +- apps/wps.c | 4 +- firmware/common/dircache.c | 41 +++++++ firmware/include/dircache.h | 3 + 8 files changed, 336 insertions(+), 75 deletions(-) diff --git a/apps/filetree.c b/apps/filetree.c index a873d85f1c..a9670e1be7 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -340,6 +340,7 @@ int ft_enter(struct tree_context* c) int start_index=0; lcd_stop_scroll(); + gui_syncsplash(0, true, str(LANG_WAIT)); switch ( file->attr & TREE_ATTR_MASK ) { case TREE_ATTR_M3U: if (bookmark_autoload(buf)) diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 4e712a22af..6afcb573c9 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -3431,3 +3431,9 @@ eng: "Clear current presets?" voice: "Clear current presets?" new: +id: LANG_WAIT +desc: general please wait splash +eng: "=== Please Wait ===" +voice: "Please wait" +new: + diff --git a/apps/playback.c b/apps/playback.c index 7f28331b75..b68cb641fe 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -165,9 +165,6 @@ static volatile int buf_widx; /* Step count to the next unbuffered track. */ static int last_peek_offset; -/* Index of the last buffered track. */ -static int last_index; - /* Track information (count in file buffer, read/write indexes for track ring structure. */ int track_count; @@ -589,7 +586,7 @@ static bool rebuffer_and_seek(int newpos) while (cur_ti->available == 0 && cur_ti->filerem > 0) { yield(); - if (ci.stop_codec || ci.reload_codec) + if (ci.stop_codec || ci.reload_codec || !queue_empty(&audio_queue)) return false; } @@ -1048,8 +1045,6 @@ bool audio_load_track(int offset, bool start_play, int peek_offset) if (tracks[track_widx].filesize != 0) return false; - last_index = playlist_get_display_index(); - peek_again: /* Get track name from current playlist read position. */ logf("Buffering track:%d/%d", track_widx, track_ridx); @@ -1456,7 +1451,6 @@ void audio_update_trackinfo(void) } else { pcmbuf_add_event(codec_track_changed); } - last_index = playlist_get_display_index(); } static void audio_stop_playback(void) @@ -1519,8 +1513,8 @@ bool codec_request_next_track_callback(void) { if (current_codec == CODEC_IDX_VOICE) { voice_remaining = 0; - /* Terminate the codec if they are messages waiting on the queue or - core has been requested the codec to be terminated. */ + /* Terminate the codec if there are messages waiting on the queue or + the core has been requested the codec to be terminated. */ return !ci_voice.stop_codec && queue_empty(&voice_codec_queue); } @@ -1531,12 +1525,7 @@ bool codec_request_next_track_callback(void) /* Advance to next track. */ if (ci.reload_codec && new_track > 0) { - if (!playlist_check(new_track)) { - ci.reload_codec = false; - return false; - } last_peek_offset--; - playlist_next(new_track); if (++track_ridx == MAX_TRACK) track_ridx = 0; @@ -1549,7 +1538,6 @@ bool codec_request_next_track_callback(void) if (tracks[track_ridx].filesize == 0) { logf("Loading from disk..."); new_track = 0; - last_index = -1; queue_post(&audio_queue, AUDIO_PLAY, 0); return false; } @@ -1557,12 +1545,7 @@ bool codec_request_next_track_callback(void) /* Advance to previous track. */ else if (ci.reload_codec && new_track < 0) { - if (!playlist_check(new_track)) { - ci.reload_codec = false; - return false; - } last_peek_offset++; - playlist_next(new_track); if (--track_ridx < 0) track_ridx = MAX_TRACK-1; if (tracks[track_ridx].filesize == 0 || @@ -1570,7 +1553,6 @@ bool codec_request_next_track_callback(void) /*+ (off_t)tracks[track_ridx].codecsize*/ > filebuflen) { logf("Loading from disk..."); new_track = 0; - last_index = -1; queue_post(&audio_queue, AUDIO_PLAY, 0); return false; } @@ -1597,7 +1579,6 @@ bool codec_request_next_track_callback(void) logf("No more tracks [2]"); ci.stop_codec = true; new_track = 0; - last_index = -1; queue_post(&audio_queue, AUDIO_PLAY, 0); return false; } @@ -1652,7 +1633,6 @@ static void initiate_track_change(int peek_index) /* Detect if disk is spinning.. */ if (filling) { - playlist_next(peek_index); queue_post(&audio_queue, AUDIO_PLAY, 0); } else { new_track = peek_index; @@ -1677,35 +1657,49 @@ static void initiate_dir_change(int direction) void audio_thread(void) { struct event ev; + int last_tick = 0; + bool play_pending = false; while (1) { - yield_codecs(); - - audio_check_buffer(); + if (!play_pending) + { + yield_codecs(); + audio_check_buffer(); + } + else + { + // ata_spin(); + sleep(1); + } queue_wait_w_tmo(&audio_queue, &ev, 0); + if (ev.id == SYS_TIMEOUT && play_pending) + { + ev.id = AUDIO_PLAY; + ev.data = 0; + } + switch (ev.id) { case AUDIO_PLAY: - /* Refuse to start playback if we are already playing - the requested track. This is needed because when skipping - tracks fast, AUDIO_PLAY commands will get queued with the - the same track and playback will stutter. */ - if (last_index == playlist_get_display_index() && playing - && pcm_is_playing()) { - logf("already playing req. track"); + /* Don't start playing immediately if user is skipping tracks + * fast to prevent UI lag. */ + track_count = 0; + last_peek_offset = 0; + if (current_tick - last_tick < HZ/2) + { + play_pending = true; break ; } - + play_pending = false; + /* Do not start crossfading if audio is paused. */ - if (paused) { - audio_stop_playback(); - paused = false; - } + if (paused) + pcmbuf_play_stop(); #ifdef CONFIG_TUNER /* check if radio is playing */ - if(radio_get_status() != FMRADIO_OFF){ - radio_stop(); + if (radio_get_status() != FMRADIO_OFF) { + radio_stop(); } #endif @@ -1751,15 +1745,13 @@ void audio_thread(void) case AUDIO_NEXT: logf("audio_next"); - if (global_settings.beep) - pcmbuf_beep(5000, 100, 2500*global_settings.beep); + last_tick = current_tick; initiate_track_change(1); break ; case AUDIO_PREV: logf("audio_prev"); - if (global_settings.beep) - pcmbuf_beep(5000, 100, 2500*global_settings.beep); + last_tick = current_tick; initiate_track_change(-1); break; @@ -1793,7 +1785,7 @@ void audio_thread(void) // audio_change_track(); break ; -#ifndef SIMULATOR +#ifndef SIMULATOR case SYS_USB_CONNECTED: logf("USB: Audio core"); audio_stop_playback(); @@ -1973,12 +1965,28 @@ void voice_init(void) struct mp3entry* audio_current_track(void) { - // logf("audio_current_track"); + const char *filename; + const char *p; + static struct mp3entry temp_id3; if (track_count > 0 && cur_ti->taginfo_ready) return (struct mp3entry *)&cur_ti->id3; - else - return NULL; + else { + filename = playlist_peek(0); + if (!filename) + filename = "No file!"; + p = strrchr(filename, '/'); + if (!p) + p = filename; + else + p++; + + memset(&temp_id3, 0, sizeof(struct mp3entry)); + strncpy(temp_id3.path, p, sizeof(temp_id3.path)-1); + temp_id3.title = &temp_id3.path[0]; + + return &temp_id3; + } } struct mp3entry* audio_next_track(void) @@ -1994,16 +2002,12 @@ struct mp3entry* audio_next_track(void) if (!tracks[next_idx].taginfo_ready) return NULL; - //logf("audio_next_track"); - return &tracks[next_idx].id3; } bool audio_has_changed_track(void) { - if (track_changed && track_count > 0 && playing) { - if (!cur_ti->taginfo_ready) - return false; + if (track_changed) { track_changed = false; return true; } @@ -2014,7 +2018,6 @@ bool audio_has_changed_track(void) void audio_play(int offset) { logf("audio_play"); - last_index = -1; queue_post(&audio_queue, AUDIO_PLAY, (void *)offset); } @@ -2043,11 +2046,37 @@ void audio_resume(void) void audio_next(void) { + /* Prevent UI lag and update the WPS immediately. */ + if (global_settings.beep) + pcmbuf_beep(5000, 100, 2500*global_settings.beep); + + if (!playlist_check(1)) + return ; + playlist_next(1); + track_changed = true; + + /* Force WPS to update even if audio thread is blocked spinning. */ + if (mutex_bufferfill.locked) + cur_ti->taginfo_ready = false; + queue_post(&audio_queue, AUDIO_NEXT, 0); } void audio_prev(void) { + /* Prevent UI lag and update the WPS immediately. */ + if (global_settings.beep) + pcmbuf_beep(5000, 100, 2500*global_settings.beep); + + if (!playlist_check(-1)) + return ; + playlist_next(-1); + track_changed = true; + + /* Force WPS to update even if audio thread is blocked spinning. */ + if (mutex_bufferfill.locked) + cur_ti->taginfo_ready = false; + queue_post(&audio_queue, AUDIO_PREV, 0); } diff --git a/apps/playlist.c b/apps/playlist.c index a2f46cf99f..ee09eecf40 100644 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -86,6 +86,9 @@ #include "button.h" #include "filetree.h" #include "abrepeat.h" +#include "dircache.h" +#include "thread.h" +#include "usb.h" #ifdef HAVE_LCD_BITMAP #include "icons.h" #include "widgets.h" @@ -162,7 +165,7 @@ static int get_next_index(const struct playlist_info* playlist, int steps, static void find_and_set_playlist_index(struct playlist_info* playlist, unsigned int seek); static int compare(const void* p1, const void* p2); -static int get_filename(struct playlist_info* playlist, int seek, +static int get_filename(struct playlist_info* playlist, int index, int seek, bool control_file, char *buf, int buf_length); static int get_next_directory(char *dir); static int get_next_dir(char *dir, bool is_forward, bool recursion); @@ -175,6 +178,14 @@ static void display_buffer_full(void); static int flush_pending_control(struct playlist_info* playlist); static int rotate_index(const struct playlist_info* playlist, int index); +#ifdef HAVE_DIRCACHE +#define PLAYLIST_LOAD_POINTERS 1 + +static struct event_queue playlist_queue; +static long playlist_stack[(DEFAULT_STACK_SIZE + 0x400)/sizeof(long)]; +static const char playlist_thread_name[] = "playlist cachectrl"; +#endif + /* * remove any files and indices associated with the playlist */ @@ -394,11 +405,15 @@ static int add_indices_to_playlist(struct playlist_info* playlist, { /* Store a new entry */ playlist->indices[ playlist->amount ] = i+count; - playlist->amount++; +#ifdef HAVE_DIRCACHE + if (playlist->filenames) + playlist->filenames[ playlist->amount ] = NULL; +#endif if ( playlist->amount >= playlist->max_playlist_size ) { display_buffer_full(); return -1; } + playlist->amount++; } } } @@ -406,6 +421,10 @@ static int add_indices_to_playlist(struct playlist_info* playlist, i+= count; } +#ifdef HAVE_DIRCACHE + queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); +#endif + return 0; } @@ -499,8 +518,14 @@ static int add_track_to_playlist(struct playlist_info* playlist, /* shift indices so that track can be added */ for (i=playlist->amount; i>insert_position; i--) + { playlist->indices[i] = playlist->indices[i-1]; - +#ifdef HAVE_DIRCACHE + if (playlist->filenames) + playlist->filenames[i] = playlist->filenames[i-1]; +#endif + } + /* update stored indices if needed */ if (playlist->amount > 0 && insert_position <= playlist->index) playlist->index++; @@ -554,6 +579,12 @@ static int add_track_to_playlist(struct playlist_info* playlist, playlist->indices[insert_position] = flags | seek_pos; +#ifdef HAVE_DIRCACHE + if (playlist->filenames) + playlist->filenames[insert_position] = NULL; + queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); +#endif + playlist->amount++; playlist->num_inserted_tracks++; @@ -693,7 +724,13 @@ static int remove_track_from_playlist(struct playlist_info* playlist, /* shift indices now that track has been removed */ for (i=position; iamount; i++) + { playlist->indices[i] = playlist->indices[i+1]; +#ifdef HAVE_DIRCACHE + if (playlist->filenames) + playlist->filenames[i] = playlist->filenames[i+1]; +#endif + } playlist->amount--; @@ -780,6 +817,14 @@ static int randomise_playlist(struct playlist_info* playlist, store = playlist->indices[candidate]; playlist->indices[candidate] = playlist->indices[count]; playlist->indices[count] = store; +#ifdef HAVE_DIRCACHE + if (playlist->filenames) + { + store = (int)playlist->filenames[candidate]; + playlist->filenames[candidate] = playlist->filenames[count]; + playlist->filenames[count] = (struct dircache_entry *)store; + } +#endif } if (start_current) @@ -817,6 +862,13 @@ static int sort_playlist(struct playlist_info* playlist, bool start_current, qsort(playlist->indices, playlist->amount, sizeof(playlist->indices[0]), compare); +#ifdef HAVE_DIRCACHE + /** We need to re-check the song names from disk because qsort can't + * sort two arrays at once :/ + * FIXME: Please implement a better way to do this. */ + queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); +#endif + if (start_current) find_and_set_playlist_index(playlist, current); @@ -1040,10 +1092,88 @@ static int compare(const void* p1, const void* p2) return *e1 - *e2; } +#ifdef HAVE_DIRCACHE +/** + * Thread to update filename pointers to dircache on background + * without affecting playlist load up performance. + */ +static void playlist_thread(void) +{ + struct event ev; + bool dirty_pointers = false; + static char tmp[MAX_PATH+1]; + + struct playlist_info *playlist; + int index; + int seek; + bool control_file; + + while (1) + { + queue_wait_w_tmo(&playlist_queue, &ev, HZ*5); + + switch (ev.id) + { + case PLAYLIST_LOAD_POINTERS: + dirty_pointers = true; + break ; + + /* Start the background scanning after 5s. */ + case SYS_TIMEOUT: + if (!dirty_pointers) + break ; + + playlist = ¤t_playlist; + if (!dircache_is_enabled() || !playlist->filenames + || playlist->amount <= 0) + break ; + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + cpu_boost(true); +#endif + for (index = 0; index < playlist->amount + && queue_empty(&playlist_queue); index++) + { + /* Process only pointers that are not already loaded. */ + if (playlist->filenames[index]) + continue ; + + control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; + seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; + + /* Load the filename from playlist file. */ + if (get_filename(playlist, index, seek, control_file, tmp, + sizeof(tmp)) < 0) + break ; + + /* Set the dircache entry pointer. */ + playlist->filenames[index] = dircache_get_entry_ptr(tmp); + + /* And be on background so user doesn't notice any delays. */ + yield(); + } + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + cpu_boost(false); +#endif + dirty_pointers = false; + break ; + +#ifndef SIMULATOR + case SYS_USB_CONNECTED: + usb_acknowledge(SYS_USB_CONNECTED_ACK); + usb_wait_for_disconnect(&playlist_queue); + break ; +#endif + } + } +} +#endif + /* * gets pathname for track at seek index */ -static int get_filename(struct playlist_info* playlist, int seek, +static int get_filename(struct playlist_info* playlist, int index, int seek, bool control_file, char *buf, int buf_length) { int fd; @@ -1054,13 +1184,26 @@ static int get_filename(struct playlist_info* playlist, int seek, if (buf_length > MAX_PATH+1) buf_length = MAX_PATH+1; - if (playlist->in_ram && !control_file) +#ifdef HAVE_DIRCACHE + if (dircache_is_enabled() && playlist->filenames) + { + if (playlist->filenames[index] != NULL) + { + dircache_copy_path(playlist->filenames[index], tmp_buf, sizeof(tmp_buf)-1); + max = strlen(tmp_buf) + 1; + } + } +#else + (void)index; +#endif + + if (playlist->in_ram && !control_file && max < 0) { strncpy(tmp_buf, &playlist->buffer[seek], sizeof(tmp_buf)); tmp_buf[MAX_PATH] = '\0'; max = strlen(tmp_buf) + 1; } - else + else if (max < 0) { if (control_file) fd = playlist->control_fd; @@ -1482,6 +1625,16 @@ void playlist_init(void) playlist->buffer = buffer_alloc(playlist->buffer_size); mutex_init(&playlist->control_mutex); empty_playlist(playlist, true); + +#ifdef HAVE_DIRCACHE + playlist->filenames = buffer_alloc( + playlist->max_playlist_size * sizeof(int)); + memset(playlist->filenames, 0, + playlist->max_playlist_size * sizeof(int)); + create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), + playlist_thread_name); + queue_init(&playlist_queue); +#endif } /* @@ -1906,8 +2059,9 @@ int playlist_add(const char *filename) return -1; } - playlist->indices[playlist->amount++] = playlist->buffer_end_pos; - + playlist->indices[playlist->amount] = playlist->buffer_end_pos; + playlist->amount++; + strcpy(&playlist->buffer[playlist->buffer_end_pos], filename); playlist->buffer_end_pos += len; playlist->buffer[playlist->buffer_end_pos++] = '\0'; @@ -1991,7 +2145,7 @@ char* playlist_peek(int steps) control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; - if (get_filename(playlist, seek, control_file, now_playing, + if (get_filename(playlist, index, seek, control_file, now_playing, MAX_PATH+1) < 0) return NULL; @@ -2003,11 +2157,21 @@ char* playlist_peek(int steps) (workaround for buggy playlist creation tools) */ while (temp_ptr) { - fd = open(temp_ptr, O_RDONLY); - if (fd >= 0) +#ifdef HAVE_DIRCACHE + if (dircache_is_enabled()) { - close(fd); - break; + if (dircache_get_entry_ptr(temp_ptr)) + break; + } + else +#endif + { + fd = open(temp_ptr, O_RDONLY); + if (fd >= 0) + { + close(fd); + break; + } } temp_ptr = strchr(temp_ptr+1, '/'); @@ -2278,16 +2442,26 @@ int playlist_create_ex(struct playlist_info* playlist, { int num_indices = index_buffer_size / sizeof(int); +#ifdef HAVE_DIRCACHE + num_indices /= 2; +#endif if (num_indices > global_settings.max_files_in_playlist) num_indices = global_settings.max_files_in_playlist; playlist->max_playlist_size = num_indices; playlist->indices = index_buffer; +#ifdef HAVE_DIRCACHE + playlist->filenames = (const struct dircache_entry **) + &playlist->indices[num_indices]; +#endif } else { playlist->max_playlist_size = current_playlist.max_playlist_size; playlist->indices = current_playlist.indices; +#ifdef HAVE_DIRCACHE + playlist->filenames = current_playlist.filenames; +#endif } playlist->buffer_size = 0; @@ -2336,9 +2510,15 @@ int playlist_set_current(struct playlist_info* playlist) current_playlist.dirlen = playlist->dirlen; if (playlist->indices && playlist->indices != current_playlist.indices) + { memcpy(current_playlist.indices, playlist->indices, - playlist->max_playlist_size*sizeof(int)); - + playlist->max_playlist_size*sizeof(int)); +#ifdef HAVE_DIRCACHE + memcpy(current_playlist.filenames, playlist->filenames, + playlist->max_playlist_size*sizeof(int)); +#endif + } + current_playlist.first_index = playlist->first_index; current_playlist.amount = playlist->amount; current_playlist.last_insert_pos = playlist->last_insert_pos; @@ -2620,7 +2800,7 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) queue = playlist->indices[index] & PLAYLIST_QUEUE_MASK; seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; - if (get_filename(playlist, seek, control_file, filename, + if (get_filename(playlist, index, seek, control_file, filename, sizeof(filename)) < 0) return -1; @@ -2812,7 +2992,7 @@ int playlist_get_track_info(struct playlist_info* playlist, int index, control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; - if (get_filename(playlist, seek, control_file, info->filename, + if (get_filename(playlist, index, seek, control_file, info->filename, sizeof(info->filename)) < 0) return -1; @@ -2883,7 +3063,7 @@ int playlist_save(struct playlist_info* playlist, char *filename) /* Don't save queued files */ if (!queue) { - if (get_filename(playlist, seek, control_file, tmp_buf, + if (get_filename(playlist, index, seek, control_file, tmp_buf, MAX_PATH+1) < 0) { result = -1; diff --git a/apps/playlist.h b/apps/playlist.h index efac303f30..286823e0cf 100644 --- a/apps/playlist.h +++ b/apps/playlist.h @@ -36,7 +36,8 @@ struct playlist_info int control_fd; /* descriptor of the open control file */ bool control_created; /* has control file been created? */ int dirlen; /* Length of the path to the playlist file */ - unsigned long *indices; /* array of indices */ + unsigned long *indices; /* array of indices */ + const struct dircache_entry **filenames; /* Entries from dircache */ int max_playlist_size; /* Max number of files in playlist. Mirror of global_settings.max_files_in_playlist */ bool in_ram; /* playlist stored in ram (dirplay) */ diff --git a/apps/wps.c b/apps/wps.c index 266c506d37..573444fdc4 100644 --- a/apps/wps.c +++ b/apps/wps.c @@ -597,6 +597,7 @@ long wps_show(void) #endif #endif left_lastclick = current_tick; + update_track = true; #ifdef AB_REPEAT_ENABLE /* if we're in A/B repeat mode and the current position @@ -604,7 +605,6 @@ long wps_show(void) if ( ab_repeat_mode_enabled() && ab_after_A_marker(id3->elapsed) ) { ab_jump_to_A_marker(); - update_track = true; break; } /* ...otherwise, do it normally */ @@ -655,6 +655,7 @@ long wps_show(void) #endif #endif right_lastclick = current_tick; + update_track = true; #ifdef AB_REPEAT_ENABLE /* if we're in A/B repeat mode and the current position is @@ -662,7 +663,6 @@ long wps_show(void) if ( ab_repeat_mode_enabled() && ab_before_A_marker(id3->elapsed) ) { ab_jump_to_A_marker(); - update_track = true; break; } /* ...otherwise, do it normally */ diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index fa24321726..259c34cdf5 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c @@ -77,6 +77,7 @@ static struct dircache_entry* allocate_entry(void) dircache_size += sizeof(struct dircache_entry); next_entry->name_len = 0; next_entry->d_name = NULL; + next_entry->up = NULL; next_entry->down = NULL; next_entry->next = NULL; @@ -88,6 +89,7 @@ static struct dircache_entry* dircache_gen_next(struct dircache_entry *ce) struct dircache_entry *next_entry; next_entry = allocate_entry(); + next_entry->up = ce->up; ce->next = next_entry; return next_entry; @@ -98,6 +100,7 @@ static struct dircache_entry* dircache_gen_down(struct dircache_entry *ce) struct dircache_entry *next_entry; next_entry = allocate_entry(); + next_entry->up = ce; ce->down = next_entry; return next_entry; @@ -176,6 +179,7 @@ static int dircache_travel(struct fat_dir *dir, struct dircache_entry *ce) int depth = 0; int result; + memset(ce, 0, sizeof(struct dircache_entry)); dir_recursion[0].dir = dir; dir_recursion[0].ce = ce; @@ -517,6 +521,43 @@ void dircache_disable(void) logf("Cache released"); } +const struct dircache_entry *dircache_get_entry_ptr(const char *filename) +{ + if (!dircache_initialized || filename == NULL) + return NULL; + + return dircache_get_entry(filename, false, false); +} + +void dircache_copy_path(const struct dircache_entry *entry, char *buf, int size) +{ + const struct dircache_entry *down[MAX_SCAN_DEPTH]; + int depth = 0; + + if (size <= 0) + return ; + + buf[0] = '\0'; + + if (entry == NULL) + return ; + + do { + down[depth] = entry; + entry = entry->up; + depth++; + } while (entry != NULL && depth < MAX_SCAN_DEPTH); + + while (--depth >= 0) + { + snprintf(buf, size, "/%s", down[depth]->d_name); + buf += down[depth]->name_len; /* '/' + d_name */ + size -= down[depth]->name_len; + if (size <= 0) + break ; + } +} + /* --- Directory cache live updating functions --- */ static struct dircache_entry* dircache_new_entry(const char *path, int attribute) { diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h index 48b74e0220..11d7335a31 100644 --- a/firmware/include/dircache.h +++ b/firmware/include/dircache.h @@ -47,6 +47,7 @@ struct dircache_maindata { /* Exported structures. */ struct dircache_entry { struct dircache_entry *next; + struct dircache_entry *up; struct dircache_entry *down; int attribute; long size; @@ -71,6 +72,8 @@ int dircache_build(int last_size); bool dircache_is_enabled(void); int dircache_get_cache_size(void); void dircache_disable(void); +const struct dircache_entry *dircache_get_entry_ptr(const char *filename); +void dircache_copy_path(const struct dircache_entry *entry, char *buf, int size); void dircache_bind(int fd, const char *path); void dircache_update_filesize(int fd, long newsize);