summaryrefslogtreecommitdiff
path: root/apps/playlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playlist.c')
-rwxr-xr-xapps/playlist.c237
1 files changed, 94 insertions, 143 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 43aa97790b..db93344ef1 100755
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -86,7 +86,7 @@
86#include "screens.h" 86#include "screens.h"
87#include "core_alloc.h" 87#include "core_alloc.h"
88#include "misc.h" 88#include "misc.h"
89#include "filefuncs.h" 89#include "pathfuncs.h"
90#include "button.h" 90#include "button.h"
91#include "filetree.h" 91#include "filetree.h"
92#include "abrepeat.h" 92#include "abrepeat.h"
@@ -107,6 +107,8 @@
107#include "panic.h" 107#include "panic.h"
108#include "logdiskf.h" 108#include "logdiskf.h"
109 109
110#undef HAVE_DIRCACHE
111
110#define PLAYLIST_CONTROL_FILE_VERSION 2 112#define PLAYLIST_CONTROL_FILE_VERSION 2
111 113
112/* 114/*
@@ -180,8 +182,8 @@ static int get_next_directory(char *dir);
180static int get_next_dir(char *dir, bool is_forward); 182static int get_next_dir(char *dir, bool is_forward);
181static int get_previous_directory(char *dir); 183static int get_previous_directory(char *dir);
182static int check_subdir_for_music(char *dir, const char *subdir, bool recurse); 184static int check_subdir_for_music(char *dir, const char *subdir, bool recurse);
183static int format_track_path(char *dest, char *src, int buf_length, int max, 185static ssize_t format_track_path(char *dest, char *src, int buf_length,
184 const char *dir); 186 const char *dir);
185static void display_playlist_count(int count, const unsigned char *fmt, 187static void display_playlist_count(int count, const unsigned char *fmt,
186 bool final); 188 bool final);
187static void display_buffer_full(void); 189static void display_buffer_full(void);
@@ -526,7 +528,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
526 int result = 0; 528 int result = 0;
527 /* get emergency buffer so we don't fail horribly */ 529 /* get emergency buffer so we don't fail horribly */
528 if (!buflen) 530 if (!buflen)
529 buffer = __builtin_alloca((buflen = 64)); 531 buffer = alloca((buflen = 64));
530 532
531 if(-1 == playlist->fd) 533 if(-1 == playlist->fd)
532 playlist->fd = open_utf8(playlist->filename, O_RDONLY); 534 playlist->fd = open_utf8(playlist->filename, O_RDONLY);
@@ -1429,7 +1431,7 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
1429 1431
1430 strlcpy(dir_buf, playlist->filename, playlist->dirlen); 1432 strlcpy(dir_buf, playlist->filename, playlist->dirlen);
1431 1433
1432 return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf)); 1434 return format_track_path(buf, tmp_buf, buf_length, dir_buf);
1433} 1435}
1434 1436
1435static int get_next_directory(char *dir){ 1437static int get_next_directory(char *dir){
@@ -1629,7 +1631,7 @@ static int get_next_dir(char *dir, bool is_forward)
1629static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) 1631static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1630{ 1632{
1631 int result = -1; 1633 int result = -1;
1632 int dirlen = strlen(dir); 1634 size_t dirlen = strlen(dir);
1633 int num_files = 0; 1635 int num_files = 0;
1634 int i; 1636 int i;
1635 struct entry *files; 1637 struct entry *files;
@@ -1637,12 +1639,11 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1637 bool has_subdir = false; 1639 bool has_subdir = false;
1638 struct tree_context* tc = tree_get_context(); 1640 struct tree_context* tc = tree_get_context();
1639 1641
1640 snprintf( 1642 if (path_append(dir + dirlen, PA_SEP_HARD, subdir, MAX_PATH - dirlen) >=
1641 dir + dirlen, MAX_PATH - dirlen, 1643 MAX_PATH - dirlen)
1642 /* only add a trailing slash if we need one */ 1644 {
1643 dirlen && dir[dirlen - 1] == '/' ? "%s" : "/%s", 1645 return 0;
1644 subdir 1646 }
1645 );
1646 1647
1647 if (ft_load(tc, dir) < 0) 1648 if (ft_load(tc, dir) < 0)
1648 { 1649 {
@@ -1695,7 +1696,7 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1695 } 1696 }
1696 else 1697 else
1697 { 1698 {
1698 strcpy(dir, "/"); 1699 strcpy(dir, PATH_ROOTSTR);
1699 } 1700 }
1700 1701
1701 /* we now need to reload our current directory */ 1702 /* we now need to reload our current directory */
@@ -1708,79 +1709,31 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
1708/* 1709/*
1709 * Returns absolute path of track 1710 * Returns absolute path of track
1710 */ 1711 */
1711static int format_track_path(char *dest, char *src, int buf_length, int max, 1712static ssize_t format_track_path(char *dest, char *src, int buf_length,
1712 const char *dir) 1713 const char *dir)
1713{ 1714{
1714 int i = 0; 1715 size_t len;
1715 int j;
1716 char *temp_ptr;
1717
1718 /* Look for the end of the string */
1719 while((i < max) &&
1720 (src[i] != '\n') &&
1721 (src[i] != '\r') &&
1722 (src[i] != '\0'))
1723 i++;
1724
1725 /* Now work back killing white space */
1726 while((i > 0) &&
1727 ((src[i-1] == ' ') ||
1728 (src[i-1] == '\t')))
1729 i--;
1730 1716
1731 /* Zero-terminate the file name */ 1717 /* strip whitespace at beginning and end */
1732 src[i]=0; 1718 len = path_trim_whitespace(src, (const char **)&src);
1719 src[len] = '\0';
1733 1720
1734 /* replace backslashes with forward slashes */ 1721 /* replace backslashes with forward slashes */
1735 for ( j=0; j<i; j++ ) 1722 path_correct_separators(src, src);
1736 if ( src[j] == '\\' )
1737 src[j] = '/';
1738 1723
1739 if('/' == src[0]) 1724 /* handle DOS style drive letter and parse non-greedily so that:
1740 { 1725 * 1) "c:/foo" becomes "/foo" and the result is absolute
1741 strlcpy(dest, src, buf_length); 1726 * 2) "c:foo becomes "foo" and the result is relative
1742 } 1727 * This is how Windows seems to handle it except drive letters are of no
1743 else 1728 * meaning here. */
1744 { 1729 path_strip_drive(src, (const char **)&src, false);
1745 /* handle dos style drive letter */
1746 if (':' == src[1])
1747 strlcpy(dest, &src[2], buf_length);
1748 else if (!strncmp(src, "../", 3))
1749 {
1750 /* handle relative paths */
1751 i=3;
1752 while(!strncmp(&src[i], "../", 3))
1753 i += 3;
1754 for (j=0; j<i/3; j++) {
1755 temp_ptr = strrchr(dir, '/');
1756 if (temp_ptr)
1757 *temp_ptr = '\0';
1758 else
1759 break;
1760 }
1761 snprintf(dest, buf_length, "%s/%s", dir, &src[i]);
1762 }
1763 else if ( '.' == src[0] && '/' == src[1] ) {
1764 snprintf(dest, buf_length, "%s/%s", dir, &src[2]);
1765 }
1766 else {
1767 snprintf(dest, buf_length, "%s/%s", dir, src);
1768 }
1769 }
1770#ifdef HAVE_MULTIVOLUME
1771 1730
1772 char vol_string[VOL_ENUM_POS + 8]; 1731 /* prepends directory only if src is relative */
1773 snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, 1); 1732 len = path_append(dest, *dir ? dir : PATH_ROOTSTR, src, buf_length);
1733 if (len >= (size_t)buf_length)
1734 return -1; /* buffer too small */
1774 1735
1775 /*check if the playlist is on a external card, and correct path if needed */ 1736 return len;
1776 if(strstr(dir, vol_string) && (strstr(dest, vol_string) == NULL)){
1777 char temp[buf_length];
1778 strlcpy(temp, dest, buf_length);
1779 snprintf(dest, buf_length, "%s%s", vol_string, temp);
1780 }
1781#endif
1782
1783 return 0;
1784} 1737}
1785 1738
1786/* 1739/*
@@ -3113,8 +3066,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
3113{ 3066{
3114 int fd; 3067 int fd;
3115 int max; 3068 int max;
3116 char *temp_ptr; 3069 char *dir;
3117 const char *dir;
3118 unsigned char *count_str; 3070 unsigned char *count_str;
3119 char temp_buf[MAX_PATH+1]; 3071 char temp_buf[MAX_PATH+1];
3120 char trackname[MAX_PATH+1]; 3072 char trackname[MAX_PATH+1];
@@ -3139,13 +3091,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
3139 } 3091 }
3140 3092
3141 /* we need the directory name for formatting purposes */ 3093 /* we need the directory name for formatting purposes */
3142 dir = filename; 3094 size_t dirlen = path_dirname(filename, (const char **)&dir);
3143 3095 dir = strmemdupa(dir, dirlen);
3144 temp_ptr = strrchr(filename+1,'/');
3145 if (temp_ptr)
3146 *temp_ptr = 0;
3147 else
3148 dir = "/";
3149 3096
3150 if (queue) 3097 if (queue)
3151 count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); 3098 count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT);
@@ -3183,8 +3130,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
3183 3130
3184 /* we need to format so that relative paths are correctly 3131 /* we need to format so that relative paths are correctly
3185 handled */ 3132 handled */
3186 if (format_track_path(trackname, temp_buf, sizeof(trackname), max, 3133 if (format_track_path(trackname, temp_buf, sizeof(trackname),
3187 dir) < 0) 3134 dir) < 0)
3188 { 3135 {
3189 result = -1; 3136 result = -1;
3190 break; 3137 break;
@@ -3223,9 +3170,6 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
3223 3170
3224 close(fd); 3171 close(fd);
3225 3172
3226 if (temp_ptr)
3227 *temp_ptr = '/';
3228
3229 sync_control(playlist, false); 3173 sync_control(playlist, false);
3230 3174
3231 cpu_boost(false); 3175 cpu_boost(false);
@@ -3537,9 +3481,9 @@ int playlist_save(struct playlist_info* playlist, char *filename,
3537 char path[MAX_PATH+1]; 3481 char path[MAX_PATH+1];
3538 char tmp_buf[MAX_PATH+1]; 3482 char tmp_buf[MAX_PATH+1];
3539 int result = 0; 3483 int result = 0;
3540 bool overwrite_current = false;
3541 int *seek_buf; 3484 int *seek_buf;
3542 bool reparse; 3485 bool reparse;
3486 ssize_t pathlen;
3543 3487
3544 ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int)); 3488 ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int));
3545 seek_buf = temp_buffer; 3489 seek_buf = temp_buffer;
@@ -3557,22 +3501,18 @@ int playlist_save(struct playlist_info* playlist, char *filename,
3557 return -1; 3501 return -1;
3558 3502
3559 /* use current working directory as base for pathname */ 3503 /* use current working directory as base for pathname */
3560 if (format_track_path(path, filename, sizeof(tmp_buf), 3504 pathlen = format_track_path(path, filename, sizeof(path), PATH_ROOTSTR);
3561 strlen(filename)+1, "/") < 0) 3505 if (pathlen < 0)
3506 return -1;
3507
3508 /* Use temporary pathname and overwrite/rename later */
3509 if (strlcat(path, "_temp", sizeof(path)) >= sizeof (path))
3562 return -1; 3510 return -1;
3563 3511
3564 /* can ignore volatile here, because core_get_data() is called later */ 3512 /* can ignore volatile here, because core_get_data() is called later */
3565 char* old_buffer = (char*)playlist->buffer; 3513 char* old_buffer = (char*)playlist->buffer;
3566 size_t old_buffer_size = playlist->buffer_size; 3514 size_t old_buffer_size = playlist->buffer_size;
3567 3515
3568 if (!strncmp(playlist->filename, path, strlen(path)))
3569 {
3570 /* Attempting to overwrite current playlist file.
3571 * use temporary pathname and overwrite later */
3572 strlcat(path, "_temp", sizeof(path));
3573 overwrite_current = true;
3574 }
3575
3576 if (is_m3u8(path)) 3516 if (is_m3u8(path))
3577 { 3517 {
3578 fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC); 3518 fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC);
@@ -3621,8 +3561,8 @@ int playlist_save(struct playlist_info* playlist, char *filename,
3621 break; 3561 break;
3622 } 3562 }
3623 3563
3624 if (overwrite_current && !reparse) 3564 if (!reparse)
3625 seek_buf[count] = lseek(fd, 0, SEEK_CUR); 3565 seek_buf[count] = filesize(fd);
3626 3566
3627 if (fdprintf(fd, "%s\n", tmp_buf) < 0) 3567 if (fdprintf(fd, "%s\n", tmp_buf) < 0)
3628 { 3568 {
@@ -3647,57 +3587,61 @@ int playlist_save(struct playlist_info* playlist, char *filename,
3647 index = (index+1)%playlist->amount; 3587 index = (index+1)%playlist->amount;
3648 } 3588 }
3649 3589
3650 display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true);
3651
3652 close(fd); 3590 close(fd);
3591 fd = -1;
3653 3592
3654 if (overwrite_current && result >= 0) 3593 display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true);
3594
3595 if (result >= 0)
3655 { 3596 {
3656 result = -1; 3597 strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */
3657 3598
3658 mutex_lock(playlist->control_mutex); 3599 mutex_lock(playlist->control_mutex);
3659 3600
3660 /* Replace the current playlist with the new one and update indices */ 3601 if (!rename(path, tmp_buf))
3661 close(playlist->fd);
3662 playlist->fd = -1;
3663 if (remove(playlist->filename) >= 0)
3664 { 3602 {
3665 if (rename(path, playlist->filename) >= 0) 3603 fd = open_utf8(tmp_buf, O_RDONLY);
3604 if (fsamefile(fd, playlist->fd) > 0)
3666 { 3605 {
3667 playlist->fd = open_utf8(playlist->filename, O_RDONLY); 3606 /* Replace the current playlist with the new one and update
3668 if (playlist->fd >= 0) 3607 indices */
3608 close(playlist->fd);
3609 playlist->fd = fd;
3610 fd = -1;
3611
3612 if (!reparse)
3669 { 3613 {
3670 if (!reparse) 3614 index = playlist->first_index;
3615 for (i=0, count=0; i<playlist->amount; i++)
3671 { 3616 {
3672 index = playlist->first_index; 3617 if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK))
3673 for (i=0, count=0; i<playlist->amount; i++)
3674 { 3618 {
3675 if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK)) 3619 playlist->indices[index] = seek_buf[count];
3676 { 3620 count++;
3677 playlist->indices[index] = seek_buf[count];
3678 count++;
3679 }
3680 index = (index+1)%playlist->amount;
3681 } 3621 }
3622 index = (index+1)%playlist->amount;
3682 } 3623 }
3683 else
3684 {
3685 NOTEF("reparsing current playlist (slow)");
3686 playlist->amount = 0;
3687 add_indices_to_playlist(playlist, temp_buffer, temp_buffer_size);
3688 }
3689 /* we need to recreate control because inserted tracks are
3690 now part of the playlist and shuffle has been
3691 invalidated */
3692 result = recreate_control(playlist);
3693 } 3624 }
3694 } 3625 else
3695 } 3626 {
3627 NOTEF("reparsing current playlist (slow)");
3628 playlist->amount = 0;
3629 add_indices_to_playlist(playlist, temp_buffer,
3630 temp_buffer_size);
3631 }
3696 3632
3697 mutex_unlock(playlist->control_mutex); 3633 /* we need to recreate control because inserted tracks are
3634 now part of the playlist and shuffle has been invalidated */
3635 result = recreate_control(playlist);
3636 }
3637 }
3698 3638
3639 mutex_unlock(playlist->control_mutex);
3699 } 3640 }
3700 3641
3642 if (fd >= 0)
3643 close(fd);
3644
3701 cpu_boost(false); 3645 cpu_boost(false);
3702 3646
3703reset_old_buffer: 3647reset_old_buffer:
@@ -3759,8 +3703,12 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
3759 if (recurse) 3703 if (recurse)
3760 { 3704 {
3761 /* recursively add directories */ 3705 /* recursively add directories */
3762 snprintf(buf, sizeof(buf), "%s/%s", 3706 if (path_append(buf, dirname, files[i].name, sizeof(buf))
3763 dirname[1]? dirname: "", files[i].name); 3707 >= sizeof(buf))
3708 {
3709 continue;
3710 }
3711
3764 result = playlist_directory_tracksearch(buf, recurse, 3712 result = playlist_directory_tracksearch(buf, recurse,
3765 callback, context); 3713 callback, context);
3766 if (result < 0) 3714 if (result < 0)
@@ -3785,8 +3733,11 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
3785 } 3733 }
3786 else if ((files[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO) 3734 else if ((files[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO)
3787 { 3735 {
3788 snprintf(buf, sizeof(buf), "%s/%s", 3736 if (path_append(buf, dirname, files[i].name, sizeof(buf))
3789 dirname[1]? dirname: "", files[i].name); 3737 >= sizeof(buf))
3738 {
3739 continue;
3740 }
3790 3741
3791 if (callback(buf, context) != 0) 3742 if (callback(buf, context) != 0)
3792 { 3743 {