58a94cbeeaa881f59a5d56ae01bc90d92590c4f4
[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 = CM_ERROR_RETRY;
214     else if (error < 0)
215         error = CM_ERROR_UNKNOWN;
216     else if (error == EROFS) 
217         error = CM_ERROR_READONLY;
218     else if (error == EACCES) 
219         error = CM_ERROR_NOACCESS;
220     else if (error == EXDEV) 
221         error = CM_ERROR_CROSSDEVLINK;
222     else if (error == EEXIST) 
223         error = CM_ERROR_EXISTS;
224     else if (error == ENOTDIR) 
225         error = CM_ERROR_NOTDIR;
226     else if (error == ENOENT)
227         error = CM_ERROR_NOSUCHFILE;
228     else if (error == EAGAIN
229              || error == 35        /* EAGAIN, Digital UNIX */
230              || error == WSAEWOULDBLOCK)
231         error = CM_ERROR_WOULDBLOCK;
232     else if (error == VDISKFULL
233               || error == ENOSPC)
234         error = CM_ERROR_SPACE;
235     else if (error == VOVERQUOTA
236               || error == EDQUOT
237               || error == 49    /* EDQUOT on Solaris */
238               || error == 88    /* EDQUOT on AIX */
239               || error == 69    /* EDQUOT on Digital UNIX and HPUX */
240               || error == 122   /* EDQUOT on Linux */
241               || error == 1133) /* EDQUOT on Irix  */
242         error = CM_ERROR_QUOTA;
243     else if (error == VNOVNODE)
244         error = CM_ERROR_BADFD;
245     else if (error == VNOSERVICE || error == VSALVAGE || error == VOFFLINE)
246         error = CM_ERROR_ALLOFFLINE;
247     else if (error == VBUSY || error == VRESTARTING)
248         error = CM_ERROR_ALLBUSY;
249     else if (error == EISDIR)
250         return CM_ERROR_ISDIR;
251     return error;
252 }
253
254 long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
255 {
256     if (error == 0) 
257         return 0;
258
259     /* If we had to stop retrying, report our saved error code. */
260     if (reqp && error == CM_ERROR_TIMEDOUT) {
261         if (reqp->accessError)
262             return reqp->accessError;
263         if (reqp->volumeError)
264             return reqp->volumeError;
265         if (reqp->rpcError)
266             return reqp->rpcError;
267         return error;
268     }
269
270     error = et_to_sys_error(error);
271
272     if (error == RX_CALL_DEAD ||
273         error == RX_CALL_TIMEOUT)
274         error = CM_ERROR_RETRY;
275     else if (error == VNOVNODE)
276         error = CM_ERROR_BADFD;
277     else if (error == VNOSERVICE || error == VSALVAGE || error == VOFFLINE)
278         error = CM_ERROR_ALLOFFLINE;
279     else if (error == VBUSY || error == VRESTARTING)
280         error = CM_ERROR_ALLBUSY;
281     else if (error < 0)
282         error = CM_ERROR_UNKNOWN;
283     else if (error == EROFS) 
284         error = CM_ERROR_READONLY;
285     else if (error == ENOTDIR) 
286         error = CM_ERROR_NOTDIR;
287     else if (error == EACCES) 
288         error = CM_ERROR_NOACCESS;
289     else if (error == ENOENT) 
290         error = CM_ERROR_NOSUCHFILE;
291     else if (error == ENOTEMPTY 
292               || error == 17            /* AIX */
293               || error == 66            /* SunOS 4, Digital UNIX */
294               || error == 93            /* Solaris 2, IRIX */
295               || error == 247)  /* HP/UX */
296         error = CM_ERROR_NOTEMPTY;
297     return error;
298 }       
299
300 long cm_MapVLRPCError(long error, cm_req_t *reqp)
301 {
302     if (error == 0) return 0;
303
304     /* If we had to stop retrying, report our saved error code. */
305     if (reqp && error == CM_ERROR_TIMEDOUT) {
306         if (reqp->accessError)
307             return reqp->accessError;
308         if (reqp->volumeError)
309             return reqp->volumeError;
310         if (reqp->rpcError)
311             return reqp->rpcError;
312         return error;
313     }
314
315     error = et_to_sys_error(error);
316
317     if (error == RX_CALL_DEAD ||
318         error == RX_CALL_TIMEOUT)
319         error = CM_ERROR_RETRY;
320     else if (error == RX_RESTARTING)
321         error = CM_ERROR_ALLBUSY;
322     else if (error < 0)
323         error = CM_ERROR_UNKNOWN;
324     else if (error == VL_NOENT || error == VL_BADNAME) 
325         error = CM_ERROR_NOSUCHVOLUME;
326     return error;
327 }
328
329 cm_space_t *cm_GetSpace(void)
330 {
331         cm_space_t *tsp;
332
333         cm_utilsInit();
334
335         lock_ObtainWrite(&cm_utilsLock);
336         if (tsp = cm_spaceListp) {
337                 cm_spaceListp = tsp->nextp;
338         }
339         else tsp = (cm_space_t *) malloc(sizeof(cm_space_t));
340         (void) memset(tsp, 0, sizeof(cm_space_t));
341         lock_ReleaseWrite(&cm_utilsLock);
342         
343         return tsp;
344 }
345
346 void cm_FreeSpace(cm_space_t *tsp)
347 {
348         lock_ObtainWrite(&cm_utilsLock);
349         tsp->nextp = cm_spaceListp;
350         cm_spaceListp = tsp;
351         lock_ReleaseWrite(&cm_utilsLock);
352 }
353
354 /* characters that are legal in an 8.3 name */
355 /*
356  * We used to have 1's for all characters from 128 to 254.  But
357  * the NT client behaves better if we create an 8.3 name for any
358  * name that has a character with the high bit on, and if we
359  * delete those characters from 8.3 names.  In particular, see
360  * Sybase defect 10859.
361  */
362 char cm_LegalChars[256] = {
363  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
364  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
366  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
367  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
368  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
369  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
370  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
371  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
375  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
376  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
377  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
378  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
379 };
380
381 #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
382
383 /* return true iff component is a valid 8.3 name */
384 int cm_Is8Dot3(clientchar_t *namep)
385 {
386     int sawDot = 0;
387     clientchar_t tc;
388     int charCount = 0;
389     
390     if (namep == NULL || !namep[0])
391         return 0;
392
393     /*
394      * can't have a leading dot;
395      * special case for . and ..
396      */
397     if (namep[0] == '.') {
398         if (namep[1] == 0)
399             return 1;
400         if (namep[1] == '.' && namep[2] == 0)
401             return 1;
402         return 0;
403     }
404     while (tc = *namep++) {
405         if (tc == '.') {
406             /* saw another dot */
407             if (sawDot) return 0;       /* second dot */
408             sawDot = 1;
409             charCount = 0;
410             continue;
411         }
412         if (!ISLEGALCHAR(tc))
413             return 0;
414         charCount++;
415         if (!sawDot && charCount > 8)
416             /* more than 8 chars in name */
417             return 0;
418         if (sawDot && charCount > 3)
419             /* more than 3 chars in extension */
420             return 0;
421     }
422     return 1;
423 }
424
425 /*
426  * Number unparsing map for generating 8.3 names;
427  * The version taken from DFS was on drugs.  
428  * You can't include '&' and '@' in a file name.
429  */
430 char cm_8Dot3Mapping[42] =
431 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
432  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
433  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
434  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '{', '}'
435 };
436 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
437
438 void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
439                         clientchar_t *shortName, clientchar_t **shortNameEndp)
440 {
441     char number[12];
442     int i, nsize = 0;
443     int vnode = ntohl(pfid->vnode);
444     char *lastDot;
445     int validExtension = 0;
446     char tc, *temp;
447     const char *name;
448
449     /* Unparse the file's vnode number to get a "uniquifier" */
450     do {
451         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
452         nsize++;
453         vnode /= cm_8Dot3MapSize;
454     } while (vnode);
455
456     /*
457      * Look for valid extension.  There has to be a dot, and
458      * at least one of the characters following has to be legal.
459      */
460     lastDot = strrchr(longname, '.');
461     if (lastDot) {
462         temp = lastDot; temp++;
463         while (tc = *temp++)
464             if (ISLEGALCHAR(tc))
465                 break;
466         if (tc)
467             validExtension = 1;
468     }
469
470     /* Copy name characters */
471     for (i = 0, name = longname;
472           i < (7 - nsize) && name != lastDot; ) {
473         tc = *name++;
474
475         if (tc == 0)
476             break;
477         if (!ISLEGALCHAR(tc))
478             continue;
479         i++;
480         *shortName++ = toupper(tc);
481     }
482
483     /* tilde */
484     *shortName++ = '~';
485
486     /* Copy uniquifier characters */
487     for (i=0; i < nsize; i++) {
488         *shortName++ = number[i];
489     }
490
491     if (validExtension) {
492         /* Copy extension characters */
493         *shortName++ = *lastDot++;      /* copy dot */
494         for (i = 0, tc = *lastDot++;
495              i < 3 && tc;
496              tc = *lastDot++) {
497             if (ISLEGALCHAR(tc)) {
498                 i++;
499                 *shortName++ = toupper(tc);
500             }
501         }
502     }
503
504     /* Trailing null */
505     *shortName = 0;
506
507     if (shortNameEndp)
508         *shortNameEndp = shortName;
509 }
510
511 void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
512                          clientchar_t *shortName, clientchar_t **shortNameEndp)
513 {
514     clientchar_t number[12];
515     int i, nsize = 0;
516     int vnode = ntohl(pfid->vnode);
517     clientchar_t *lastDot;
518     int validExtension = 0;
519     clientchar_t tc, *temp;
520     const clientchar_t *name;
521
522     /* Unparse the file's vnode number to get a "uniquifier" */
523     do {
524         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
525         nsize++;
526         vnode /= cm_8Dot3MapSize;
527     } while (vnode);
528
529     /*
530      * Look for valid extension.  There has to be a dot, and
531      * at least one of the characters following has to be legal.
532      */
533     lastDot = cm_ClientStrRChr(longname, '.');
534     if (lastDot) {
535         temp = lastDot; temp++;
536         while (tc = *temp++)
537             if (ISLEGALCHAR(tc))
538                 break;
539         if (tc)
540             validExtension = 1;
541     }
542
543     /* Copy name characters */
544     for (i = 0, name = longname;
545           i < (7 - nsize) && name != lastDot; ) {
546         tc = *name++;
547
548         if (tc == 0)
549             break;
550         if (!ISLEGALCHAR(tc))
551             continue;
552         i++;
553         *shortName++ = toupper((char) tc);
554     }
555
556     /* tilde */
557     *shortName++ = '~';
558
559     /* Copy uniquifier characters */
560     for (i=0; i < nsize; i++) {
561         *shortName++ = number[i];
562     }
563
564     if (validExtension) {
565         /* Copy extension characters */
566         *shortName++ = *lastDot++;      /* copy dot */
567         for (i = 0, tc = *lastDot++;
568              i < 3 && tc;
569              tc = *lastDot++) {
570             if (ISLEGALCHAR(tc)) {
571                 i++;
572                 *shortName++ = toupper(tc);
573             }
574         }
575     }
576
577     /* Trailing null */
578     *shortName = 0;
579
580     if (shortNameEndp)
581         *shortNameEndp = shortName;
582 }
583
584 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
585
586   \note This procedure works recursively calling itself.
587
588   \param[in] pattern string containing metacharacters.
589   \param[in] name File name to be compared with 'pattern'.
590
591   \return BOOL : TRUE/FALSE (match/mistmatch)
592 */
593 static BOOL 
594 szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold) 
595 {
596     clientchar_t upattern[MAX_PATH];
597     clientchar_t uname[MAX_PATH];
598
599     clientchar_t * pename;         // points to the last 'name' character
600     clientchar_t * p;
601     clientchar_t * pattern_next;
602
603     if (casefold) {
604         cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
605         cm_ClientStrUpr(upattern);
606         pattern = upattern;
607
608         cm_ClientStrCpy(uname, lengthof(uname), name);
609         cm_ClientStrUpr(uname);
610         name = uname;
611
612         /* The following translations all work on single byte
613            characters */
614         for (p=upattern; *p; p++) {
615             if (*p == '"') *p = '.'; continue;
616             if (*p == '<') *p = '*'; continue;
617             if (*p == '>') *p = '?'; continue;
618         }
619
620         for (p=uname; *p; p++) {
621             if (*p == '"') *p = '.'; continue;
622             if (*p == '<') *p = '*'; continue;
623             if (*p == '>') *p = '?'; continue;
624         }
625     }
626
627     pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
628
629     while (*name) {
630         switch (*pattern) {
631         case '?':
632             pattern = cm_ClientCharNext(pattern);
633             if (*name == '.')
634                 continue;
635             name = cm_ClientCharNext(name);
636             break;
637
638          case '*':
639             pattern = cm_ClientCharNext(pattern);
640             if (*pattern == '\0')
641                 return TRUE;
642
643             pattern_next = cm_ClientCharNext(pattern);
644
645             for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
646                 if (*p == *pattern &&
647                     szWildCardMatchFileName(pattern_next,
648                                             cm_ClientCharNext(p), FALSE))
649                     return TRUE;
650             } /* endfor */
651             if (*pattern == '.' && *pattern_next == '\0') {
652                 for (p = name; p && *p; p = cm_ClientCharNext(p))
653                     if (*p == '.')
654                         break;
655                 if (p && *p)
656                     return FALSE;
657                 return TRUE;
658             }
659             return FALSE;
660
661         default:
662             if (*name != *pattern)
663                 return FALSE;
664             pattern = cm_ClientCharNext(pattern);
665             name = cm_ClientCharNext(name);
666             break;
667         } /* endswitch */
668     } /* endwhile */
669
670     /* if all we have left are wildcards, then we match */
671     for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
672         if (*pattern != '*' && *pattern != '?')
673             return FALSE;
674     }
675     return TRUE;
676 }
677
678 /* do a case-folding search of the star name mask with the name in namep.
679  * Return 1 if we match, otherwise 0.
680  */
681 int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
682 {
683     clientchar_t *newmask, lastchar = _C('\0');
684     int    i, j, casefold, retval;
685     int  star = 0, qmark = 0, dot = 0;
686
687     /* make sure we only match 8.3 names, if requested */
688     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
689         return 0;
690
691     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
692
693     /* optimize the pattern:
694      * if there is a mixture of '?' and '*',
695      * for example  the sequence "*?*?*?*"
696      * must be turned into the form "*"
697      */
698     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+2)*sizeof(clientchar_t));
699     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
700         lastchar = maskp[i];
701         switch ( maskp[i] ) {
702         case '?':
703         case '>':
704             qmark++;
705             break;
706         case '<':
707         case '*':
708             star++;
709             break;
710         case '.':
711             dot++;
712             /* fallthrough */
713         default:
714             if ( star ) {
715                 newmask[j++] = '*';
716             } else if ( qmark ) {
717                 while ( qmark-- )
718                     newmask[j++] = '?';
719             }
720             newmask[j++] = maskp[i];
721             star = 0;
722             qmark = 0;
723         }
724     }
725     if ( star ) {
726         newmask[j++] = '*';
727     } else if ( qmark ) {
728         while ( qmark-- )
729             newmask[j++] = '?';
730     }
731     if (dot == 0 && lastchar == '<')
732         newmask[j++] = '.';
733     newmask[j++] = '\0';
734
735     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
736
737     free(newmask);
738     return retval;
739 }
740
741 BOOL
742 cm_TargetPerceivedAsDirectory(const fschar_t *target)
743 {
744     char        * ext;
745
746     ext = PathFindExtension(target);
747     if (!ext[0])
748         return TRUE;
749
750     return FALSE;
751 }
752
753 HANDLE 
754 cm_LoadAfsdHookLib(void)
755 {
756     char dllname[260];
757     char *p;
758     HANDLE hLib;
759
760     if (!GetModuleFileName(NULL, dllname, sizeof(dllname)))
761         return NULL;
762
763     p = strrchr(dllname, '\\');
764     if (p) {
765         p++;
766         strcpy(p, AFSD_HOOK_DLL);
767         hLib = LoadLibrary(dllname);
768     } else {
769         hLib = LoadLibrary(AFSD_HOOK_DLL);
770     }
771
772     return hLib;
773 }
774
775 /*
776  * Obtain the file info structure for the specified file.
777  * If a full path is not specified, the search order is the
778  * same as that used by LoadLibrary().
779  */
780 BOOL
781 cm_GetOSFileVersion (char *filename, LARGE_INTEGER *liVer)
782 {
783     DWORD dwHandle;
784     DWORD dwSize;
785     char* pInfo = NULL;
786     BOOL  rc;
787     UINT uLen;
788     void *pbuf;
789     VS_FIXEDFILEINFO vsf;
790
791     dwSize = GetFileVersionInfoSizeA(filename,&dwHandle);
792     if (dwSize == 0) {
793         rc = FALSE;
794         goto done;
795     }
796     pInfo = (char*)malloc(dwSize);
797     if (!pInfo) {
798         rc = FALSE;
799         goto done;
800     }
801     rc = GetFileVersionInfoA(filename, dwHandle, dwSize, pInfo);
802     if (!rc)
803         goto done;
804     rc = VerQueryValueA(pInfo,"\\",&pbuf, &uLen);
805     if (!rc)
806         goto done;
807     memcpy(&vsf, pbuf, sizeof(VS_FIXEDFILEINFO));
808
809     liVer->LowPart = vsf.dwFileVersionLS;
810     liVer->HighPart = vsf.dwFileVersionMS;
811     rc = TRUE;
812
813   done:
814     if (pInfo)
815         free(pInfo);
816     return rc;
817 }
818
819 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
820 typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID *);
821 typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID);
822
823 BOOL msftSMBRedirectorSupportsExtendedTimeouts(void) 
824 {
825     static BOOL fChecked = FALSE;
826     static BOOL fSupportsExtendedTimeouts = FALSE;
827
828     if (!fChecked)
829     {
830         BOOL isWow64 = FALSE;
831         OSVERSIONINFOEX Version;
832         HANDLE h1 = NULL;
833         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
834         LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection = NULL;
835         LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection = NULL;
836         PVOID Wow64RedirectionState;
837         LARGE_INTEGER fvFile, fvHotFixMin;
838
839         h1 = GetModuleHandle("kernel32.dll"); /* no refcount increase */
840         /* 
841          * If we don't find the fnIsWow64Process function then we
842          * are not running in a Wow64 environment
843          */
844         fnIsWow64Process =
845             (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process");
846
847         memset (&Version, 0x00, sizeof(Version));
848         Version.dwOSVersionInfoSize = sizeof(Version);
849         GetVersionEx((OSVERSIONINFO *) &Version);
850
851         /* 
852          * Support is available as hot fixes / service packs on:
853          *   XP SP2
854          *   XP SP3
855          *   2003 and XP64 SP2
856          *   Vista and 2008 SP2
857          *   Win7 and 2008 R2
858          */
859         if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
860             Version.dwMajorVersion >= 5) {
861
862             /* 32-bit XP */
863             if (Version.dwMajorVersion == 5 &&
864                 Version.dwMinorVersion == 1) {
865                 
866                 fvHotFixMin.HighPart = (5 << 16) | 1;
867
868                 switch (Version.wServicePackMajor) {
869                 case 3:
870                     fvHotFixMin.LowPart = (2600 << 16) | 5815;
871                     break;
872                 case 2:
873                     fvHotFixMin.LowPart = (2600 << 16) | 3572;
874                     break;
875                 default:
876                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 3);
877                     goto checked;
878                 }
879             }
880
881             /* 64-bit XP and Server 2003 */
882             else if (Version.dwMajorVersion == 5 &&
883                      Version.dwMinorVersion == 2) {
884                 
885                 fvHotFixMin.HighPart = (5 << 16) | 2;
886
887                 switch (Version.wServicePackMajor) {
888                 case 2:
889                     fvHotFixMin.LowPart = (3790 << 16) | 4479;
890                     break;
891                 case 1:
892                     fvHotFixMin.LowPart = (3790 << 16) | 3310;
893                     break;
894                 default:
895                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
896                     goto checked;
897                 }
898             }
899
900             /* Vista and Server 2008 */
901             else if (Version.dwMajorVersion == 6 &&
902                      Version.dwMinorVersion == 0) {
903                 
904                 fvHotFixMin.HighPart = (6 << 16) | 0;
905
906                 switch (Version.wServicePackMajor) {
907                 case 2:
908                     fvHotFixMin.LowPart = (6002 << 16) | 18005;
909                     break;
910                 default:
911                     fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2);
912                     goto checked;
913                 }
914             }
915
916             /* Windows 7 and Server 2008 R2 and beyond */
917             else if (Version.dwMajorVersion > 6 ||
918                      Version.dwMajorVersion == 6 &&
919                      Version.dwMinorVersion >= 1) {
920                 fSupportsExtendedTimeouts = TRUE;
921                 goto checked;
922             }
923
924             /* If wow64, disable wow64 redirection and preserve the existing state */
925             if (fnIsWow64Process && 
926                  fnIsWow64Process(GetCurrentProcess(), &isWow64) &&
927                  isWow64) {
928                 fnDisableWow64FsRedirection =
929                     (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64DisableWow64FsRedirection");
930                 fnRevertWow64FsRedirection =
931                     (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64RevertWow64FsRedirection");
932                 fnDisableWow64FsRedirection(&Wow64RedirectionState);
933             }
934             
935             if (cm_GetOSFileVersion("drivers\\mrxsmb.sys", &fvFile) ||
936                 (fvFile.QuadPart >= fvHotFixMin.QuadPart))
937                 fSupportsExtendedTimeouts = TRUE;
938
939             /* If wow64, restore the previous redirection state */
940             if (fnIsWow64Process && isWow64) {
941                 fnRevertWow64FsRedirection(Wow64RedirectionState);
942             }            
943         }
944       checked:
945         fChecked = TRUE;
946     }
947
948     return fSupportsExtendedTimeouts;
949 }
950
951 void cm_ResetServerPriority()
952 {
953     void * p = TlsGetValue(cm_TlsRequestSlot);
954     if (p) {
955         free(p);
956         TlsSetValue(cm_TlsRequestSlot, NULL);
957         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
958     }
959 }
960
961 void cm_SetRequestStartTime()
962 {
963     time_t * tp = TlsGetValue(cm_TlsRequestSlot);
964     if (!tp)
965         tp = malloc(sizeof(time_t));
966     if (tp) {
967         *tp = osi_Time();
968
969         if (!TlsSetValue(cm_TlsRequestSlot, tp))
970             free(tp);
971     }   
972 }
973
974 void cm_UpdateServerPriority()
975 {       
976     time_t *tp = TlsGetValue(cm_TlsRequestSlot);
977
978     if (tp) {
979         time_t now = osi_Time();
980
981         /* Give one priority boost for each 15 seconds */
982         SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
983     }
984 }
985
986
987 void cm_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
988 {
989     // Note that LONGLONG is a 64-bit value
990     LONGLONG ll;
991
992     ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
993     largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
994     largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
995 }
996
997 void cm_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
998 {
999     // Note that LONGLONG is a 64-bit value
1000     LONGLONG ll;
1001
1002     ll = largeTimep->dwHighDateTime;
1003     ll <<= 32;
1004     ll += largeTimep->dwLowDateTime;
1005
1006     ll -= 116444736000000000;
1007     ll /= 10000000;
1008
1009     *unixTimep = (DWORD)ll;
1010 }
1011
1012 void cm_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
1013 {
1014     struct tm *ltp;
1015     int dosDate;
1016     int dosTime;
1017     struct tm localJunk;
1018     time_t t = unixTime;
1019
1020     ltp = localtime(&t);
1021
1022     /* if we fail, make up something */
1023     if (!ltp) {
1024         ltp = &localJunk;
1025         localJunk.tm_year = 89 - 20;
1026         localJunk.tm_mon = 4;
1027         localJunk.tm_mday = 12;
1028         localJunk.tm_hour = 0;
1029         localJunk.tm_min = 0;
1030         localJunk.tm_sec = 0;
1031     }   
1032
1033     dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
1034     dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
1035     *searchTimep = (dosDate<<16) | dosTime;
1036 }       
1037
1038 void cm_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
1039 {
1040     unsigned short dosDate;
1041     unsigned short dosTime;
1042     struct tm localTm;
1043         
1044     dosDate = (unsigned short) (searchTime & 0xffff);
1045     dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
1046
1047     localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
1048     localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;        /* January is 0 in localTm */
1049     localTm.tm_mday = (dosDate) & 0x1f;
1050     localTm.tm_hour = (dosTime>>11) & 0x1f;
1051     localTm.tm_min = (dosTime >> 5) & 0x3f;
1052     localTm.tm_sec = (dosTime & 0x1f) * 2;
1053     localTm.tm_isdst = -1;                              /* compute whether DST in effect */
1054
1055     *unixTimep = mktime(&localTm);
1056 }