8ade0c4059c1826553cef3482982ea82a7d75f12
[openafs.git] / src / WINNT / afsd / cm_utils.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <afs/stds.h>
15
16 #include <errno.h>
17 #include <windows.h>
18 #include <shlwapi.h>
19 #include <winsock2.h>
20 #include <string.h>
21 #include <malloc.h>
22 #define STRSAFE_NO_DEPRECATE
23 #include <strsafe.h>
24
25 #include "afsd.h"
26 #include <osi.h>
27 #include <rx/rx.h>
28
29 #include <afs/unified_afs.h>
30
31 static osi_once_t cm_utilsOnce;
32
33 osi_rwlock_t cm_utilsLock;
34
35 cm_space_t *cm_spaceListp;
36
37 static int et2sys[512];
38
39 static DWORD cm_TlsRequestSlot = -1;
40
41 void cm_utilsInit(void)
42 {
43     if (osi_Once(&cm_utilsOnce)) {
44         lock_InitializeRWLock(&cm_utilsLock, "cm_utilsLock", LOCK_HIERARCHY_UTILS_GLOBAL);
45
46         cm_TlsRequestSlot = TlsAlloc();
47
48         osi_EndOnce(&cm_utilsOnce);
49     }
50 }
51
52 void cm_utilsCleanup(void)
53 {
54     TlsFree(cm_TlsRequestSlot);
55 }
56
57 void
58 init_et_to_sys_error(void)
59 {
60     memset(&et2sys, 0, sizeof(et2sys));
61     et2sys[(UAEPERM - ERROR_TABLE_BASE_uae)] = EPERM;
62     et2sys[(UAENOENT - ERROR_TABLE_BASE_uae)] = ENOENT;
63     et2sys[(UAESRCH - ERROR_TABLE_BASE_uae)] = ESRCH;
64     et2sys[(UAEINTR - ERROR_TABLE_BASE_uae)] = EINTR;
65     et2sys[(UAEIO - ERROR_TABLE_BASE_uae)] = EIO;
66     et2sys[(UAENXIO - ERROR_TABLE_BASE_uae)] = ENXIO;
67     et2sys[(UAE2BIG - ERROR_TABLE_BASE_uae)] = E2BIG;
68     et2sys[(UAENOEXEC - ERROR_TABLE_BASE_uae)] = ENOEXEC;
69     et2sys[(UAEBADF - ERROR_TABLE_BASE_uae)] = EBADF;
70     et2sys[(UAECHILD - ERROR_TABLE_BASE_uae)] = ECHILD;
71     et2sys[(UAEAGAIN - ERROR_TABLE_BASE_uae)] = EAGAIN;
72     et2sys[(UAENOMEM - ERROR_TABLE_BASE_uae)] = ENOMEM;
73     et2sys[(UAEACCES - ERROR_TABLE_BASE_uae)] = EACCES;
74     et2sys[(UAEFAULT - ERROR_TABLE_BASE_uae)] = EFAULT;
75     et2sys[(UAENOTBLK - ERROR_TABLE_BASE_uae)] = ENOTBLK;
76     et2sys[(UAEBUSY - ERROR_TABLE_BASE_uae)] = EBUSY;
77     et2sys[(UAEEXIST - ERROR_TABLE_BASE_uae)] = EEXIST;
78     et2sys[(UAEXDEV - ERROR_TABLE_BASE_uae)] = EXDEV;
79     et2sys[(UAENODEV - ERROR_TABLE_BASE_uae)] = ENODEV;
80     et2sys[(UAENOTDIR - ERROR_TABLE_BASE_uae)] = ENOTDIR;
81     et2sys[(UAEISDIR - ERROR_TABLE_BASE_uae)] = EISDIR;
82     et2sys[(UAEINVAL - ERROR_TABLE_BASE_uae)] = EINVAL;
83     et2sys[(UAENFILE - ERROR_TABLE_BASE_uae)] = ENFILE;
84     et2sys[(UAEMFILE - ERROR_TABLE_BASE_uae)] = EMFILE;
85     et2sys[(UAENOTTY - ERROR_TABLE_BASE_uae)] = ENOTTY;
86     et2sys[(UAETXTBSY - ERROR_TABLE_BASE_uae)] = ETXTBSY;
87     et2sys[(UAEFBIG - ERROR_TABLE_BASE_uae)] = EFBIG;
88     et2sys[(UAENOSPC - ERROR_TABLE_BASE_uae)] = ENOSPC;
89     et2sys[(UAESPIPE - ERROR_TABLE_BASE_uae)] = ESPIPE;
90     et2sys[(UAEROFS - ERROR_TABLE_BASE_uae)] = EROFS;
91     et2sys[(UAEMLINK - ERROR_TABLE_BASE_uae)] = EMLINK;
92     et2sys[(UAEPIPE - ERROR_TABLE_BASE_uae)] = EPIPE;
93     et2sys[(UAEDOM - ERROR_TABLE_BASE_uae)] = EDOM;
94     et2sys[(UAERANGE - ERROR_TABLE_BASE_uae)] = ERANGE;
95     et2sys[(UAEDEADLK - ERROR_TABLE_BASE_uae)] = EDEADLK;
96     et2sys[(UAENAMETOOLONG - ERROR_TABLE_BASE_uae)] = ENAMETOOLONG;
97     et2sys[(UAENOLCK - ERROR_TABLE_BASE_uae)] = ENOLCK;
98     et2sys[(UAENOSYS - ERROR_TABLE_BASE_uae)] = ENOSYS;
99     et2sys[(UAENOTEMPTY - ERROR_TABLE_BASE_uae)] = ENOTEMPTY;
100     et2sys[(UAELOOP - ERROR_TABLE_BASE_uae)] = ELOOP;
101     et2sys[(UAEWOULDBLOCK - ERROR_TABLE_BASE_uae)] = EWOULDBLOCK;
102     et2sys[(UAENOMSG - ERROR_TABLE_BASE_uae)] = ENOMSG;
103     et2sys[(UAEIDRM - ERROR_TABLE_BASE_uae)] = EIDRM;
104     et2sys[(UAECHRNG - ERROR_TABLE_BASE_uae)] = ECHRNG;
105     et2sys[(UAEL2NSYNC - ERROR_TABLE_BASE_uae)] = EL2NSYNC;
106     et2sys[(UAEL3HLT - ERROR_TABLE_BASE_uae)] = EL3HLT;
107     et2sys[(UAEL3RST - ERROR_TABLE_BASE_uae)] = EL3RST;
108     et2sys[(UAELNRNG - ERROR_TABLE_BASE_uae)] = ELNRNG;
109     et2sys[(UAEUNATCH - ERROR_TABLE_BASE_uae)] = EUNATCH;
110     et2sys[(UAENOCSI - ERROR_TABLE_BASE_uae)] = ENOCSI;
111     et2sys[(UAEL2HLT - ERROR_TABLE_BASE_uae)] = EL2HLT;
112     et2sys[(UAEBADE - ERROR_TABLE_BASE_uae)] = EBADE;
113     et2sys[(UAEBADR - ERROR_TABLE_BASE_uae)] = EBADR;
114     et2sys[(UAEXFULL - ERROR_TABLE_BASE_uae)] = EXFULL;
115     et2sys[(UAENOANO - ERROR_TABLE_BASE_uae)] = ENOANO;
116     et2sys[(UAEBADRQC - ERROR_TABLE_BASE_uae)] = EBADRQC;
117     et2sys[(UAEBADSLT - ERROR_TABLE_BASE_uae)] = EBADSLT;
118     et2sys[(UAEBFONT - ERROR_TABLE_BASE_uae)] = EBFONT;
119     et2sys[(UAENOSTR - ERROR_TABLE_BASE_uae)] = ENOSTR;
120     et2sys[(UAENODATA - ERROR_TABLE_BASE_uae)] = ENODATA;
121     et2sys[(UAETIME - ERROR_TABLE_BASE_uae)] = ETIME;
122     et2sys[(UAENOSR - ERROR_TABLE_BASE_uae)] = ENOSR;
123     et2sys[(UAENONET - ERROR_TABLE_BASE_uae)] = ENONET;
124     et2sys[(UAENOPKG - ERROR_TABLE_BASE_uae)] = ENOPKG;
125     et2sys[(UAEREMOTE - ERROR_TABLE_BASE_uae)] = EREMOTE;
126     et2sys[(UAENOLINK - ERROR_TABLE_BASE_uae)] = ENOLINK;
127     et2sys[(UAEADV - ERROR_TABLE_BASE_uae)] = EADV;
128     et2sys[(UAESRMNT - ERROR_TABLE_BASE_uae)] = ESRMNT;
129     et2sys[(UAECOMM - ERROR_TABLE_BASE_uae)] = ECOMM;
130     et2sys[(UAEPROTO - ERROR_TABLE_BASE_uae)] = EPROTO;
131     et2sys[(UAEMULTIHOP - ERROR_TABLE_BASE_uae)] = EMULTIHOP;
132     et2sys[(UAEDOTDOT - ERROR_TABLE_BASE_uae)] = EDOTDOT;
133     et2sys[(UAEBADMSG - ERROR_TABLE_BASE_uae)] = EBADMSG;
134     et2sys[(UAEOVERFLOW - ERROR_TABLE_BASE_uae)] = EOVERFLOW;
135     et2sys[(UAENOTUNIQ - ERROR_TABLE_BASE_uae)] = ENOTUNIQ;
136     et2sys[(UAEBADFD - ERROR_TABLE_BASE_uae)] = EBADFD;
137     et2sys[(UAEREMCHG - ERROR_TABLE_BASE_uae)] = EREMCHG;
138     et2sys[(UAELIBACC - ERROR_TABLE_BASE_uae)] = ELIBACC;
139     et2sys[(UAELIBBAD - ERROR_TABLE_BASE_uae)] = ELIBBAD;
140     et2sys[(UAELIBSCN - ERROR_TABLE_BASE_uae)] = ELIBSCN;
141     et2sys[(UAELIBMAX - ERROR_TABLE_BASE_uae)] = ELIBMAX;
142     et2sys[(UAELIBEXEC - ERROR_TABLE_BASE_uae)] = ELIBEXEC;
143     et2sys[(UAEILSEQ - ERROR_TABLE_BASE_uae)] = EILSEQ;
144     et2sys[(UAERESTART - ERROR_TABLE_BASE_uae)] = ERESTART;
145     et2sys[(UAESTRPIPE - ERROR_TABLE_BASE_uae)] = ESTRPIPE;
146     et2sys[(UAEUSERS - ERROR_TABLE_BASE_uae)] = EUSERS;
147     et2sys[(UAENOTSOCK - ERROR_TABLE_BASE_uae)] = ENOTSOCK;
148     et2sys[(UAEDESTADDRREQ - ERROR_TABLE_BASE_uae)] = EDESTADDRREQ;
149     et2sys[(UAEMSGSIZE - ERROR_TABLE_BASE_uae)] = EMSGSIZE;
150     et2sys[(UAEPROTOTYPE - ERROR_TABLE_BASE_uae)] = EPROTOTYPE;
151     et2sys[(UAENOPROTOOPT - ERROR_TABLE_BASE_uae)] = ENOPROTOOPT;
152     et2sys[(UAEPROTONOSUPPORT - ERROR_TABLE_BASE_uae)] = EPROTONOSUPPORT;
153     et2sys[(UAESOCKTNOSUPPORT - ERROR_TABLE_BASE_uae)] = ESOCKTNOSUPPORT;
154     et2sys[(UAEOPNOTSUPP - ERROR_TABLE_BASE_uae)] = EOPNOTSUPP;
155     et2sys[(UAEPFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EPFNOSUPPORT;
156     et2sys[(UAEAFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EAFNOSUPPORT;
157     et2sys[(UAEADDRINUSE - ERROR_TABLE_BASE_uae)] = EADDRINUSE;
158     et2sys[(UAEADDRNOTAVAIL - ERROR_TABLE_BASE_uae)] = EADDRNOTAVAIL;
159     et2sys[(UAENETDOWN - ERROR_TABLE_BASE_uae)] = ENETDOWN;
160     et2sys[(UAENETUNREACH - ERROR_TABLE_BASE_uae)] = ENETUNREACH;
161     et2sys[(UAENETRESET - ERROR_TABLE_BASE_uae)] = ENETRESET;
162     et2sys[(UAECONNABORTED - ERROR_TABLE_BASE_uae)] = ECONNABORTED;
163     et2sys[(UAECONNRESET - ERROR_TABLE_BASE_uae)] = ECONNRESET;
164     et2sys[(UAENOBUFS - ERROR_TABLE_BASE_uae)] = ENOBUFS;
165     et2sys[(UAEISCONN - ERROR_TABLE_BASE_uae)] = EISCONN;
166     et2sys[(UAENOTCONN - ERROR_TABLE_BASE_uae)] = ENOTCONN;
167     et2sys[(UAESHUTDOWN - ERROR_TABLE_BASE_uae)] = ESHUTDOWN;
168     et2sys[(UAETOOMANYREFS - ERROR_TABLE_BASE_uae)] = ETOOMANYREFS;
169     et2sys[(UAETIMEDOUT - ERROR_TABLE_BASE_uae)] = ETIMEDOUT;
170     et2sys[(UAECONNREFUSED - ERROR_TABLE_BASE_uae)] = ECONNREFUSED;
171     et2sys[(UAEHOSTDOWN - ERROR_TABLE_BASE_uae)] = EHOSTDOWN;
172     et2sys[(UAEHOSTUNREACH - ERROR_TABLE_BASE_uae)] = EHOSTUNREACH;
173     et2sys[(UAEALREADY - ERROR_TABLE_BASE_uae)] = EALREADY;
174     et2sys[(UAEINPROGRESS - ERROR_TABLE_BASE_uae)] = EINPROGRESS;
175     et2sys[(UAESTALE - ERROR_TABLE_BASE_uae)] = ESTALE;
176     et2sys[(UAEUCLEAN - ERROR_TABLE_BASE_uae)] = EUCLEAN;
177     et2sys[(UAENOTNAM - ERROR_TABLE_BASE_uae)] = ENOTNAM;
178     et2sys[(UAENAVAIL - ERROR_TABLE_BASE_uae)] = ENAVAIL;
179     et2sys[(UAEISNAM - ERROR_TABLE_BASE_uae)] = EISNAM;
180     et2sys[(UAEREMOTEIO - ERROR_TABLE_BASE_uae)] = EREMOTEIO;
181     et2sys[(UAEDQUOT - ERROR_TABLE_BASE_uae)] = EDQUOT;
182     et2sys[(UAENOMEDIUM - ERROR_TABLE_BASE_uae)] = ENOMEDIUM;
183     et2sys[(UAEMEDIUMTYPE - ERROR_TABLE_BASE_uae)] = EMEDIUMTYPE;
184 }
185
186 static afs_int32
187 et_to_sys_error(afs_int32 in)
188 {
189     if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512)
190         return in;
191     if (et2sys[in - ERROR_TABLE_BASE_uae] != 0)
192         return et2sys[in - ERROR_TABLE_BASE_uae];
193     return in;
194 }
195
196 long cm_MapRPCError(long error, cm_req_t *reqp)
197 {
198     if (error == 0)
199         return 0;
200
201     /* If we had to stop retrying, report our saved error code. */
202     if (reqp && error == CM_ERROR_TIMEDOUT) {
203         if (reqp->accessError)
204             return reqp->accessError;
205         if (reqp->volumeError)
206             return reqp->volumeError;
207         if (reqp->rpcError)
208             return reqp->rpcError;
209         return error;
210     }
211
212     error = et_to_sys_error(error);
213
214     if (error == RX_CALL_DEAD ||
215         error == RX_CALL_TIMEOUT ||
216         error == RX_CALL_BUSY ||
217         error == RX_MSGSIZE)
218         error = CM_ERROR_RETRY;
219     else if (error == RX_CALL_IDLE)
220         error = EIO;
221     else if (error < 0)
222         error = CM_ERROR_UNKNOWN;
223     else if (error == EINVAL)
224         error = CM_ERROR_INVAL;
225     else if (error == EROFS)
226         error = CM_ERROR_READONLY;
227     else if (error == EACCES)
228         error = CM_ERROR_NOACCESS;
229     else if (error == EXDEV)
230         error = CM_ERROR_CROSSDEVLINK;
231     else if (error == EEXIST)
232         error = CM_ERROR_EXISTS;
233     else if (error == ENOTDIR)
234         error = CM_ERROR_NOTDIR;
235     else if (error == ENOENT)
236         error = CM_ERROR_NOSUCHFILE;
237     else if (error == EAGAIN
238              || error == 35        /* EAGAIN, Digital UNIX */
239              || error == WSAEWOULDBLOCK)
240         error = CM_ERROR_WOULDBLOCK;
241     else if (error == VDISKFULL
242               || error == ENOSPC)
243         error = CM_ERROR_SPACE;
244     else if (error == VOVERQUOTA
245               || error == EDQUOT
246               || error == 49    /* EDQUOT on Solaris */
247               || error == 88    /* EDQUOT on AIX */
248               || error == 69    /* EDQUOT on Digital UNIX and HPUX */
249               || error == 122   /* EDQUOT on Linux */
250               || error == 1133) /* EDQUOT on Irix  */
251         error = CM_ERROR_QUOTA;
252     else if (error == VNOVNODE)
253         error = CM_ERROR_BADFD;
254     else if (error == VNOSERVICE || error == VSALVAGE || error == VOFFLINE)
255         error = CM_ERROR_ALLOFFLINE;
256     else if (error == VBUSY || error == VRESTARTING)
257         error = CM_ERROR_ALLBUSY;
258     else if (error == EISDIR)
259         return CM_ERROR_ISDIR;
260     return error;
261 }
262
263 long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
264 {
265     if (error == 0)
266         return 0;
267
268     /* If we had to stop retrying, report our saved error code. */
269     if (reqp && error == CM_ERROR_TIMEDOUT) {
270         if (reqp->accessError)
271             return reqp->accessError;
272         if (reqp->volumeError)
273             return reqp->volumeError;
274         if (reqp->rpcError)
275             return reqp->rpcError;
276         return error;
277     }
278
279     error = et_to_sys_error(error);
280
281     if (error == RX_CALL_DEAD ||
282         error == RX_CALL_TIMEOUT ||
283         error == RX_CALL_BUSY ||
284         error == RX_CALL_IDLE ||
285         error == RX_MSGSIZE)
286         error = CM_ERROR_RETRY;
287     else if (error == VNOVNODE)
288         error = CM_ERROR_BADFD;
289     else if (error == VNOSERVICE || error == VSALVAGE || error == VOFFLINE)
290         error = CM_ERROR_ALLOFFLINE;
291     else if (error == VBUSY || error == VRESTARTING)
292         error = CM_ERROR_ALLBUSY;
293     else if (error < 0)
294         error = CM_ERROR_UNKNOWN;
295     else if (error == EROFS)
296         error = CM_ERROR_READONLY;
297     else if (error == ENOTDIR)
298         error = CM_ERROR_NOTDIR;
299     else if (error == EACCES)
300         error = CM_ERROR_NOACCESS;
301     else if (error == ENOENT)
302         error = CM_ERROR_NOSUCHFILE;
303     else if (error == EINVAL)
304         error = CM_ERROR_INVAL;
305     else if (error == ENOTEMPTY
306               || error == 17            /* AIX */
307               || error == 66            /* SunOS 4, Digital UNIX */
308               || error == 93            /* Solaris 2, IRIX */
309               || error == 247)  /* HP/UX */
310         error = CM_ERROR_NOTEMPTY;
311     return error;
312 }
313
314 long cm_MapVLRPCError(long error, cm_req_t *reqp)
315 {
316     if (error == 0) return 0;
317
318     /* If we had to stop retrying, report our saved error code. */
319     if (reqp && error == CM_ERROR_TIMEDOUT) {
320         if (reqp->accessError)
321             return reqp->accessError;
322         if (reqp->volumeError)
323             return reqp->volumeError;
324         if (reqp->rpcError)
325             return reqp->rpcError;
326         return error;
327     }
328
329     error = et_to_sys_error(error);
330
331     if (error == RX_CALL_DEAD ||
332         error == RX_CALL_TIMEOUT ||
333         error == RX_CALL_BUSY ||
334         error == RX_CALL_IDLE ||
335         error == RX_MSGSIZE)
336         error = CM_ERROR_RETRY;
337     else if (error == RX_RESTARTING)
338         error = CM_ERROR_ALLBUSY;
339     else if (error < 0)
340         error = CM_ERROR_UNKNOWN;
341     else if (error == EINVAL)
342         error = CM_ERROR_INVAL;
343     else if (error == VL_NOENT || error == VL_BADNAME)
344         error = CM_ERROR_NOSUCHVOLUME;
345     return error;
346 }
347
348 cm_space_t *cm_GetSpace(void)
349 {
350         cm_space_t *tsp;
351
352         cm_utilsInit();
353
354         lock_ObtainWrite(&cm_utilsLock);
355         if (tsp = cm_spaceListp) {
356                 cm_spaceListp = tsp->nextp;
357         }
358         else tsp = (cm_space_t *) malloc(sizeof(cm_space_t));
359         (void) memset(tsp, 0, sizeof(cm_space_t));
360         lock_ReleaseWrite(&cm_utilsLock);
361
362         return tsp;
363 }
364
365 void cm_FreeSpace(cm_space_t *tsp)
366 {
367         lock_ObtainWrite(&cm_utilsLock);
368         tsp->nextp = cm_spaceListp;
369         cm_spaceListp = tsp;
370         lock_ReleaseWrite(&cm_utilsLock);
371 }
372
373 /* characters that are legal in an 8.3 name */
374 /*
375  * We used to have 1's for all characters from 128 to 254.  But
376  * the NT client behaves better if we create an 8.3 name for any
377  * name that has a character with the high bit on, and if we
378  * delete those characters from 8.3 names.  In particular, see
379  * Sybase defect 10859.
380  */
381 char cm_LegalChars[256] = {
382  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
385  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
386  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
387  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
388  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
389  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
390  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
391  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
392  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
393  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
394  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
395  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
398 };
399
400 #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
401
402 /* return true iff component is a valid 8.3 name */
403 int cm_Is8Dot3(clientchar_t *namep)
404 {
405     int sawDot = 0;
406     clientchar_t tc;
407     int charCount = 0;
408
409     if (namep == NULL || !namep[0])
410         return 0;
411
412     /*
413      * can't have a leading dot;
414      * special case for . and ..
415      */
416     if (namep[0] == '.') {
417         if (namep[1] == 0)
418             return 1;
419         if (namep[1] == '.' && namep[2] == 0)
420             return 1;
421         return 0;
422     }
423     while (tc = *namep++) {
424         if (tc == '.') {
425             /* saw another dot */
426             if (sawDot) return 0;       /* second dot */
427             sawDot = 1;
428             charCount = 0;
429             continue;
430         }
431         if (!ISLEGALCHAR(tc))
432             return 0;
433         charCount++;
434         if (!sawDot && charCount > 8)
435             /* more than 8 chars in name */
436             return 0;
437         if (sawDot && charCount > 3)
438             /* more than 3 chars in extension */
439             return 0;
440     }
441     return 1;
442 }
443
444 /*
445  * Number unparsing map for generating 8.3 names;
446  * The version taken from DFS was on drugs.
447  * You can't include '&' and '@' in a file name.
448  */
449 char cm_8Dot3Mapping[42] =
450 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
451  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
452  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
453  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '{', '}'
454 };
455 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
456
457 void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
458                         clientchar_t *shortName, clientchar_t **shortNameEndp)
459 {
460     char number[12];
461     int i, nsize = 0;
462     int vnode = ntohl(pfid->vnode);
463     char *lastDot;
464     int validExtension = 0;
465     char tc, *temp;
466     const char *name;
467
468     /* Unparse the file's vnode number to get a "uniquifier" */
469     do {
470         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
471         nsize++;
472         vnode /= cm_8Dot3MapSize;
473     } while (vnode);
474
475     /*
476      * Look for valid extension.  There has to be a dot, and
477      * at least one of the characters following has to be legal.
478      */
479     lastDot = strrchr(longname, '.');
480     if (lastDot) {
481         temp = lastDot; temp++;
482         while (tc = *temp++)
483             if (ISLEGALCHAR(tc))
484                 break;
485         if (tc)
486             validExtension = 1;
487     }
488
489     /* Copy name characters */
490     for (i = 0, name = longname;
491           i < (7 - nsize) && name != lastDot; ) {
492         tc = *name++;
493
494         if (tc == 0)
495             break;
496         if (!ISLEGALCHAR(tc))
497             continue;
498         i++;
499         *shortName++ = toupper(tc);
500     }
501
502     /* tilde */
503     *shortName++ = '~';
504
505     /* Copy uniquifier characters */
506     for (i=0; i < nsize; i++) {
507         *shortName++ = number[i];
508     }
509
510     if (validExtension) {
511         /* Copy extension characters */
512         *shortName++ = *lastDot++;      /* copy dot */
513         for (i = 0, tc = *lastDot++;
514              i < 3 && tc;
515              tc = *lastDot++) {
516             if (ISLEGALCHAR(tc)) {
517                 i++;
518                 *shortName++ = toupper(tc);
519             }
520         }
521     }
522
523     /* Trailing null */
524     *shortName = 0;
525
526     if (shortNameEndp)
527         *shortNameEndp = shortName;
528 }
529
530 void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
531                          clientchar_t *shortName, clientchar_t **shortNameEndp)
532 {
533     clientchar_t number[12];
534     int i, nsize = 0;
535     int vnode = ntohl(pfid->vnode);
536     clientchar_t *lastDot;
537     int validExtension = 0;
538     clientchar_t tc, *temp;
539     const clientchar_t *name;
540
541     /* Unparse the file's vnode number to get a "uniquifier" */
542     do {
543         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
544         nsize++;
545         vnode /= cm_8Dot3MapSize;
546     } while (vnode);
547
548     /*
549      * Look for valid extension.  There has to be a dot, and
550      * at least one of the characters following has to be legal.
551      */
552     lastDot = cm_ClientStrRChr(longname, '.');
553     if (lastDot) {
554         temp = lastDot; temp++;
555         while (tc = *temp++)
556             if (ISLEGALCHAR(tc))
557                 break;
558         if (tc)
559             validExtension = 1;
560     }
561
562     /* Copy name characters */
563     for (i = 0, name = longname;
564           i < (7 - nsize) && name != lastDot; ) {
565         tc = *name++;
566
567         if (tc == 0)
568             break;
569         if (!ISLEGALCHAR(tc))
570             continue;
571         i++;
572         *shortName++ = toupper((char) tc);
573     }
574
575     /* tilde */
576     *shortName++ = '~';
577
578     /* Copy uniquifier characters */
579     for (i=0; i < nsize; i++) {
580         *shortName++ = number[i];
581     }
582
583     if (validExtension) {
584         /* Copy extension characters */
585         *shortName++ = *lastDot++;      /* copy dot */
586         for (i = 0, tc = *lastDot++;
587              i < 3 && tc;
588              tc = *lastDot++) {
589             if (ISLEGALCHAR(tc)) {
590                 i++;
591                 *shortName++ = toupper(tc);
592             }
593         }
594     }
595
596     /* Trailing null */
597     *shortName = 0;
598
599     if (shortNameEndp)
600         *shortNameEndp = shortName;
601 }
602
603 void cm_Gen8Dot3VolNameW(afs_uint32 cell, afs_uint32 volume,
604                          clientchar_t *shortName, clientchar_t **shortNameEndp)
605 {
606     clientchar_t number[12];
607     int i, nsize = 0;
608     int validExtension = 0;
609
610     /* Unparse the file's cell and volume numbers */
611     do {
612         number[nsize] = cm_8Dot3Mapping[cell % cm_8Dot3MapSize];
613         nsize++;
614         cell /= cm_8Dot3MapSize;
615     } while (cell);
616     do {
617         number[nsize] = cm_8Dot3Mapping[volume % cm_8Dot3MapSize];
618         nsize++;
619         volume /= cm_8Dot3MapSize;
620     } while (volume && nsize < 8);
621
622     /* Copy uniquifier characters */
623     for (i=0; i < nsize; i++) {
624         *shortName++ = number[i];
625     }
626
627     /* Add extension characters */
628     *shortName++ = '.'; /* copy dot */
629     *shortName++ = 'v';
630     *shortName++ = 'o';
631     *shortName++ = 'l';
632
633     /* Trailing null */
634     *shortName = 0;
635
636     if (shortNameEndp)
637         *shortNameEndp = shortName;
638 }
639
640 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
641
642   \note This procedure works recursively calling itself.
643
644   \param[in] pattern string containing metacharacters.
645   \param[in] name File name to be compared with 'pattern'.
646
647   \return BOOL : TRUE/FALSE (match/mistmatch)
648 */
649 static BOOL
650 szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold)
651 {
652     clientchar_t upattern[MAX_PATH];
653     clientchar_t uname[MAX_PATH];
654
655     clientchar_t * pename;         // points to the last 'name' character
656     clientchar_t * p;
657     clientchar_t * pattern_next;
658
659     if (casefold) {
660         cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
661         cm_ClientStrUpr(upattern);
662         pattern = upattern;
663
664         cm_ClientStrCpy(uname, lengthof(uname), name);
665         cm_ClientStrUpr(uname);
666         name = uname;
667
668         /* The following translations all work on single byte
669            characters */
670         for (p=upattern; *p; p++) {
671             if (*p == '"') *p = '.'; continue;
672             if (*p == '<') *p = '*'; continue;
673             if (*p == '>') *p = '?'; continue;
674         }
675
676         for (p=uname; *p; p++) {
677             if (*p == '"') *p = '.'; continue;
678             if (*p == '<') *p = '*'; continue;
679             if (*p == '>') *p = '?'; continue;
680         }
681     }
682
683     pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
684
685     while (*name) {
686         switch (*pattern) {
687         case '?':
688             pattern = cm_ClientCharNext(pattern);
689             if (*name == '.')
690                 continue;
691             name = cm_ClientCharNext(name);
692             break;
693
694          case '*':
695             pattern = cm_ClientCharNext(pattern);
696             if (*pattern == '\0')
697                 return TRUE;
698
699             pattern_next = cm_ClientCharNext(pattern);
700
701             for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
702                 if (*p == *pattern &&
703                     szWildCardMatchFileName(pattern_next,
704                                             cm_ClientCharNext(p), FALSE))
705                     return TRUE;
706             } /* endfor */
707             if (*pattern == '.' && *pattern_next == '\0') {
708                 for (p = name; p && *p; p = cm_ClientCharNext(p))
709                     if (*p == '.')
710                         break;
711                 if (p && *p)
712                     return FALSE;
713                 return TRUE;
714             }
715             return FALSE;
716
717         default:
718             if (*name != *pattern)
719                 return FALSE;
720             pattern = cm_ClientCharNext(pattern);
721             name = cm_ClientCharNext(name);
722             break;
723         } /* endswitch */
724     } /* endwhile */
725
726     /* if all we have left are wildcards, then we match */
727     for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
728         if (*pattern != '*' && *pattern != '?')
729             return FALSE;
730     }
731     return TRUE;
732 }
733
734 /* do a case-folding search of the star name mask with the name in namep.
735  * Return 1 if we match, otherwise 0.
736  */
737 int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags)
738 {
739     clientchar_t *newmask, lastchar = _C('\0');
740     int    i, j, casefold, retval;
741     int  star = 0, qmark = 0, dot = 0;
742
743     /* make sure we only match 8.3 names, if requested */
744     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep))
745         return 0;
746
747     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
748
749     /* optimize the pattern:
750      * if there is a mixture of '?' and '*',
751      * for example  the sequence "*?*?*?*"
752      * must be turned into the form "*"
753      */
754     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+2)*sizeof(clientchar_t));
755     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
756         lastchar = maskp[i];
757         switch ( maskp[i] ) {
758         case '?':
759         case '>':
760             qmark++;
761             break;
762         case '<':
763         case '*':
764             star++;
765             break;
766         case '.':
767             dot++;
768             /* fallthrough */
769         default:
770             if ( star ) {
771                 newmask[j++] = '*';
772             } else if ( qmark ) {
773                 while ( qmark-- )
774                     newmask[j++] = '?';
775             }
776             newmask[j++] = maskp[i];
777             star = 0;
778             qmark = 0;
779         }
780     }
781     if ( star ) {
782         newmask[j++] = '*';
783     } else if ( qmark ) {
784         while ( qmark-- )
785             newmask[j++] = '?';
786     }
787     if (dot == 0 && lastchar == '<')
788         newmask[j++] = '.';
789     newmask[j++] = '\0';
790
791     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
792
793     free(newmask);
794     return retval;
795 }
796
797 BOOL
798 cm_TargetPerceivedAsDirectory(const fschar_t *target)
799 {
800     char        * ext;
801
802     ext = PathFindExtension(target);
803     if (!ext[0])
804         return TRUE;
805
806     return FALSE;
807 }
808
809 HANDLE
810 cm_LoadAfsdHookLib(void)
811 {
812     char dllname[260];
813     char *p;
814     HANDLE hLib;
815
816     if (!GetModuleFileName(NULL, dllname, sizeof(dllname)))
817         return NULL;
818
819     p = strrchr(dllname, '\\');
820     if (p) {
821         p++;
822         strcpy(p, AFSD_HOOK_DLL);
823         hLib = LoadLibrary(dllname);
824     } else {
825         hLib = LoadLibrary(AFSD_HOOK_DLL);
826     }
827
828     return hLib;
829 }
830
831 /*
832  * Obtain the file info structure for the specified file.
833  * If a full path is not specified, the search order is the
834  * same as that used by LoadLibrary().
835  */
836 BOOL
837 cm_GetOSFileVersion (char *filename, LARGE_INTEGER *liVer)
838 {
839     DWORD dwHandle;
840     DWORD dwSize;
841     char* pInfo = NULL;
842     BOOL  rc;
843     UINT uLen;
844     void *pbuf;
845     VS_FIXEDFILEINFO vsf;
846
847     dwSize = GetFileVersionInfoSizeA(filename,&dwHandle);
848     if (dwSize == 0) {
849         rc = FALSE;
850         goto done;
851     }
852     pInfo = (char*)malloc(dwSize);
853     if (!pInfo) {
854         rc = FALSE;
855         goto done;
856     }
857     rc = GetFileVersionInfoA(filename, dwHandle, dwSize, pInfo);
858     if (!rc)
859         goto done;
860     rc = VerQueryValueA(pInfo,"\\",&pbuf, &uLen);
861     if (!rc)
862         goto done;
863     memcpy(&vsf, pbuf, sizeof(VS_FIXEDFILEINFO));
864
865     liVer->LowPart = vsf.dwFileVersionLS;
866     liVer->HighPart = vsf.dwFileVersionMS;
867     rc = TRUE;
868
869   done:
870     if (pInfo)
871         free(pInfo);
872     return rc;
873 }
874
875 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
876 typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID *);
877 typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID);
878
879 BOOL msftSMBRedirectorSupportsExtendedTimeouts(void)
880 {
881     static BOOL fChecked = FALSE;
882     static BOOL fSupportsExtendedTimeouts = FALSE;
883
884     if (!fChecked)
885     {
886         BOOL isWow64 = FALSE;
887         OSVERSIONINFOEX Version;
888         HANDLE h1 = NULL;
889         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
890         LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection = NULL;
891         LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection = NULL;
892         PVOID Wow64RedirectionState;
893         LARGE_INTEGER fvFile, fvHotFixMin;
894
895         h1 = GetModuleHandle("kernel32.dll"); /* no refcount increase */
896         /*
897          * If we don't find the fnIsWow64Process function then we
898          * are not running in a Wow64 environment
899          */
900         fnIsWow64Process =
901             (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process");
902
903         memset (&Version, 0x00, sizeof(Version));
904         Version.dwOSVersionInfoSize = sizeof(Version);
905         GetVersionEx((OSVERSIONINFO *) &Version);
906
907         /*
908          * Support is available as hot fixes / service packs on:
909          *   XP SP2
910          *   XP SP3
911          *   2003 and XP64 SP2
912          *   Vista and 2008 SP2
913          *   Win7 and 2008 R2
914          */
915         if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
916             Version.dwMajorVersion >= 5) {
917
918             /* 32-bit XP */
919             if (Version.dwMajorVersion == 5 &&
920                 Version.dwMinorVersion == 1) {
921
922                 fvHotFixMin.HighPart = (5 << 16) | 1;
923
924                 switch (Version.wServicePackMajor) {
925                 case 3:
926                     fvHotFixMin.LowPart = (2600 << 16) | 5815;
927                     break;
928                 case 2:
929                     fvHotFixMin.LowPart = (2600 << 16) | 3572;
930                     break;
931                 default:
932                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 3);
933                     goto checked;
934                 }
935             }
936
937             /* 64-bit XP and Server 2003 */
938             else if (Version.dwMajorVersion == 5 &&
939                      Version.dwMinorVersion == 2) {
940
941                 fvHotFixMin.HighPart = (5 << 16) | 2;
942
943                 switch (Version.wServicePackMajor) {
944                 case 2:
945                     fvHotFixMin.LowPart = (3790 << 16) | 4479;
946                     break;
947                 case 1:
948                     fvHotFixMin.LowPart = (3790 << 16) | 3310;
949                     break;
950                 default:
951                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
952                     goto checked;
953                 }
954             }
955
956             /* Vista and Server 2008 */
957             else if (Version.dwMajorVersion == 6 &&
958                      Version.dwMinorVersion == 0) {
959
960                 fvHotFixMin.HighPart = (6 << 16) | 0;
961
962                 switch (Version.wServicePackMajor) {
963                 case 2:
964                     fvHotFixMin.LowPart = (6002 << 16) | 18005;
965                     break;
966                 default:
967                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
968                     goto checked;
969                 }
970             }
971
972             /* Windows 7 and Server 2008 R2 and beyond */
973             else if (Version.dwMajorVersion > 6 ||
974                      Version.dwMajorVersion == 6 &&
975                      Version.dwMinorVersion >= 1) {
976                 fSupportsExtendedTimeouts = TRUE;
977                 goto checked;
978             }
979
980             /* If wow64, disable wow64 redirection and preserve the existing state */
981             if (fnIsWow64Process &&
982                  fnIsWow64Process(GetCurrentProcess(), &isWow64) &&
983                  isWow64) {
984                 fnDisableWow64FsRedirection =
985                     (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64DisableWow64FsRedirection");
986                 fnRevertWow64FsRedirection =
987                     (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64RevertWow64FsRedirection");
988                 fnDisableWow64FsRedirection(&Wow64RedirectionState);
989             }
990
991             if (cm_GetOSFileVersion("drivers\\mrxsmb.sys", &fvFile) ||
992                 (fvFile.QuadPart >= fvHotFixMin.QuadPart))
993                 fSupportsExtendedTimeouts = TRUE;
994
995             /* If wow64, restore the previous redirection state */
996             if (fnIsWow64Process && isWow64) {
997                 fnRevertWow64FsRedirection(Wow64RedirectionState);
998             }
999         }
1000       checked:
1001         fChecked = TRUE;
1002     }
1003
1004     return fSupportsExtendedTimeouts;
1005 }
1006
1007 void cm_ResetServerPriority()
1008 {
1009     void * p = TlsGetValue(cm_TlsRequestSlot);
1010     if (p) {
1011         free(p);
1012         TlsSetValue(cm_TlsRequestSlot, NULL);
1013         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
1014     }
1015 }
1016
1017 void cm_SetRequestStartTime()
1018 {
1019     time_t * tp = TlsGetValue(cm_TlsRequestSlot);
1020     if (!tp)
1021         tp = malloc(sizeof(time_t));
1022     if (tp) {
1023         *tp = osi_Time();
1024
1025         if (!TlsSetValue(cm_TlsRequestSlot, tp))
1026             free(tp);
1027     }
1028 }
1029
1030 void cm_UpdateServerPriority()
1031 {
1032     time_t *tp = TlsGetValue(cm_TlsRequestSlot);
1033
1034     if (tp) {
1035         time_t now = osi_Time();
1036
1037         /* Give one priority boost for each 15 seconds */
1038         SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
1039     }
1040 }
1041
1042
1043 void cm_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
1044 {
1045     // Note that LONGLONG is a 64-bit value
1046     LONGLONG ll;
1047
1048     ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
1049     largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
1050     largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
1051 }
1052
1053 void cm_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
1054 {
1055     // Note that LONGLONG is a 64-bit value
1056     LONGLONG ll;
1057
1058     ll = largeTimep->dwHighDateTime;
1059     ll <<= 32;
1060     ll += largeTimep->dwLowDateTime;
1061
1062     ll -= 116444736000000000;
1063     ll /= 10000000;
1064
1065     *unixTimep = (DWORD)ll;
1066 }
1067
1068 void cm_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
1069 {
1070     struct tm *ltp;
1071     int dosDate;
1072     int dosTime;
1073     struct tm localJunk;
1074     time_t t = unixTime;
1075
1076     ltp = localtime(&t);
1077
1078     /* if we fail, make up something */
1079     if (!ltp) {
1080         ltp = &localJunk;
1081         localJunk.tm_year = 89 - 20;
1082         localJunk.tm_mon = 4;
1083         localJunk.tm_mday = 12;
1084         localJunk.tm_hour = 0;
1085         localJunk.tm_min = 0;
1086         localJunk.tm_sec = 0;
1087     }
1088
1089     dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
1090     dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
1091     *searchTimep = (dosDate<<16) | dosTime;
1092 }
1093
1094 void cm_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
1095 {
1096     unsigned short dosDate;
1097     unsigned short dosTime;
1098     struct tm localTm;
1099
1100     dosDate = (unsigned short) (searchTime & 0xffff);
1101     dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
1102
1103     localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
1104     localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;        /* January is 0 in localTm */
1105     localTm.tm_mday = (dosDate) & 0x1f;
1106     localTm.tm_hour = (dosTime>>11) & 0x1f;
1107     localTm.tm_min = (dosTime >> 5) & 0x3f;
1108     localTm.tm_sec = (dosTime & 0x1f) * 2;
1109     localTm.tm_isdst = -1;                              /* compute whether DST in effect */
1110
1111     *unixTimep = mktime(&localTm);
1112 }
1113
1114 afs_uint32
1115 cm_NextHighestPowerOf2(afs_uint32 n)
1116 {
1117     n--;
1118     n |= n >> 1;
1119     n |= n >> 2;
1120     n |= n >> 4;
1121     n |= n >> 8;
1122     n |= n >> 16;
1123     n++;
1124     return n;
1125 }