9 #include "play_queue.h"
19 static struct track_info
*ti_buffer
[32];
20 static int ti_buffer_fill
;
21 static struct add_data
*jd
;
23 static void flush_ti_buffer(void)
28 for (i
= 0; i
< ti_buffer_fill
; i
++) {
29 jd
->add(ti_buffer
[i
]);
30 track_info_unref(ti_buffer
[i
]);
36 static void add_ti(struct track_info
*ti
)
38 if (ti_buffer_fill
== sizeof(ti_buffer
) / sizeof(ti_buffer
[0]))
40 ti_buffer
[ti_buffer_fill
++] = ti
;
43 static void add_url(const char *filename
)
45 add_ti(track_info_url_new(filename
));
48 /* add file to the playlist
50 * @filename: absolute filename with extraneous slashes stripped
52 static void add_file(const char *filename
)
54 struct track_info
*ti
;
57 ti
= cache_get_ti(filename
);
64 static int dir_entry_cmp(const void *ap
, const void *bp
)
66 struct dir_entry
*a
= *(struct dir_entry
**)ap
;
67 struct dir_entry
*b
= *(struct dir_entry
**)bp
;
69 return strcmp(a
->name
, b
->name
);
72 static int dir_entry_cmp_reverse(const void *ap
, const void *bp
)
74 struct dir_entry
*a
= *(struct dir_entry
**)ap
;
75 struct dir_entry
*b
= *(struct dir_entry
**)bp
;
77 return strcmp(b
->name
, a
->name
);
80 static int points_within(const char *target
, const char *root
)
82 int tlen
= strlen(target
);
83 int rlen
= strlen(root
);
87 if (strncmp(target
, root
, rlen
))
89 return target
[rlen
] == '/' || !target
[rlen
];
92 static void add_dir(const char *dirname
, const char *root
)
95 struct dir_entry
**ents
;
100 if (dir_open(&dir
, dirname
)) {
101 d_print("error: opening %s: %s\n", dirname
, strerror(errno
));
104 while ((name
= dir_read(&dir
))) {
105 struct dir_entry
*ent
;
114 int rc
= readlink(dir
.path
, buf
, sizeof(buf
));
116 if (rc
< 0 || rc
== sizeof(buf
))
119 target
= path_absolute_cwd(buf
, dirname
);
120 if (points_within(target
, root
)) {
121 /* symlink points withing the root */
122 d_print("%s -> %s points within %s. ignoring\n",
123 dir
.path
, target
, root
);
130 size
= strlen(name
) + 1;
131 ent
= xmalloc(sizeof(struct dir_entry
) + size
);
132 ent
->mode
= dir
.st
.st_mode
;
133 memcpy(ent
->name
, name
, size
);
134 ptr_array_add(&array
, ent
);
138 if (jd
->add
== play_queue_prepend
) {
139 ptr_array_sort(&array
, dir_entry_cmp_reverse
);
141 ptr_array_sort(&array
, dir_entry_cmp
);
144 for (i
= 0; i
< array
.count
; i
++) {
145 if (!worker_cancelling()) {
146 /* abuse dir.path because
147 * - it already contains dirname + '/'
148 * - it is guaranteed to be large enough
150 int len
= strlen(ents
[i
]->name
);
152 memcpy(dir
.path
+ dir
.len
, ents
[i
]->name
, len
+ 1);
153 if (S_ISDIR(ents
[i
]->mode
)) {
154 add_dir(dir
.path
, root
);
164 static int handle_line(void *data
, const char *line
)
166 if (worker_cancelling())
177 static void add_pl(const char *filename
)
182 buf
= mmap_file(filename
, &size
);
188 reverse
= jd
->add
== play_queue_prepend
;
190 cmus_playlist_for_each(buf
, size
, reverse
, handle_line
, NULL
);
195 void do_add_job(void *data
)
206 add_dir(jd
->name
, jd
->name
);
211 case FILE_TYPE_INVALID
:
219 void free_add_job(void *data
)
221 struct add_data
*d
= data
;
226 void do_update_job(void *data
)
228 struct update_data
*d
= data
;
231 for (i
= 0; i
< d
->used
; i
++) {
232 struct track_info
*ti
= d
->ti
[i
];
236 /* stat follows symlinks, lstat does not */
237 rc
= stat(ti
->filename
, &s
);
238 if (rc
|| ti
->mtime
!= s
.st_mtime
) {
248 d_print("removing dead file %s\n", ti
->filename
);
250 d_print("mtime changed: %s\n", ti
->filename
);
251 cmus_add(lib_add_track
, ti
->filename
, FILE_TYPE_FILE
, JOB_TYPE_LIB
);
254 track_info_unref(ti
);
258 void free_update_job(void *data
)
260 struct update_data
*d
= data
;
266 void do_update_cache_job(void *data
)
268 struct track_info
**tis
;
272 tis
= cache_refresh(&count
);
274 for (i
= 0; i
< count
; i
++) {
275 struct track_info
*new, *old
= tis
[i
];
281 if (lib_remove(old
) && new)
283 // FIXME: other views
285 track_info_unref(old
);
287 track_info_unref(new);
294 void free_update_cache_job(void *data
)