1 /* MiniDLNA media server
2 * Copyright (C) 2008-2009 Justin Maggard
4 * This file is part of MiniDLNA.
6 * MiniDLNA is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * MiniDLNA is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/limits.h>
25 #include <sys/types.h>
30 #include "minidlnatypes.h"
31 #include "upnpglobalvars.h"
35 strcatf(struct string_s
*str
, const char *fmt
, ...)
41 ret
= vsnprintf(str
->data
+ str
->off
, str
->size
- str
->off
, fmt
, ap
);
49 strncpyt(char *dst
, const char *src
, size_t len
)
51 strncpy(dst
, src
, len
);
56 ends_with(const char * haystack
, const char * needle
)
59 int nlen
= strlen(needle
);
60 int hlen
= strlen(haystack
);
64 end
= haystack
+ hlen
- nlen
;
66 return (strcasecmp(end
, needle
) ? 0 : 1);
79 for (i
=len
-1; i
>= 0 && isspace(str
[i
]); i
--)
90 if (str
[0] == '"' && str
[len
-1] == '"')
100 /* Find the first occurrence of p in s, where s is terminated by t */
102 strstrc(const char *s
, const char *p
, const char t
)
107 endptr
= strchr(s
, t
);
115 if (*s
== *p
&& strncmp(s
+1, p
+1, plen
-1) == 0)
125 strcasestrc(const char *s
, const char *p
, const char t
)
130 endptr
= strchr(s
, t
);
132 return strcasestr(s
, p
);
138 if (*s
== *p
&& strncasecmp(s
+1, p
+1, plen
-1) == 0)
148 modifyString(char * string
, const char * before
, const char * after
, short like
)
150 int oldlen
, newlen
, chgcnt
= 0;
153 oldlen
= strlen(before
);
154 newlen
= strlen(after
);
155 if( newlen
+like
> oldlen
)
158 while( (p
= strstr(s
, before
)) )
163 s
= realloc(string
, strlen(string
)+((newlen
-oldlen
)*chgcnt
)+1+like
);
164 /* If we failed to realloc, return the original alloc'd string */
174 p
= strcasestr(s
, before
);
177 memmove(p
+ newlen
, p
+ oldlen
, strlen(p
+ oldlen
) + 1);
178 memcpy(p
, after
, newlen
);
188 memmove(t
+2, t
+1, strlen(t
+1)+1);
193 memmove(t
+1, t
, strlen(t
)+1);
204 escape_tag(const char *tag
, int force_alloc
)
206 char *esc_tag
= NULL
;
208 if( strchr(tag
, '&') || strchr(tag
, '<') || strchr(tag
, '>') || strchr(tag
, '"') )
210 esc_tag
= strdup(tag
);
211 esc_tag
= modifyString(esc_tag
, "&", "&amp;", 0);
212 esc_tag
= modifyString(esc_tag
, "<", "&lt;", 0);
213 esc_tag
= modifyString(esc_tag
, ">", "&gt;", 0);
214 esc_tag
= modifyString(esc_tag
, "\"", "&quot;", 0);
216 else if( force_alloc
)
217 esc_tag
= strdup(tag
);
223 strip_ext(char * name
)
227 period
= strrchr(name
, '.');
232 /* Code basically stolen from busybox */
234 make_dir(char * path
, mode_t mode
)
243 /* Bypass leading non-'/'s and then subsequent '/'s. */
249 c
= *s
; /* Save the current char */
250 *s
= '\0'; /* and replace it with nul. */
256 if (mkdir(path
, mode
) < 0) {
257 /* If we failed for any other reason than the directory
258 * already exists, output a diagnostic and return -1.*/
259 if (errno
!= EEXIST
|| (stat(path
, &st
) < 0 || !S_ISDIR(st
.st_mode
))) {
260 DPRINTF(E_WARN
, L_GENERAL
, "make_dir: cannot create directory '%s'\n", path
);
269 /* Remove any inserted nul from the path. */
275 /* Simple, efficient hash function from Daniel J. Bernstein */
277 DJBHash(const char *str
, int len
)
279 unsigned int hash
= 5381;
282 for(i
= 0; i
< len
; str
++, i
++)
284 hash
= ((hash
<< 5) + hash
) + (*str
);
291 is_video(const char * file
)
293 return (ends_with(file
, ".mpg") || ends_with(file
, ".mpeg") ||
294 ends_with(file
, ".avi") || ends_with(file
, ".divx") ||
295 ends_with(file
, ".asf") || ends_with(file
, ".wmv") ||
296 ends_with(file
, ".mp4") || ends_with(file
, ".m4v") ||
297 ends_with(file
, ".mts") || ends_with(file
, ".m2ts") ||
298 ends_with(file
, ".m2t") || ends_with(file
, ".mkv") ||
299 ends_with(file
, ".vob") || ends_with(file
, ".ts") ||
300 ends_with(file
, ".flv") || ends_with(file
, ".xvid") ||
302 ends_with(file
, ".TiVo") ||
304 ends_with(file
, ".mov") || ends_with(file
, ".3gp"));
308 is_audio(const char * file
)
310 return (ends_with(file
, ".mp3") || ends_with(file
, ".flac") ||
311 ends_with(file
, ".wma") || ends_with(file
, ".asf") ||
312 ends_with(file
, ".fla") || ends_with(file
, ".flc") ||
313 ends_with(file
, ".m4a") || ends_with(file
, ".aac") ||
314 ends_with(file
, ".mp4") || ends_with(file
, ".m4p") ||
315 ends_with(file
, ".wav") || ends_with(file
, ".ogg") ||
316 ends_with(file
, ".pcm") || ends_with(file
, ".3gp"));
320 is_image(const char * file
)
322 return (ends_with(file
, ".jpg") || ends_with(file
, ".jpeg"));
326 is_playlist(const char * file
)
328 return (ends_with(file
, ".m3u") || ends_with(file
, ".pls"));
332 is_album_art(const char * name
)
334 struct album_art_name_s
* album_art_name
;
336 /* Check if this file name matches one of the default album art names */
337 for( album_art_name
= album_art_names
; album_art_name
; album_art_name
= album_art_name
->next
)
339 if( album_art_name
->wildcard
)
341 if( strncmp(album_art_name
->name
, name
, strlen(album_art_name
->name
)) == 0 )
346 if( strcmp(album_art_name
->name
, name
) == 0 )
351 return (album_art_name
? 1 : 0);
355 resolve_unknown_type(const char * path
, enum media_types dir_type
)
358 unsigned char type
= TYPE_UNKNOWN
;
359 char str_buf
[PATH_MAX
];
362 if( lstat(path
, &entry
) == 0 )
364 if( S_ISLNK(entry
.st_mode
) )
366 if( (len
= readlink(path
, str_buf
, PATH_MAX
-1)) > 0 )
369 //DEBUG DPRINTF(E_DEBUG, L_GENERAL, "Checking for recursive symbolic link: %s (%s)\n", path, str_buf);
370 if( strncmp(path
, str_buf
, strlen(str_buf
)) == 0 )
372 DPRINTF(E_DEBUG
, L_GENERAL
, "Ignoring recursive symbolic link: %s (%s)\n", path
, str_buf
);
379 if( S_ISDIR(entry
.st_mode
) )
383 else if( S_ISREG(entry
.st_mode
) )
388 if( is_image(path
) ||
395 if( is_audio(path
) ||
421 flag
= fopen("/ramfs/.upnp-av_scan", "w");
425 mkdir("/var/notice", 0755);
426 flag
= fopen("/var/notice/dlna", "w");
429 fprintf(flag
, "Scan in progress");
439 if( access("/ramfs/.rescan_done", F_OK
) == 0 )
440 system("/bin/sh /ramfs/.rescan_done");
441 unlink("/ramfs/.upnp-av_scan");
443 unlink("/var/notice/dlna");