📄 xdb_file.c
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "JOSL"). You may not copy or use this file, in either * source code or executable form, except in compliance with the JOSL. You * may obtain a copy of the JOSL at http://www.jabber.org/ or at * http://www.opensource.org/. * * Software distributed under the JOSL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the JOSL * for the specific language governing rights and limitations under the * JOSL. * * Copyrights * * Portions created by or assigned to Jabber.com, Inc. are * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Jeremie Miller. * * Acknowledgements * * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. * * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License Version 2 or later (the "GPL"), in which case * the provisions of the GPL are applicable instead of those above. If you * wish to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the JOSL, * indicate your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL. If you do not * delete the provisions above, a recipient may use your version of this file * under either the JOSL or the GPL. * * * --------------------------------------------------------------------------*/ #include <jabberd.h>#include <dirent.h>#define FILES_PRIME 509/* gcc -fPIC -shared -o xdb_file.so xdb_file.c -I../srcneeds to have a spool section in the config:<load><xdb_file>../load/xdb_file.so</xdb_file></load><xdb_file xmlns="jabber:config:xdb_file"> <spool>/var/spool/jabber</spool></xdb_file>within the spool, xdb_file will make folders for hostnames it has to save data for, and within those save username.xml files containing a user's namespaces*/typedef struct cacher_struct{ char *fname; xmlnode file; int lastset;} *cacher, _cacher;typedef struct xdbf_struct{ char *spool; instance i; int timeout; xht cache; int sizelimit; int use_hashspool;} *xdbf, _xdbf;void _xdb_file_purge(xht h, const char *key, void *data, void *arg){ xdbf xf = (xdbf)arg; cacher c = (cacher)data; int now = time(NULL); if((now - c->lastset) > xf->timeout) { log_debug2(ZONE, LOGT_STORAGE, "purging %s",c->fname); xhash_zap(xf->cache,c->fname); xmlnode_free(c->file); }}/* walk the table looking for stale files to expire */result xdb_file_purge(void *arg){ xdbf xf = (xdbf)arg; log_debug2(ZONE, LOGT_STORAGE, "purge check"); xhash_walk(xf->cache,_xdb_file_purge,(void *)xf); return r_DONE;}/* this function acts as a loader, getting xml data from a file */xmlnode xdb_file_load(char *host, char *fname, xht cache){ xmlnode data = NULL; cacher c; int fd; log_debug2(ZONE, LOGT_STORAGE, "loading %s",fname); /* first, check the cache */ if((c = xhash_get(cache,fname)) != NULL) return c->file; /* test the file first, so we can be more descriptive */ fd = open(fname,O_RDONLY); if(fd < 0) { if (errno == ENOENT) { log_debug2(ZONE, LOGT_STORAGE, "xdb_file failed to open file %s: %s", fname, strerror(errno)); } else { log_warn(host,"xdb_file failed to open file %s: %s",fname,strerror(errno)); } } else { close(fd); data = xmlnode_file(fname); } /* if there's nothing on disk, create an empty root node */ if(data == NULL) data = xmlnode_new_tag("xdb"); log_debug2(ZONE, LOGT_STORAGE, "caching %s",fname); c = pmalloco(xmlnode_pool(data),sizeof(_cacher)); c->fname = pstrdup(xmlnode_pool(data),fname); c->lastset = time(NULL); c->file = data; xhash_put(cache,c->fname,c); return data;}/** * calculate the left-most four digits of the SHA-1 hash over a filename * * @param filename the filename * @param digit01 where to place the first two digits (size 3 chars!) * @param digit23 where to place the next two digits (size 3 chars!) */void _xdb_get_hashes(const char *filename, char digit01[3], char digit23[3]){ char hashedfilename[9]; /* generate a hash over the filename */ bzero(hashedfilename, sizeof(hashedfilename)); bzero(digit01, sizeof(digit01)); bzero(digit23, sizeof(digit23)); crc32_r(filename, hashedfilename); log_debug2(ZONE, LOGT_STORAGE, "hash of %s is %s", filename, hashedfilename); memcpy(digit01, hashedfilename+1, 2); memcpy(digit23, hashedfilename+4, 2); return;}/** * create folders in the spool * * @param spoolroot the root of the spool * @param host the host for which the directory should be created * @param hash1 the hash for the first subdirectory * @param hash2 the second subdirectory * @param use_subdirs true if file should be located in subdirectories * @return 1 on success, 0 on failure */int _xdb_gen_dirs(spool sp, const char *spoolroot, char *host, const char *hash1, const char *hash2, int use_subdirs){ struct stat s; char *tmp; /* check that the root of the spool structure exists */ if (stat(spoolroot, &s) < 0) { log_error(host, "the spool root directory %s does not seem to exist", spoolroot); return 0; } /* check and create the host-named folder */ spooler(sp, spoolroot, "/", host, sp); tmp = spool_print(sp); if(stat(tmp,&s) < 0 && mkdir(tmp, S_IRWXU) < 0) { log_error(host, "could not create spool folder %s: %s", tmp, strerror(errno)); return 0; } if (use_subdirs) { /* check or create the first level subdirectory */ spooler(sp, "/", hash1, sp); tmp = spool_print(sp); if(stat(tmp,&s) < 0 && mkdir(tmp, S_IRWXU) < 0) { log_error(host, "could not create spool folder %s: %s", tmp, strerror(errno)); return 0; } /* check or create the second level subdirectory */ spooler(sp, "/", hash2, sp); tmp = spool_print(sp); if(stat(tmp,&s) < 0 && mkdir(tmp, S_IRWXU) < 0) { log_error(host, "could not create spool folder %s: %s", tmp, strerror(errno)); return 0; } } return 1;}/** * utility that generates the filename for a spool file * * @param create true if the directory for the file should be generated * @param p pool that should be used for string operations * @param spl location for the spool root * @param host host of the xdb request (the 'spool folder') * @param file the basename of the xdb file * @param ext the extension for the xdb file * @param use_subdirs true if file should be located in subdirectories * @return concatenated string of the form spl+"/"+somehashes+"/"+file+"."+ext */char *xdb_file_full(int create, pool p, char *spl, char *host, char *file, char *ext, int use_subdirs){ spool sp = spool_new(p); char digit01[3], digit23[3]; char *ret; char *filename; filename = spools(p, file, ".", ext, p); _xdb_get_hashes(filename, digit01, digit23); /* is the creation of the folder requested? */ if(create) { if (!_xdb_gen_dirs(sp, spl, host, digit01, digit23, use_subdirs)) { log_error(host, "xdb request failed, necessary directory was not created"); return NULL; } } else if (use_subdirs) { spooler(sp, spl, "/", host, "/", digit01, "/", digit23, sp); } else { spooler(sp, spl, "/", host, sp); } /* full path to file */ spooler(sp,"/",filename, sp); ret = spool_print(sp); return ret;}/* the callback to handle xdb packets */result xdb_file_phandler(instance i, dpacket p, void *arg){ char *full, *ns, *act, *match; xdbf xf = (xdbf)arg; xmlnode file, top, data; int ret = 0, flag_set = 0; log_debug2(ZONE, LOGT_STORAGE|LOGT_DELIVER, "handling xdb request %s",xmlnode2str(p->x)); if((ns = xmlnode_get_attrib(p->x,"ns")) == NULL) return r_ERR; if(j_strcmp(xmlnode_get_attrib(p->x,"type"), "set") == 0) flag_set = 1; /* is this request specific to a user or global data? use that for the file name */ if(p->id->user != NULL) full = xdb_file_full(flag_set, p->p, xf->spool, p->id->server, p->id->user, "xml", xf->use_hashspool); else full = xdb_file_full(flag_set, p->p, xf->spool, p->id->server, "global", "xdb", 0); if(full == NULL) return r_ERR; /* load the data from disk/cache */ top = file = xdb_file_load(p->host, full, xf->cache); /* if we're dealing w/ a resource, just get that element */ if(p->id->resource != NULL) { if((top = xmlnode_get_tag(top,spools(p->p,"res?id=",p->id->resource,p->p))) == NULL) { top = xmlnode_insert_tag(file,"res"); xmlnode_put_attrib(top,"id",p->id->resource); } } /* just query the relevant namespace */ data = xmlnode_get_tag(top,spools(p->p,"?xdbns=",ns,p->p));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -