📄 databasefs.c
字号:
/***************************************************************************** * DatabaseFS - Copyright Eric Lorimer (5/02) * * DatabaseFS is a samba VFS module connecting to a MySQL database and allowing * dynamic database browsing * * see the file README for some explanation of how it works. * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * **************************************************************************/#include "config.h"#include <stdio.h>#include <sys/stat.h>#include <utime.h>#include <dirent.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <includes.h>#include <vfs.h>#include "mysql.h"#include "shortcut.h"#include "musicdb.h"//static struct vfs_ops default_vfs_ops; /* For passthrough operation *///static struct smb_vfs_handle_struct *musicdb_handle;extern userdom_struct current_user_info;MYSQL mysql;/*************************************************************************** * int musicdb_connect * * connect to the mysql database mp3 as user samba * *************************************************************************///static int musicdb_connect(struct connection_struct *conn, const char *service,// const char *user) static int musicdb_connect(struct vfs_handle_struct *musicdb_handle, struct connection_struct *conn, const char *service, const char *user) { char *username, *password; int entries, i = 0; struct musicdb_ctx *mydata; report_mem_usage("connect"); /* start out by initializing our private data */ mydata = (struct musicdb_ctx *)MALLOC(sizeof(struct musicdb_ctx)); mydata->memory = talloc_init("musicdb"); mydata->dtable = talloc(mydata->memory, sizeof(struct dirtbl)); musicdb_handle->data = mydata; parse_config(lp_parm_const_string(SNUM(conn), musicdb_handle->param, "config_file", "databasefs.conf")); username = get_string_option("user"); password = get_string_option("password"); if ( !(mydata->sock = mysql_connect(&mysql, NULL, username, password)) ) { DEBUG(1, ("mysql_connect failed for user %s.\n", username)); return -1; } if ( mysql_select_db(mydata->sock, get_string_option("database")) ) { DEBUG(1, ("mysql_select_db failed.\n")); return -1; } /* load dirtbl into memory */ mydata->dtable->rows = (struct dirtbl_row *) talloc(mydata->memory, sizeof(struct dirtbl_row) * DIRTBL_ROWS); mydata->dtable->size = DIRTBL_ROWS; entries = load_dirtbl(mydata->sock, mydata->dtable); /* hmm... apparently the last mysql_select_db call does not execute fast * enough. There must be a better way to check the status of the database * before executing the query, but this works for now. big hack */ while ( entries == 0 && i < 5 ) { entries = load_dirtbl(mydata->sock, mydata->dtable); i++; } /* check that this host name is allowed */ /* if ( check_black_list(get_remote_machine_name(), mydata->sock) ) smb_panic("User blacklisted."); */ /* now initialize the cache */ mydata->cache = (ubi_cacheRoot *) talloc(mydata->memory, sizeof(ubi_cacheRoot)); if ( mydata->cache == 0 ) { DEBUG(1, ("musicdb: mydata->cache initialization failed!\n")); return -1; } ubi_cacheInit(mydata->cache, compare_nodes, killnode, CACHE_ENTRIES, CACHE_ROWS); /* we set the entry_size as the number of rows */ if ( !module_init() ) smb_panic("FATAL error. unable to initialize module\n"); return 0;}/************************************************************************** * void musicdb_disconnect * * closes the mysql database socket * ************************************************************************/static void musicdb_disconnect(struct vfs_handle_struct *musicdb_handle, struct connection_struct *conn){ struct musicdb_ctx *mydata = (struct musicdb_ctx *)musicdb_handle->data; ubi_cacheClear(mydata->cache); mysql_close(mydata->sock); talloc_destroy(mydata->memory); cleanup_config();// SAFE_FREE(mydata); FREE(mydata); report_mem_usage("disconnect"); return;}/************************************************************************** * DIR *musicdb_opendir * * open the directory given by fname by executing a SQL statement * ************************************************************************/static DIR *musicdb_opendir(struct vfs_handle_struct *musicdb_handle, struct connection_struct *conn, const char *fname){ struct directory *dirptr = (struct directory *)MALLOC(sizeof(struct directory)); struct dirtbl_row *drow; struct strstack stack; char newfname[128]; struct cache_node *cache_entry; struct musicdb_ctx *mydata = (struct musicdb_ctx *)musicdb_handle->data; stack.stackptr = 0; /* if it doesn't end in a slash, tack one on */ strncpy(newfname, fname, 128); if ( newfname[strlen(fname)-1] != '/' ) { newfname[strlen(fname)] = '/'; newfname[strlen(fname)+1] = '\0'; } if ( !search(1, newfname, &drow, &stack, mydata->dtable) ) return NULL; if ( drow->subptr != -1 ) { dirptr->dtable_ptr = dirtbl_search(drow->subptr, mydata->dtable); dirptr->sdirid = drow->subptr; } else dirptr->dtable_ptr = -1; if ( drow->fileqry[0] == '\0' ) dirptr->filequery = NULL; else { pstring filledqry; replace(drow->fileqry, &stack, filledqry, mydata->sock); cache_entry = (struct cache_node *)ubi_cacheGet(mydata->cache, filledqry); if ( cache_entry == NULL ) { /* couldn't find it in the cache. we have to load it */ dirptr->filequery = (struct song_entry *) cache_load(SONG, filledqry, mydata->sock, mydata->cache); } else { /* found in the cache */ dirptr->filequery = (struct song_entry *) ubi_slFirst((ubi_slListPtr)cache_entry->data); } } if ( drow->dirqry[0] == '\0' ) dirptr->dirquery = NULL; else { pstring filledqry; replace(drow->dirqry, &stack, filledqry, mydata->sock); cache_entry = (struct cache_node *)ubi_cacheGet(mydata->cache, filledqry); if ( cache_entry == NULL ) { /* couldn't find it in the cache. we have to load it */ dirptr->dirquery = (struct dir_entry *) cache_load(DDIR, filledqry, mydata->sock, mydata->cache); } else { /* found in the cache */ dirptr->dirquery = (struct dir_entry *) ubi_slFirst((ubi_slListPtr)cache_entry->data); } } return (DIR *)dirptr;}/************************************************************************** * struct dirent *musicdb_readdir * * read and return the directory contents from the mysql result pointer * ************************************************************************/static struct dirent *musicdb_readdir(struct vfs_handle_struct *musicdb_handle, struct connection_struct *conn, DIR *dirp){ struct directory *dirptr = (struct directory *)dirp; struct musicdb_ctx *mydata = (struct musicdb_ctx *)musicdb_handle->data; static struct dirent dirbuf; struct song_entry *filerow; int ptr; memset(&dirbuf, 0, sizeof(struct dirent)); // zero the struct if ( (filerow = dirptr->filequery) ) { strncpy(dirbuf.d_name, filerow->fname, 255); dirptr->filequery = (struct song_entry *)ubi_slNext(dirptr->filequery); return &dirbuf; } if ( dirptr->dirquery ) { snprintf(dirbuf.d_name, 255, "%s", dirptr->dirquery->template); dirptr->dirquery = (struct dir_entry *)ubi_slNext(dirptr->dirquery); return &dirbuf; } ptr = dirptr->dtable_ptr; if ( ptr > -1 && ptr < mydata->dtable->size && mydata->dtable->rows[ptr].dirid == dirptr->sdirid) { snprintf(dirbuf.d_name, 255, "%s", mydata->dtable->rows[ptr].template); dirbuf.d_name[strlen(dirbuf.d_name) - 1] = '\0'; /* chop the trailing / */ dirptr->dtable_ptr++; return &dirbuf; } return NULL; // no more data}/************************************************************************** * int musicdb_closedir * * free the mysql result handle for this directory. * ************************************************************************/static int musicdb_closedir(struct vfs_handle_struct *musicdb_handle, struct connection_struct *conn, DIR *dirp){// SAFE_FREE(dirp); FREE(dirp); return 0;}/************************************************************************** * int musicdb_open * * search the directory for the file and then pass it on to the module * ************************************************************************/static int musicdb_open(struct vfs_handle_struct *musicdb_handle, struct connection_struct *conn, const char *fname, int flags, mode_t mode){ char base[512], leaf[128], *ptr; struct musicdb_ctx *mydata = (struct musicdb_ctx *)musicdb_handle->data; struct dirtbl_row *drow; struct strstack sstack; pstring filledqry; struct cache_node *cache_entry; struct song_entry *songs; sstack.stackptr = 0; strncpy(base, fname, 512); if ( (ptr = strrchr(base, '/')) != NULL ) { strncpy(leaf, ptr+1, 128); *(ptr+1) = '\0'; } else { /* is this correct? can we get a stat request for a file with no /? */ strncpy(leaf, base, 128); strncpy(base, "./", 512); } if ( !search(1, base, &drow, &sstack, mydata->dtable) ) { errno = ENOENT; return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -