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