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);
41 #define TRANSFER_BUF_SIZE (RPC_BUF_SIZE + TRANSFER_CHUNK_SIZE)
42 #define SCPL_LOCK EnterCriticalSection(&scp_list_lock);
43 #define SCPL_UNLOCK LeaveCriticalSection(&scp_list_lock);
46 /****************************/
48 /****************************/
49 struct user_map_entry /* how we keep users straight. total of MAX_AFS_USERS of these */
51 LARGE_INTEGER id; /* internal id created by kernel */
52 cm_user_t *creds; /* global (thread-specific) var userp is set to this */
55 struct scp_status /* one for each unique file in afs */
57 struct scp_status *next; /* stored in a global chain in a chain locked by SCPL_[UN]LOCK */
58 cm_scache_t *scp; /* file handle used with cm_ fns */
59 ULONG fid; /* internal id generated by FID_HASH_FN from AFS's 128-bit FID */
61 typedef struct scp_status scp_status_t;
63 struct readdir_context /* temporary struct, allocated as necessary, for cm_Apply callback */
65 char *matchString; /* for matching against */
66 char *buf, *buf_pos; /* filling buffer to length, currently at buf_pos */
68 ULONG count; /* number of entries packed so far */
70 typedef struct readdir_context readdir_context_t;
73 /****************************/
75 /****************************/
76 /* the table user_map is used to store cm_user structs keyed on the calling
77 * process' 64-bit ID token. the rpc library sets userp to point to this
78 * entry; userp is specific to each thread, and thus may be used securely
81 __declspec(thread) cm_user_t *userp;
82 struct user_map_entry user_map[MAX_AFS_USERS];
84 CRITICAL_SECTION mapLock, scp_list_lock;
86 scp_status_t *scp_list_head = NULL;
89 /****************************/
91 /****************************/
92 char *IfslErrorToText(unsigned long ifsl)
98 case IFSL_DOES_NOT_EXIST:
99 return "does not exist";
100 case IFSL_NOT_IMPLEMENTED:
101 return "not implemented";
102 case IFSL_END_OF_ENUM:
103 return "end of enum";
104 case IFSL_CANNOT_MAKE:
105 return "cannot make";
106 case IFSL_END_OF_FILE:
107 return "end of file";
110 case IFSL_BUFFER_TOO_SMALL:
111 return "buffer too small";
112 case IFSL_SHARING_VIOLATION:
113 return "sharing violation";
116 case IFSL_GENERIC_FAILURE:
117 return "generic failure";
118 case IFSL_OPEN_CREATED:
119 return "open created";
120 case IFSL_OPEN_EXISTS:
121 return "open exists";
122 case IFSL_OPEN_OPENED:
124 case IFSL_OPEN_OVERWRITTEN:
125 return "overwritten";
126 case IFSL_OPEN_SUPERSCEDED:
127 return "supersceded";
128 case IFSL_BADFILENAME:
129 return "bad filename";
134 case IFSL_PATH_DOES_NOT_EXIST:
135 return "path does not exist";
139 return "dir not empty";
141 return "unspecified error";
147 unsigned long ifs_MapCmError(unsigned long code)
151 case CM_ERROR_STOPNOW:
154 case CM_ERROR_NOSUCHCELL:
155 case CM_ERROR_NOSUCHVOLUME:
156 case CM_ERROR_NOSUCHFILE:
157 return IFSL_DOES_NOT_EXIST;
158 case CM_ERROR_NOSUCHPATH:
159 return IFSL_PATH_DOES_NOT_EXIST;
160 case CM_ERROR_BADNTFILENAME:
161 return IFSL_BADFILENAME;
162 case CM_ERROR_TIMEDOUT:
163 case CM_ERROR_ALLOFFLINE:
164 case CM_ERROR_CLOCKSKEW:
165 case CM_ERROR_REMOTECONN:
166 case CM_ERROR_ALLBUSY:
167 return IFSL_GENERIC_FAILURE;
168 case CM_ERROR_NOACCESS:
169 return IFSL_NO_ACCESS;
171 case CM_ERROR_TOOBIG:
173 case CM_ERROR_BADFDOP:
174 case CM_ERROR_CROSSDEVLINK:
175 return IFSL_GENERIC_FAILURE;
176 case CM_ERROR_EXISTS:
177 return IFSL_OPEN_EXISTS;
180 case CM_ERROR_UNKNOWN:
181 case CM_ERROR_BADSMB:
182 return IFSL_GENERIC_FAILURE;
183 case CM_ERROR_NOTDIR:
185 case CM_ERROR_READONLY:
186 return IFSL_BAD_INPUT;
187 case CM_ERROR_BUFFERTOOSMALL:
188 return IFSL_BUFFER_TOO_SMALL;
189 case CM_ERROR_WOULDBLOCK:
190 case CM_ERROR_BADSHARENAME:
191 case CM_ERROR_NOMORETOKENS:
192 case CM_ERROR_NOTEMPTY:
193 case CM_ERROR_USESTD:
195 return IFSL_GENERIC_FAILURE;
196 case CM_ERROR_NOFILES:
197 case CM_ERROR_BADTID:
198 return IFSL_END_OF_ENUM;
199 case CM_ERROR_PARTIALWRITE:
201 case CM_ERROR_RENAME_IDENTICAL:
202 case CM_ERROR_AMBIGUOUS_FILENAME:
203 return IFSL_GENERIC_FAILURE;
204 case IFSL_SHARING_VIOLATION:
205 return IFSL_SHARING_VIOLATION;
207 return IFSL_NOT_EMPTY;
210 return IFSL_OVERQUOTA;
212 return IFSL_GENERIC_FAILURE;
216 /****************************/
218 /****************************/
219 cm_scache_t *ifs_FindScp(ULONG fid) /* walk list to find scp<->fid mapping */
225 curr = scp_list_head;
228 if (curr->fid == fid)
239 /* must call with scp write-locked. will always return correct results
240 unless network fails (it loops properly). */
241 ifs_CheckAcl(cm_scache_t *scp, ULONG access, ULONG *granted)
248 /* ripped from cm_scache.c */
251 if (cm_HaveAccessRights(scp, userp, access, granted))
257 /* we don't know the required access rights */
258 code = cm_GetAccessRights(scp, userp, &req);
267 /* extract data from scp. an ifs_ support function to centralize changes. */
268 ifs_CopyInfo(cm_scache_t *scp, ULONG *attribs, LARGE_INTEGER *size,
269 LARGE_INTEGER *creation, LARGE_INTEGER *access,
270 LARGE_INTEGER *change, LARGE_INTEGER *written)
272 access->QuadPart = 0; /* these mappings are not quite correct. we can */
273 change->QuadPart = scp->clientModTime; /* leave them zero, if necessary. */
274 written->QuadPart = scp->clientModTime;
275 creation->QuadPart = scp->serverModTime;
278 if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
279 scp->fileType == CM_SCACHETYPE_SYMLINK ||
280 scp->fileType == CM_SCACHETYPE_MOUNTPOINT/* ||
281 scp->fileType == 0*/)
282 *attribs |= FILE_ATTRIBUTE_DIRECTORY;
284 /*if (!attribs && scp->fileType == CM_SCACHETYPE_FILE)
285 *attribs |= FILE_ATTRIBUTE_NORMAL;*/
287 if (*attribs == FILE_ATTRIBUTE_DIRECTORY)
296 /* close and zero scp pointer. zeroing pointer should
297 help eliminate accessing discarded cache entries. */
298 void ifs_InternalClose(cm_scache_t **scpp)
300 osi_assert(scpp && *scpp);
301 cm_ReleaseSCache(*scpp);
305 /* normalizes path by removing trailing slashes. separates last
306 * path component with a null, so that *dirp points to parent path
307 * and *filep points to filename. modifies string path.
309 BOOLEAN ifs_FindComponents(char *path, const char **dirp, const char **filep)
313 static char emptyPath[] = "\\"; /* if the path contains only one component, this is the parent. */
318 removed = (path[strlen(path)-1] == '\\');
322 lastSep = strrchr(path, '\\');
323 while (lastSep == path + strlen(path) - 1)
326 lastSep = strrchr(path, '\\');
334 *filep = lastSep + 1;
338 lastSep = path + strlen(path);
347 /* here to make maintenance easy */
348 unsigned long ifs_ConvertFileName(wchar_t *in, unsigned int inchars, char *out, unsigned int outchars)
352 code = WideCharToMultiByte(CP_UTF8, 0/*WC_NO_BEST_FIT_CHARS*/, in, inchars, out, outchars-1, NULL, NULL);
354 return IFSL_BADFILENAME;
359 /* called by rpc_ library to let us initialize environment.
360 * call with id of zero to clear current thread auth. */
361 ifs_ImpersonateClient(LARGE_INTEGER user_id)
365 if (!user_id.QuadPart)
372 EnterCriticalSection(&mapLock);
373 for (x = 0; x < MAX_AFS_USERS; x++)
375 if (user_map[x].id.QuadPart == 0)
377 if (user_map[x].id.QuadPart == user_id.QuadPart)
382 LeaveCriticalSection(&mapLock);
385 user_map[empty].id = user_id;
386 user_map[empty].creds = cm_NewUser();
390 userp = user_map[x].creds;
391 LeaveCriticalSection(&mapLock);
397 /****************************/
399 /****************************/
400 long uc_namei(WCHAR *name, ULONG *fid) /* performs name<->fid mapping, and enters it into table */
402 char *buffer; /* we support semi-infinite path lengths */
404 cm_scache_t *scp, *dscp;
412 len = (short)wcslen(name)+20; /* characters *should* map 1<->1, but in case */
413 buffer = malloc(len);
414 code = ifs_ConvertFileName(name, -1, buffer, len);
420 ifs_FindComponents(buffer, &dirp, &filep);
422 code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
429 code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
431 cm_HoldSCache(scp = dscp);
432 cm_ReleaseSCache(dscp);
440 if (ifs_FindScp(FID_HASH_FN(&scp->fid)))
442 osi_assertx(ifs_FindScp(FID_HASH_FN(&scp->fid)) == scp, "uc_namei: same fid hash for two files");
443 *fid = FID_HASH_FN(&scp->fid);
444 osi_assert(scp->refCount > 1);
445 cm_ReleaseSCache(scp);
450 st = malloc(sizeof(scp_status_t));
452 st->fid = FID_HASH_FN(&scp->fid);
453 st->next = scp_list_head;
456 osi_assert(scp->refCount == 1);
465 /* this should only be called right after open, so we do not need to stat file.
466 * we only check the server's restrictions. sharing violations are handled in the
467 * kernel. the access mode we grant sticks with the file_object until its death. */
468 long uc_check_access(ULONG fid, ULONG access, ULONG *granted)
470 ULONG afs_acc, afs_gr;
477 scp = ifs_FindScp(fid);
479 return IFSL_BAD_INPUT;
481 file = (scp->fileType == CM_SCACHETYPE_FILE);
484 /* access definitions from prs_fs.h */
486 if (access & FILE_READ_DATA)
487 afs_acc |= PRSFS_READ;
488 if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
489 afs_acc |= PRSFS_WRITE;
490 if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
491 afs_acc |= PRSFS_WRITE;
492 if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
493 afs_acc |= PRSFS_INSERT;
494 if (dir && (access & FILE_LIST_DIRECTORY))
495 afs_acc |= PRSFS_LOOKUP;
496 if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
497 afs_acc |= PRSFS_LOOKUP;
498 if (file && (access & FILE_EXECUTE))
499 afs_acc |= PRSFS_WRITE;
500 if (dir && (access & FILE_TRAVERSE))
501 afs_acc |= PRSFS_READ;
502 if (dir && (access & FILE_DELETE_CHILD))
503 afs_acc |= PRSFS_DELETE;
504 if ((access & DELETE))
505 afs_acc |= PRSFS_DELETE;
507 /* check ACL with server */
508 lock_ObtainWrite(&scp->rw);
509 ifs_CheckAcl(scp, afs_acc, &afs_gr);
510 lock_ReleaseWrite(&scp->rw);
513 if (afs_gr & PRSFS_READ)
514 *granted |= FILE_READ_DATA | FILE_EXECUTE;
515 if (afs_gr & PRSFS_WRITE)
516 *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE;
517 if (afs_gr & PRSFS_INSERT)
518 *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
519 if (afs_gr & PRSFS_LOOKUP)
520 *granted |= (dir ? FILE_LIST_DIRECTORY : 0) | FILE_READ_EA | FILE_READ_ATTRIBUTES;
521 if (afs_gr & PRSFS_DELETE)
522 *granted |= FILE_DELETE_CHILD | DELETE;
523 if (afs_gr & PRSFS_LOCK)
525 if (afs_gr & PRSFS_ADMINISTER)
528 * granted |= SYNCHRONIZE | READ_CONTROL;
533 long uc_create(WCHAR *name, ULONG attribs, LARGE_INTEGER alloc, ULONG access, ULONG *granted, ULONG *fid)
535 char *buffer; /* we support semi-infinite path lengths */
537 cm_scache_t *scp, *dscp;
539 unsigned char removed;
547 len = (short)wcslen(name)+20; /* characters *should* map 1<->1, but in case */
548 buffer = malloc(len);
549 code = ifs_ConvertFileName(name, -1, buffer, len);
555 removed = ifs_FindComponents(buffer, &dirp, &filep);
557 /* lookup the parent directory, which must exist */
558 code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
568 attr.mask = CM_ATTRMASK_LENGTH;
571 if (attribs & FILE_ATTRIBUTE_DIRECTORY)
573 code = cm_MakeDir(dscp, filep, 0, &attr, userp, &req);
575 code = cm_Lookup(dscp, filep, 0, userp, &req, &scp);
578 code = cm_Create(dscp, filep, 0, &attr, &scp, userp, &req);
580 cm_ReleaseSCache(dscp);
589 st = malloc(sizeof(scp_status_t));
591 st->fid = FID_HASH_FN(&scp->fid);
592 st->next = scp_list_head;
604 /* this does not fill the attribs member completely. additional flags must
605 be added in the kernel, such as read-only. */
606 long uc_stat(ULONG fid, ULONG *attribs, LARGE_INTEGER *size, LARGE_INTEGER *creation,
607 LARGE_INTEGER *access, LARGE_INTEGER *change, LARGE_INTEGER *written)
613 scp = ifs_FindScp(fid);
615 return IFSL_BAD_INPUT;
617 /* stat file; don't want callback */
619 lock_ObtainWrite(&(scp->rw));
621 code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
622 cm_ReleaseUser(userp);
625 lock_ReleaseWrite(&(scp->rw));
628 code = ifs_CopyInfo(scp, attribs, size, creation, access, change, written);
629 lock_ReleaseWrite(&(scp->rw));
635 /* set atime, mtime, etc. */
636 long uc_setinfo(ULONG fid, ULONG attribs, LARGE_INTEGER creation, LARGE_INTEGER access,
637 LARGE_INTEGER change, LARGE_INTEGER written)
639 return IFSL_GENERIC_FAILURE;
642 /* FIXFIX: this code may not catch over-quota errors, because the end
643 * of the file is not written to the server by the time this returns. */
644 /* truncate or extend file, in cache and on server */
645 long uc_trunc(ULONG fid, LARGE_INTEGER size)
652 scp = ifs_FindScp(fid);
654 return IFSL_BAD_INPUT;
656 /* we have already checked permissions in the kernel; but, if we do not
657 * have access as this userp, code will fail in rpc layer.
661 lock_ObtainWrite(&(scp->rw));
663 code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS);
666 lock_ReleaseWrite(&(scp->rw));
669 oldLen = scp->length;
670 lock_ReleaseWrite(&(scp->rw));
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 bring out quota errors 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);
694 /* read data from a file */
695 long uc_read(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *read, char *data)
702 scp = ifs_FindScp(fid);
704 return IFSL_BAD_INPUT;
706 if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
707 return IFSL_IS_A_DIR;
709 code = ReadData(scp, offset, (unsigned long)length, data, userp, read);
715 /* FIXFIX: this does not catch all overquota errors, because the file
716 * is not necessarily written to the server when this returns. */
717 /* write data to a file */
718 long uc_write(ULONG fid, LARGE_INTEGER offset, ULONG length, ULONG *written, char *data)
723 scp = ifs_FindScp(fid);
725 return IFSL_BAD_INPUT;
727 if (offset.QuadPart == -1)
728 offset = scp->length;
729 code = WriteData(scp, offset, (unsigned long)length, data, userp, written);
735 long uc_rename(ULONG fid, WCHAR *curr, WCHAR *new_dir, WCHAR *new_name, ULONG *new_fid)
739 char *curdir, *curfile, *newdir, *newfile;
740 cm_scache_t *dscp1, *dscp2, *scp;
741 char b1[MAX_PATH], b2[MAX_PATH], b3[MAX_PATH];
742 wchar_t b3_w[MAX_PATH];
744 code = !(scp = ifs_FindScp(fid));
746 code = ifs_ConvertFileName(curr, -1, b1, MAX_PATH);
748 code = ifs_ConvertFileName(new_name, -1, b2, MAX_PATH);
750 code = ifs_ConvertFileName(new_dir, -1, b3, MAX_PATH);
753 ifs_FindComponents(b1, &curdir, &curfile);
754 ifs_FindComponents(b2, &newdir, &newfile);
757 code = cm_NameI(cm_data.rootSCachep, curdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp1);
761 if (!strcmp(curdir, newdir))
767 code = cm_NameI(cm_data.rootSCachep, newdir, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp2);
770 code = cm_Rename(dscp1, curfile, dscp2, newfile, userp, &req);
775 mbstowcs(b3_w, b3, MAX_PATH);
776 uc_namei(b3_w, new_fid);
780 code = uc_namei(curr, new_fid);
782 ifs_InternalClose(&dscp2);
786 code = uc_namei(curr, new_fid);
788 ifs_InternalClose(&dscp1);
801 scp = ifs_FindScp(fid);
803 return IFSL_BAD_INPUT;
806 code = cm_FSync(scp, userp, &req);
812 ifs_ReaddirCallback(cm_scache_t *scp, cm_dirEntry_t *entry, void *param, osi_hyper_t *offset)
814 readdir_context_t *context;
816 readdir_data_t *info;
817 char short_name[14], *endp;
820 cm_scache_t *child_scp;
826 name_len = (ULONG) strlen(entry->name);
828 info = (readdir_data_t *)context->buf_pos;
829 if (context->length - (context->buf_pos - context->buf) < sizeof(readdir_data_t) + name_len * sizeof(WCHAR) + sizeof(LARGE_INTEGER))
831 if (context->count == 0)
832 return CM_ERROR_BUFFERTOOSMALL;
833 info->cookie = *offset;
834 return CM_ERROR_STOPNOW;
837 if ((context->matchString && context->matchString[0] && (!strcmp(context->matchString, entry->name) || context->matchString[0]=='*')) ||
838 !(context->matchString && context->matchString[0]))
847 child_fid.cell = scp->fid.cell;
848 child_fid.volume = scp->fid.volume;
849 child_fid.vnode = ntohl(entry->fid.vnode);
850 child_fid.unique = ntohl(entry->fid.unique);
851 code = cm_GetSCache(&child_fid, &child_scp, userp, &req);
852 if (code || !child_scp)
854 cm_ReleaseUser(userp);
859 lock_ObtainWrite(&child_scp->rw);
860 code = cm_SyncOp(child_scp, NULL, userp, &req, 0, CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
861 lock_ReleaseWrite(&child_scp->rw);
864 if (code) /* perhaps blank fields we do not know, and continue. bad filents should not prevent readdirs. */
867 info->cookie = *offset;
869 lock_ObtainWrite(&(child_scp->rw));
870 code = ifs_CopyInfo(child_scp, &info->attribs, &info->size, &info->creation, &info->access, &info->change, &info->write);
872 /* make files we do not have write access to read-only */
873 /* this is a handy feature, but it takes a lot of time and traffic to enumerate */
874 ifs_CheckAcl(child_scp, FILE_WRITE_DATA, &gr); /* perhaps add flag to not loop, to avoid network traffic if not found*/
875 if (gr & FILE_READ_DATA && !(gr & FILE_WRITE_DATA))
876 info->attribs |= FILE_ATTRIBUTE_READONLY;
878 lock_ReleaseWrite(&(child_scp->rw));
879 ifs_InternalClose(&child_scp);
882 cm_Gen8Dot3Name(entry, short_name, &endp);
884 info->short_name_length = (CCHAR)sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, short_name, -1, info->short_name, 14))?t-1:0);
885 info->name_length = sizeof(WCHAR)*((t=MultiByteToWideChar(CP_UTF8, 0, entry->name, -1, info->name, 600))?t-1:0);
887 context->buf_pos = ((char*)info) + sizeof(readdir_data_t) + info->name_length;
890 info = (readdir_data_t *)context->buf_pos;
891 info->cookie.QuadPart = -1;
896 long uc_readdir(ULONG fid, LARGE_INTEGER cookie_in, WCHAR *filter, ULONG *count, char *data, ULONG_PTR *len)
902 readdir_context_t context;
903 LARGE_INTEGER cookie;
905 if (cookie_in.QuadPart == -1)
912 scp = ifs_FindScp(fid);
914 return IFSL_BAD_INPUT;
915 code = ifs_ConvertFileName(filter, -1, buffer, 2048);
923 context.matchString = buffer;
924 context.buf_pos = context.buf = data;
925 context.length = *len;
929 ((LARGE_INTEGER *)context.buf)->QuadPart = -1;
931 code = cm_ApplyDir(scp, ifs_ReaddirCallback, &context, &cookie, userp, &req, NULL);
933 context.buf_pos += sizeof(LARGE_INTEGER);
935 *count = context.count;
937 cm_ReleaseUser(userp);
938 *len = context.buf_pos - context.buf;
940 code = ifs_MapCmError(code);
944 long uc_close(ULONG fid)
948 scp_status_t *prev, *curr;
950 scp = ifs_FindScp(fid);
952 return IFSL_BAD_INPUT;
955 cm_FSync(scp, userp, &req);
957 SCPL_LOCK; /* perhaps this should be earlier */
959 cm_ReleaseSCache(scp);
961 prev = NULL, curr = scp_list_head;
965 if (curr->fid == fid)
968 prev->next = curr->next;
970 scp_list_head = curr->next;
983 long uc_unlink(WCHAR *name)
989 unsigned char removed;
994 code = ifs_ConvertFileName(name, -1, buffer, 2048);
996 removed = ifs_FindComponents(buffer, &dirp, &filep);
999 return IFSL_BADFILENAME;
1001 code = cm_NameI(cm_data.rootSCachep, dirp, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH, userp, ROOTPATH, &req, &dscp);
1004 code = cm_Unlink(dscp, filep, userp, &req);
1006 code = cm_RemoveDir(dscp, filep, userp, &req);
1008 cm_ReleaseSCache(dscp);
1015 long uc_ioctl_write(ULONG length, char *data, ULONG_PTR *key)
1019 iop = malloc(sizeof(smb_ioctl_t));
1020 memset(iop, 0, sizeof(smb_ioctl_t));
1021 smb_IoctlPrepareWrite(NULL, iop);
1023 memcpy(iop->inDatap + iop->inCopied, data, length);
1024 iop->inCopied += length;
1025 *key = (ULONG_PTR)iop;
1030 long uc_ioctl_read(ULONG_PTR key, ULONG *length, char *data)
1034 iop = (smb_ioctl_t *)key;
1038 smb_IoctlPrepareRead(NULL, iop, userp);
1039 cm_ReleaseUser(userp);
1041 *length = iop->outDatap - iop->outAllocp;
1042 memcpy(data, iop->outAllocp, *length);
1048 int ifs_Init(char **reason)
1052 kcom = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
1053 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1055 if (kcom == INVALID_HANDLE_VALUE)
1057 *reason = "error creating communications file";
1058 return CM_ERROR_REMOTECONN;
1062 memset(user_map, 0, MAX_AFS_USERS*sizeof(struct user_map_entry));
1063 InitializeCriticalSection(&mapLock);
1064 InitializeCriticalSection(&scp_list_lock);
1069 ifs_TransactRpc(char *outbuf, int outlen, char *inbuf, int *inlen)
1075 if (!outbuf || !inbuf)
1076 return IFSL_GENERIC_FAILURE;
1078 hf = CreateFile("\\\\.\\afscom\\downcall", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1079 if (hf == INVALID_HANDLE_VALUE)
1083 if (!DeviceIoControl(hf, IOCTL_AFSRDR_DOWNCALL, outbuf, outlen, inbuf, inmax, inlen, NULL))
1086 return IFSL_GENERIC_FAILURE;
1090 return inlen ? IFSL_SUCCESS : IFSL_GENERIC_FAILURE;
1094 DWORD WINAPI ifs_MainLoop(LPVOID param)
1098 unsigned char *bufIn, *bufOut;
1103 bufIn = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
1104 bufOut = VirtualAlloc(NULL, TRANSFER_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE);
1105 if (!bufIn || !bufOut)
1107 if (bufIn) VirtualFree(bufIn, 0, MEM_RELEASE);
1108 if (bufOut) VirtualFree(bufOut, 0, MEM_RELEASE);
1109 osi_panic("ifs: allocate transfer buffers", __FILE__, __LINE__);
1112 pipe = CreateFile("\\\\.\\afscom\\upcallhook", GENERIC_READ | GENERIC_WRITE,
1113 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1115 if (pipe == INVALID_HANDLE_VALUE)
1117 VirtualFree(bufIn, 0, MEM_RELEASE);
1118 VirtualFree(bufOut, 0, MEM_RELEASE);
1119 osi_panic("ifs: creating communications handle", __FILE__, __LINE__);
1124 /* just check if the event is already signalled, do not wait */
1125 if (WaitForSingleObject(WaitToTerminate, 0) == WAIT_OBJECT_0)
1128 /* read request... */
1129 st = ReadFile(pipe, bufIn, TRANSFER_BUF_SIZE, &lenIn, NULL);
1131 if (GetLastError() == ERROR_INVALID_HANDLE)
1137 ZeroMemory(&rpc, sizeof(rpc));
1138 rpc.in_buf = rpc.in_pos = bufIn;
1139 rpc.out_buf = rpc.out_pos = bufOut;
1141 /* ...process it... */
1144 /* ...and write it back */
1145 st = WriteFile(pipe, rpc.out_buf, rpc.out_pos - rpc.out_buf, &written, NULL);
1147 if (GetLastError() == ERROR_INVALID_HANDLE)