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