2 * the regents of the university of michigan
5 * permission is granted to use, copy, create derivative works and
6 * redistribute this software and such derivative works for any purpose,
7 * so long as the name of the university of michigan is not used in
8 * any advertising or publicity pertaining to the use or distribution
9 * of this software without specific, written prior authorization. if
10 * the above copyright notice or any other identification of the
11 * university of michigan is included in any copy of any portion of
12 * this software, then the disclaimer below must also be included.
14 * this software is provided as is, without representation from the
15 * university of michigan as to its fitness for any purpose, and without
16 * warranty by the university of michigan of any kind, either express
17 * or implied, including without limitation the implied warranties of
18 * merchantability and fitness for a particular purpose. the regents
19 * of the university of michigan shall not be liable for any damages,
20 * including special, indirect, incidental, or consequential damages,
21 * with respect to any claim arising out or in connection with the use
22 * of the software, even if it has been or is hereafter advised of the
23 * possibility of such damages.
29 #include "..\afsrdr\kif.h"
30 #include "..\afsrdr\ifs_rpc.h"
35 /****************************/
36 /* parameters, macros, etc. */
37 /****************************/
38 #define IFSL_SUCCEEDED(st) (!(st & IFSL_FAIL_BASE))
39 #define MAP_RETURN(code) if (code) return ifs_MapCmError(code);
40 /* defined in multiple places (search source) */
41 #define BUF_FILEHASH(fidp) ((((fidp)->vnode+((fidp)->unique << 13) + ((fidp)->unique >> (32-13)) \
42 +(fidp)->volume+(fidp)->cell) \
45 //#define ROOTPATH "\\CITI.UMICH.EDU"
46 #define TRANSFER_BUF_SIZE (2*1024*1024)
47 #define SCPL_LOCK EnterCriticalSection(&scp_list_lock);
48 #define SCPL_UNLOCK LeaveCriticalSection(&scp_list_lock);
51 /****************************/
53 /****************************/
54 struct user_map_entry /* how we keep users straight. total of MAX_USERS of these */
56 LARGE_INTEGER id; /* internal id created by kernel */
57 cm_user_t *creds; /* global (thread-specific) var userp is set to this */
60 struct scp_status /* one for each unique file in afs */
62 struct scp_status *next; /* stored in a global chain in a chain locked by SCPL_[UN]LOCK */
63 cm_scache_t *scp; /* file handle used with cm_ fns */
64 ULONG fid; /* internal id generated by BUF_FILEHASH from AFS's 128-bit FID */
66 typedef struct scp_status scp_status_t;
68 struct readdir_context /* temporary struct, allocated as necessary, for cm_Apply callback */
70 char *matchString; /* for matching against */
71 char *buf, *buf_pos; /* filling buffer to length, currently at buf_pos */
73 ULONG count; /* number of entries packed so far */
75 typedef struct readdir_context readdir_context_t;
78 /****************************/
80 /****************************/
81 __declspec(thread) cm_user_t *userp;
82 struct user_map_entry user_map[MAX_USERS];
84 CRITICAL_SECTION mapLock, scp_list_lock;
86 extern HANDLE DoTerminate;
88 scp_status_t *scp_list_head = NULL;
91 /****************************/
93 /****************************/
94 char *IfslErrorToText(unsigned long ifsl)
100 case IFSL_DOES_NOT_EXIST:
101 return "does not exist";
102 case IFSL_NOT_IMPLEMENTED:
103 return "not implemented";
104 case IFSL_END_OF_ENUM:
105 return "end of enum";
106 case IFSL_CANNOT_MAKE:
107 return "cannot make";
108 case IFSL_END_OF_FILE:
109 return "end of file";
112 case IFSL_BUFFER_TOO_SMALL:
113 return "buffer too small";
114 case IFSL_SHARING_VIOLATION:
115 return "sharing violation";
118 case IFSL_GENERIC_FAILURE:
119 return "generic failure";
120 case IFSL_OPEN_CREATED:
121 return "open created";
122 case IFSL_OPEN_EXISTS:
123 return "open exists";
124 case IFSL_OPEN_OPENED:
126 case IFSL_OPEN_OVERWRITTEN:
127 return "overwritten";
128 case IFSL_OPEN_SUPERSCEDED:
129 return "supersceded";
130 case IFSL_BADFILENAME:
131 return "bad filename";
136 case IFSL_PATH_DOES_NOT_EXIST:
137 return "path does not exist";
141 return "dir not empty";
143 return "unspecified error";
149 unsigned long ifs_MapCmError(unsigned long code)
153 case CM_ERROR_STOPNOW:
156 case CM_ERROR_NOSUCHCELL:
157 case CM_ERROR_NOSUCHVOLUME:
158 case CM_ERROR_NOSUCHFILE: // x
159 return IFSL_DOES_NOT_EXIST;
160 case CM_ERROR_NOSUCHPATH: // x
161 return IFSL_PATH_DOES_NOT_EXIST;
162 case CM_ERROR_BADNTFILENAME:
163 return IFSL_BADFILENAME;
164 case CM_ERROR_TIMEDOUT:
165 case CM_ERROR_ALLOFFLINE:
166 case CM_ERROR_CLOCKSKEW:
167 case CM_ERROR_REMOTECONN:
168 case CM_ERROR_ALLBUSY:
169 return IFSL_GENERIC_FAILURE;
170 case CM_ERROR_NOACCESS:
171 return IFSL_NO_ACCESS;
173 case CM_ERROR_TOOBIG:
175 case CM_ERROR_BADFDOP:
176 case CM_ERROR_CROSSDEVLINK:
177 return IFSL_GENERIC_FAILURE;
178 case CM_ERROR_EXISTS:
179 return IFSL_OPEN_EXISTS;
182 case CM_ERROR_UNKNOWN:
183 case CM_ERROR_BADSMB:
184 return IFSL_GENERIC_FAILURE;//TODO:? ERR - STATUS_NO_MORE_FILES;
185 case CM_ERROR_NOTDIR:
187 case CM_ERROR_READONLY:
188 return IFSL_BAD_INPUT;
189 case CM_ERROR_BUFFERTOOSMALL:
190 return IFSL_BUFFER_TOO_SMALL;
191 case CM_ERROR_WOULDBLOCK:
192 case CM_ERROR_BADSHARENAME:
193 case CM_ERROR_NOMORETOKENS:
194 case CM_ERROR_NOTEMPTY:
195 case CM_ERROR_USESTD:
197 return IFSL_GENERIC_FAILURE;
198 case CM_ERROR_NOFILES:
199 case CM_ERROR_BADTID:
200 return IFSL_END_OF_ENUM;
201 case CM_ERROR_PARTIALWRITE:
203 case CM_ERROR_RENAME_IDENTICAL:
204 case CM_ERROR_AMBIGUOUS_FILENAME:
205 return IFSL_GENERIC_FAILURE;
206 case IFSL_SHARING_VIOLATION:
207 return IFSL_SHARING_VIOLATION;
209 return IFSL_NOT_EMPTY;
212 return IFSL_OVERQUOTA;
214 return IFSL_GENERIC_FAILURE;
218 /****************************/
220 /****************************/
221 cm_scache_t *ifs_FindScp(ULONG fid) /* walk list to find scp<->fid mapping */
227 curr = scp_list_head;
230 if (curr->fid == fid)
241 /* must call with scp write-locked. will always return correct results
242 unless network fails (it loops properly). */
243 ifs_CheckAcl(cm_scache_t *scp, ULONG access, ULONG *granted)
245 long outRights, code;
250 /* ripped from cm_scache.c */
253 if (cm_HaveAccessRights(scp, userp, access, granted))
259 /* we don't know the required access rights */
260 code = cm_GetAccessRights(scp, userp, &req);
269 /* extract data from scp. in ifs_ support function to centralize changes. */
270 ifs_CopyInfo(cm_scache_t *scp, ULONG *attribs, LARGE_INTEGER *size,
271 LARGE_INTEGER *creation, LARGE_INTEGER *access,
272 LARGE_INTEGER *change, LARGE_INTEGER *written)
274 access->QuadPart = 0; /* these mappings are not quite correct. we have the */
275 change->QuadPart = scp->clientModTime; /* right to leave them zero, if necessary. */
276 written->QuadPart = scp->clientModTime;
277 creation->QuadPart = scp->serverModTime;
280 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
281 scp->fileType == CM_SCACHETYPE_SYMLINK ||
282 scp->fileType == CM_SCACHETYPE_MOUNTPOINT/* ||
283 scp->fileType == 0*/)
284 *attribs |= FILE_ATTRIBUTE_DIRECTORY;
286 /*if (!attribs && scp->fileType == CM_SCACHETYPE_FILE)
287 *attribs |= FILE_ATTRIBUTE_NORMAL;*/
289 if (*attribs == FILE_ATTRIBUTE_DIRECTORY)
298 /* close and zero scp pointer. zeroing pointer should
299 help eliminate accessing discarded cache entries. */
300 void ifs_InternalClose(cm_scache_t **scp)
302 osi_assert(scp && *scp);
303 lock_ObtainMutex(&((*scp)->mx));
304 cm_ReleaseSCache(*scp);
305 if ((*scp)->refCount == 0) /* we haven't held scache for external use yet */
306 cm_DiscardSCache(*scp);
307 lock_ReleaseMutex(&((*scp)->mx));
311 /* normalizes path by removing trailing slashes. separates last
312 path component with a null, so that *dirp points to parent path
313 and *filep points to filename. modifies string path. */
314 BOOLEAN ifs_FindComponents(char *path, const char **dirp, const char **filep)
318 static char emptyPath[] = "\\"; /* if the path contains only one component, this is the parent. */
323 removed = (path[strlen(path)-1] == '\\');
327 lastSep = strrchr(path, '\\');
328 while (lastSep == path + strlen(path) - 1)
331 lastSep = strrchr(path, '\\');
339 *filep = lastSep + 1;
343 lastSep = path + strlen(path);
352 /* here to make maintenance easy */
353 unsigned long ifs_ConvertFileName(wchar_t *in, unsigned int inchars, char *out, unsigned int outchars)
357 code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, in, inchars, out, outchars-1, NULL, NULL);
359 return IFSL_BADFILENAME;
364 /* called by rpc_ library to let us initialize environment.
365 call with id of zero to clear current thread auth. */
366 ifs_ImpersonateClient(LARGE_INTEGER user_id)
370 if (!user_id.QuadPart)
377 EnterCriticalSection(&mapLock);
378 for (x = 0; x < MAX_USERS; x++)
380 if (user_map[x].id.QuadPart == 0)
382 if (user_map[x].id.QuadPart == user_id.QuadPart)
387 LeaveCriticalSection(&mapLock);
390 user_map[empty].id = user_id;
391 user_map[empty].creds = cm_NewUser();
395 userp = user_map[x].creds;
396 LeaveCriticalSection(&mapLock);
402 /****************************/
404 /****************************/
405 uc_namei(WCHAR *name, ULONG *fid) /* performs name<->fid mapping, and enters it into table */
407 char *buffer; /* we support semi-infinite path lengths */
409 cm_scache_t *scp, *dscp;
417 len = wcslen(name)+20; /* characters *should* map 1<->1, but in case */
418 buffer = malloc(len);
419 code = ifs_ConvertFileName(name, -1, buffer, len);
425 ifs_FindComponents(buffer, &dirp, &filep);
427 code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
434 code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
436 cm_HoldSCache(scp = dscp);
437 cm_ReleaseSCache(dscp);
446 st = malloc(sizeof(scp_status_t));
448 st->fid = BUF_FILEHASH(&scp->fid);
449 st->next = scp_list_head;
459 /* this should only be called right after open, so we do not need to stat file.
460 * we only check the server's restrictions. sharing violations are handled in the
461 * kernel. the access mode we grant sticks with the file_object until its death. */
462 uc_check_access(ULONG fid, ULONG access, ULONG *granted)
464 ULONG afs_acc, afs_gr;
471 scp = ifs_FindScp(fid);
473 return IFSL_BAD_INPUT;
475 file = (scp->fileType == CM_SCACHETYPE_FILE);
478 /* access definitions from prs_fs.h */
480 if (access & FILE_READ_DATA)
481 afs_acc |= PRSFS_READ;
482 if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
483 afs_acc |= PRSFS_WRITE;
484 if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
485 afs_acc |= PRSFS_WRITE;
486 if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
487 afs_acc |= PRSFS_INSERT;
488 if (dir && (access & FILE_LIST_DIRECTORY))
489 afs_acc |= PRSFS_LOOKUP;
490 if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
491 afs_acc |= PRSFS_LOOKUP;
492 if (file && (access & FILE_EXECUTE)) /* look at making this require write access */
493 afs_acc |= PRSFS_WRITE;
494 if (dir && (access & FILE_TRAVERSE))
495 afs_acc |= PRSFS_READ;
496 if (dir && (access & FILE_DELETE_CHILD))
497 afs_acc |= PRSFS_DELETE;
498 if (/*file && */(access & DELETE))
499 afs_acc |= PRSFS_DELETE;
501 /* check ACL with server */
502 lock_ObtainMutex(&(scp->mx));
503 ifs_CheckAcl(scp, afs_acc, &afs_gr);
504 lock_ReleaseMutex(&(scp->mx));
507 if (afs_gr & PRSFS_READ)
508 *granted |= FILE_READ_DATA | FILE_EXECUTE;
509 if (afs_gr & PRSFS_WRITE)
510 *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE; // last one hack
511 if (afs_gr & PRSFS_INSERT)
512 *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
513 if (afs_gr & PRSFS_LOOKUP)
514 *granted |= (dir ? FILE_LIST_DIRECTORY : 0) | FILE_READ_EA | FILE_READ_ATTRIBUTES;
515 if (afs_gr & PRSFS_DELETE)
516 *granted |= FILE_DELETE_CHILD | DELETE;
517 if (afs_gr & PRSFS_LOCK)
519 if (afs_gr & PRSFS_ADMINISTER)
522 * granted |= SYNCHRONIZE | READ_CONTROL;
527 uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid)
529 char *buffer; /* we support semi-infinite path lengths */
531 cm_scache_t *scp, *dscp;
533 unsigned char removed;
541 len = wcslen(name)+20; /* characters *should* map 1<->1, but in case */
542 buffer = malloc(len);
543 code = ifs_ConvertFileName(name, -1, buffer, len);
549 removed = ifs_FindComponents(buffer, &dirp, &filep);
551 /* lookup the parent directory, which must exist */
552 code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
562 attr.mask = CM_ATTRMASK_LENGTH;
565 if (attribs & FILE_ATTRIBUTE_DIRECTORY)
567 code = cm_MakeDir(dscp, filep, 0, &attr, userp, &req);
569 code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
573 /* for debugging strange error */
574 /*if (!strcmp(filep+strlen(filep)-3, "478") ||
575 !strcmp(filep+strlen(filep)-3, "503"))
577 code = cm_Create(dscp, filep, 0, &attr, &scp, userp, &req);
580 cm_ReleaseSCache(dscp);
589 st = malloc(sizeof(scp_status_t));
591 st->fid = BUF_FILEHASH(&scp->fid);
592 st->next = scp_list_head;
602 /* this does not fill the attribs member completely. additional flags must
603 be added in the kernel, such as read-only. */
604 uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation,
605 LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written)
611 scp = ifs_FindScp(fid);
613 return IFSL_BAD_INPUT;
615 /* stat file; don't want callback */
617 lock_ObtainMutex(&(scp->mx));
619 code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
620 cm_ReleaseUser(userp);
623 lock_ReleaseMutex(&(scp->mx));
626 code = ifs_CopyInfo(scp, attribs, size, creation, access, change, written);
627 lock_ReleaseMutex(&(scp->mx));
633 /* set atime, mtime, etc. */
634 uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access,
635 LARGE_INTEGER change, LARGE_INTEGER written)
637 return IFSL_GENERIC_FAILURE;
641 /* truncate or extend file, in cache and on server */
642 uc_trunc(ULONG fid, LARGE_INTEGER size)
647 osi_hyper_t oldLen, writePos;
650 scp = ifs_FindScp(fid);
652 return IFSL_BAD_INPUT;
654 /*code = ifs_CheckAcl(scp, FILE_WRITE_DATA, &gr);
657 if (!(gr & FILE_WRITE_DATA))
658 return IFSL_NO_ACCESS;*/
661 lock_ObtainMutex(&(scp->mx));
663 code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
666 lock_ReleaseMutex(&(scp->mx));
669 oldLen = scp->length;
670 lock_ReleaseMutex(&(scp->mx));
672 code = cm_SetLength(scp, &size, userp, &req);
674 /*code = cm_FSync(scp, userp, &req);
676 /*code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
680 /* attempt to write last byte of file. fails to help because of delayed writing. */
681 if (oldLen.QuadPart < size.QuadPart)
683 writePos.QuadPart = size.QuadPart - 1;
684 WriteData(scp, writePos, 1, &"\0\0\0", userp, &written);
690 /*cm_SyncOp(scp, NULL,
697 /* read data from a file */
698 uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data)
708 scp = ifs_FindScp(fid);
710 return IFSL_BAD_INPUT;
712 if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
713 return IFSL_IS_A_DIR;
715 code = ReadData(scp, offset, (unsigned long)length, data, userp, read);
721 //FIX/ handle quota errors properly
722 /* write data to a file */
723 uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data)
729 scp = ifs_FindScp(fid);
731 return IFSL_BAD_INPUT;
733 /*code = ifs_CheckAcl(scp, FILE_WRITE_DATA, &gr);
736 if (!(gr & FILE_WRITE_DATA))
737 return IFSL_NO_ACCESS;*/
739 if (offset.QuadPart == -1) // perhaps re-stat here?
740 offset = scp->length;
741 code = WriteData(scp, offset, (unsigned long)length, data, userp, written);
747 //need downcall for new length
749 uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid)
753 //struct vnode *node;
756 char *curdir, *curfile, *newdir, *newfile;
757 cm_scache_t *dscp1, *dscp2, *scp;
758 char b1[MAX_PATH], b2[MAX_PATH], b3[MAX_PATH];
762 code = !(scp = ifs_FindScp(fid));
764 code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
766 code = ifs_ConvertFileName(new_name, -1, b2, MAX_PATH);
768 code = ifs_ConvertFileName(new_dir, -1, b3, MAX_PATH);
771 ifs_FindComponents(b1, &curdir, &curfile);
772 ifs_FindComponents(b2, &newdir, &newfile);
774 /*lock_ReleaseMutex(&scp->mx);
775 cm_FSync(scp, userp, &req);
776 if (scp->refCount != 1)
778 ifs_InternalClose(&scp);*/
780 code = cm_NameI(cm_data.rootSCachep, curdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp1);
784 if (!strcmp(curdir, newdir))
790 code = cm_NameI(cm_data.rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2);
793 code = cm_Rename(dscp1, curfile, dscp2, newfile, userp, &req);
794 //ifs_InternalClose(&dscp2);
796 //code = cm_NameI(cm_rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2);
799 code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
800 code = uc_namei(b1, new_fid);
803 //code = cm_Lookup(dscp2, newfile, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &node->scp);
805 ifs_InternalClose(&dscp2);
809 //code = cm_Lookup(dscp1, curfile, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &node->scp);
810 code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
811 code = uc_namei(b1, new_fid);
815 ifs_InternalClose(&dscp1);
821 ifs_ReaddirCallback(cm_scache_t *scp, cm_dirEntry_t *entry, void *param, osi_hyper_t *offset)
823 readdir_context_t *context;
825 readdir_data_t *info;
826 char short_name[14], *endp;
829 cm_scache_t *child_scp;
835 name_len = strlen(entry->name);
837 info = (readdir_data_t *)context->buf_pos;
838 if (context->length - (context->buf_pos - context->buf) < sizeof(readdir_data_t) + name_len * sizeof(WCHAR) + sizeof(LARGE_INTEGER))
840 if (context->count == 0)
841 return CM_ERROR_BUFFERTOOSMALL;
842 info->cookie = *offset;
843 return CM_ERROR_STOPNOW;
846 if ((context->matchString && context->matchString[0] && (!strcmp(context->matchString, entry->name) || context->matchString[0]=='*')) ||
847 !(context->matchString && context->matchString[0]))
856 child_fid.cell = scp->fid.cell;
857 child_fid.volume = scp->fid.volume;
858 child_fid.vnode = ntohl(entry->fid.vnode);
859 child_fid.unique = ntohl(entry->fid.unique);
860 code = cm_GetSCache(&child_fid, &child_scp, userp, &req);
861 //code = cm_Lookup(scp, entry->name, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, userp, &req, &child_scp);
862 if (code || !child_scp)
864 cm_ReleaseUser(userp);
868 //if (child_scp->refCount == 1)
870 lock_ObtainMutex(&child_scp->mx);
871 code = cm_SyncOp(child_scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK); // do not need callback
872 lock_ReleaseMutex(&child_scp->mx);
875 if (code) /* perhaps blank fields we do not know, and continue. bad filents should not prevent readdirs. */
878 info->cookie = *offset;
880 lock_ObtainMutex(&(child_scp->mx));
881 code = ifs_CopyInfo(child_scp, &info->attribs, &info->size, &info->creation, &info->access, &info->change, &info->write);
882 //ifs_CheckAcl(child_scp, FILE_WRITE_DATA, &gr); /* perhaps add flag to not loop, to avoid network traffic if not found*/
883 //if (gr & FILE_READ_DATA && !(gr & FILE_WRITE_DATA))
884 // info->attribs |= FILE_ATTRIBUTE_READONLY;
885 lock_ReleaseMutex(&(child_scp->mx));
886 ifs_InternalClose(&child_scp);
889 cm_Gen8Dot3Name(entry, short_name, &endp);
891 info->short_name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, short_name, -1, info->short_name, 14))?t-1:0);
892 info->name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, entry->name, -1, info->name, 600))?t-1:0);
894 context->buf_pos = ((char*)info) + sizeof(readdir_data_t) + info->name_length;
897 info = (readdir_data_t *)context->buf_pos;
898 info->cookie.QuadPart = -1;
903 uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG *len)
908 cm_scache_t *scp, *child_scp;
909 readdir_context_t context;
910 LARGE_INTEGER cookie;
912 if (cookie_in.QuadPart == -1)
919 scp = ifs_FindScp(fid);
921 return IFSL_BAD_INPUT;
922 code = ifs_ConvertFileName(filter, -1, buffer, 2048);
930 context.matchString = buffer;
931 context.buf_pos = context.buf = data;
932 context.length = *len;
938 ((LARGE_INTEGER *)context.buf)->QuadPart = -1;
940 code = cm_ApplyDir(scp, ifs_ReaddirCallback, &context, &cookie, userp, &req, NULL);
942 context.buf_pos += sizeof(LARGE_INTEGER);
944 if (code != CM_ERROR_STOPNOW)
958 *count = context.count;
960 cm_ReleaseUser(userp);
961 *len = context.buf_pos - context.buf;
963 code = ifs_MapCmError(code);
972 scp_status_t *prev, *curr;
974 scp = ifs_FindScp(fid);
976 return IFSL_BAD_INPUT;
979 cm_FSync(scp, userp, &req);
981 SCPL_LOCK; /* perhaps this should be earlier */
983 lock_ObtainMutex(&(scp->mx));
984 cm_ReleaseSCache(scp);
986 cm_DiscardSCache(scp);
987 lock_ReleaseMutex(&(scp->mx));
989 prev = NULL, curr = scp_list_head;
993 if (curr->fid == fid)
996 prev->next = curr->next;
998 scp_list_head = curr->next;
1011 uc_unlink(WCHAR *name)
1015 cm_scache_t *scp, *dscp;
1017 unsigned char removed;
1023 code = ifs_ConvertFileName(name, -1, buffer, 2048);
1025 removed = ifs_FindComponents(buffer, &dirp, &filep);
1027 code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
1031 code = cm_Unlink(dscp, filep, userp, &req);
1033 code = cm_RemoveDir(dscp, filep, userp, &req);
1037 cm_ReleaseSCache(dscp);
1044 int uc_ioctl_write(ULONG length, char *data, ULONG *key)
1050 iop = malloc(sizeof(smb_ioctl_t));
1051 memset(iop, 0, sizeof(smb_ioctl_t));
1052 smb_IoctlPrepareWrite(NULL, iop);
1054 memcpy(iop->inDatap + iop->inCopied, data, length);
1055 iop->inCopied += length;
1061 int uc_ioctl_read(ULONG key, ULONG *length, char *data)
1071 smb_IoctlPrepareRead(NULL, iop, userp);
1072 cm_ReleaseUser(userp);
1074 *length = iop->outDatap - iop->outAllocp;
1075 memcpy(data, iop->outAllocp, *length);
1081 int ifs_Init(char **reason)
1086 kcom = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
1087 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1088 /*FILE_FLAG_OVERLAPPED*/0, NULL);
1089 if (kcom == INVALID_HANDLE_VALUE)
1091 *reason = "error creating communications file";
1092 return CM_ERROR_REMOTECONN;
1096 memset(user_map, 0, 32*sizeof(struct user_map_entry));
1097 InitializeCriticalSection(&mapLock);
1098 InitializeCriticalSection(&scp_list_lock);
1103 ifs_TransactRpc(char *outbuf, int outlen, char *inbuf, int *inlen)
1107 DWORD err, read = 0;
1110 if (!outbuf || !inbuf)
1111 return IFSL_GENERIC_FAILURE;
1113 hf = CreateFile("\\\\.\\afscom\\downcall", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1114 if (hf == INVALID_HANDLE_VALUE)
1118 if (!DeviceIoControl(hf, IOCTL_AFSRDR_DOWNCALL, outbuf, outlen, inbuf, inmax, inlen, NULL))
1121 return IFSL_GENERIC_FAILURE;
1125 return inlen ? IFSL_SUCCESS : IFSL_GENERIC_FAILURE;
1129 DWORD WINAPI ifs_MainLoop(LPVOID param)
1133 unsigned char *bufIn, *bufOut;
1134 DWORD lenIn, lenOut, status;
1140 bufIn = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
1141 bufOut = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
1142 if (!bufIn || !bufOut)
1144 if (bufIn) VirtualFree(bufIn, 0, MEM_RELEASE);
1145 if (bufOut) VirtualFree(bufOut, 0, MEM_RELEASE);
1146 printf("could not allocate transfer bufs\n");
1147 PostMessage(NULL, WM_CLOSE, 0, 0);
1152 pipe = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
1153 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1154 /*FILE_FLAG_OVERLAPPED*/0, NULL);
1155 if (pipe == INVALID_HANDLE_VALUE)
1157 VirtualFree(bufIn, 0, MEM_RELEASE);
1158 VirtualFree(bufOut, 0, MEM_RELEASE);
1159 printf("error creating communications file\n");
1160 PostMessage(NULL, WM_CLOSE, 0, 0);
1167 if (WaitForSingleObject(DoTerminate, 0) == WAIT_OBJECT_0)
1169 st = ReadFile(pipe, bufIn, TRANSFER_BUF_SIZE, &lenIn, NULL);
1171 if (GetLastError() == ERROR_INVALID_HANDLE)
1176 ZeroMemory(&rpc, sizeof(rpc));
1177 rpc.in_buf = rpc.in_pos = bufIn;
1178 rpc.out_buf = rpc.out_pos = bufOut;
1182 st = WriteFile(pipe, rpc.out_buf, rpc.out_pos - rpc.out_buf, &written, NULL);
1184 if (GetLastError() == ERROR_INVALID_HANDLE)