📄 library.c
字号:
/* Copyright (c) 2000 Kevin Sullivan <nite@gis.net> * * Please refer to the COPYRIGHT file for more information. *//* ---------------------------------------------------------------------- *//* functions that deal with reading and writing the library file. */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include "library.h"#include "nap.h"#include "defines.h"#include "lists.h"#include "codes.h"#include "alias.h"#include "winio.h"#ifdef MEMWATCH #include "memwatch.h"#endifmasquerade_t *masqlist = NULL;int masqcounter = 0;/* read the library file SD into a library data structure. Return NULL on failure. */library_t *read_library_file(char *sd) { library_t *l, *elt; char *p0, *p1, *p2, *p3, *p4, *r; FILE *f; if (!sd) { return NULL; } f = fopen(sd, "r"); if (!f) { return NULL; } r = nap_getline(f); if (!r) { fclose(f); return NULL; } if (strcmp(r, NAP_LIBRARY_HEADER)!=0) { fclose(f); free(r); return 0; } free(r); l = NULL; while (1) { r = nap_getline(f); if (!r) { break; } if (*r != '\"') { free(r); continue; /* skip headers and junk */ } p0 = strchr(r+1, '\"'); if (!p0 || p0[1]!=' ') { free(r); continue; } p1 = strchr(p0+2, ' '); if (!p1) { free(r); continue; } p2 = strchr(p1+1, ' '); if (!p2) { free(r); continue; } p3 = strchr(p2+1, ' '); if (!p3) { free(r); continue; } p4 = strchr(p3+1, ' '); if (!p4) { free(r); continue; } elt = malloc(sizeof(library_t)); if (!elt) { free(r); continue; } *p0 = 0; *p1 = 0; *p2 = 0; *p3 = 0; *p4 = 0; elt->lfn = strdup(r+1); elt->hash = strdup(p0+2); elt->sz = atoi(p1+1); elt->bitrate = atoi(p2+1); elt->freq = atoi(p3+1); elt->len = atoi(p4+1); free(r); list_append(library_t, l, elt); } fclose(f); return l;} /* Note: the format of the library file changed in v1.4.4-ps5: two lines were added at the beginning: a title, and the "upload" path that was used to create the file. This allows us to check whether the library needs re-building, see up_to_date(). -PS *//* "unshare" the old files with the server, then rebuild library, then "share" new files. */int rebuild(int s, char *sd, char *path){ /* tell server to unshare files */ if (s!=-1) { sendpack(s, NAP_UNSHARE, NULL); } if (buildflist(sd, path) == -1) { return(-1); } /* schedule new file list for sending to server */ lfiles(s, sd); return(1);}/* check whether the given filename FN is shared, by looking it up in the library file SD. This is used for security purposes before allowing an upload. Note: filename must use "/" and not "\". Return 1 if shared, 0 if not. When in doubt, return 0. Note: we compare filenames here in a case sensitive manner. This may or may not be correct. Pros: we have exact control over which files are shared. Cons: dumb remote clients, or dumb servers, may convert filenames to lowercase or to uppercase, thus resulting in a request that we cannot fulfill. However, I have not seen this happen in practice. */int isshared(char *fn, char *sd) { FILE *f; char *r, *p; f = fopen(sd, "r"); if (f == NULL) { return(0); } while (1) { r = nap_getline(f); if (!r) break; if (*r != '\"') { free(r); continue; /* skip headers and junk */ } p = strchr(r+1, '\"'); if (!p) { free(r); continue; } *p = 0; if (!strcmp(r+1, fn)) { free(r); fclose(f); return 1; } free(r); } fclose(f); return 0;} /* build the library file. sd is the name of the library file, and path is the ";"-separated sequence of upload directories. New in 1.5.1: read the old contents first, and do not regenerate file stats where they are already known. */int buildflist(char *sd, char *path){ FILE *f; char *t, *n; dev_inode_t *di_list=NULL, *e; char *sharetypes = getval("sharetypes"); library_t *l, *le; struct stat st; time_t reftime; int r; r = stat(sd, &st); if (r==0) { reftime = st.st_mtime; l = read_library_file(sd); } else { reftime = 0; l = NULL; } f = fopen(sd, "w"); if (f == NULL) { wp(NULL, "Error opening \"%s\": %s\n", sd, strerror(errno)); list_forall_unlink(le, l) { free(le->lfn); free(le->hash); free(le); } return(-1); } fprintf(f, NAP_LIBRARY_HEADER "\n"); fprintf(f, "PATH=%s\n", path ? path : ""); fprintf(f, "SHARETYPES=%s\n", sharetypes ? sharetypes : ""); /* note: if path==NULL, we just generate an empty file */ if (path) { n = strdup(path); t = strtok(n, ";"); while (t) { t = strip(t); /* remove whitespace on both ends */ t = home_file(t); if (t[0] && t[strlen(t)-1]=='/') { /* strip '/' from end */ t[strlen(t)-1]=0; } addfile(t, f, &di_list, l, reftime); free(t); t = strtok(NULL, ";"); } free(n); } fclose(f); list_forall_unlink(e, di_list) { free(e); } list_forall_unlink(le, l) { free(le->lfn); free(le->hash); free(le); } return(1);}/* add the file or directory nm to the library file f. Be careful to avoid loops due to symlinks: DI_LIST is a linked list of device/inode pairs (of directories) that we have already seen. */void addfile(char *fn, FILE *f, dev_inode_t **di_list_p, library_t *l, time_t reftime){ DIR *dir; struct stat st; int ret; dev_inode_t *e; mhdr_t *m; struct dirent *dirent; library_t *elt; ret = stat(fn, &st); if (ret) { /* ignore files that don't exist */ return; } if (S_ISDIR(st.st_mode)) { /* is it a directory? */ /* do not recurse if we've seen this dir before */ list_find(e, *di_list_p, e->dev == st.st_dev && e->ino == st.st_ino); if (e) { return; } /* else, remember dir */ e = (dev_inode_t *)malloc(sizeof(dev_inode_t)); e->dev = st.st_dev; e->ino = st.st_ino; list_prepend(*di_list_p, e); /* now go through each file in this directory. */ dir = opendir(fn); /* open directory */ if (dir==NULL) { /* ignore failures */ return; } while ((dirent = readdir(dir)) != NULL) { /* go through each entry */ /* make sure to ignore ".." and "." */ if (strcmp(dirent->d_name, "..")!=0 && strcmp(dirent->d_name, ".")!=0) { int len = strlen(fn)+strlen(dirent->d_name)+2; char filename[len]; /* Note: this goes on the stack */ strcpy(filename, fn); strcat(filename, "/"); strcat(filename, dirent->d_name); addfile(filename, f, di_list_p, l, reftime); } } closedir(dir); return; } else if (S_ISREG(st.st_mode)) { /* is it a regular file? */ /* see if the stats for this file are already known */ if (st.st_mtime < reftime) { list_find(elt, l, strcmp(elt->lfn, fn)==0); /* as a special case, if hashing is requested but the cached value is bogus, we don't use the cached value */ if (elt && !(nvar_default("hash",0) && strncmp(elt->hash, BOGUS_HASH, 32)==0)) { fprintf(f, "\"%s\" %s %i %i %i %i\n", elt->lfn, elt->hash, elt->sz, elt->bitrate, elt->freq, elt->len); return; } } /* otherwise, calculate stats now */ m = filestats(fn); if (m) { fprintf(f, "\"%s\" %s-%i %i %i %i %i\n", fn, m->check, m->sz1, m->sz, m->bitrate, m->freq, m->len); free(m); } return; }}/* decide whether a given file is shared, and if yes, get the file stats (checksum, size, bitrate etc). A file is shared if: either it is a valid mp3 file, or its file extension is in the sharetypes list. Thus, the sharetypes variable only needs to list file extensions other than mp3 - valid mp3 files are shared irrespective of their extension. */mhdr_t *filestats(char *fn) { mhdr_t *m; char *p, *q; int plen, fnlen; int r;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -