00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00043 #include "cache.h"
00044 #include "playlist.h"
00045
00046 #ifdef CACHE_SQL
00047
00048 short cache_check_dir(request_rec * r, mu_config *conf, mu_cache_data *cachedata);
00049 short cache_check_file(request_rec * r, mu_config *conf, mu_cache_data *cachedata);
00050 mu_ent *cache_read_file(request_rec * r, mu_ent *head, mu_config *conf, mu_cache_data *cachedata);
00051 short cache_write_file(request_rec * r, mu_ent *p, mu_config *conf, mu_cache_data *cachedata);
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #else
00076 #ifndef NO_CACHE
00077
00087 static void error_handler(request_rec *r, const char *caller)
00088 {
00089 switch (errno) {
00090 case EPERM:
00091
00092 ap_log_printf(r->server, "[musicindex] (%s) Can't create directory.", caller);
00093 break;
00094 #if 0
00095 case EISDIR:
00096
00097 case EINVAL:
00098
00099 case EEXIST:
00100
00101 case EFAULT:
00102
00103 #endif
00104 case EACCES:
00105
00106
00107 ap_log_printf(r->server, "[musicindex] (%s) Permission denied.", caller);
00108 break;
00109 case EMFILE:
00110
00111 case ENFILE:
00112
00113 ap_log_printf(r->server, "[musicindex] (%s) Too many open files!", caller);
00114 break;
00115 case ENAMETOOLONG:
00116
00117 ap_log_printf(r->server, "[musicindex] (%s) Pathname was too long.", caller);
00118 break;
00119 #if 0
00120 case ENOENT:
00121
00122 case ENOTDIR:
00123
00124 case ENOTEMPTY:
00125
00126 #endif
00127 case ENOMEM:
00128
00129 ap_log_printf(r->server, "[musicindex] (%s) Out Of Memory!", caller);
00130 break;
00131 case EROFS:
00132
00133 ap_log_printf(r->server, "[musicindex] (%s) Read-Only filesystem!", caller);
00134 break;
00135 case ELOOP:
00136
00137 ap_log_printf(r->server, "[musicindex] (%s) Too many symbolic links.", caller);
00138 break;
00139 case EIO:
00140
00141 ap_log_printf(r->server, "[musicindex] (%s) I/O error.", caller);
00142 break;
00143 case ENOSPC:
00144
00145
00146 ap_log_printf(r->server, "[musicindex] (%s) No space left on device!", caller);
00147 break;
00148 default:
00149 ap_log_printf(r->server, "[musicindex] (%s) - error_handler! errno=%i", caller, errno);
00150 break;
00151 }
00152 return;
00153 }
00154
00168 static short cache_make_dir(request_rec *r, char *dirpath)
00169 {
00170 short l = 0, m = 0;
00171 char *tempdir = NULL;
00172
00173 do {
00174 tempdir = ap_pstrndup(r->pool, dirpath, (m + (l = strcspn(dirpath + m, "/"))));
00175 m += l;
00176
00177 if (!l)
00178 break;
00179
00180
00181 while (dirpath[m] == '/')
00182 m++;
00183
00184 if (mkdir(tempdir, S_IRWXU)) {
00185 if (errno == EEXIST);
00186 else
00187 goto error_out;
00188 }
00189 } while (1);
00190
00191 return 0;
00192
00193 error_out:
00194 error_handler(r, __FUNCTION__);
00195 return CA_FATAL;
00196 }
00197
00209 static void cache_remove_dir(request_rec *r, DIR *cachedir, char *curdir)
00210 {
00211 DIR *subdir = NULL;
00212 struct dirent *cachedirent = NULL;
00213 struct stat origdirstat;
00214 char *origdir = NULL;
00215
00216 fchdir(dirfd(cachedir));
00217 while ((cachedirent = readdir(cachedir))) {
00218 if (!(strcmp(cachedirent->d_name, ".")) || !(strcmp(cachedirent->d_name, "..")))
00219 continue;
00220
00221 if (unlink(cachedirent->d_name)) {
00222 if (errno == EISDIR) {
00223
00224
00225 origdir = ap_pstrcat(r->pool, curdir, "/", cachedirent->d_name, NULL);
00226 if (stat(origdir, &origdirstat)) {
00227 if (rmdir(cachedirent->d_name)) {
00228 if (errno == ENOTEMPTY) {
00229 subdir = opendir(cachedirent->d_name);
00230 cache_remove_dir(r, subdir, origdir);
00231 closedir(subdir);
00232 fchdir(dirfd(cachedir));
00233 rmdir(cachedirent->d_name);
00234 }
00235 else
00236 error_handler(r, __FUNCTION__);
00237 }
00238 }
00239 }
00240 else
00241 error_handler(r, __FUNCTION__);
00242 }
00243 }
00244
00245 return;
00246 }
00247
00258 static short cache_init(request_rec * r, mu_config *conf)
00259 {
00260 chdir("/");
00261 if (cache_make_dir(r, conf->cache_path + 1))
00262 goto error_out;
00263
00264 return 0;
00265
00266 error_out:
00267 error_handler(r, __FUNCTION__);
00268 return CA_FATAL;
00269 }
00270
00285 short cache_check_dir(request_rec * r, mu_config *conf, mu_cache_data *cachedata)
00286 {
00287 DIR *cachedir = NULL;
00288 struct stat cachedirstat, dirstat;
00289
00290 if (!cachedata->name)
00291 return CA_MISSARG;
00292
00293
00294
00295 if (chdir(conf->cache_path)) {
00296 if (errno == ENOENT) {
00297 if (cache_init(r, conf))
00298 return CA_FATAL;
00299 chdir(conf->cache_path);
00300 }
00301 else
00302 goto error_out;
00303 }
00304
00305
00306
00307 if (!(cachedir = opendir(cachedata->name + 1))) {
00308 if (errno == ENOENT) {
00309 if (cache_make_dir(r, cachedata->name + 1))
00310 goto error_out;
00311 }
00312 else
00313 goto error_out;
00314 }
00315 else {
00316 fstat(dirfd(cachedir), &cachedirstat);
00317 stat(cachedata->name, &dirstat);
00318 if (cachedirstat.st_mtime < dirstat.st_mtime)
00319 cache_remove_dir(r, cachedir, cachedata->name);
00320 closedir(cachedir);
00321 }
00322
00323 return 0;
00324
00325 error_out:
00326 error_handler(r, __FUNCTION__);
00327 return CA_FATAL;
00328 }
00329
00346 short cache_check_file(request_rec * r, mu_config *conf, mu_cache_data *cachedata)
00347 {
00348 if (!cachedata->name)
00349 return CA_MISSARG;
00350
00351
00352
00353 if (chdir(conf->cache_path)) {
00354 if (errno == ENOENT) {
00355 if (cache_init(r, conf))
00356 return CA_FATAL;
00357 chdir(conf->cache_path);
00358 }
00359 else
00360 goto error_out;
00361 }
00362
00363
00364
00365 if (!(cachedata->stream = fopen(cachedata->name + 1, "r"))) {
00366 if (errno == ENOENT)
00367 return CA_CREATE;
00368 else
00369 goto error_out;
00370 }
00371
00372
00373 return 0;
00374
00375 error_out:
00376 error_handler(r, __FUNCTION__);
00377 return CA_FATAL;
00378 }
00379
00396 mu_ent *cache_read_file(request_rec * r, mu_ent *head, mu_config *conf, mu_cache_data *cachedata)
00397 {
00398 mu_ent *p = head;
00399 short result = 0;
00400
00401
00402
00403 if (flock(fileno((FILE *)cachedata->stream), LOCK_SH|LOCK_NB))
00404 return p;
00405
00406 p = new_ent(r->pool, head);
00407 p->title = ap_pcalloc(r->pool, MAX_STRING);
00408 p->album = ap_pcalloc(r->pool, MAX_STRING);
00409 p->artist = ap_pcalloc(r->pool, MAX_STRING);
00410 p->genre = ap_pcalloc(r->pool, 64);
00411
00412 result = fscanf(cachedata->stream, "album: %[^\n]\nartist: %[^\n]\n"
00413 "title: %[^\n]\ndate: %hu\ntrack: %hu\nposn: %hu\n"
00414 "length: %lu\nbitrate: %lu\nsize: %lu\nfiletype: %c\n"
00415 "genre: %[^\n]\n",
00416 p->album, p->artist, p->title, &p->date, &p->track, &p->posn, &p->length,
00417 &p->bitrate, &p->size, &p->filetype, p->genre);
00418
00419
00420 flock(fileno((FILE *)cachedata->stream), LOCK_UN);
00421 fclose(cachedata->stream);
00422
00423
00424 if (!result)
00425 return head;
00426
00427 if (!strcmp(p->album, "(null)"))
00428 p->album[0] = '\0';
00429 if (!strcmp(p->artist, "(null)"))
00430 p->artist[0] = '\0';
00431 if (!strcmp(p->genre, "(null)"))
00432 p->genre[0] = '\0';
00433
00434 return p;
00435 }
00436
00450 short cache_write_file(request_rec * r, mu_ent *p, mu_config *conf, mu_cache_data *cachedata)
00451 {
00452 chdir(conf->cache_path);
00453
00454 if (!(cachedata->stream = fopen(cachedata->name + 1, "w+")))
00455 goto error_out;
00456
00457
00458
00459 if (flock(fileno((FILE *)cachedata->stream), LOCK_EX|LOCK_NB)) {
00460 if (errno == EWOULDBLOCK)
00461 return CA_LOCKED;
00462 else
00463 goto error_out;
00464 }
00465
00466 fprintf(cachedata->stream, "album: %s\nartist: %s\ntitle: %s\ndate: %hu\n"
00467 "track: %hu\nposn: %hu\nlength: %lu\nbitrate: %lu\n"
00468 "size: %lu\nfiletype: %s\ngenre: %s\n",
00469 p->album, p->artist, p->title, p->date, p->track, p->posn, p->length,
00470 p->bitrate, p->size, &p->filetype, p->genre);
00471
00472
00473 flock(fileno((FILE *)cachedata->stream), LOCK_UN);
00474 fclose(cachedata->stream);
00475
00476 return 0;
00477
00478 error_out:
00479 error_handler(r, __FUNCTION__);
00480 return CA_FATAL;
00481 }
00482 #endif
00483 #endif