+++ /dev/null
-/* copyright (c) 2005
- * the regents of the university of michigan
- * all rights reserved
- *
- * permission is granted to use, copy, create derivative works and
- * redistribute this software and such derivative works for any purpose,
- * so long as the name of the university of michigan is not used in
- * any advertising or publicity pertaining to the use or distribution
- * of this software without specific, written prior authorization. if
- * the above copyright notice or any other identification of the
- * university of michigan is included in any copy of any portion of
- * this software, then the disclaimer below must also be included.
- *
- * this software is provided as is, without representation from the
- * university of michigan as to its fitness for any purpose, and without
- * warranty by the university of michigan of any kind, either express
- * or implied, including without limitation the implied warranties of
- * merchantability and fitness for a particular purpose. the regents
- * of the university of michigan shall not be liable for any damages,
- * including special, indirect, incidental, or consequential damages,
- * with respect to any claim arising out or in connection with the use
- * of the software, even if it has been or is hereafter advised of the
- * possibility of such damages.
- */
-
-#include <osi.h>
-#include "afsd.h"
-#include <winioctl.h>
-#include "..\afsrdr\kif.h"
-#include "..\afsrdr\ifs_rpc.h"
-
-#include "afsdifs.h"
-
-
-/****************************/
-/* parameters, macros, etc. */
-/****************************/
-#define IFSL_SUCCEEDED(st) (!(st & IFSL_FAIL_BASE))
-#define MAP_RETURN(code) if (code) return ifs_MapCmError(code);
-#define ROOTPATH "\\"
-#define TRANSFER_BUF_SIZE (RPC_BUF_SIZE + TRANSFER_CHUNK_SIZE)
-#define SCPL_LOCK EnterCriticalSection(&scp_list_lock);
-#define SCPL_UNLOCK LeaveCriticalSection(&scp_list_lock);
-
-
-/****************************/
-/* structs */
-/****************************/
-struct user_map_entry /* how we keep users straight. total of MAX_AFS_USERS of these */
-{
- LARGE_INTEGER id; /* internal id created by kernel */
- cm_user_t *creds; /* global (thread-specific) var userp is set to this */
-};
-
-struct scp_status /* one for each unique file in afs */
-{
- struct scp_status *next; /* stored in a global chain in a chain locked by SCPL_[UN]LOCK */
- cm_scache_t *scp; /* file handle used with cm_ fns */
- ULONG fid; /* internal id generated by FID_HASH_FN from AFS's 128-bit FID */
-};
-typedef struct scp_status scp_status_t;
-
-struct readdir_context /* temporary struct, allocated as necessary, for cm_Apply callback */
-{
- char *matchString; /* for matching against */
- char *buf, *buf_pos; /* filling buffer to length, currently at buf_pos */
- ULONG_PTR length;
- ULONG count; /* number of entries packed so far */
-};
-typedef struct readdir_context readdir_context_t;
-
-
-/****************************/
-/* global vars */
-/****************************/
-/* the table user_map is used to store cm_user structs keyed on the calling
- * process' 64-bit ID token. the rpc library sets userp to point to this
- * entry; userp is specific to each thread, and thus may be used securely
- * as a global.
- */
-__declspec(thread) cm_user_t *userp;
-struct user_map_entry user_map[MAX_AFS_USERS];
-
-CRITICAL_SECTION mapLock, scp_list_lock;
-
-scp_status_t *scp_list_head = NULL;
-
-
-/****************************/
-/* error functions */
-/****************************/
-char *IfslErrorToText(unsigned long ifsl)
-{
- switch (ifsl)
- {
- case IFSL_SUCCESS:
- return "success";
- case IFSL_DOES_NOT_EXIST:
- return "does not exist";
- case IFSL_NOT_IMPLEMENTED:
- return "not implemented";
- case IFSL_END_OF_ENUM:
- return "end of enum";
- case IFSL_CANNOT_MAKE:
- return "cannot make";
- case IFSL_END_OF_FILE:
- return "end of file";
- case IFSL_NO_ACCESS:
- return "no access";
- case IFSL_BUFFER_TOO_SMALL:
- return "buffer too small";
- case IFSL_SHARING_VIOLATION:
- return "sharing violation";
- case IFSL_BAD_INPUT:
- return "bad input";
- case IFSL_GENERIC_FAILURE:
- return "generic failure";
- case IFSL_OPEN_CREATED:
- return "open created";
- case IFSL_OPEN_EXISTS:
- return "open exists";
- case IFSL_OPEN_OPENED:
- return "opened";
- case IFSL_OPEN_OVERWRITTEN:
- return "overwritten";
- case IFSL_OPEN_SUPERSCEDED:
- return "supersceded";
- case IFSL_BADFILENAME:
- return "bad filename";
- case IFSL_READONLY:
- return "read only";
- case IFSL_IS_A_DIR:
- return "is a dir";
- case IFSL_PATH_DOES_NOT_EXIST:
- return "path does not exist";
- case IFSL_IS_A_FILE:
- return "is a file";
- case IFSL_NOT_EMPTY:
- return "dir not empty";
- case IFSL_UNSPEC:
- return "unspecified error";
- default:
- return "NOT FOUND";
- }
-}
-
-unsigned long ifs_MapCmError(unsigned long code)
-{
- switch (code)
- {
- case CM_ERROR_STOPNOW:
- case 0:
- return IFSL_SUCCESS;
- case CM_ERROR_NOSUCHCELL:
- case CM_ERROR_NOSUCHVOLUME:
- case CM_ERROR_NOSUCHFILE:
- return IFSL_DOES_NOT_EXIST;
- case CM_ERROR_NOSUCHPATH:
- return IFSL_PATH_DOES_NOT_EXIST;
- case CM_ERROR_BADNTFILENAME:
- return IFSL_BADFILENAME;
- case CM_ERROR_TIMEDOUT:
- case CM_ERROR_ALLOFFLINE:
- case CM_ERROR_CLOCKSKEW:
- case CM_ERROR_REMOTECONN:
- case CM_ERROR_ALLBUSY:
- return IFSL_GENERIC_FAILURE;
- case CM_ERROR_NOACCESS:
- return IFSL_NO_ACCESS;
- case CM_ERROR_RETRY:
- case CM_ERROR_TOOBIG:
- case CM_ERROR_BADFD:
- case CM_ERROR_BADFDOP:
- case CM_ERROR_CROSSDEVLINK:
- return IFSL_GENERIC_FAILURE;
- case CM_ERROR_EXISTS:
- return IFSL_OPEN_EXISTS;
- case CM_ERROR_BADOP:
- case CM_ERROR_INVAL:
- case CM_ERROR_UNKNOWN:
- case CM_ERROR_BADSMB:
- return IFSL_GENERIC_FAILURE;
- case CM_ERROR_NOTDIR:
- case CM_ERROR_ISDIR:
- case CM_ERROR_READONLY:
- return IFSL_BAD_INPUT;
- case CM_ERROR_BUFFERTOOSMALL:
- return IFSL_BUFFER_TOO_SMALL;
- case CM_ERROR_WOULDBLOCK:
- case CM_ERROR_BADSHARENAME:
- case CM_ERROR_NOMORETOKENS:
- case CM_ERROR_NOTEMPTY:
- case CM_ERROR_USESTD:
- case CM_ERROR_ATSYS:
- return IFSL_GENERIC_FAILURE;
- case CM_ERROR_NOFILES:
- case CM_ERROR_BADTID:
- return IFSL_END_OF_ENUM;
- case CM_ERROR_PARTIALWRITE:
- case CM_ERROR_NOIPC:
- case CM_ERROR_RENAME_IDENTICAL:
- case CM_ERROR_AMBIGUOUS_FILENAME:
- return IFSL_GENERIC_FAILURE;
- case IFSL_SHARING_VIOLATION:
- return IFSL_SHARING_VIOLATION;
- case IFSL_NOT_EMPTY:
- return IFSL_NOT_EMPTY;
- case CM_ERROR_SPACE:
- case CM_ERROR_QUOTA:
- return IFSL_OVERQUOTA;
- }
- return IFSL_GENERIC_FAILURE;
-}
-
-
-/****************************/
-/* support fns */
-/****************************/
-cm_scache_t *ifs_FindScp(ULONG fid) /* walk list to find scp<->fid mapping */
-{
- scp_status_t *curr;
-
- SCPL_LOCK;
-
- curr = scp_list_head;
- while (curr)
- {
- if (curr->fid == fid)
- {
- SCPL_UNLOCK;
- return curr->scp;
- }
- curr = curr->next;
- }
- SCPL_UNLOCK;
- return NULL;
-}
-
-/* must call with scp write-locked. will always return correct results
- unless network fails (it loops properly). */
-ifs_CheckAcl(cm_scache_t *scp, ULONG access, ULONG *granted)
-{
- long code;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- /* ripped from cm_scache.c */
- while (1)
- {
- if (cm_HaveAccessRights(scp, userp, access, granted))
- {
- return 0;
- }
- else
- {
- /* we don't know the required access rights */
- code = cm_GetAccessRights(scp, userp, &req);
- MAP_RETURN(code);
- continue;
- }
- }
-
- return 0;
-}
-
-/* extract data from scp. an ifs_ support function to centralize changes. */
-ifs_CopyInfo(cm_scache_t *scp, ULONG *attribs, LARGE_INTEGER *size,
- LARGE_INTEGER *creation, LARGE_INTEGER *access,
- LARGE_INTEGER *change, LARGE_INTEGER *written)
-{
- access->QuadPart = 0; /* these mappings are not quite correct. we can */
- change->QuadPart = scp->clientModTime; /* leave them zero, if necessary. */
- written->QuadPart = scp->clientModTime;
- creation->QuadPart = scp->serverModTime;
-
- *attribs = 0;
- if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
- scp->fileType == CM_SCACHETYPE_SYMLINK ||
- scp->fileType == CM_SCACHETYPE_MOUNTPOINT/* ||
- scp->fileType == 0*/)
- *attribs |= FILE_ATTRIBUTE_DIRECTORY;
-
- /*if (!attribs && scp->fileType == CM_SCACHETYPE_FILE)
- *attribs |= FILE_ATTRIBUTE_NORMAL;*/
-
- if (*attribs == FILE_ATTRIBUTE_DIRECTORY)
- size->QuadPart = 0;
- else
- *size = scp->length;
-
- return 0;
-}
-
-
-/* close and zero scp pointer. zeroing pointer should
- help eliminate accessing discarded cache entries. */
-void ifs_InternalClose(cm_scache_t **scpp)
-{
- osi_assert(scpp && *scpp);
- cm_ReleaseSCache(*scpp);
- *scpp = NULL;
-}
-
-/* normalizes path by removing trailing slashes. separates last
- * path component with a null, so that *dirp points to parent path
- * and *filep points to filename. modifies string path.
- */
-BOOLEAN ifs_FindComponents(char *path, const char **dirp, const char **filep)
-{
- char *lastSep;
- BOOLEAN removed;
- static char emptyPath[] = "\\"; /* if the path contains only one component, this is the parent. */
-
- osi_assert(path);
-
- if (strlen(path))
- removed = (path[strlen(path)-1] == '\\');
- else
- removed = 1;
-
- lastSep = strrchr(path, '\\');
- while (lastSep == path + strlen(path) - 1)
- {
- *lastSep = '\0';
- lastSep = strrchr(path, '\\');
- }
-
- if (lastSep)
- {
- *lastSep = '\0';
-
- *dirp = path;
- *filep = lastSep + 1;
- }
- else
- {
- lastSep = path + strlen(path);
-
- *dirp = emptyPath;
- *filep = path;
- }
-
- return removed;
-}
-
-/* here to make maintenance easy */
-unsigned long ifs_ConvertFileName(wchar_t *in, unsigned int inchars, char *out, unsigned int outchars)
-{
- unsigned long code;
-
- code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, in, inchars, out, outchars-1, NULL, NULL);
- if (!code)
- return IFSL_BADFILENAME;
-
- return 0;
-}
-
-/* called by rpc_ library to let us initialize environment.
- * call with id of zero to clear current thread auth. */
-ifs_ImpersonateClient(LARGE_INTEGER user_id)
-{
- int x, empty;
-
- if (!user_id.QuadPart)
- {
- userp = NULL;
- return 0;
- }
-
- empty = -1;
- EnterCriticalSection(&mapLock);
- for (x = 0; x < MAX_AFS_USERS; x++)
- {
- if (user_map[x].id.QuadPart == 0)
- empty = x;
- if (user_map[x].id.QuadPart == user_id.QuadPart)
- goto done;
- }
- if (empty == -1)
- {
- LeaveCriticalSection(&mapLock);
- return -1;
- }
- user_map[empty].id = user_id;
- user_map[empty].creds = cm_NewUser();
- x = empty;
-
- done:
- userp = user_map[x].creds;
- LeaveCriticalSection(&mapLock);
-
- return 0;
-}
-
-
-/****************************/
-/* upcalls */
-/****************************/
-long uc_namei(WCHAR *name, ULONG *fid) /* performs name<->fid mapping, and enters it into table */
-{
- char *buffer; /* we support semi-infinite path lengths */
- long code;
- cm_scache_t *scp, *dscp;
- char *dirp, *filep;
- cm_req_t req;
- scp_status_t *st;
- short len;
-
- cm_InitReq(&req);
-
- len = (short)wcslen(name)+20; /* characters *should* map 1<->1, but in case */
- buffer = malloc(len);
- code = ifs_ConvertFileName(name, -1, buffer, len);
- if (code)
- {
- free(buffer);
- MAP_RETURN(code);
- }
- ifs_FindComponents(buffer, &dirp, &filep);
-
- code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
- if (code)
- {
- free(buffer);
- MAP_RETURN(code);
- }
- if (*filep)
- code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
- else
- cm_HoldSCache(scp = dscp);
- cm_ReleaseSCache(dscp);
-
- if (code)
- {
- free(buffer);
- MAP_RETURN(code);
- }
-
- if (ifs_FindScp(FID_HASH_FN(&scp->fid)))
- {
- osi_assertx(ifs_FindScp(FID_HASH_FN(&scp->fid)) == scp, "uc_namei: same fid hash for two files");
- *fid = FID_HASH_FN(&scp->fid);
- osi_assert(scp->refCount > 1);
- cm_ReleaseSCache(scp);
- }
- else
- {
- SCPL_LOCK;
- st = malloc(sizeof(scp_status_t));
- st->scp = scp;
- st->fid = FID_HASH_FN(&scp->fid);
- st->next = scp_list_head;
- scp_list_head = st;
- SCPL_UNLOCK;
- osi_assert(scp->refCount == 1);
- *fid = st->fid;
- }
-
- free(buffer);
-
- return 0;
-}
-
-/* this should only be called right after open, so we do not need to stat file.
- * we only check the server's restrictions. sharing violations are handled in the
- * kernel. the access mode we grant sticks with the file_object until its death. */
-long uc_check_access(ULONG fid, ULONG access, ULONG *granted)
-{
- ULONG afs_acc, afs_gr;
- cm_scache_t *scp;
- ULONG gr;
- BOOLEAN file, dir;
-
- gr = 0;
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
-
- file = (scp->fileType == CM_SCACHETYPE_FILE);
- dir = !file;
-
- /* access definitions from prs_fs.h */
- afs_acc = 0;
- if (access & FILE_READ_DATA)
- afs_acc |= PRSFS_READ;
- if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
- afs_acc |= PRSFS_WRITE;
- if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
- afs_acc |= PRSFS_WRITE;
- if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
- afs_acc |= PRSFS_INSERT;
- if (dir && (access & FILE_LIST_DIRECTORY))
- afs_acc |= PRSFS_LOOKUP;
- if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
- afs_acc |= PRSFS_LOOKUP;
- if (file && (access & FILE_EXECUTE))
- afs_acc |= PRSFS_WRITE;
- if (dir && (access & FILE_TRAVERSE))
- afs_acc |= PRSFS_READ;
- if (dir && (access & FILE_DELETE_CHILD))
- afs_acc |= PRSFS_DELETE;
- if ((access & DELETE))
- afs_acc |= PRSFS_DELETE;
-
- /* check ACL with server */
- lock_ObtainWrite(&scp->rw);
- ifs_CheckAcl(scp, afs_acc, &afs_gr);
- lock_ReleaseWrite(&scp->rw);
-
- *granted = 0;
- if (afs_gr & PRSFS_READ)
- *granted |= FILE_READ_DATA | FILE_EXECUTE;
- if (afs_gr & PRSFS_WRITE)
- *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE;
- if (afs_gr & PRSFS_INSERT)
- *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
- if (afs_gr & PRSFS_LOOKUP)
- *granted |= (dir ? FILE_LIST_DIRECTORY : 0) | FILE_READ_EA | FILE_READ_ATTRIBUTES;
- if (afs_gr & PRSFS_DELETE)
- *granted |= FILE_DELETE_CHILD | DELETE;
- if (afs_gr & PRSFS_LOCK)
- *granted |= 0;
- if (afs_gr & PRSFS_ADMINISTER)
- *granted |= 0;
-
- * granted |= SYNCHRONIZE | READ_CONTROL;
-
- return 0;
-}
-
-long uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid)
-{
- char *buffer; /* we support semi-infinite path lengths */
- long code;
- cm_scache_t *scp, *dscp;
- char *dirp, *filep;
- unsigned char removed;
- cm_req_t req;
- scp_status_t *st;
- cm_attr_t attr;
- short len;
-
- cm_InitReq(&req);
-
- len = (short)wcslen(name)+20; /* characters *should* map 1<->1, but in case */
- buffer = malloc(len);
- code = ifs_ConvertFileName(name, -1, buffer, len);
- if (code)
- {
- free(buffer);
- MAP_RETURN(code);
- }
- removed = ifs_FindComponents(buffer, &dirp, &filep);
-
- /* lookup the parent directory, which must exist */
- code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
- if (code)
- {
- free(buffer);
- MAP_RETURN(code);
- }
-
- osi_assert(filep);
- if (*filep)
- {
- attr.mask = CM_ATTRMASK_LENGTH;
- attr.length = alloc;
-
- if (attribs & FILE_ATTRIBUTE_DIRECTORY)
- {
- code = cm_MakeDir(dscp, filep, 0, &attr, userp, &req);
- if (!code)
- code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
- }
- else
- code = cm_Create(dscp, filep, 0, &attr, &scp, userp, &req);
- }
- cm_ReleaseSCache(dscp);
-
- if (code)
- {
- free(buffer);
- MAP_RETURN(code);
- }
-
- SCPL_LOCK;
- st = malloc(sizeof(scp_status_t));
- st->scp = scp;
- st->fid = FID_HASH_FN(&scp->fid);
- st->next = scp_list_head;
- scp_list_head = st;
- SCPL_UNLOCK;
-
- *fid = st->fid;
- *granted = access;
-
- free(buffer);
-
- return 0;
-}
-
-/* this does not fill the attribs member completely. additional flags must
- be added in the kernel, such as read-only. */
-long uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation,
- LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written)
-{
- cm_scache_t *scp;
- cm_req_t req;
- ULONG code;
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
-
- /* stat file; don't want callback */
- cm_InitReq(&req);
- lock_ObtainWrite(&(scp->rw));
- cm_HoldUser(userp);
- code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
- cm_ReleaseUser(userp);
-
- if (code)
- lock_ReleaseWrite(&(scp->rw));
- MAP_RETURN(code);
-
- code = ifs_CopyInfo(scp, attribs, size, creation, access, change, written);
- lock_ReleaseWrite(&(scp->rw));
- MAP_RETURN(code);
-
- return 0;
-}
-
-/* set atime, mtime, etc. */
-long uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access,
- LARGE_INTEGER change, LARGE_INTEGER written)
-{
- return IFSL_GENERIC_FAILURE;
-}
-
-/* FIXFIX: this code may not catch over-quota errors, because the end
- * of the file is not written to the server by the time this returns. */
-/* truncate or extend file, in cache and on server */
-long uc_trunc(ULONG fid, LARGE_INTEGER size)
-{
- ULONG code;
- cm_scache_t *scp;
- cm_req_t req;
- osi_hyper_t oldLen;
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
-
- /* we have already checked permissions in the kernel; but, if we do not
- * have access as this userp, code will fail in rpc layer.
- */
-
- cm_InitReq(&req);
- lock_ObtainWrite(&(scp->rw));
-
- code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
-
- if (code)
- lock_ReleaseWrite(&(scp->rw));
- MAP_RETURN(code);
-
- oldLen = scp->length;
- lock_ReleaseWrite(&(scp->rw));
-
- code = cm_SetLength(scp, &size, userp, &req);
- MAP_RETURN(code);
- /*code = cm_FSync(scp, userp, &req);
- MAP_RETURN(code);*/
- /*code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
- MAP_RETURN(code);*/
-
-#if 0
- /* attempt to write last byte of file. fails to bring out quota errors because of delayed writing. */
- if (oldLen.QuadPart < size.QuadPart)
- {
- writePos.QuadPart = size.QuadPart - 1;
- WriteData(scp, writePos, 1, &"\0\0\0", userp, &written);
- MAP_RETURN(code);
- if (written != 1)
- return IFSL_UNSPEC;
- }
-#endif
-
- return 0;
-}
-
-/* read data from a file */
-long uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data)
-{
- ULONG code;
- cm_scache_t *scp;
-
- *read = 0;
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
-
- if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
- return IFSL_IS_A_DIR;
-
- code = ReadData(scp, offset, (unsigned long)length, data, userp, read);
- MAP_RETURN(code);
-
- return 0;
-}
-
-/* FIXFIX: this does not catch all overquota errors, because the file
- * is not necessarily written to the server when this returns. */
-/* write data to a file */
-long uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data)
-{
- ULONG code;
- cm_scache_t *scp;
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
-
- if (offset.QuadPart == -1)
- offset = scp->length;
- code = WriteData(scp, offset, (unsigned long)length, data, userp, written);
- MAP_RETURN(code);
-
- return 0;
-}
-
-long uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid)
-{
- int code;
- cm_req_t req;
- char *curdir, *curfile, *newdir, *newfile;
- cm_scache_t *dscp1, *dscp2, *scp;
- char b1[MAX_PATH], b2[MAX_PATH], b3[MAX_PATH];
- wchar_t b3_w[MAX_PATH];
-
- code = !(scp = ifs_FindScp(fid));
- if (!code)
- code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
- if (!code)
- code = ifs_ConvertFileName(new_name, -1, b2, MAX_PATH);
- if (!code)
- code = ifs_ConvertFileName(new_dir, -1, b3, MAX_PATH);
- if (!code)
- {
- ifs_FindComponents(b1, &curdir, &curfile);
- ifs_FindComponents(b2, &newdir, &newfile);
- newdir = b3;
- uc_close(fid);
- code = cm_NameI(cm_data.rootSCachep, curdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp1);
- }
- if (!code)
- {
- if (!strcmp(curdir, newdir))
- {
- dscp2 = dscp1;
- dscp1->refCount++;
- }
- else
- code = cm_NameI(cm_data.rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2);
- if (!code)
- {
- code = cm_Rename(dscp1, curfile, dscp2, newfile, userp, &req);
- if (!code)
- {
- strcat(b3, "\\");
- strcat(b3, b2);
- mbstowcs(b3_w, b3, MAX_PATH);
- uc_namei(b3_w, new_fid);
- }
- else
- {
- code = uc_namei(curr, new_fid);
- }
- ifs_InternalClose(&dscp2);
- }
- else
- {
- code = uc_namei(curr, new_fid);
- }
- ifs_InternalClose(&dscp1);
- }
-
- MAP_RETURN(code);
- return 0;
-}
-
-uc_flush(ULONG fid)
-{
- ULONG code;
- cm_scache_t *scp;
- cm_req_t req;
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
-
- cm_InitReq(&req);
- code = cm_FSync(scp, userp, &req);
-
- MAP_RETURN(code);
- return 0;
-}
-
-ifs_ReaddirCallback(cm_scache_t *scp, cm_dirEntry_t *entry, void *param, osi_hyper_t *offset)
-{
- readdir_context_t *context;
- ULONG name_len;
- readdir_data_t *info;
- char short_name[14], *endp;
- ULONG code;
- cm_req_t req;
- cm_scache_t *child_scp;
- cm_fid_t child_fid;
- int t;
-
- context = param;
-
- name_len = (ULONG) strlen(entry->name);
-
- info = (readdir_data_t *)context->buf_pos;
- if (context->length - (context->buf_pos - context->buf) < sizeof(readdir_data_t) + name_len * sizeof(WCHAR) + sizeof(LARGE_INTEGER))
- {
- if (context->count == 0)
- return CM_ERROR_BUFFERTOOSMALL;
- info->cookie = *offset;
- return CM_ERROR_STOPNOW;
- }
-
- if ((context->matchString && context->matchString[0] && (!strcmp(context->matchString, entry->name) || context->matchString[0]=='*')) ||
- !(context->matchString && context->matchString[0]))
- ;
- else
- return 0;
-
- cm_InitReq(&req);
- cm_HoldUser(userp);
- child_scp = NULL;
-
- child_fid.cell = scp->fid.cell;
- child_fid.volume = scp->fid.volume;
- child_fid.vnode = ntohl(entry->fid.vnode);
- child_fid.unique = ntohl(entry->fid.unique);
- code = cm_GetSCache(&child_fid, &child_scp, userp, &req);
- if (code || !child_scp)
- {
- cm_ReleaseUser(userp);
- return 0;
- }
-
- {
- lock_ObtainWrite(&child_scp->rw);
- code = cm_SyncOp(child_scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
- lock_ReleaseWrite(&child_scp->rw);
- }
-
- if (code) /* perhaps blank fields we do not know, and continue. bad filents should not prevent readdirs. */
- ;
-
- info->cookie = *offset;
-
- lock_ObtainWrite(&(child_scp->rw));
- code = ifs_CopyInfo(child_scp, &info->attribs, &info->size, &info->creation, &info->access, &info->change, &info->write);
-#if 0
- /* make files we do not have write access to read-only */
- /* this is a handy feature, but it takes a lot of time and traffic to enumerate */
- ifs_CheckAcl(child_scp, FILE_WRITE_DATA, &gr); /* perhaps add flag to not loop, to avoid network traffic if not found*/
- if (gr & FILE_READ_DATA && !(gr & FILE_WRITE_DATA))
- info->attribs |= FILE_ATTRIBUTE_READONLY;
-#endif
- lock_ReleaseWrite(&(child_scp->rw));
- ifs_InternalClose(&child_scp);
- MAP_RETURN(code);
-
- cm_Gen8Dot3Name(entry, short_name, &endp);
- *endp = '\0';
- info->short_name_length = (CCHAR)sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, short_name, -1, info->short_name, 14))?t-1:0);
- info->name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, entry->name, -1, info->name, 600))?t-1:0);
-
- context->buf_pos = ((char*)info) + sizeof(readdir_data_t) + info->name_length;
- context->count++;
-
- info = (readdir_data_t *)context->buf_pos;
- info->cookie.QuadPart = -1;
-
- return 0;
-}
-
-long uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG_PTR *len)
-{
- ULONG code;
- char buffer[2048];
- cm_req_t req;
- cm_scache_t *scp;
- readdir_context_t context;
- LARGE_INTEGER cookie;
-
- if (cookie_in.QuadPart == -1)
- {
- *len = 0;
- *count = 0;
- return 0;
- }
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
- code = ifs_ConvertFileName(filter, -1, buffer, 2048);
- if (code)
- return code;
-
- cm_InitReq(&req);
- cm_HoldUser(userp);
-
- cookie = cookie_in;
- context.matchString = buffer;
- context.buf_pos = context.buf = data;
- context.length = *len;
- context.count = 0;
- *count = 0;
-
- ((LARGE_INTEGER *)context.buf)->QuadPart = -1;
-
- code = cm_ApplyDir(scp, ifs_ReaddirCallback, &context, &cookie, userp, &req, NULL);
-
- context.buf_pos += sizeof(LARGE_INTEGER);
-
- *count = context.count;
-
- cm_ReleaseUser(userp);
- *len = context.buf_pos - context.buf;
-
- code = ifs_MapCmError(code);
- return code;
-}
-
-long uc_close(ULONG fid)
-{
- cm_scache_t *scp;
- cm_req_t req;
- scp_status_t *prev, *curr;
-
- scp = ifs_FindScp(fid);
- if (!scp)
- return IFSL_BAD_INPUT;
-
- cm_InitReq(&req);
- cm_FSync(scp, userp, &req);
-
- SCPL_LOCK; /* perhaps this should be earlier */
-
- cm_ReleaseSCache(scp);
-
- prev = NULL, curr = scp_list_head;
-
- while (curr)
- {
- if (curr->fid == fid)
- {
- if (prev)
- prev->next = curr->next;
- else
- scp_list_head = curr->next;
- free(curr);
- break;
- }
- prev = curr;
- curr = curr->next;
- }
-
- SCPL_UNLOCK;
-
- return 0;
-}
-
-long uc_unlink(WCHAR *name)
-{
- char buffer[2048];
- long code;
- cm_scache_t *dscp;
- char *dirp, *filep;
- unsigned char removed;
- cm_req_t req;
-
- cm_InitReq(&req);
-
- code = ifs_ConvertFileName(name, -1, buffer, 2048);
- MAP_RETURN(code);
- removed = ifs_FindComponents(buffer, &dirp, &filep);
-
- if (!(*filep))
- return IFSL_BADFILENAME;
-
- code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
- MAP_RETURN(code);
-
- code = cm_Unlink(dscp, filep, userp, &req);
- if (code)
- code = cm_RemoveDir(dscp, filep, userp, &req);
-
- cm_ReleaseSCache(dscp);
- MAP_RETURN(code);
-
- return 0;
-}
-
-
-long uc_ioctl_write(ULONG length, char *data, ULONG_PTR *key)
-{
- smb_ioctl_t *iop;
-
- iop = malloc(sizeof(smb_ioctl_t));
- memset(iop, 0, sizeof(smb_ioctl_t));
- smb_IoctlPrepareWrite(NULL, iop);
-
- memcpy(iop->inDatap + iop->inCopied, data, length);
- iop->inCopied += length;
- *key = (ULONG_PTR)iop;
-
- return 0;
-}
-
-long uc_ioctl_read(ULONG_PTR key, ULONG *length, char *data)
-{
- smb_ioctl_t *iop;
-
- iop = (smb_ioctl_t *)key;
- osi_assert(iop);
-
- cm_HoldUser(userp);
- smb_IoctlPrepareRead(NULL, iop, userp);
- cm_ReleaseUser(userp);
-
- *length = iop->outDatap - iop->outAllocp;
- memcpy(data, iop->outAllocp, *length);
- free(iop);
-
- return 0;
-}
-
-int ifs_Init(char **reason)
-{
- HANDLE kcom;
-
- kcom = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- 0, NULL);
- if (kcom == INVALID_HANDLE_VALUE)
- {
- *reason = "error creating communications file";
- return CM_ERROR_REMOTECONN;
- }
- CloseHandle(kcom);
-
- memset(user_map, 0, MAX_AFS_USERS*sizeof(struct user_map_entry));
- InitializeCriticalSection(&mapLock);
- InitializeCriticalSection(&scp_list_lock);
-
- return 0;
-}
-
-ifs_TransactRpc(char *outbuf, int outlen, char *inbuf, int *inlen)
-{
- HANDLE hf;
- DWORD read = 0;
- DWORD inmax;
-
- if (!outbuf || !inbuf)
- return IFSL_GENERIC_FAILURE;
-
- hf = CreateFile("\\\\.\\afscom\\downcall", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
- if (hf == INVALID_HANDLE_VALUE)
- return 0;
-
- inmax = *inlen;
- if (!DeviceIoControl(hf, IOCTL_AFSRDR_DOWNCALL, outbuf, outlen, inbuf, inmax, inlen, NULL))
- {
- CloseHandle(hf);
- return IFSL_GENERIC_FAILURE;
- }
-
- CloseHandle(hf);
- return inlen ? IFSL_SUCCESS : IFSL_GENERIC_FAILURE;
-}
-
-
-DWORD WINAPI ifs_MainLoop(LPVOID param)
-{
- HANDLE pipe;
- DWORD written;
- unsigned char *bufIn, *bufOut;
- DWORD lenIn;
- rpc_t rpc;
- BOOL st;
-
- bufIn = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
- bufOut = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
- if (!bufIn || !bufOut)
- {
- if (bufIn) VirtualFree(bufIn, 0, MEM_RELEASE);
- if (bufOut) VirtualFree(bufOut, 0, MEM_RELEASE);
- osi_panic("ifs: allocate transfer buffers", __FILE__, __LINE__);
- }
-
- pipe = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- 0, NULL);
- if (pipe == INVALID_HANDLE_VALUE)
- {
- VirtualFree(bufIn, 0, MEM_RELEASE);
- VirtualFree(bufOut, 0, MEM_RELEASE);
- osi_panic("ifs: creating communications handle", __FILE__, __LINE__);
- }
-
- while (1)
- {
- /* just check if the event is already signalled, do not wait */
- if (WaitForSingleObject(WaitToTerminate, 0) == WAIT_OBJECT_0)
- break;
-
- /* read request... */
- st = ReadFile(pipe, bufIn, TRANSFER_BUF_SIZE, &lenIn, NULL);
- if (!st) {
- if (GetLastError() == ERROR_INVALID_HANDLE)
- break;
- else
- continue;
- }
-
- ZeroMemory(&rpc, sizeof(rpc));
- rpc.in_buf = rpc.in_pos = bufIn;
- rpc.out_buf = rpc.out_pos = bufOut;
-
- /* ...process it... */
- rpc_parse(&rpc);
-
- /* ...and write it back */
- st = WriteFile(pipe, rpc.out_buf, rpc.out_pos - rpc.out_buf, &written, NULL);
- if (!st)
- if (GetLastError() == ERROR_INVALID_HANDLE)
- break;
- else
- continue;
- }
-
- return (DWORD)1;
-}