--- /dev/null
+#ifndef _AFSCP_H_
+#define _AFSCP_H_
+
+/* AUTORIGHTS */
+#include <afs/param.h>
+#include <afs/afsint.h>
+struct afs_server;
+struct afs_cell;
+struct afs_callback ;
+
+struct afs_volume
+{
+ struct afs_cell *cell;
+ afs_uint32 id;
+ int voltype;
+ int nservers;
+ int servers[16];
+ char name[256];
+ void *statcache;
+ void *dircache;
+};
+
+struct afs_venusfid
+{
+ struct afs_cell *cell;
+ struct AFSFid fid;
+};
+
+struct afs_dirent
+{
+ afs_uint32 vnode;
+ afs_uint32 unique;
+ char name[16+32*(64-2)]; /* 64 is EPP. */
+};
+
+typedef struct afs_dirstream afs_DIR;
+typedef struct afs_openfile afs_FILE;
+
+extern int afs_errno;
+int afscp_init(const char *cellname);
+void afscp_finalize(void);
+
+#ifdef API_COMPAT
+#define GetCellByName afs_cellbyname
+#define GetCellById afs_cellbyid
+#define GetDefaultCell afs_defaultcell
+#define SetDefaultCell afs_setdefaultcell
+#define GetCellID afs_cellid
+#endif
+struct afs_cell *afs_defaultcell(void);
+struct afs_cell *afs_cellbyname(const char *cellname) ;
+int afs_setdefaultcell(const char *cellname);
+struct afs_cell *afs_cellbyid(int id);
+int afs_cellid(struct afs_cell *cell);
+
+
+#ifdef API_COMPAT
+#define GetServerById afs_serverbyid
+#define GetServerByAddr afs_serverbyaddr
+#define GetAnyServerById afs_anyserverbyaddr
+#define GetAnyServerByIndex afs_serverbyindex
+#define GetConnection afs_serverconnection
+#endif
+
+struct afs_server *afs_serverbyid(struct afs_cell *thecell, afsUUID *u);
+struct afs_server *afs_serverbyaddr(struct afs_cell *thecell,
+ afs_uint32 addr);
+struct afs_server *afs_anyserverbyaddr(afs_uint32 addr) ;
+struct afs_server *afs_serverbyindex(int idx) ;
+struct rx_connection *afs_serverconnection(const struct afs_server *srv,
+ int i);
+
+int AddCallBack(const struct afs_server *server, const struct AFSFid *fid,
+ const struct AFSFetchStatus *st, const struct AFSCallBack *cb);
+int RemoveCallBack(const struct afs_server *server, const struct afs_venusfid *fid);
+int ReturnCallBacks(const struct afs_server *server);
+int ReturnAllCallBacks(void);
+
+
+/* file metastuff */
+/* frees with free() */
+struct afs_venusfid *makefid(struct afs_cell *cell, afs_uint32 volume,
+ afs_uint32 vnode, afs_uint32 unique);
+struct afs_venusfid *dupfid(const struct afs_venusfid *in);
+
+struct stat;
+int afs_stat(const struct afs_venusfid *fid, struct stat *s);
+
+ssize_t afs_pread(const struct afs_venusfid *fid, void *buffer, size_t count, off_t offset);
+ssize_t afs_pwrite(const struct afs_venusfid *fid, const void *buffer, size_t count, off_t offset);
+afs_FILE *afs_open(const char *path);
+afs_FILE *afs_fidopen(const struct afs_venusfid *fid);
+off_t afs_fseek (afs_FILE *f, off_t o, int whence);
+ssize_t afs_fread(const afs_FILE *f, void *buffer, size_t count);
+ssize_t afs_fwrite(const afs_FILE *f, const void *buffer, size_t count);
+
+/* rpc wrappers */
+int afs_GetStatus(const struct afs_venusfid *fid, struct AFSFetchStatus *s);
+int afs_StoreStatus(const struct afs_venusfid *fid, struct AFSStoreStatus *s);
+int afs_CreateFile(const struct afs_venusfid *fid, /* const */ char *name,
+ struct AFSStoreStatus *sst,
+ struct afs_venusfid **ret);
+int afs_MakeDir(const struct afs_venusfid *fid, /* const */ char *name,
+ struct AFSStoreStatus *sst,
+ struct afs_venusfid **ret);
+int afs_Symlink(const struct afs_venusfid *fid, /* const */ char *name,
+ /*const*/ char *target, struct AFSStoreStatus *sst);
+int afs_RemoveFile(const struct afs_venusfid *dir, char *name);
+int afs_RemoveDir(const struct afs_venusfid *dir, char *name);
+int afs_FetchACL(const struct afs_venusfid *dir,
+ struct AFSOpaque *acl);
+int afs_StoreACL(const struct afs_venusfid *dir,
+ struct AFSOpaque *acl);
+/* directory parsing stuff*/
+struct afs_dirstream *afs_opendir(const struct afs_venusfid *fid);
+struct afs_dirent *afs_readdir(struct afs_dirstream *d);
+int afs_rewinddir(struct afs_dirstream *d);
+int afs_closedir(struct afs_dirstream *d);
+struct afs_venusfid *DirLookup(struct afs_dirstream *d, const char *name);
+struct afs_venusfid *ResolveName(const struct afs_venusfid *dir, const char *name);
+struct afs_venusfid *ResolvePath(const char *path);
+struct afs_venusfid *ResolvePath2(const struct afs_volume *start, const char *path);
+
+/* vldb stuff */
+struct afs_volume *afs_volumebyname(struct afs_cell *cell, const char *vname, afs_int32 vtype);
+struct afs_volume *afs_volumebyid(struct afs_cell *cell, afs_uint32 id);
+
+#define DIRMODE_CELL 0
+#define DIRMODE_DYNROOT 1
+
+#define VOLTYPE_RW 0
+#define VOLTYPE_RO 1
+#define VOLTYPE_BK 2
+int SetDirMode(int mode);
+
+#endif
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/vlserver.h>
+#include <afs/vldbint.h>
+#include <afs/dir.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+
+int afs_FetchACL(const struct afs_venusfid *dir,
+ struct AFSOpaque *acl) {
+ int code, i, j;
+ struct AFSFid df = dir->fid;
+ struct afs_volume *vol;
+ struct AFSFetchStatus dfst;
+ struct AFSVolSync vs;
+ struct afs_volume *volume;
+ struct afs_server *server;
+
+ vol=afs_volumebyid(dir->cell, dir->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_FetchACL(server->conns[j], &df, acl, &dfst, &vs);
+ if (code >= 0)
+ break;
+ }
+ }
+ if (code >= 0)
+ break;
+ }
+ if (code) {
+ _StatInvalidate(dir);
+ afs_errno=code;
+ return -1;
+ }
+ _StatStuff(dir, &dfst);
+ return 0;
+}
+
+
+int afs_StoreACL(const struct afs_venusfid *dir,
+ struct AFSOpaque *acl) {
+ int code, i, j;
+ struct AFSFid df = dir->fid;
+ struct afs_volume *vol;
+ struct AFSFetchStatus dfst;
+ struct AFSVolSync vs;
+ struct afs_volume *volume;
+ struct afs_server *server;
+
+ vol=afs_volumebyid(dir->cell, dir->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_StoreACL(server->conns[j], &df, acl, &dfst, &vs);
+ if (code >= 0)
+ break;
+ }
+ }
+ if (code >= 0)
+ break;
+ }
+ if (code) {
+ _StatInvalidate(dir);
+ afs_errno=code;
+ return -1;
+ }
+ _StatStuff(dir, &dfst);
+ return 0;
+}
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/afsint.h> /*Callback interface defs*/
+#include <afs/afsutil.h>
+#include <stdlib.h>
+#include <string.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+int afs_cb_inited = 0;
+struct interfaceAddr afs_cb_interface;
+static int afs_maxcallbacks=0, afs_cballoced=0;
+struct afs_callback *allcallbacks=NULL;
+
+static int init_afs_cb() {
+ int count;
+
+ afs_uuid_create(&afs_cb_interface.uuid);
+ count = rx_getAllAddr(&afs_cb_interface.addr_in, AFS_MAX_INTERFACE_ADDR);
+ if ( count <= 0 )
+ afs_cb_interface.numberOfInterfaces = 0;
+ else
+ afs_cb_interface.numberOfInterfaces = count;
+ afs_cb_inited = 1;
+ return 0;
+}
+
+int AddCallBack(const struct afs_server *server, const struct AFSFid *fid,
+ const struct AFSFetchStatus *fst, const struct AFSCallBack *cb)
+{
+ int i;
+ struct afs_callback *use=NULL, *newlist;
+ struct afs_venusfid f;
+ time_t now;
+
+ time(&now);
+
+ for (i=0;i<afs_maxcallbacks;i++) {
+ if (allcallbacks[i].cb.ExpirationTime < now) {
+ if (allcallbacks[i].valid) {
+ f.cell=afs_cellbyid(allcallbacks[i].server->cell);
+ memcpy(&f.fid, &allcallbacks[i].fid, sizeof(struct afs_venusfid));
+ _StatInvalidate(&f);
+ }
+ allcallbacks[i].valid=0;
+
+ }
+
+ if (allcallbacks[i].valid == 0)
+ use=&allcallbacks[i];
+ if (allcallbacks[i].server==server &&
+ fid->Volume == allcallbacks[i].fid.Volume &&
+ fid->Vnode == allcallbacks[i].fid.Vnode &&
+ fid->Unique == allcallbacks[i].fid.Unique) {
+ use=&allcallbacks[i];
+ break;
+ }
+ }
+ if (!use) {
+ if (afs_maxcallbacks >= afs_cballoced) {
+ if (afs_cballoced)
+ afs_cballoced = afs_cballoced *2;
+ else
+ afs_cballoced = 4;
+ newlist=realloc(allcallbacks, afs_cballoced *
+ sizeof(struct afs_callback));
+ if (!newlist)
+ return -1;
+ allcallbacks=newlist;
+ }
+ use=&allcallbacks[afs_maxcallbacks++];
+ }
+ use->valid=1;
+ use->server=server;
+ memmove(&use->fid, fid, sizeof(struct AFSFid));
+ memmove(&use->cb, cb, sizeof(struct AFSCallBack));
+ f.cell=afs_cellbyid(server->cell);
+ memcpy(&f.fid, fid, sizeof(struct AFSFid));
+ _StatStuff(&f, fst);
+ return 0;
+}
+int RemoveCallBack(const struct afs_server *server, const struct afs_venusfid *f)
+{
+ struct afs_callback *cb;
+ int i;
+
+ _StatInvalidate(f);
+ if (!server)
+ return 0;
+ for (i=0;i<afs_maxcallbacks;i++) {
+ cb=&allcallbacks[i];
+ if (cb->server == server &&
+ f->fid.Volume == cb->fid.Volume &&
+ f->fid.Vnode == cb->fid.Vnode &&
+ f->fid.Unique == cb->fid.Unique) {
+ cb->valid = 0;
+ break;
+ }
+ }
+ return 0;
+}
+
+int ReturnCallBacks(const struct afs_server *server)
+{
+ struct AFSCBFids theFids;
+ struct AFSCBs theCBs;
+ struct afs_callback *cb;
+ struct afs_venusfid f;
+ int inited=0;
+ int ncallbacks=0;
+ int i,j;
+ time_t now;
+
+ time(&now);
+
+ for (i=0;i<afs_maxcallbacks;i++) {
+ cb=&allcallbacks[i];
+/* printf("%d %x %x %ld %d", i, cb, cb->server, cb->cb.ExpirationTime,
+ cb->valid);*/
+ if (cb->server != server)
+ continue;
+ if (cb->cb.ExpirationTime < now) {
+ if (cb->valid) {
+ f.cell=afs_cellbyid(cb->server->cell);
+ memcpy(&f.fid, &cb->fid, sizeof(struct afs_venusfid));
+ _StatInvalidate(&f);
+ }
+
+ cb->valid=0;
+ continue;
+ }
+ if (!inited) {
+ theFids.AFSCBFids_val=malloc(sizeof(struct AFSCallBack) * AFSCBMAX);
+ if (!theFids.AFSCBFids_val)
+ return -1;
+ theCBs.AFSCBs_val=malloc(sizeof(struct AFSFid) * AFSCBMAX);
+ if (!theCBs.AFSCBs_val) {
+ free(theFids.AFSCBFids_val);
+ return -1;
+ }
+ }
+
+ if (ncallbacks == AFSCBMAX) {
+ theFids.AFSCBFids_len=ncallbacks;
+ theCBs.AFSCBs_len=ncallbacks;
+ for (j=0;j<server->naddrs;j++) {
+ if (!RXAFS_GiveUpCallBacks(server->conns[j], &theFids,
+ &theCBs))
+ break;
+ }
+ ncallbacks=0;
+ }
+ memmove(&theFids.AFSCBFids_val[ncallbacks], &cb->fid,
+ sizeof(struct AFSFid));
+ memmove(&theCBs.AFSCBs_val[ncallbacks], &cb->cb,
+ sizeof(struct AFSCallBack));
+
+ theCBs.AFSCBs_val[ncallbacks].CallBackType = CB_DROPPED;
+ ncallbacks++;
+ if (cb->valid) {
+ f.cell=afs_cellbyid(cb->server->cell);
+ memcpy(&f.fid, &cb->fid, sizeof(struct afs_callback));
+ _StatInvalidate(&f);
+ }
+
+ cb->valid=0;
+ }
+ if (ncallbacks) {
+ theFids.AFSCBFids_len=ncallbacks;
+ theCBs.AFSCBs_len=ncallbacks;
+ for (j=0;j<server->naddrs;j++) {
+ if (!RXAFS_GiveUpCallBacks(server->conns[j], &theFids,
+ &theCBs))
+ break;
+ }
+ free(theFids.AFSCBFids_val);
+ free(theCBs.AFSCBs_val);
+ }
+ return 0;
+}
+
+int ReturnAllCallBacks(void)
+{
+ struct afs_server *s;
+ int i;
+
+ for (i=0;(s=afs_serverbyindex(i));i++)
+ ReturnCallBacks(s);
+ return 0;
+}
+
+
+
+afs_int32 SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array)
+ struct rx_call *rxcall;
+ AFSCBFids *Fids_Array;
+ AFSCBs *CallBack_Array;
+
+{ /*SRXAFSCB_CallBack*/
+ struct rx_connection *rxconn=rx_ConnectionOf(rxcall);
+ struct rx_peer *rxpeer=rx_PeerOf(rxconn);
+ struct afs_server *server=afs_anyserverbyaddr(rxpeer->host);
+ struct afs_callback *cb;
+ struct afs_venusfid f;
+ struct AFSFid *fid;
+ int i,j;
+
+ if (!server)
+ return 0;
+ for (i=0;i<afs_maxcallbacks;i++) {
+ cb=&allcallbacks[i];
+ if (cb->server != server)
+ continue;
+ for (j=0;j<Fids_Array->AFSCBFids_len;j++) {
+ fid=&Fids_Array->AFSCBFids_val[j];
+ if (fid->Volume == cb->fid.Volume &&
+ fid->Vnode == cb->fid.Vnode &&
+ fid->Unique == cb->fid.Unique)
+ cb->valid = 0;
+ f.cell=afs_cellbyid(cb->server->cell);
+ memcpy(&f.fid, &cb->fid, sizeof(struct afs_venusfid));
+ _StatInvalidate(&f);
+ }
+ }
+
+ return(0);
+
+} /*SRXAFSCB_CallBack*/
+
+
+afs_int32 SRXAFSCB_InitCallBackState(rxcall)
+ struct rx_call *rxcall;
+
+{ /*SRXAFSCB_InitCallBackState*/
+ struct rx_connection *rxconn=rx_ConnectionOf(rxcall);
+ struct rx_peer *rxpeer=rx_PeerOf(rxconn);
+ struct afs_server *server=afs_anyserverbyaddr(rxpeer->host);
+ struct afs_callback *cb;
+ struct afs_venusfid f;
+ int i;
+
+ if (!server)
+ return 0;
+ for (i=0;i<afs_maxcallbacks;i++) {
+ cb=&allcallbacks[i];
+ if (cb->server != server)
+ continue;
+ if (cb->valid) {
+ f.cell=afs_cellbyid(cb->server->cell);
+ memcpy(&f.fid, &cb->fid, sizeof(struct afs_callback));
+ _StatInvalidate(&f);
+ }
+ cb->valid = 0;
+ }
+ return(0);
+
+} /*SRXAFSCB_InitCallBackState*/
+
+afs_int32 SRXAFSCB_Probe(rxcall)
+ struct rx_call *rxcall;
+
+{ /*SRXAFSCB_Probe*/
+ return(0);
+
+} /*SRXAFSCB_Probe*/
+
+
+afs_int32 SRXAFSCB_GetCE(rxcall)
+ struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetCE*/
+ return(0);
+} /*SRXAFSCB_GetCE*/
+
+afs_int32 SRXAFSCB_GetCE64(rxcall)
+ struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetCE*/
+ return(0);
+} /*SRXAFSCB_GetCE*/
+
+
+afs_int32 SRXAFSCB_GetLock(rxcall)
+ struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetLock*/
+ return(0);
+
+} /*SRXAFSCB_GetLock*/
+afs_int32 SRXAFSCB_XStatsVersion(rxcall)
+ struct rx_call *rxcall;
+
+{ /*SRXAFSCB_XStatsVersion*/
+ return(0);
+
+} /*SRXAFSCB_XStatsVersion*/
+
+afs_int32 SRXAFSCB_GetXStats(rxcall)
+ struct rx_call *rxcall;
+
+{ /*SRXAFSCB_GetXStats*/
+ return(0);
+} /*SRXAFSCB_GetXStats*/
+
+int SRXAFSCB_InitCallBackState2(rxcall, addr)
+struct rx_call *rxcall;
+struct interfaceAddr * addr;
+{
+ return RXGEN_OPCODE;
+}
+
+int SRXAFSCB_WhoAreYou(rxcall, addr)
+struct rx_call *rxcall;
+struct interfaceAddr *addr;
+{
+ XDR x;
+ if ( rxcall && addr )
+ {
+ if (!afs_cb_inited) init_afs_cb();
+ *addr = afs_cb_interface;
+ }
+#ifdef STRANGEDEBUG
+ xdrrx_create(&x, rxcall, XDR_ENCODE);
+ xdr_interfaceAddr(&x, addr);
+ rx_Write(rxcall,"",0);
+ rxi_FlushWrite(rxcall);
+ rx_EndCall(rxcall, 0);
+ IOMGR_Sleep(10);
+ IOMGR_Sleep(600);
+#endif
+ return(0);
+}
+
+int SRXAFSCB_InitCallBackState3(rxcall, uuidp)
+struct rx_call *rxcall;
+afsUUID *uuidp;
+{
+ struct rx_connection *rxconn=rx_ConnectionOf(rxcall);
+ struct rx_peer *rxpeer=rx_PeerOf(rxconn);
+ struct afs_server *server=afs_anyserverbyaddr(rxpeer->host);
+ struct afs_callback *cb;
+ struct afs_venusfid f;
+ int i;
+
+ if (!server)
+ return 0;
+ for (i=0;i<afs_maxcallbacks;i++) {
+ cb=&allcallbacks[i];
+ if (cb->server != server)
+ continue;
+ if (cb->valid) {
+ f.cell=afs_cellbyid(cb->server->cell);
+ memcpy(&f.fid, &cb->fid, sizeof(struct afs_callback));
+ _StatInvalidate(&f);
+ }
+ cb->valid = 0;
+ }
+ return(0);
+}
+int SRXAFSCB_ProbeUuid(rxcall, uuidp)
+struct rx_call *rxcall;
+afsUUID *uuidp;
+{
+ int code = 0;
+ if (!afs_cb_inited) init_afs_cb();
+ if (!afs_uuid_equal(uuidp, &afs_cb_interface.uuid))
+ code = 1; /* failure */
+#ifdef STRANGEDEBUG
+ rx_EndCall(rxcall,code);
+ IOMGR_Sleep(600);
+#endif
+ return code;
+}
+int SRXAFSCB_GetServerPrefs(
+ struct rx_call *a_call,
+ afs_int32 a_index,
+ afs_int32 *a_srvr_addr,
+ afs_int32 *a_srvr_rank)
+{
+ *a_srvr_addr = 0xffffffff;
+ *a_srvr_rank = 0xffffffff;
+ return 0;
+}
+
+int SRXAFSCB_GetCellServDB(
+ struct rx_call *a_call,
+ afs_int32 a_index,
+ char **a_name,
+ afs_int32 *a_hosts)
+{
+ return RXGEN_OPCODE;
+}
+
+int SRXAFSCB_GetLocalCell(
+ struct rx_call *a_call,
+ char **a_name)
+{
+ return RXGEN_OPCODE;
+}
+
+int SRXAFSCB_GetCacheConfig(
+ struct rx_call *a_call,
+ afs_uint32 callerVersion,
+ afs_uint32 *serverVersion,
+ afs_uint32 *configCount,
+ cacheConfig *config)
+{
+ return RXGEN_OPCODE;
+}
+int SRXAFSCB_GetCellByNum(
+ struct rx_call *a_call,
+ afs_int32 a_index,
+ char **a_name,
+ afs_int32 *a_hosts)
+{
+ return RXGEN_OPCODE;
+}
+#ifdef AFS_64BIT_CLIENT
+afs_int32
+SRXAFSCB_TellMeAboutYourself(struct rx_call * rxcall,
+ struct interfaceAddr * addr,
+ Capabilities * capabilities)
+{
+ if ( rxcall && addr )
+ {
+ if (!afs_cb_inited) init_afs_cb();
+ *addr = afs_cb_interface;
+ }
+ return(0);
+}
+#endif
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/vlserver.h>
+#include <afs/vldbint.h>
+#include <afs/dir.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <search.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+static int dirmode=DIRMODE_CELL;
+
+int SetDirMode(int mode) {
+
+ if (mode != DIRMODE_CELL && mode != DIRMODE_DYNROOT) {
+ afs_errno=EINVAL;
+ return -1;
+ }
+ dirmode=mode;
+ return 0;
+}
+
+/* comparison function for tsearch */
+static int dircompare(const void *a, const void *b)
+{
+ const struct afs_dircache *sa=a,*sb=b;
+ if (sa->me.fid.Vnode < sb->me.fid.Vnode) return -1;
+ if (sa->me.fid.Vnode > sb->me.fid.Vnode) return 1;
+ if (sa->me.fid.Unique < sb->me.fid.Unique) return -1;
+ if (sa->me.fid.Unique > sb->me.fid.Unique) return 1;
+ return 0;
+}
+
+/* make sure the dirstream contains the most up to date directory contents */
+static int _DirUpdate (struct afs_dirstream *d) {
+ struct AFSFetchStatus s;
+ int code;
+ struct afs_volume *v;
+ struct afs_dircache key, *stored;
+ void **cached;
+
+
+ code=afs_GetStatus(&d->fid, &s);
+ if (code)
+ return code;
+
+ if (d->dirbuffer && d->dv == s.DataVersion)
+ return 0;
+ v=afs_volumebyid(d->fid.cell, d->fid.fid.Volume);
+ if (!v) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+
+ memcpy(&key.me, &d->fid, sizeof(struct afs_venusfid));
+ cached=tfind(&key, &v->dircache, dircompare);
+ if (cached) {
+ stored=*(struct afs_dircache **)cached;
+ if (d->dv == s.DataVersion) {
+ d->dirbuffer = stored->dirbuffer;
+ d->buflen = stored->buflen;
+ d->dv = stored->dv;
+ return 0;
+ }
+ tdelete(&key, &v->dircache, dircompare);
+ if (d->dirbuffer != stored->dirbuffer)
+ free(stored->dirbuffer);
+ free(stored);
+ }
+ if (s.Length > BIGMAXPAGES * AFS_PAGESIZE) {
+ afs_errno=EFBIG;
+ return -1;
+ }
+ if (d->buflen != s.Length) {
+ char *new;
+ if (d->dirbuffer) {
+ new=realloc(d->dirbuffer, s.Length);
+ } else {
+ new=malloc(s.Length);
+ }
+ if (new) {
+ d->dirbuffer=new;
+ } else {
+ afs_errno=ENOMEM;
+ return -1;
+ }
+ d->buflen=s.Length;
+ }
+
+ code=afs_pread(&d->fid, d->dirbuffer, s.Length, 0);
+ if (code < 0) {
+ return -1;
+ }
+ d->dv=s.DataVersion;
+ cached=tsearch(&key, &v->dircache, dircompare);
+ if (cached) {
+ stored=malloc(sizeof(struct afs_dircache));
+ if (stored) {
+ memcpy(&stored->me, &d->fid, sizeof(struct afs_venusfid));
+ stored->buflen=d->buflen;
+ stored->dirbuffer=d->dirbuffer;
+ stored->dv=d->dv;
+ *(struct afs_dircache **)cached=stored;
+ } else {
+ tdelete(&key, &v->dircache, dircompare);
+ }
+ }
+ return 0;
+}
+
+
+static struct DirEntry *dir_get_entry(struct afs_dirstream *d, int entry) {
+
+ struct DirHeader *h=(struct DirHeader *)d->dirbuffer;
+ struct PageHeader *p;
+ struct DirEntry *ret;
+ int fr;
+ int pg, off;
+
+
+ pg=entry >> LEPP;
+ off=entry & (EPP-1);
+
+ if (pg * AFS_PAGESIZE >= d->buflen) { /* beyond end of file */
+ return NULL;
+ }
+ if (!off || (!pg && off < DHE + 1)) { /* offset refers to metadata */
+ return NULL;
+ }
+ if (pg < MAXPAGES && h->alloMap[pg] == EPP) { /* page is empty */
+ return NULL;
+ }
+ p=(struct PageHeader *)&d->dirbuffer[pg * AFS_PAGESIZE];
+ fr=p->freebitmap[off >> 8];
+#if 0
+ if ((fr & (1<<(off & 7))) == 0 ) { /* entry isn't allocated */
+ return NULL;
+ }
+#endif
+
+ ret=(struct DirEntry *)&d->dirbuffer[pg * AFS_PAGESIZE + 32 * off];
+
+ return ret;
+}
+
+struct afs_dirstream *afs_opendir(const struct afs_venusfid *fid) {
+ struct afs_dirstream *ret;
+ struct AFSFetchStatus s;
+ int code;
+
+ code=afs_GetStatus(fid, &s);
+ if (code) {
+ return NULL;
+ }
+
+ if (s.FileType != Directory) {
+ afs_errno=ENOTDIR;
+ return NULL;
+ }
+ ret=malloc(sizeof(struct afs_dirstream));
+ if (!ret) {
+ afs_errno=ENOMEM;
+ return NULL;
+ }
+ memset(ret,0,sizeof(struct afs_dirstream));
+ memmove(&ret->fid, fid, sizeof(struct afs_venusfid));
+ code=_DirUpdate(ret);
+ if (code < 0) {
+ afs_closedir(ret);
+ return NULL;
+ }
+ ret->hashent=-1;
+ ret->entry=0;
+ return ret;
+}
+
+struct afs_dirent *afs_readdir(struct afs_dirstream *d) {
+ struct DirHeader *h=(struct DirHeader *)d->dirbuffer;
+ struct DirEntry *info;
+ int ent;
+
+
+ ent=d->entry;
+ while (ent == 0 && d->hashent < NHASHENT-1) {
+ d->hashent++;
+ ent=ntohs(h->hashTable[d->hashent]);
+ }
+ if (ent == 0) {
+ afs_errno=0;
+ return NULL;
+ }
+ info=dir_get_entry(d, ent);
+ if (!info) {
+ afs_errno=0;
+ return NULL;
+ }
+ d->ret.vnode=ntohl(info->fid.vnode);
+ d->ret.unique=ntohl(info->fid.vunique);
+ strcpy(d->ret.name, info->name); /* guaranteed to be NULL terminated? */
+ d->entry=ntohs(info->next);
+
+ return &d->ret;
+}
+
+/* as it calls _DirUpdate, this may corrupt any previously returned dirent's */
+int afs_rewinddir(struct afs_dirstream *d) {
+ _DirUpdate(d);
+ d->hashent=-1;
+ d->entry=0;
+ return 0;
+}
+int afs_closedir(struct afs_dirstream *d) {
+ free(d);
+ return 0;
+}
+
+static int namehash(const char *name)
+{
+ int hval, tval;
+
+ hval=0;
+ while (*name) hval = (hval * 173) + *name++;
+ tval = hval & (NHASHENT - 1);
+ return tval ?
+ (hval < 0 ? NHASHENT - tval : tval)
+ : 0;
+}
+
+
+struct afs_venusfid *DirLookup(struct afs_dirstream *d, const char *name) {
+ int fid[3];
+ int code;
+ int hval, entry;
+ struct DirHeader *h=(struct DirHeader *)d->dirbuffer;
+ struct DirEntry *info;
+
+ code=_DirUpdate(d);
+ if (code)
+ return NULL;
+ hval=namehash(name);
+ entry=ntohs(h->hashTable[hval]);
+
+ while (entry) {
+ info=dir_get_entry(d, entry);
+ if (!info) {
+ afs_errno=EIO;
+ return NULL;
+ }
+ if (!strcmp(info->name, name))
+ break;
+ entry=ntohs(info->next);
+ }
+ if (entry) {
+ return makefid(d->fid.cell, d->fid.fid.Volume,
+ ntohl(info->fid.vnode),
+ ntohl(info->fid.vunique));
+ } else {
+ afs_errno=ENOENT;
+ return NULL;
+ }
+}
+
+struct afs_venusfid *ResolveName(const struct afs_venusfid *dir, const char *name) {
+ struct afs_venusfid *ret;
+ struct afs_dirstream *d;
+
+ d=afs_opendir(dir);
+ if (!d)
+ return NULL;
+ ret=DirLookup(d, name);
+ afs_closedir(d);
+ return ret;
+}
+
+static int gettoproot(struct afs_cell *cell, char *p, char **q, struct afs_venusfid **root) {
+ struct afs_volume *rootvol;
+ char *r;
+
+ if (dirmode == DIRMODE_DYNROOT && !strcmp(p, "/afs")) {
+ afs_errno=EINVAL;
+ return 1;
+ }
+ if (!strncmp(p,"/afs",4)) {
+ afscp_dprintf(("gettoproot: path is absolute\n"));
+ p=&p[5];
+ while (*p == '/') p++;
+ if (dirmode == DIRMODE_DYNROOT) {
+ int voltype;
+ retry_dot:
+ voltype = VOLTYPE_RO;
+ if (*p == '.') {
+ p++;
+ voltype=VOLTYPE_RW;
+ }
+ if (*p == '/') {
+ while (*p == '/') p++;
+ goto retry_dot;
+ }
+ if (*p == '.' || *p == 0) {
+ afs_errno=EINVAL;
+ return 1;
+ }
+ r=p;
+ while (*r && *r != '/') r++;
+ if (!*r) {
+ afs_errno=ENODEV;
+ return 1;
+ }
+ *r++=0;
+ *q=r;
+ afscp_dprintf(("gettoproot: dynroot looking up cell %s\n", p));
+ cell=afs_cellbyname(p);
+ if (!cell) {
+ afscp_dprintf(("gettoproot: no such cell\n"));
+ afs_errno=ENODEV;
+ return 1;
+ }
+ rootvol=afs_volumebyname(cell, "root.cell", voltype);
+ if (!rootvol && voltype == VOLTYPE_RO)
+ rootvol=afs_volumebyname(cell, "root.cell", VOLTYPE_RW);
+ } else {
+ *q=p;
+ rootvol=afs_volumebyname(cell, "root.afs", VOLTYPE_RO);
+ if (!rootvol)
+ rootvol=afs_volumebyname(cell, "root.afs", VOLTYPE_RW);
+ }
+ if (!rootvol)
+ afscp_dprintf(("gettoproot: volume not found\n"));
+ } else {
+ afscp_dprintf(("gettoproot: path is relative\n"));
+ if (p[0] == '/') {
+ afs_errno=EXDEV;
+ return 1;
+ }
+ rootvol=afs_volumebyname(cell, "root.cell", VOLTYPE_RO);
+ if (!rootvol)
+ rootvol=afs_volumebyname(cell, "root.cell", VOLTYPE_RW);
+ *q=p;
+ }
+ if (!rootvol) { afs_errno=ENODEV; return 1;}
+ *root=makefid(cell, rootvol->id, 1, 1);
+ return 0;
+}
+
+static int getvolumeroot(struct afs_cell *cell, int voltype, const char *vname, struct afs_venusfid **root) {
+ struct afs_volume *vol;
+ vol=afs_volumebyname(cell, vname, voltype);
+ if (!vol && voltype == VOLTYPE_RO)
+ vol=afs_volumebyname(cell, vname, VOLTYPE_RW);
+ if (!vol) { afs_errno=ENODEV; return 1;}
+ *root=makefid(cell, vol->id, 1, 1);
+ return 0;
+}
+
+typedef struct fidstack_s
+{
+ int alloc;
+ int count;
+ struct afs_venusfid ** entries;
+} *fidstack;
+
+static fidstack fidstack_alloc() {
+ fidstack ret;
+
+ ret=malloc(sizeof(struct fidstack_s));
+ if (!ret) {
+ afs_errno=ENOMEM;
+ return NULL;
+ }
+ ret->alloc=10;
+ ret->count=0;
+ ret->entries=malloc(ret->alloc * sizeof(struct afs_venusfid *));
+ if (!ret->entries) {
+ free(ret);
+ afs_errno=ENOMEM;
+ return NULL;
+ }
+ return ret;
+}
+
+static void fidstack_push(fidstack s, struct afs_venusfid *entry) {
+ struct afs_venusfid **new;
+ if (s->count >= s->alloc) {
+ new=realloc(s->entries, (s->alloc + 10) *
+ sizeof(struct afs_venusfid *));
+ if (!new)
+ return;
+ s->entries=new;
+ s->alloc += 10;
+ }
+ s->entries[s->count++]=entry;
+ return;
+}
+
+static struct afs_venusfid *fidstack_pop(fidstack s) {
+ if (s->count)
+ return s->entries[-- s->count];
+ return NULL;
+}
+
+static void fidstack_free(fidstack s) {
+ int i;
+
+ for (i=0;i<s->count;i++)
+ free(s->entries[i]);
+ free (s->entries);
+ free(s);
+}
+
+static struct afs_venusfid *_ResolvePath(const struct afs_venusfid *, fidstack, char *, int);
+
+static struct afs_venusfid *HandleLink(struct afs_venusfid *in, const struct afs_venusfid *parent, fidstack fids, int follow,
+ const struct AFSFetchStatus *s, int terminal) {
+ char *linkbuf, *linkbufq;
+ struct afs_cell *cell;
+ struct afs_volume *v;
+ struct afs_venusfid *root,*ret;
+ int voltype;
+ int code;
+ if ((s->UnixModeBits & 0111) &&
+ (follow == 0) &&
+ terminal) { /* normal link */
+ return in;
+ }
+ linkbuf=malloc(s->Length + 1);
+ code=afs_pread(in, linkbuf, s->Length, 0);
+ if (code < 0) {
+ free(linkbuf);
+ free(in);
+ return NULL;
+ }
+ if (code != s->Length) {
+ afs_errno=EIO;
+ free(linkbuf);
+ free(in);
+ return NULL;
+ }
+ linkbuf[s->Length]=0;
+ if (s->UnixModeBits & 0111) { /* normal link */
+ afscp_dprintf(("Recursing on symlink %s...\n", linkbuf));
+ if (linkbuf[0] == '/') {
+ if (gettoproot(in->cell, linkbuf, &linkbufq, &root)) {
+ free(linkbuf);
+ free(in);
+ return NULL;
+ }
+ free(in);
+ ret=_ResolvePath(root, 0, linkbufq, 0);
+ free(root);
+ } else {
+ free(in);
+ ret=_ResolvePath(parent, fids, linkbuf, 0);
+ }
+
+ free(linkbuf);
+
+ } else { /* mountpoint */
+ afscp_dprintf(("EvalMountPoint %s...\n", linkbuf));
+ linkbufq=strchr(linkbuf, ':');
+ cell=in->cell;
+ v=afs_volumebyid(cell, in->fid.Volume);
+ free(in);
+ if (!v) {
+ free(linkbuf);
+ afs_errno=ENODEV;
+ return NULL;
+ }
+ voltype=v->voltype;
+ if (linkbuf[0] == '%')
+ voltype=VOLTYPE_RW;
+ if (!linkbufq) {
+ linkbufq=linkbuf+1;
+ } else {
+ *linkbufq++ = 0;
+ cell=afs_cellbyname(linkbuf+1);
+ if (linkbuf[0] != '%')
+ voltype=VOLTYPE_RO;
+ }
+ if (!cell) {
+ free(linkbuf);
+ afs_errno=ENODEV;
+ return NULL;
+ }
+ if (strlen(linkbufq) < 2) {
+ free(linkbuf);
+ afs_errno=ENODEV;
+ return NULL;
+ }
+ linkbufq[strlen(linkbufq)-1]=0; /* eliminate trailer */
+ if (getvolumeroot(cell, voltype, linkbufq, &ret)) {
+ free(linkbuf);
+ return NULL;
+ }
+ free(linkbuf);
+ }
+ return ret;
+}
+
+static struct afs_venusfid *_ResolvePath(const struct afs_venusfid *start,
+ fidstack infids, char *path,
+ int follow) {
+ struct afs_venusfid *ret,*cwd,*parent;
+ struct AFSFetchStatus s;
+ char *p,*q;
+ int code;
+ int linkcount;
+ fidstack fids;
+
+ p=path;
+ ret=cwd=dupfid(start);
+ fids=infids;
+ if (!fids)
+ fids=fidstack_alloc();
+ if (!fids)
+ return NULL;
+
+ while (p && *p) {
+ q=strchr(p, '/');
+ if (q) *q++=0;
+ if (!strcmp(p,".")) {
+ } else if (!strcmp(p,"..")) {
+ ret=fidstack_pop(fids);
+ if (!ret)
+ ret=cwd;
+ else
+ free(cwd);
+ } else {
+ ret=ResolveName(cwd, p);
+ if (!ret) {
+ afscp_dprintf(("Lookup %s in %lu.%lu.%lu failed\n", p, cwd->fid.Volume, cwd->fid.Vnode, cwd->fid.Unique));
+ free(cwd);
+ if (!infids)
+ fidstack_free(fids);
+ return NULL;
+
+ }
+ afscp_dprintf(("Lookup %s in %lu.%lu.%lu->%lu.%lu.%lu\n", p, cwd->fid.Volume, cwd->fid.Vnode, cwd->fid.Unique, ret->fid.Volume, ret->fid.Vnode, ret->fid.Unique));
+ linkcount=0;
+
+ retry:
+ if ((ret->fid.Vnode & 1) == 0) { /* not a directory; check for link */
+ code=afs_GetStatus(ret, &s);
+ if (code) {
+ if (!infids)
+ fidstack_free(fids);
+ free(cwd);
+ free(ret);
+ return NULL;
+ }
+ if (s.FileType == SymbolicLink) {
+ if (linkcount++ > 5) {
+ afs_errno=ELOOP;
+ if (!infids)
+ fidstack_free(fids);
+ free(cwd);
+ free(ret);
+ return NULL;
+ }
+ ret=HandleLink(ret, cwd, fids, follow, &s, (q==NULL));
+ if (!ret) {
+ free(cwd);
+ if (!infids)
+ fidstack_free(fids);
+ return NULL;
+ }
+ afscp_dprintf((" ....-> %lu.%lu.%lu\n", ret->fid.Volume, ret->fid.Vnode, ret->fid.Unique));
+ goto retry;
+ } else {
+ if (q) {
+ afs_errno=ENOTDIR;
+ free(cwd);
+ free(ret);
+ if (!infids)
+ fidstack_free(fids);
+ return NULL;
+ }
+ }
+ }
+ fidstack_push(fids,cwd);
+ }
+ cwd=ret;
+
+ if (q)
+ while (*q == '/')
+ q++;
+ p=q;
+ }
+ if (!infids)
+ fidstack_free(fids);
+ return ret;
+}
+/* 3 cases:
+ begins with /afs: start in root.afs of cell or home cell
+ else begins with /: error
+ else start in root.cell of cell or home cell
+*/
+struct afs_venusfid *ResolvePath(const char *path) {
+ struct afs_venusfid *root,*ret;
+ struct afs_cell *cell;
+
+ char *p,*q;
+ /* so we can modify the string */
+ p=strdup(path);
+ if (!p) {
+ afs_errno=ENOMEM;
+ return NULL;
+ }
+ cell=afs_defaultcell();
+ if (!cell) { afs_errno=EINVAL; return NULL;}
+ if (gettoproot(cell, p, &q, &root)) {
+ free(p);
+ return NULL;
+ }
+ if (q && *q) {
+ ret=_ResolvePath(root, 0, q, 1);
+ free(root);
+ } else
+ ret=root;
+ free(p);
+ return ret;
+}
+
+struct afs_venusfid *ResolvePath2(const struct afs_volume *v, const char *path) {
+ struct afs_venusfid *root,*ret;
+
+ char *p,*q;
+ /* so we can modify the string */
+ p=strdup(path);
+ if (!p) {
+ afs_errno=ENOMEM;
+ return NULL;
+ }
+ root=makefid(v->cell, v->id, 1,1);
+ while (*p == '/') p++;
+ if (*p) {
+ ret=_ResolvePath(root, 0, p, 1);
+ free(root);
+ } else
+ ret=root;
+ free(p);
+ return ret;
+}
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/vlserver.h>
+#include <afs/vldbint.h>
+#include <afs/dir.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <search.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+
+int afs_CreateFile(const struct afs_venusfid *dir, char *name,
+ struct AFSStoreStatus *sst,
+ struct afs_venusfid **ret) {
+ int code, i, j;
+ struct AFSFid df = dir->fid;
+ struct afs_volume *vol;
+ struct AFSFetchStatus dfst, fst;
+ struct AFSVolSync vs;
+ struct AFSCallBack cb;
+ struct AFSFid ff;
+ struct afs_volume *volume;
+ struct afs_server *server;
+ struct rx_call *c;
+
+ vol=afs_volumebyid(dir->cell, dir->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_CreateFile(server->conns[j], &df, name, sst, &ff,
+ &fst, &dfst, &cb, &vs);
+ if (code >= 0)
+ break;
+ }
+ }
+ if (code >= 0)
+ break;
+ }
+ if (code) {
+ _StatInvalidate(dir);
+ afs_errno=code;
+ return -1;
+ }
+ _StatStuff(dir, &dfst);
+ AddCallBack(server, &ff, &fst, &cb);
+ if (ret)
+ *ret=makefid(vol->cell, ff.Volume, ff.Vnode, ff.Unique);
+ return 0;
+}
+
+int afs_MakeDir(const struct afs_venusfid *dir, char *name,
+ struct AFSStoreStatus *sst,
+ struct afs_venusfid **ret) {
+ int code, i, j;
+ struct AFSFid df = dir->fid;
+ struct afs_volume *vol;
+ struct AFSFetchStatus dfst, fst;
+ struct AFSVolSync vs;
+ struct AFSCallBack cb;
+ struct AFSFid ff;
+ struct afs_volume *volume;
+ struct afs_server *server;
+
+ vol=afs_volumebyid(dir->cell, dir->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_MakeDir(server->conns[j], &df, name, sst, &ff,
+ &fst, &dfst, &cb, &vs);
+ if (code >= 0)
+ break;
+ }
+ }
+ if (code >= 0)
+ break;
+ }
+ if (code) {
+ _StatInvalidate(dir);
+ afs_errno=code;
+ return -1;
+ }
+ _StatStuff(dir, &dfst);
+ AddCallBack(server, &ff, &fst, &cb);
+ if (ret)
+ *ret=makefid(vol->cell, ff.Volume, ff.Vnode, ff.Unique);
+ return 0;
+}
+
+int afs_Symlink(const struct afs_venusfid *dir, char *name,
+ char *target,
+ struct AFSStoreStatus *sst) {
+ int code, i, j;
+ struct AFSFid df = dir->fid;
+ struct afs_volume *vol;
+ struct AFSFetchStatus dfst, fst;
+ struct AFSVolSync vs;
+ struct AFSCallBack cb;
+ struct AFSFid ff;
+ struct afs_volume *volume;
+ struct afs_server *server;
+
+ vol=afs_volumebyid(dir->cell, dir->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_Symlink(server->conns[j], &df, name, target, sst, &ff,
+ &fst, &dfst, &vs);
+ if (code >= 0)
+ break;
+ }
+ }
+ if (code >= 0)
+ break;
+ }
+ if (code) {
+ _StatInvalidate(dir);
+ afs_errno=code;
+ return -1;
+ }
+ _StatStuff(dir, &dfst);
+ return 0;
+}
+
+
+int afs_RemoveFile(const struct afs_venusfid *dir, char *name) {
+ int code, i, j;
+ struct AFSFid df = dir->fid;
+ struct afs_volume *vol;
+ struct AFSFetchStatus dfst;
+ struct AFSVolSync vs;
+ struct AFSCallBack cb;
+ struct afs_volume *volume;
+ struct afs_server *server;
+
+ vol=afs_volumebyid(dir->cell, dir->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_RemoveFile(server->conns[j], &df, name, &dfst, &vs);
+ if (code >= 0)
+ break;
+ }
+ }
+ if (code >= 0)
+ break;
+ }
+ if (code) {
+ _StatInvalidate(dir);
+ afs_errno=code;
+ return -1;
+ }
+ _StatStuff(dir, &dfst);
+ return 0;
+}
+
+int afs_RemoveDir(const struct afs_venusfid *dir, char *name) {
+ int code, i, j;
+ struct AFSFid df = dir->fid;
+ struct afs_volume *vol;
+ struct AFSFetchStatus dfst;
+ struct AFSVolSync vs;
+ struct AFSCallBack cb;
+ struct afs_volume *volume;
+ struct afs_server *server;
+
+ vol=afs_volumebyid(dir->cell, dir->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_RemoveDir(server->conns[j], &df, name, &dfst, &vs);
+ if (code >= 0)
+ break;
+ }
+ }
+ if (code >= 0)
+ break;
+ }
+ if (code) {
+ _StatInvalidate(dir);
+ afs_errno=code;
+ return -1;
+ }
+ _StatStuff(dir, &dfst);
+ return 0;
+}
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/vlserver.h>
+#include <afs/vldbint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <search.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+struct afs_venusfid *makefid(struct afs_cell *cell, afs_uint32 volume,
+ afs_uint32 vnode, afs_uint32 unique)
+{
+ struct afs_venusfid *ret;
+
+ if (!cell)
+ return NULL;
+ ret=malloc(sizeof(struct afs_venusfid));
+ if (!ret) {
+ afs_errno=errno;
+ return NULL;
+ }
+ ret->cell=cell;
+ ret->fid.Volume=volume;
+ ret->fid.Vnode=vnode;
+ ret->fid.Unique=unique;
+ return ret;
+}
+
+struct afs_venusfid *dupfid(const struct afs_venusfid *in)
+{
+ struct afs_venusfid *ret;
+
+ ret=malloc(sizeof(struct afs_venusfid));
+ if (!ret) {
+ afs_errno=errno;
+ return NULL;
+ }
+ ret->cell=in->cell;
+ ret->fid.Volume=in->fid.Volume;
+ ret->fid.Vnode=in->fid.Vnode;
+ ret->fid.Unique=in->fid.Unique;
+ return ret;
+}
+
+
+static int statcompare(const void *a, const void *b)
+{
+ const struct afs_statent *sa=a,*sb=b;
+ if (sa->me.fid.Vnode < sb->me.fid.Vnode) return -1;
+ if (sa->me.fid.Vnode > sb->me.fid.Vnode) return 1;
+ if (sa->me.fid.Unique < sb->me.fid.Unique) return -1;
+ if (sa->me.fid.Unique > sb->me.fid.Unique) return 1;
+ return 0;
+}
+
+
+int afs_GetStatus(const struct afs_venusfid *fid, struct AFSFetchStatus *s)
+{
+ struct afs_volume *v;
+ struct afs_server *server;
+ struct AFSCallBack cb;
+ struct AFSVolSync vs;
+ struct AFSFid tf = fid->fid;
+ struct afs_statent *stored,key;
+ void *cached;
+
+ int code,i,j;
+
+ v=afs_volumebyid(fid->cell, fid->fid.Volume);
+ if (!v)
+ return -1;
+ memset(&key, 0, sizeof(key));
+ memcpy(&key.me,fid,sizeof(*fid));
+
+ cached=tfind(&key, &v->statcache, statcompare);
+ if (cached) {
+ stored=*(struct afs_statent **)cached;
+ memmove(s, &stored->status,sizeof(*s));
+ afscp_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n",
+ fid->cell->id, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique));
+ return 0;
+ }
+
+
+ code=ENOENT;
+ for (i=0;i<v->nservers;i++) {
+ server=afs_serverbyindex(v->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs);
+ if (!code) {
+ AddCallBack(server, &fid->fid, s, &cb); /* calls _StatStuff */
+ afscp_dprintf(("Stat %u.%" PRIu32 ".%" PRIu32 ".%" PRIu32 " ok: type %" PRId32 " size %" PRId32 "\n",
+ fid->cell->id, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique, s->FileType, s->Length));
+ return 0;
+ }
+ }
+ }
+ }
+ afs_errno=code;
+ return -1;
+}
+
+
+
+int afs_stat(const struct afs_venusfid *fid, struct stat *s)
+{
+
+ struct AFSFetchStatus status;
+ int code;
+
+ code=afs_GetStatus(fid, &status);
+ if (code)
+ return code;
+
+ if (status.FileType==File)
+ s->st_mode=S_IFREG;
+ else if (status.FileType==Directory)
+ s->st_mode=S_IFDIR;
+ else if (status.FileType==SymbolicLink)
+ s->st_mode=S_IFLNK;
+ else {
+ afs_errno=EINVAL;
+ return -1;
+ }
+ s->st_mode |= (status.UnixModeBits & (~S_IFMT));
+ s->st_nlink = status.LinkCount;
+ s->st_size =status.Length;
+ s->st_uid =status.Owner;
+ /*s->st_blksize=status.SegSize;*/
+ s->st_atime=s->st_mtime=status.ClientModTime;
+ s->st_ctime=status.ServerModTime;
+ s->st_gid = status.Group;
+ return 0;
+}
+
+
+int _StatInvalidate(const struct afs_venusfid *fid) {
+ struct afs_volume *v;
+ struct afs_statent key;
+ void **cached;
+
+ v=afs_volumebyid(fid->cell, fid->fid.Volume);
+ if (!v)
+ return -1;
+ memmove(&key.me,fid,sizeof(*fid));
+
+ cached=tfind(&key, &v->statcache, statcompare);
+ if (cached) {
+ free(*cached);
+ tdelete(&key, &v->statcache, statcompare);
+ }
+ return 0;
+}
+
+int _StatStuff(const struct afs_venusfid *fid, const struct AFSFetchStatus *s) {
+ struct afs_volume *v;
+ struct afs_statent key, *stored;
+ void **cached;
+
+ v=afs_volumebyid(fid->cell, fid->fid.Volume);
+ if (!v)
+ return -1;
+ memmove(&key.me,fid,sizeof(*fid));
+
+ cached=tsearch(&key, &v->statcache, statcompare);
+ if (cached) {
+ stored=malloc(sizeof(struct afs_statent));
+ if (stored) {
+ memmove(&stored->me, fid, sizeof(*fid));
+ memmove(&stored->status,s,sizeof(*s));
+ *(struct afs_statent **)cached=stored;
+ } else {
+ tdelete(&key, &v->statcache, statcompare);
+ }
+ }
+ return 0;
+}
+
+int afs_StoreStatus(const struct afs_venusfid *fid, struct AFSStoreStatus *s)
+{
+ struct afs_volume *v;
+ struct afs_server *server;
+ struct AFSCallBack cb;
+ struct AFSVolSync vs;
+ struct AFSFetchStatus fst;
+ struct AFSFid tf = fid->fid;
+ int code,i,j;
+
+ v=afs_volumebyid(fid->cell, fid->fid.Volume);
+ if (!v)
+ return -1;
+
+
+ code=ENOENT;
+ for (i=0;i<v->nservers;i++) {
+ server=afs_serverbyindex(v->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_StoreStatus(server->conns[j], &tf, s, &fst, &vs);
+ if (!code) {
+ _StatStuff(fid, &fst); /* calls _StatStuff */
+ return 0;
+ }
+ }
+ }
+ }
+ afs_errno=code;
+ return -1;
+}
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/vlserver.h>
+#include <afs/vldbint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+ssize_t afs_pread(const struct afs_venusfid *fid, void *buffer, size_t count, off_t offset) {
+ struct AFSFetchStatus fst;
+ struct AFSVolSync vs;
+ struct AFSCallBack cb;
+ struct AFSFid tf = fid->fid;
+ struct afs_volume *vol;
+ struct afs_server *server;
+
+ struct rx_call *c=NULL;
+ int code,code2;
+ int i,j,bytes,totalbytes;
+ int bytesremaining;
+ char *p;
+
+ vol=afs_volumebyid(fid->cell, fid->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ c=rx_NewCall(server->conns[j]);
+ if (c) {
+ p=buffer;
+ code=StartRXAFS_FetchData(c, &tf, offset, count);
+ if (code) {
+ code=rx_EndCall(c,code);
+ continue;
+ }
+ bytes=rx_Read(c,(char *)&bytesremaining,sizeof(afs_int32));
+ if (bytes != sizeof(afs_int32)) {
+ code=rx_EndCall(c,bytes);
+ continue;
+ }
+ bytesremaining=ntohl(bytesremaining);
+ totalbytes=0;
+ while (bytesremaining > 0) {
+ bytes=rx_Read(c, p, bytesremaining);
+ if (bytes <= 0)
+ break;
+ p+=bytes;
+ totalbytes+=bytes;
+ bytesremaining-=bytes;
+ }
+ if (bytesremaining == 0) {
+ code2=EndRXAFS_FetchData(c, &fst, &cb, &vs);
+ if (code2 == 0)
+ AddCallBack(server, &fid->fid, &fst, &cb);
+ }
+ code=rx_EndCall(c, code2);
+ }
+ if (code == 0)
+ return totalbytes;
+ }
+ }
+ }
+ afs_errno=code;
+ return -1;
+}
+
+
+
+ssize_t afs_pwrite(const struct afs_venusfid *fid, const void *buffer, size_t count, off_t offset) {
+
+ struct AFSFetchStatus fst;
+ struct AFSStoreStatus sst;
+ struct AFSVolSync vs;
+ struct AFSCallBack cb;
+ struct AFSFid tf=fid->fid;
+ struct afs_volume *vol;
+ struct afs_server *server;
+
+ struct rx_call *c=NULL;
+ int code,code2;
+ int i,j,bytes,totalbytes;
+ int bytesremaining;
+ const char *p;
+ size_t filesize;
+ time_t now;
+
+
+ vol=afs_volumebyid(fid->cell, fid->fid.Volume);
+ if (!vol) {
+ afs_errno=ENOENT;
+ return -1;
+ }
+ if (vol->voltype != VOLTYPE_RW) {
+ afs_errno = EROFS;
+ return -1;
+ }
+
+ code=ENOENT;
+ for (i=0;i<vol->nservers;i++) {
+ server=afs_serverbyindex(vol->servers[i]);
+ if (server && server->naddrs > 0) {
+ for (j=0;j < server->naddrs;j++) {
+ code=RXAFS_FetchStatus(server->conns[j], &tf, &fst, &cb, &vs);
+ if (code)
+ continue;
+ sst.Mask=AFS_SETMODTIME;
+ time(&now);
+ sst.ClientModTime = now;
+ filesize=fst.Length;
+ if (offset + count > filesize)
+ filesize = offset + count;
+ c=rx_NewCall(server->conns[j]);
+ if (c) {
+ p=buffer;
+ code=StartRXAFS_StoreData(c, &tf, &sst, offset, count, filesize);
+ if (code) {
+ code=rx_EndCall(c,code);
+ continue;
+ }
+ bytesremaining=htonl(count);
+ bytes=rx_Write(c,(char *)&bytesremaining,sizeof(afs_int32));
+ if (bytes != sizeof(afs_int32)) {
+ code=rx_EndCall(c,bytes);
+ continue;
+ }
+ bytesremaining=count;
+ totalbytes=0;
+ while (bytesremaining > 0) {
+ bytes=rx_Write(c, (char *)p, bytesremaining);
+ if (bytes <= 0)
+ break;
+ p+=bytes;
+ totalbytes+=bytes;
+ bytesremaining-=bytes;
+ }
+ if (bytesremaining == 0) {
+ code2=EndRXAFS_StoreData(c, &fst, &vs);
+ }
+ code=rx_EndCall(c, code2);
+ }
+ if (code == 0)
+ return totalbytes;
+ }
+ }
+ }
+ afs_errno=code;
+ return -1;
+}
+
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+
+#include <afs/param.h>
+#include <lwp.h>
+#include <rx/rx_null.h>
+#include <rx/rx.h>
+
+#include <com_err.h>
+
+#include "afscp.h"
+#include "afscp_internal.h"
+
+#ifndef AFSCONF_CLIENTNAME
+#include <afs/dirpath.h>
+#define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
+#endif
+
+static int init=0;
+extern int RXAFSCB_ExecuteRequest();
+static struct rx_securityClass *sc;
+static struct rx_service *serv;
+extern PROCESS rx_listenerPid;
+static int start_cb_server()
+{
+
+ sc=rxnull_NewServerSecurityObject();
+ serv=rx_NewService(0,1,"afs", &sc, 1, RXAFSCB_ExecuteRequest);
+ if (!serv)
+ return 1;
+ rx_StartServer(0);
+ return 0;
+}
+
+
+int afscp_init(const char *cell)
+{
+ if (init)
+ return 0;
+ if (_rx_InitRandomPort())
+ return -1;
+ init=1;
+ if (start_cb_server()) {
+ printf("Cannot start callback service\n");
+ return -1;
+ }
+ init=2;
+ if (cell)
+ return afs_setdefaultcell(cell);
+ return 0;
+}
+
+void afscp_finalize(void) {
+ if (!init)
+ return;
+
+ ReturnAllCallBacks();
+ IOMGR_Sleep(1);
+ rx_Finalize();
+#if 0
+ LWP_DestroyProcess(rx_listenerPid);
+ close(serv->socket);
+ rxi_FreeService(serv);
+#endif
+ IOMGR_Finalize();
+ LWP_TerminateProcessSupport();
+#if 1
+ close(serv->socket);
+#endif
+}
+
+
--- /dev/null
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/cellconfig.h>
+#define MAXADDRS 16
+
+/* AUTORIGHTS */
+struct afs_server
+{
+ afsUUID id;
+ int index;
+ int cell;
+ int naddrs;
+ afs_uint32 addrs[MAXADDRS];
+ struct rx_connection *conns[MAXADDRS];
+};
+struct afs_cell
+{
+ int id;
+ char name[MAXCELLCHARS];
+ struct rx_securityClass *security;
+ int scindex;
+ struct ubik_client *vlservers;
+ int nservers;
+ int srvsalloced;
+ struct afs_server **fsservers;
+ void *volsbyname;
+ void *volsbyid;
+};
+
+struct afs_callback
+{
+ int valid;
+ const struct afs_server *server;
+ struct AFSFid fid;
+ struct AFSCallBack cb;
+};
+
+struct afs_dirstream
+{
+ struct afs_venusfid fid;
+ int buflen;
+ char *dirbuffer;
+ int hashent;
+ int entry;
+ int dv;
+ struct afs_dirent ret;
+};
+
+struct afs_dircache
+{
+ struct afs_venusfid me;
+ int buflen;
+ char *dirbuffer;
+ int dv;
+};
+
+struct afs_statent
+{
+ struct afs_venusfid me;
+ struct AFSFetchStatus status;
+};
+
+struct afs_openfile
+{
+ struct afs_venusfid fid;
+ off_t offset;
+};
+
+extern int _rx_InitRandomPort(void);
+extern int _GetSecurityObject(struct afs_cell *);
+extern int _GetVLservers(struct afs_cell *);
+extern int _StatInvalidate(const struct afs_venusfid *fid);
+extern int _StatStuff(const struct afs_venusfid *fid, const struct AFSFetchStatus *s);
+
+#ifdef AFSCP_DEBUG
+#define afscp_dprintf(x) printf x
+#else
+#define afscp_dprintf(x)
+#endif
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/vlserver.h>
+#include <afs/vldbint.h>
+#include <afs/volint.h>
+#include <afs/cellconfig.h>
+#ifndef AFSCONF_CLIENTNAME
+#include <afs/dirpath.h>
+#define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <rx/rx.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+static int afs_ncells=0,afs_cellsalloced=0;
+static struct afs_cell *allcells=NULL;
+static int afs_nservers=0,afs_srvsalloced=0;
+static struct afs_server **allservers=NULL;
+static char *defcell;
+int afs_errno=0;
+
+struct afs_cell *afs_cellbyid(int id)
+{
+ if (id >= afs_ncells)
+ return NULL;
+ return &allcells[id];
+}
+
+struct afs_cell *afs_cellbyname(const char *cellname)
+{
+ int i;
+ struct afs_cell *newlist, *thecell;
+
+ for (i=0;i<afs_ncells;i++) {
+ if (!strcmp(allcells[i].name, cellname))
+ return &allcells[i];
+ }
+ if (afs_ncells >= afs_cellsalloced) {
+ if (afs_cellsalloced)
+ afs_cellsalloced = afs_cellsalloced *2;
+ else
+ afs_cellsalloced = 4;
+ newlist=realloc(allcells, afs_cellsalloced * sizeof(struct afs_cell));
+ if (!newlist)
+ return NULL;
+ allcells=newlist;
+ }
+ thecell=&allcells[afs_ncells];
+ memset(thecell, 0, sizeof(struct afs_cell));
+ strcpy(thecell->name, cellname);
+ if (_GetSecurityObject(thecell))
+ return NULL;
+ if (_GetVLservers(thecell)) {
+ RXS_Close(thecell->security);
+ return NULL;
+ }
+ thecell->id=afs_ncells++;
+ return thecell;
+}
+struct afs_cell *afs_defaultcell(void)
+{
+ struct afsconf_dir *dir;
+ char localcell[MAXCELLCHARS+1];
+ int code;
+
+
+ if (defcell) {
+ return afs_cellbyname(defcell);
+ }
+
+ dir=afsconf_Open(AFSCONF_CLIENTNAME);
+ if (!dir) {
+ afs_errno=AFSCONF_NODB;
+ return NULL;
+ }
+ code=afsconf_GetLocalCell(dir, localcell, MAXCELLCHARS);
+ if (code){
+ afs_errno=code;
+ return NULL;
+ }
+ afsconf_Close(dir);
+ return afs_cellbyname(localcell);
+}
+
+int afs_setdefaultcell(const char *cellname) {
+ struct afs_cell *this;
+ char *newdefcell;
+ if (!cellname) {
+ if (defcell)
+ free(defcell);
+ defcell=NULL;
+ return 0;
+ }
+
+ this=afs_cellbyname(cellname);
+ if (!this)
+ return -1;
+ newdefcell=strdup(cellname);
+ if (!newdefcell)
+ return -1;
+ if (defcell)
+ free(defcell);
+ defcell = newdefcell;
+ return 0;
+}
+
+int afs_cellid(struct afs_cell *cell) {
+ return cell->id;
+}
+
+static void _xdr_free(bool_t (*fn)(XDR *xdrs, void *obj), void *obj) {
+ XDR xdrs;
+ xdrs.x_op=XDR_FREE;
+ fn(&xdrs, obj);
+}
+static bool_t _xdr_bulkaddrs(XDR *xdrs, void *objp) {
+ return xdr_bulkaddrs(xdrs, objp);
+}
+
+
+struct afs_server *afs_serverbyid(struct afs_cell *thecell, afsUUID *u)
+{
+ /* impliment uniquifiers? */
+ int i;
+ struct afs_server **newlist;
+ struct afs_server **newall;
+ struct afs_server *ret;
+ afsUUID tmp;
+ bulkaddrs addrs;
+ struct ListAddrByAttributes attrs;
+ afs_int32 nentries, uniq;
+
+ char s[512];
+
+ afsUUID_to_string(u, s, 511);
+ afscp_dprintf(("GetServerByID %s\n", s));
+
+ for (i=0;i<thecell->nservers;i++) {
+ if (afs_uuid_equal(&thecell->fsservers[i]->id, u))
+ return thecell->fsservers[i];
+ }
+
+ if (thecell->nservers >= thecell->srvsalloced) {
+ if (thecell->srvsalloced)
+ thecell->srvsalloced = thecell->srvsalloced *2;
+ else
+ thecell->srvsalloced = 4;
+ newlist=realloc(thecell->fsservers,
+ thecell->srvsalloced * sizeof(struct afs_server *));
+ if (!newlist)
+ return NULL;
+ thecell->fsservers=newlist;
+ }
+ ret=malloc(sizeof(struct afs_server));
+ if (!ret)
+ return NULL;
+ thecell->fsservers[thecell->nservers]=ret;
+ memmove(&ret->id, u, sizeof(afsUUID));
+ ret->cell=thecell->id;
+ memset(&tmp, 0, sizeof(tmp));
+ memset(&addrs, 0, sizeof(addrs));
+ memset(&attrs, 0, sizeof(attrs));
+ attrs.Mask = VLADDR_UUID;
+ memmove(&attrs.uuid, u, sizeof(afsUUID));
+
+ if (ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &tmp,
+ &uniq, &nentries, &addrs))
+ return NULL;
+ if (nentries > MAXADDRS) {
+ nentries=MAXADDRS;
+ /* XXX I don't want to do *that* much dynamic allocation */
+ abort();
+ }
+
+ ret->naddrs=nentries;
+ for (i=0; i< nentries;i++) {
+ ret->addrs[i]=htonl(addrs.bulkaddrs_val[i]);
+ ret->conns[i]=rx_NewConnection(ret->addrs[i],
+ htons(AFSCONF_FILEPORT),
+ 1, thecell->security,
+ thecell->scindex);
+ }
+ _xdr_free(_xdr_bulkaddrs, &addrs);
+ thecell->nservers++;
+
+ if (afs_nservers >= afs_srvsalloced) {
+ if (afs_srvsalloced)
+ afs_srvsalloced = afs_srvsalloced *2;
+ else
+ afs_srvsalloced = 4;
+ newall=realloc(allservers,
+ afs_srvsalloced * sizeof(struct afs_server *));
+ if (!newall)
+ return ret;
+ allservers=newall;
+ }
+ ret->index=afs_nservers;
+ allservers[afs_nservers++]=ret;
+ return ret;
+}
+
+struct afs_server *afs_serverbyaddr(struct afs_cell *thecell, afs_uint32 addr)
+{
+ /* impliment uniquifiers? */
+ int i,j;
+ struct afs_server **newlist;
+ struct afs_server **newall;
+ struct afs_server *ret;
+ afsUUID uuid;
+ bulkaddrs addrs;
+ struct ListAddrByAttributes attrs;
+ afs_int32 nentries, code, uniq;
+
+
+ for (i=0;i<thecell->nservers;i++) {
+ ret=thecell->fsservers[i];
+ for (j=0;j<ret->naddrs;j++)
+ if (ret->addrs[j] == htonl(addr))
+ return ret;
+ }
+
+ if (thecell->nservers >= thecell->srvsalloced) {
+ if (thecell->srvsalloced)
+ thecell->srvsalloced = thecell->srvsalloced *2;
+ else
+ thecell->srvsalloced = 4;
+ newlist=realloc(thecell->fsservers,
+ thecell->srvsalloced * sizeof(struct afs_server));
+ if (!newlist)
+ return NULL;
+ thecell->fsservers=newlist;
+ }
+ ret=malloc(sizeof(struct afs_server));
+ if (!ret)
+ return NULL;
+ thecell->fsservers[thecell->nservers]=ret;
+ ret->cell=thecell->id;
+ memset(&uuid, 0, sizeof(uuid));
+ memset(&addrs, 0, sizeof(addrs));
+ memset(&attrs, 0, sizeof(attrs));
+ attrs.Mask = VLADDR_IPADDR;
+ attrs.ipaddr=addr;
+
+
+ if ((code=ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &uuid,
+ &uniq, &nentries, &addrs))) {
+ memset(&ret->id, 0, sizeof(uuid));
+ ret->naddrs=1;
+ ret->addrs[0]=htonl(addr);
+ ret->conns[0]=rx_NewConnection(ret->addrs[0],
+ htons(AFSCONF_FILEPORT),
+ 1, thecell->security,
+ thecell->scindex);
+ } else {
+ char s[512];
+
+ afsUUID_to_string(&uuid, s, 511);
+ afscp_dprintf(("GetServerByAddr 0x%x -> uuid %s\n", addr, s));
+
+ if (nentries > MAXADDRS) {
+ nentries=MAXADDRS;
+ /* XXX I don't want to do *that* much dynamic allocation */
+ abort();
+ }
+ memmove(&ret->id, &uuid, sizeof(afsUUID));
+
+ ret->naddrs=nentries;
+ for (i=0; i< nentries;i++) {
+ ret->addrs[i]=htonl(addrs.bulkaddrs_val[i]);
+ ret->conns[i]=rx_NewConnection(ret->addrs[i],
+ htons(AFSCONF_FILEPORT),
+ 1, thecell->security,
+ thecell->scindex);
+ }
+ _xdr_free(_xdr_bulkaddrs, &addrs);
+ }
+
+ thecell->nservers++;
+ if (afs_nservers >= afs_srvsalloced) {
+ if (afs_srvsalloced)
+ afs_srvsalloced = afs_srvsalloced *2;
+ else
+ afs_srvsalloced = 4;
+ newall=realloc(allservers,
+ afs_srvsalloced * sizeof(struct afs_server *));
+ if (!newall)
+ return ret;
+ allservers=newall;
+ }
+ ret->index=afs_nservers;
+ allservers[afs_nservers++]=ret;
+ return ret;
+}
+
+struct afs_server *afs_anyserverbyaddr(afs_uint32 addr)
+{
+ /* no idea what this means: "impliment uniquifiers?" */
+ int i,j;
+ struct afs_server *ret;
+
+ for (i=0;i<afs_nservers;i++) {
+ ret=allservers[i];
+ for (j=0;j<ret->naddrs;j++)
+ if (ret->addrs[j] == htonl(addr))
+ return ret;
+ }
+ return NULL;
+}
+
+struct afs_server *afs_serverbyindex(int i)
+{
+
+ if (i>= afs_nservers)
+ return NULL;
+ return allservers[i];
+}
+
+struct rx_connection *afs_serverconnection(const struct afs_server *srv, int i) {
+ if (i >= srv->naddrs)
+ return NULL;
+ return srv->conns[i];
+}
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <afs/param.h>
+#include <afs/cellconfig.h>
+#ifndef AFSCONF_CLIENTNAME
+#include <afs/dirpath.h>
+#define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
+#endif
+
+#include <ubik.h>
+#include <rx/rxkad.h>
+#include <rx/rx_null.h>
+
+#include <krb5.h>
+
+#include "afscp.h"
+#include "afscp_internal.h"
+
+#define HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
+
+#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
+#define Z_keydata(keyblock) ((keyblock)->contents)
+#define Z_keylen(keyblock) ((keyblock)->length)
+#define Z_credskey(creds) (&(creds)->keyblock)
+#define Z_enctype(keyblock) ((keyblock)->enctype)
+#else
+#define Z_keydata(keyblock) ((keyblock)->keyvalue.data)
+#define Z_keylen(keyblock) ((keyblock)->keyvalue.length)
+#define Z_credskey(creds) (&(creds)->session)
+#define Z_enctype(keyblock) ((keyblock)->keytype)
+#endif
+
+int _rx_InitRandomPort(void) {
+ int sock;
+ unsigned int port;
+ struct sockaddr_in sin;
+
+ sock=socket(PF_INET, SOCK_DGRAM, 0);
+ if (sock == -1)
+ return errno;
+ sin.sin_family=AF_INET;
+ sin.sin_addr.s_addr=INADDR_ANY;
+ sin.sin_port=0;
+ if (bind(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0)
+ return errno;
+
+ port=sizeof(struct sockaddr_in);
+ if (getsockname(sock, (struct sockaddr *)&sin, &port) < 0)
+ return errno;
+ port=sin.sin_port;
+ close(sock);
+ return rx_Init(port);
+
+}
+
+static int insecure;
+
+int afscp_Insecure(void) {
+ insecure=1;
+ return 0;
+}
+static struct afsconf_dir *confdir;
+
+static int _GetCellInfo(char *cell, struct afsconf_cell *celldata) {
+
+ if (!confdir)
+ confdir=afsconf_Open(AFSCONF_CLIENTNAME);
+ if (!confdir)
+ return AFSCONF_NODB;
+ return afsconf_GetCellInfo(confdir, cell, AFSCONF_VLDBSERVICE, celldata);
+}
+
+int _GetSecurityObject(struct afs_cell *cell) {
+ int code;
+ krb5_context context;
+ krb5_creds match;
+ krb5_creds *cred;
+ krb5_ccache cc;
+ char **realms,*realm;
+ struct afsconf_cell celldata;
+ char localcell[MAXCELLCHARS];
+ struct rx_securityClass *sc;
+ struct ktc_encryptionKey k;
+ int i;
+ rxkad_level l;
+
+ code=_GetCellInfo(cell->name, &celldata);
+ if (code)
+ return code;
+
+ code=krb5_init_context(&context);
+ if (code)
+ return code;
+ realm=NULL;
+ code=krb5_get_host_realm(context, celldata.hostName[0], &realms);
+ if (!code) {
+ strcpy(localcell,realms[0]);
+ krb5_free_host_realm(context,realms);
+ realm=localcell;
+ }
+ if (!realm) {
+ for (i=0; (i < MAXCELLCHARS && cell->name[i]); i++) {
+ if (isalpha(cell->name[i]))
+ localcell[i]=toupper(cell->name[i]);
+ else
+ localcell[i]=cell->name[i];
+ }
+ localcell[i]='\0';
+ realm=localcell;
+ }
+ cc=NULL;
+ code=krb5_cc_default(context, &cc);
+
+ memset(&match, 0, sizeof(match));
+ Z_enctype(Z_credskey(&match))=ENCTYPE_DES_CBC_CRC;
+
+ if (!code)
+ code=krb5_cc_get_principal(context, cc, &match.client);
+ if (!code)
+ code=krb5_build_principal(context, &match.server,
+ strlen(realm), realm,
+ "afs", cell->name, NULL);
+
+ if (code) {
+ krb5_free_cred_contents(context, &match);
+ if (cc)
+ krb5_cc_close(context, cc);
+ krb5_free_context(context);
+ return code;
+ }
+
+ code = krb5_get_credentials(context, 0, cc, &match, &cred);
+ if (code) {
+ krb5_free_principal(context, match.server);
+ match.server=NULL;
+ code=krb5_build_principal(context, &match.server,
+ strlen(realm), realm,
+ "afs", NULL); /* afs@cell instead? */
+ if (!code)
+ code = krb5_get_credentials(context, 0, cc, &match, &cred);
+ if (code) {
+ krb5_free_cred_contents(context, &match);
+ if (cc)
+ krb5_cc_close(context, cc);
+ krb5_free_context(context);
+ return code;
+ }
+ }
+
+ if (insecure)
+ l=rxkad_clear;
+ else
+ l=rxkad_crypt;
+ memcpy(&k.data, Z_keydata(Z_credskey(cred)), 8);
+ sc = (struct rx_securityClass *)rxkad_NewClientSecurityObject
+ (l, &k, RXKAD_TKT_TYPE_KERBEROS_V5,
+ cred->ticket.length, cred->ticket.data);
+ krb5_free_creds(context, cred);
+ krb5_free_cred_contents(context, &match);
+ if (cc)
+ krb5_cc_close(context, cc);
+ krb5_free_context(context);
+ cell->security=sc;
+ cell->scindex=2;
+ return 0;
+}
+int _GetVLservers(struct afs_cell *cell) {
+ struct rx_connection *conns[MAXHOSTSPERCELL+1];
+ int i;
+ int code;
+ struct afsconf_cell celldata;
+
+ code=_GetCellInfo(cell->name, &celldata);
+ if (code)
+ return code;
+
+ for (i=0; i < celldata.numServers; i++) {
+ conns[i] = rx_NewConnection(celldata.hostAddr[i].sin_addr.s_addr,
+ htons(AFSCONF_VLDBPORT),
+ USER_SERVICE_ID, cell->security,
+ cell->scindex);
+ }
+ conns[i]=0;
+ return ubik_ClientInit(conns, &cell->vlservers);
+}
--- /dev/null
+/* AUTORIGHTS
+Copyright (C) 2003 - 2010 Chaskiel Grundman
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <afs/param.h>
+#include <afs/vlserver.h>
+#include <afs/vldbint.h>
+#include <afs/volint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include "afscp.h"
+#include "afscp_internal.h"
+
+#include <search.h>
+#include <time.h>
+
+static int icompare(const void *pa, const void *pb) {
+ const struct afs_volume *va=pa,*vb=pb;
+
+ if (va->id > vb->id) return 1;
+ if (va->id < vb->id) return -1;
+ return 0;
+}
+
+
+static int ncompare(const void *pa, const void *pb) {
+ const struct afs_volume *va=pa,*vb=pb;
+
+ if (va->voltype > vb->voltype) return 1;
+ if (vb->voltype < va->voltype) return -1;
+ return strcmp(va->name, vb->name);
+}
+
+
+union allvldbentry
+{
+ struct uvldbentry u;
+ struct nvldbentry n;
+ struct vldbentry o;
+};
+
+struct afs_volume *afs_volumebyname(struct afs_cell *cell, const char *vname, afs_int32 intype)
+{
+ union allvldbentry u;
+ struct afs_volume *ret,key;
+ struct afs_server *server;
+ afs_int32 code,vtype,type,srv;
+ void *s;
+ struct in_addr i;
+
+ if (intype == VOLTYPE_RW)
+ vtype=VLSF_RWVOL;
+ else if (intype == VOLTYPE_RO)
+ vtype=VLSF_ROVOL;
+ else if (intype == VOLTYPE_BK)
+ vtype=VLSF_BACKVOL;
+ else {
+ afs_errno=EINVAL;
+ return NULL;
+ }
+
+ memset(&key,0, sizeof(key));
+ strcpy(key.name,vname);
+ key.voltype=vtype;
+ s=tfind(&key, &cell->volsbyname, ncompare);
+ if (s) {
+ ret=*(struct afs_volume **)s;
+ return ret;
+ }
+
+ type=0;
+ if ((code=ubik_VL_GetEntryByNameU(cell->vlservers, 0, (char *)vname, &u.u))
+ == RXGEN_OPCODE) {
+ type=1;
+ if ((code=ubik_VL_GetEntryByNameN(cell->vlservers, 0, (char *)vname, &u.n))
+ == RXGEN_OPCODE) {
+ type=2;
+ code=ubik_VL_GetEntryByNameO(cell->vlservers, 0, (char *)vname, &u.o);
+ }
+ }
+ if (code) {
+ afs_errno=code;
+ return NULL;
+ }
+ ret=malloc(sizeof(struct afs_volume));
+ if (!ret) {
+ afs_errno=ENOMEM;
+ return NULL;
+ }
+ memset(ret,0,sizeof(struct afs_volume));
+ strcpy(ret->name, u.u.name);
+ ret->nservers=0;
+ ret->cell=cell;
+ switch (type) {
+ case 0:
+ ret->id=u.u.volumeId[intype];
+ for (srv=0;srv < u.u.nServers;srv++) {
+ if ((u.u.serverFlags[srv] & vtype) == 0)
+ continue;
+ //printf("uvldbentry server %d flags: %x\n",srv, u.u.serverFlags[srv]);
+
+ if ((u.u.serverFlags[srv] & VLSERVER_FLAG_UUID) == 0)
+ server=afs_serverbyaddr(cell, u.u.serverNumber[srv].time_low);
+ else
+ server=afs_serverbyid(cell, &u.u.serverNumber[srv]);
+ if (!server)
+ continue;
+ ret->servers[ret->nservers++]=server->index;
+ }
+ break;
+ case 1:
+ ret->id=u.n.volumeId[intype];
+ for (srv=0;srv < u.n.nServers;srv++) {
+ if ((u.n.serverFlags[srv] & vtype) == 0)
+ continue;
+ server=afs_serverbyaddr(cell, u.n.serverNumber[srv]);
+ if (!server)
+ continue;
+ ret->servers[ret->nservers++]=server->index;
+ }
+ break;
+ case 2:
+ ret->id=u.o.volumeId[intype];
+ for (srv=0;srv < u.o.nServers;srv++) {
+ if ((u.o.serverFlags[srv] & vtype) == 0)
+ continue;
+ server=afs_serverbyaddr(cell, u.o.serverNumber[srv]);
+ if (!server)
+ continue;
+ ret->servers[ret->nservers++]=server->index;
+ }
+ break;
+ }
+ if (!ret->nservers || !ret->id) {
+ free(ret);
+ return NULL;
+ }
+
+ ret->voltype=intype;
+ server=afs_serverbyindex(ret->servers[0]);
+ if (server)
+ i.s_addr=server->addrs[0];
+ else
+ i.s_addr=0;
+ afscp_dprintf(("New volume BYNAME %s (%lu) on %s (%d)\n", ret->name, ret->id, inet_ntoa(i),ret->servers[0]));
+ s=tsearch(&key, &cell->volsbyname, ncompare);
+ if (s)
+ *(struct afs_volume **)s=ret;
+ key.id=ret->id;
+ s=tsearch(&key, &cell->volsbyid, icompare);
+ if (s)
+ *(struct afs_volume **)s=ret;
+ return ret;
+}
+
+struct afs_volume *afs_volumebyid(struct afs_cell *cell, afs_uint32 id)
+{
+ union allvldbentry u;
+ struct afs_volume *ret,key;
+ struct afs_server *server;
+ afs_int32 code,vtype,type,srv;
+ int voltype;
+ char idbuffer[16];
+ void *s;
+ struct in_addr i;
+
+ memset(&key,0, sizeof(key));
+ key.id=id;
+ s=tfind(&key, &cell->volsbyid, icompare);
+ if (s) {
+ ret=*(struct afs_volume **)s;
+ return ret;
+ }
+
+ sprintf(idbuffer,"%" PRIu32, id);
+ type=0;
+ if ((code=ubik_VL_GetEntryByNameU(cell->vlservers, 0, idbuffer, &u.u))
+ == RXGEN_OPCODE) {
+ type=1;
+ if ((code=ubik_VL_GetEntryByIDN(cell->vlservers, 0, id, -1, &u.n))
+ == RXGEN_OPCODE) {
+ type=2;
+ code=ubik_VL_GetEntryByID(cell->vlservers, 0, id, -1, &u.o);
+ }
+ }
+ if (code) {
+ afs_errno=code;
+ return NULL;
+ }
+ ret=malloc(sizeof(struct afs_volume));
+ if (!ret) {
+ afs_errno=ENOMEM;
+ return NULL;
+ }
+
+ memset(ret,0,sizeof(struct afs_volume));
+ strcpy(ret->name, u.u.name);
+ ret->nservers=0;
+ ret->cell=cell;
+
+ switch (type) {
+ case 0:
+ if (id == u.u.volumeId[RWVOL]) {
+ vtype=VLSF_RWVOL;
+ voltype=VOLTYPE_RW;
+ } else if (id == u.u.volumeId[ROVOL]) {
+ vtype=VLSF_ROVOL;
+ voltype=VOLTYPE_RO;
+ } else if (id == u.u.volumeId[BACKVOL]) {
+ vtype=VLSF_BACKVOL;
+ voltype=VOLTYPE_BK;
+ } else {
+ vtype=0;
+ voltype=-1;
+ }
+ for (srv=0;srv < u.u.nServers;srv++) {
+ if ((u.u.serverFlags[srv] & vtype) == 0)
+ continue;
+ if ((u.u.serverFlags[srv] & VLSERVER_FLAG_UUID) == 0)
+ server=afs_serverbyaddr(cell, u.u.serverNumber[srv].time_low);
+ else
+ server=afs_serverbyid(cell, &u.u.serverNumber[srv]);
+ if (!server)
+ continue;
+ ret->servers[ret->nservers++]=server->index;
+ }
+ break;
+ case 1:
+ if (id == u.n.volumeId[RWVOL]) {
+ vtype=VLSF_RWVOL;
+ voltype=VOLTYPE_RW;
+ } else if (id == u.n.volumeId[ROVOL]) {
+ vtype=VLSF_ROVOL;
+ voltype=VOLTYPE_RO;
+ } else if (id == u.n.volumeId[BACKVOL]) {
+ vtype=VLSF_BACKVOL;
+ voltype=VOLTYPE_BK;
+ } else {
+ vtype=0;
+ voltype=-1;
+ }
+ for (srv=0;srv < u.n.nServers;srv++) {
+ if ((u.n.serverFlags[srv] & vtype) == 0)
+ continue;
+ server=afs_serverbyaddr(cell, u.n.serverNumber[srv]);
+ if (!server)
+ continue;
+ ret->servers[ret->nservers++]=server->index;
+ }
+ break;
+ case 2:
+ if (id == u.o.volumeId[RWVOL]) {
+ vtype=VLSF_RWVOL;
+ voltype=VOLTYPE_RW;
+ } else if (id == u.o.volumeId[ROVOL]) {
+ vtype=VLSF_ROVOL;
+ voltype=VOLTYPE_RO;
+ } else if (id == u.o.volumeId[BACKVOL]) {
+ vtype=VLSF_BACKVOL;
+ voltype=VOLTYPE_BK;
+ } else {
+ vtype=0;
+ voltype=-1;
+ }
+ for (srv=0;srv < u.o.nServers;srv++) {
+ if ((u.o.serverFlags[srv] & vtype) == 0)
+ continue;
+ server=afs_serverbyaddr(cell, u.o.serverNumber[srv]);
+ if (!server)
+ continue;
+ ret->servers[ret->nservers++]=server->index;
+ }
+ break;
+ }
+ ret->voltype=voltype;
+ server=afs_serverbyindex(ret->servers[0]);
+ if (server)
+ i.s_addr=server->addrs[0];
+ else
+ i.s_addr=0;
+ afscp_dprintf(("New volume BYID %s (%lu) on %s (%d)\n", ret->name, ret->id, inet_ntoa(i), ret->servers[0]));
+ s=tsearch(&key, &cell->volsbyid, icompare);
+ if (s)
+ *(struct afs_volume **)s=ret;
+ strcpy(key.name, ret->name);
+ s=tsearch(&key, &cell->volsbyname, ncompare);
+ if (s)
+ *(struct afs_volume **)s=ret;
+ return ret;
+}
+