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