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