smb-symlink-to-vnovnode-attribute-20081017
[openafs.git] / src / WINNT / afsd / cm_utils.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <errno.h>
14 #include <windows.h>
15 #include <shlwapi.h>
16 #include <winsock2.h>
17 #ifndef EWOULDBLOCK
18 #define EWOULDBLOCK             WSAEWOULDBLOCK
19 #define EINPROGRESS             WSAEINPROGRESS
20 #define EALREADY                WSAEALREADY
21 #define ENOTSOCK                WSAENOTSOCK
22 #define EDESTADDRREQ            WSAEDESTADDRREQ
23 #define EMSGSIZE                WSAEMSGSIZE
24 #define EPROTOTYPE              WSAEPROTOTYPE
25 #define ENOPROTOOPT             WSAENOPROTOOPT
26 #define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
27 #define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
28 #define EOPNOTSUPP              WSAEOPNOTSUPP
29 #define EPFNOSUPPORT            WSAEPFNOSUPPORT
30 #define EAFNOSUPPORT            WSAEAFNOSUPPORT
31 #define EADDRINUSE              WSAEADDRINUSE
32 #define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
33 #define ENETDOWN                WSAENETDOWN
34 #define ENETUNREACH             WSAENETUNREACH
35 #define ENETRESET               WSAENETRESET
36 #define ECONNABORTED            WSAECONNABORTED
37 #define ECONNRESET              WSAECONNRESET
38 #define ENOBUFS                 WSAENOBUFS
39 #define EISCONN                 WSAEISCONN
40 #define ENOTCONN                WSAENOTCONN
41 #define ESHUTDOWN               WSAESHUTDOWN
42 #define ETOOMANYREFS            WSAETOOMANYREFS
43 #define ETIMEDOUT               WSAETIMEDOUT
44 #define ECONNREFUSED            WSAECONNREFUSED
45 #ifdef ELOOP
46 #undef ELOOP
47 #endif
48 #define ELOOP                   WSAELOOP
49 #ifdef ENAMETOOLONG
50 #undef ENAMETOOLONG
51 #endif
52 #define ENAMETOOLONG            WSAENAMETOOLONG
53 #define EHOSTDOWN               WSAEHOSTDOWN
54 #define EHOSTUNREACH            WSAEHOSTUNREACH
55 #ifdef ENOTEMPTY
56 #undef ENOTEMPTY
57 #endif 
58 #define ENOTEMPTY               WSAENOTEMPTY
59 #define EPROCLIM                WSAEPROCLIM
60 #define EUSERS                  WSAEUSERS
61 #define EDQUOT                  WSAEDQUOT
62 #define ESTALE                  WSAESTALE
63 #define EREMOTE                 WSAEREMOTE
64 #endif /* EWOULDBLOCK */
65 #include <afs/unified_afs.h>
66
67 #include <string.h>
68 #include <malloc.h>
69 #include "afsd.h"
70 #include <osi.h>
71 #include <rx/rx.h>
72
73 #define STRSAFE_NO_DEPRECATE
74 #include <strsafe.h>
75
76
77 static osi_once_t cm_utilsOnce;
78
79 osi_rwlock_t cm_utilsLock;
80
81 cm_space_t *cm_spaceListp;
82
83 static int et2sys[512];
84
85 void
86 init_et_to_sys_error(void)
87 {
88     memset(&et2sys, 0, sizeof(et2sys));
89     et2sys[(UAEPERM - ERROR_TABLE_BASE_uae)] = EPERM;
90     et2sys[(UAENOENT - ERROR_TABLE_BASE_uae)] = ENOENT;
91     et2sys[(UAESRCH - ERROR_TABLE_BASE_uae)] = ESRCH;
92     et2sys[(UAEINTR - ERROR_TABLE_BASE_uae)] = EINTR;
93     et2sys[(UAEIO - ERROR_TABLE_BASE_uae)] = EIO;
94     et2sys[(UAENXIO - ERROR_TABLE_BASE_uae)] = ENXIO;
95     et2sys[(UAE2BIG - ERROR_TABLE_BASE_uae)] = E2BIG;
96     et2sys[(UAENOEXEC - ERROR_TABLE_BASE_uae)] = ENOEXEC;
97     et2sys[(UAEBADF - ERROR_TABLE_BASE_uae)] = EBADF;
98     et2sys[(UAECHILD - ERROR_TABLE_BASE_uae)] = ECHILD;
99     et2sys[(UAEAGAIN - ERROR_TABLE_BASE_uae)] = EAGAIN;
100     et2sys[(UAENOMEM - ERROR_TABLE_BASE_uae)] = ENOMEM;
101     et2sys[(UAEACCES - ERROR_TABLE_BASE_uae)] = EACCES;
102     et2sys[(UAEFAULT - ERROR_TABLE_BASE_uae)] = EFAULT;
103     et2sys[(UAENOTBLK - ERROR_TABLE_BASE_uae)] = ENOTBLK;
104     et2sys[(UAEBUSY - ERROR_TABLE_BASE_uae)] = EBUSY;
105     et2sys[(UAEEXIST - ERROR_TABLE_BASE_uae)] = EEXIST;
106     et2sys[(UAEXDEV - ERROR_TABLE_BASE_uae)] = EXDEV;
107     et2sys[(UAENODEV - ERROR_TABLE_BASE_uae)] = ENODEV;
108     et2sys[(UAENOTDIR - ERROR_TABLE_BASE_uae)] = ENOTDIR;
109     et2sys[(UAEISDIR - ERROR_TABLE_BASE_uae)] = EISDIR;
110     et2sys[(UAEINVAL - ERROR_TABLE_BASE_uae)] = EINVAL;
111     et2sys[(UAENFILE - ERROR_TABLE_BASE_uae)] = ENFILE;
112     et2sys[(UAEMFILE - ERROR_TABLE_BASE_uae)] = EMFILE;
113     et2sys[(UAENOTTY - ERROR_TABLE_BASE_uae)] = ENOTTY;
114     et2sys[(UAETXTBSY - ERROR_TABLE_BASE_uae)] = ETXTBSY;
115     et2sys[(UAEFBIG - ERROR_TABLE_BASE_uae)] = EFBIG;
116     et2sys[(UAENOSPC - ERROR_TABLE_BASE_uae)] = ENOSPC;
117     et2sys[(UAESPIPE - ERROR_TABLE_BASE_uae)] = ESPIPE;
118     et2sys[(UAEROFS - ERROR_TABLE_BASE_uae)] = EROFS;
119     et2sys[(UAEMLINK - ERROR_TABLE_BASE_uae)] = EMLINK;
120     et2sys[(UAEPIPE - ERROR_TABLE_BASE_uae)] = EPIPE;
121     et2sys[(UAEDOM - ERROR_TABLE_BASE_uae)] = EDOM;
122     et2sys[(UAERANGE - ERROR_TABLE_BASE_uae)] = ERANGE;
123     et2sys[(UAEDEADLK - ERROR_TABLE_BASE_uae)] = EDEADLK;
124     et2sys[(UAENAMETOOLONG - ERROR_TABLE_BASE_uae)] = ENAMETOOLONG;
125     et2sys[(UAENOLCK - ERROR_TABLE_BASE_uae)] = ENOLCK;
126     et2sys[(UAENOSYS - ERROR_TABLE_BASE_uae)] = ENOSYS;
127     et2sys[(UAENOTEMPTY - ERROR_TABLE_BASE_uae)] = ENOTEMPTY;
128     et2sys[(UAELOOP - ERROR_TABLE_BASE_uae)] = ELOOP;
129     et2sys[(UAEWOULDBLOCK - ERROR_TABLE_BASE_uae)] = EWOULDBLOCK;
130     et2sys[(UAENOMSG - ERROR_TABLE_BASE_uae)] = ENOMSG;
131     et2sys[(UAEIDRM - ERROR_TABLE_BASE_uae)] = EIDRM;
132     et2sys[(UAECHRNG - ERROR_TABLE_BASE_uae)] = ECHRNG;
133     et2sys[(UAEL2NSYNC - ERROR_TABLE_BASE_uae)] = EL2NSYNC;
134     et2sys[(UAEL3HLT - ERROR_TABLE_BASE_uae)] = EL3HLT;
135     et2sys[(UAEL3RST - ERROR_TABLE_BASE_uae)] = EL3RST;
136     et2sys[(UAELNRNG - ERROR_TABLE_BASE_uae)] = ELNRNG;
137     et2sys[(UAEUNATCH - ERROR_TABLE_BASE_uae)] = EUNATCH;
138     et2sys[(UAENOCSI - ERROR_TABLE_BASE_uae)] = ENOCSI;
139     et2sys[(UAEL2HLT - ERROR_TABLE_BASE_uae)] = EL2HLT;
140     et2sys[(UAEBADE - ERROR_TABLE_BASE_uae)] = EBADE;
141     et2sys[(UAEBADR - ERROR_TABLE_BASE_uae)] = EBADR;
142     et2sys[(UAEXFULL - ERROR_TABLE_BASE_uae)] = EXFULL;
143     et2sys[(UAENOANO - ERROR_TABLE_BASE_uae)] = ENOANO;
144     et2sys[(UAEBADRQC - ERROR_TABLE_BASE_uae)] = EBADRQC;
145     et2sys[(UAEBADSLT - ERROR_TABLE_BASE_uae)] = EBADSLT;
146     et2sys[(UAEBFONT - ERROR_TABLE_BASE_uae)] = EBFONT;
147     et2sys[(UAENOSTR - ERROR_TABLE_BASE_uae)] = ENOSTR;
148     et2sys[(UAENODATA - ERROR_TABLE_BASE_uae)] = ENODATA;
149     et2sys[(UAETIME - ERROR_TABLE_BASE_uae)] = ETIME;
150     et2sys[(UAENOSR - ERROR_TABLE_BASE_uae)] = ENOSR;
151     et2sys[(UAENONET - ERROR_TABLE_BASE_uae)] = ENONET;
152     et2sys[(UAENOPKG - ERROR_TABLE_BASE_uae)] = ENOPKG;
153     et2sys[(UAEREMOTE - ERROR_TABLE_BASE_uae)] = EREMOTE;
154     et2sys[(UAENOLINK - ERROR_TABLE_BASE_uae)] = ENOLINK;
155     et2sys[(UAEADV - ERROR_TABLE_BASE_uae)] = EADV;
156     et2sys[(UAESRMNT - ERROR_TABLE_BASE_uae)] = ESRMNT;
157     et2sys[(UAECOMM - ERROR_TABLE_BASE_uae)] = ECOMM;
158     et2sys[(UAEPROTO - ERROR_TABLE_BASE_uae)] = EPROTO;
159     et2sys[(UAEMULTIHOP - ERROR_TABLE_BASE_uae)] = EMULTIHOP;
160     et2sys[(UAEDOTDOT - ERROR_TABLE_BASE_uae)] = EDOTDOT;
161     et2sys[(UAEBADMSG - ERROR_TABLE_BASE_uae)] = EBADMSG;
162     et2sys[(UAEOVERFLOW - ERROR_TABLE_BASE_uae)] = EOVERFLOW;
163     et2sys[(UAENOTUNIQ - ERROR_TABLE_BASE_uae)] = ENOTUNIQ;
164     et2sys[(UAEBADFD - ERROR_TABLE_BASE_uae)] = EBADFD;
165     et2sys[(UAEREMCHG - ERROR_TABLE_BASE_uae)] = EREMCHG;
166     et2sys[(UAELIBACC - ERROR_TABLE_BASE_uae)] = ELIBACC;
167     et2sys[(UAELIBBAD - ERROR_TABLE_BASE_uae)] = ELIBBAD;
168     et2sys[(UAELIBSCN - ERROR_TABLE_BASE_uae)] = ELIBSCN;
169     et2sys[(UAELIBMAX - ERROR_TABLE_BASE_uae)] = ELIBMAX;
170     et2sys[(UAELIBEXEC - ERROR_TABLE_BASE_uae)] = ELIBEXEC;
171     et2sys[(UAEILSEQ - ERROR_TABLE_BASE_uae)] = EILSEQ;
172     et2sys[(UAERESTART - ERROR_TABLE_BASE_uae)] = ERESTART;
173     et2sys[(UAESTRPIPE - ERROR_TABLE_BASE_uae)] = ESTRPIPE;
174     et2sys[(UAEUSERS - ERROR_TABLE_BASE_uae)] = EUSERS;
175     et2sys[(UAENOTSOCK - ERROR_TABLE_BASE_uae)] = ENOTSOCK;
176     et2sys[(UAEDESTADDRREQ - ERROR_TABLE_BASE_uae)] = EDESTADDRREQ;
177     et2sys[(UAEMSGSIZE - ERROR_TABLE_BASE_uae)] = EMSGSIZE;
178     et2sys[(UAEPROTOTYPE - ERROR_TABLE_BASE_uae)] = EPROTOTYPE;
179     et2sys[(UAENOPROTOOPT - ERROR_TABLE_BASE_uae)] = ENOPROTOOPT;
180     et2sys[(UAEPROTONOSUPPORT - ERROR_TABLE_BASE_uae)] = EPROTONOSUPPORT;
181     et2sys[(UAESOCKTNOSUPPORT - ERROR_TABLE_BASE_uae)] = ESOCKTNOSUPPORT;
182     et2sys[(UAEOPNOTSUPP - ERROR_TABLE_BASE_uae)] = EOPNOTSUPP;
183     et2sys[(UAEPFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EPFNOSUPPORT;
184     et2sys[(UAEAFNOSUPPORT - ERROR_TABLE_BASE_uae)] = EAFNOSUPPORT;
185     et2sys[(UAEADDRINUSE - ERROR_TABLE_BASE_uae)] = EADDRINUSE;
186     et2sys[(UAEADDRNOTAVAIL - ERROR_TABLE_BASE_uae)] = EADDRNOTAVAIL;
187     et2sys[(UAENETDOWN - ERROR_TABLE_BASE_uae)] = ENETDOWN;
188     et2sys[(UAENETUNREACH - ERROR_TABLE_BASE_uae)] = ENETUNREACH;
189     et2sys[(UAENETRESET - ERROR_TABLE_BASE_uae)] = ENETRESET;
190     et2sys[(UAECONNABORTED - ERROR_TABLE_BASE_uae)] = ECONNABORTED;
191     et2sys[(UAECONNRESET - ERROR_TABLE_BASE_uae)] = ECONNRESET;
192     et2sys[(UAENOBUFS - ERROR_TABLE_BASE_uae)] = ENOBUFS;
193     et2sys[(UAEISCONN - ERROR_TABLE_BASE_uae)] = EISCONN;
194     et2sys[(UAENOTCONN - ERROR_TABLE_BASE_uae)] = ENOTCONN;
195     et2sys[(UAESHUTDOWN - ERROR_TABLE_BASE_uae)] = ESHUTDOWN;
196     et2sys[(UAETOOMANYREFS - ERROR_TABLE_BASE_uae)] = ETOOMANYREFS;
197     et2sys[(UAETIMEDOUT - ERROR_TABLE_BASE_uae)] = ETIMEDOUT;
198     et2sys[(UAECONNREFUSED - ERROR_TABLE_BASE_uae)] = ECONNREFUSED;
199     et2sys[(UAEHOSTDOWN - ERROR_TABLE_BASE_uae)] = EHOSTDOWN;
200     et2sys[(UAEHOSTUNREACH - ERROR_TABLE_BASE_uae)] = EHOSTUNREACH;
201     et2sys[(UAEALREADY - ERROR_TABLE_BASE_uae)] = EALREADY;
202     et2sys[(UAEINPROGRESS - ERROR_TABLE_BASE_uae)] = EINPROGRESS;
203     et2sys[(UAESTALE - ERROR_TABLE_BASE_uae)] = ESTALE;
204     et2sys[(UAEUCLEAN - ERROR_TABLE_BASE_uae)] = EUCLEAN;
205     et2sys[(UAENOTNAM - ERROR_TABLE_BASE_uae)] = ENOTNAM;
206     et2sys[(UAENAVAIL - ERROR_TABLE_BASE_uae)] = ENAVAIL;
207     et2sys[(UAEISNAM - ERROR_TABLE_BASE_uae)] = EISNAM;
208     et2sys[(UAEREMOTEIO - ERROR_TABLE_BASE_uae)] = EREMOTEIO;
209     et2sys[(UAEDQUOT - ERROR_TABLE_BASE_uae)] = EDQUOT;
210     et2sys[(UAENOMEDIUM - ERROR_TABLE_BASE_uae)] = ENOMEDIUM;
211     et2sys[(UAEMEDIUMTYPE - ERROR_TABLE_BASE_uae)] = EMEDIUMTYPE;
212 }
213
214 static afs_int32
215 et_to_sys_error(afs_int32 in)
216 {
217     if (in < ERROR_TABLE_BASE_uae || in >= ERROR_TABLE_BASE_uae + 512)
218         return in;
219     if (et2sys[in - ERROR_TABLE_BASE_uae] != 0)
220         return et2sys[in - ERROR_TABLE_BASE_uae];
221     return in;
222 }
223
224 long cm_MapRPCError(long error, cm_req_t *reqp)
225 {
226     if (error == 0) 
227         return 0;
228
229     /* If we had to stop retrying, report our saved error code. */
230     if (reqp && error == CM_ERROR_TIMEDOUT) {
231         if (reqp->accessError)
232             return reqp->accessError;
233         if (reqp->volumeError)
234             return reqp->volumeError;
235         if (reqp->rpcError)
236             return reqp->rpcError;
237         return error;
238     }
239
240     error = et_to_sys_error(error);
241
242     if (error < 0) 
243         error = CM_ERROR_TIMEDOUT;
244     else if (error == EROFS) 
245         error = CM_ERROR_READONLY;
246     else if (error == EACCES) 
247         error = CM_ERROR_NOACCESS;
248     else if (error == EXDEV) 
249         error = CM_ERROR_CROSSDEVLINK;
250     else if (error == EEXIST) 
251         error = CM_ERROR_EXISTS;
252     else if (error == ENOTDIR) 
253         error = CM_ERROR_NOTDIR;
254     else if (error == ENOENT)
255         error = CM_ERROR_NOSUCHFILE;
256     else if (error == EAGAIN
257              || error == 35        /* EAGAIN, Digital UNIX */
258              || error == WSAEWOULDBLOCK)
259         error = CM_ERROR_WOULDBLOCK;
260     else if (error == VDISKFULL
261               || error == ENOSPC)
262         error = CM_ERROR_SPACE;
263     else if (error == VOVERQUOTA
264               || error == EDQUOT
265               || error == 49    /* EDQUOT on Solaris */
266               || error == 88    /* EDQUOT on AIX */
267               || error == 69    /* EDQUOT on Digital UNIX and HPUX */
268               || error == 122   /* EDQUOT on Linux */
269               || error == 1133) /* EDQUOT on Irix  */
270         error = CM_ERROR_QUOTA;
271     else if (error == VNOVNODE)
272         error = CM_ERROR_BADFD;
273     else if (error == EISDIR)
274         return CM_ERROR_ISDIR;
275     return error;
276 }
277
278 long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp)
279 {
280     if (error == 0) 
281         return 0;
282
283     /* If we had to stop retrying, report our saved error code. */
284     if (reqp && error == CM_ERROR_TIMEDOUT) {
285         if (reqp->accessError)
286             return reqp->accessError;
287         if (reqp->volumeError)
288             return reqp->volumeError;
289         if (reqp->rpcError)
290             return reqp->rpcError;
291         return error;
292     }
293
294     error = et_to_sys_error(error);
295
296     if (error < 0) 
297         error = CM_ERROR_TIMEDOUT;
298     else if (error == EROFS) 
299         error = CM_ERROR_READONLY;
300     else if (error == ENOTDIR) 
301         error = CM_ERROR_NOTDIR;
302     else if (error == EACCES) 
303         error = CM_ERROR_NOACCESS;
304     else if (error == ENOENT) 
305         error = CM_ERROR_NOSUCHFILE;
306     else if (error == ENOTEMPTY 
307               || error == 17            /* AIX */
308               || error == 66            /* SunOS 4, Digital UNIX */
309               || error == 93            /* Solaris 2, IRIX */
310               || error == 247)  /* HP/UX */
311         error = CM_ERROR_NOTEMPTY;
312     return error;
313 }       
314
315 long cm_MapVLRPCError(long error, cm_req_t *reqp)
316 {
317     if (error == 0) return 0;
318
319     /* If we had to stop retrying, report our saved error code. */
320     if (reqp && error == CM_ERROR_TIMEDOUT) {
321         if (reqp->accessError)
322             return reqp->accessError;
323         if (reqp->volumeError)
324             return reqp->volumeError;
325         if (reqp->rpcError)
326             return reqp->rpcError;
327         return error;
328     }
329
330     error = et_to_sys_error(error);
331
332     if (error < 0) 
333         error = CM_ERROR_TIMEDOUT;
334     else if (error == VL_NOENT || error == VL_BADNAME) 
335         error = CM_ERROR_NOSUCHVOLUME;
336     return error;
337 }
338
339 cm_space_t *cm_GetSpace(void)
340 {
341         cm_space_t *tsp;
342
343         if (osi_Once(&cm_utilsOnce)) {
344                 lock_InitializeRWLock(&cm_utilsLock, "cm_utilsLock", LOCK_HIERARCHY_UTILS_GLOBAL);
345                 osi_EndOnce(&cm_utilsOnce);
346         }
347         
348         lock_ObtainWrite(&cm_utilsLock);
349         if (tsp = cm_spaceListp) {
350                 cm_spaceListp = tsp->nextp;
351         }
352         else tsp = (cm_space_t *) malloc(sizeof(cm_space_t));
353         (void) memset(tsp, 0, sizeof(cm_space_t));
354         lock_ReleaseWrite(&cm_utilsLock);
355         
356         return tsp;
357 }
358
359 void cm_FreeSpace(cm_space_t *tsp)
360 {
361         lock_ObtainWrite(&cm_utilsLock);
362         tsp->nextp = cm_spaceListp;
363         cm_spaceListp = tsp;
364         lock_ReleaseWrite(&cm_utilsLock);
365 }
366
367 /* characters that are legal in an 8.3 name */
368 /*
369  * We used to have 1's for all characters from 128 to 254.  But
370  * the NT client behaves better if we create an 8.3 name for any
371  * name that has a character with the high bit on, and if we
372  * delete those characters from 8.3 names.  In particular, see
373  * Sybase defect 10859.
374  */
375 char cm_LegalChars[256] = {
376  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
377  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
378  0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
379  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
380  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
381  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
382  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
383  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
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  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
392 };
393
394 #define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
395
396 /* return true iff component is a valid 8.3 name */
397 int cm_Is8Dot3(clientchar_t *namep)
398 {
399     int sawDot = 0;
400     clientchar_t tc;
401     int charCount = 0;
402         
403     /*
404      * can't have a leading dot;
405      * special case for . and ..
406      */
407     if (namep[0] == '.') {
408         if (namep[1] == 0)
409             return 1;
410         if (namep[1] == '.' && namep[2] == 0)
411             return 1;
412         return 0;
413     }
414     while (tc = *namep++) {
415         if (tc == '.') {
416             /* saw another dot */
417             if (sawDot) return 0;       /* second dot */
418             sawDot = 1;
419             charCount = 0;
420             continue;
421         }
422         if (!ISLEGALCHAR(tc))
423             return 0;
424         charCount++;
425         if (!sawDot && charCount > 8)
426             /* more than 8 chars in name */
427             return 0;
428         if (sawDot && charCount > 3)
429             /* more than 3 chars in extension */
430             return 0;
431     }
432     return 1;
433 }
434
435 /*
436  * Number unparsing map for generating 8.3 names;
437  * The version taken from DFS was on drugs.  
438  * You can't include '&' and '@' in a file name.
439  */
440 char cm_8Dot3Mapping[42] =
441 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
442  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
443  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
444  'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '{', '}'
445 };
446 int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
447
448 void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
449                         clientchar_t *shortName, clientchar_t **shortNameEndp)
450 {
451     char number[12];
452     int i, nsize = 0;
453     int vnode = ntohl(pfid->vnode);
454     char *lastDot;
455     int validExtension = 0;
456     char tc, *temp;
457     const char *name;
458
459     /* Unparse the file's vnode number to get a "uniquifier" */
460     do {
461         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
462         nsize++;
463         vnode /= cm_8Dot3MapSize;
464     } while (vnode);
465
466     /*
467      * Look for valid extension.  There has to be a dot, and
468      * at least one of the characters following has to be legal.
469      */
470     lastDot = strrchr(longname, '.');
471     if (lastDot) {
472         temp = lastDot; temp++;
473         while (tc = *temp++)
474             if (ISLEGALCHAR(tc))
475                 break;
476         if (tc)
477             validExtension = 1;
478     }
479
480     /* Copy name characters */
481     for (i = 0, name = longname;
482           i < (7 - nsize) && name != lastDot; ) {
483         tc = *name++;
484
485         if (tc == 0)
486             break;
487         if (!ISLEGALCHAR(tc))
488             continue;
489         i++;
490         *shortName++ = toupper(tc);
491     }
492
493     /* tilde */
494     *shortName++ = '~';
495
496     /* Copy uniquifier characters */
497     for (i=0; i < nsize; i++) {
498         *shortName++ = number[i];
499     }
500
501     if (validExtension) {
502         /* Copy extension characters */
503         *shortName++ = *lastDot++;      /* copy dot */
504         for (i = 0, tc = *lastDot++;
505              i < 3 && tc;
506              tc = *lastDot++) {
507             if (ISLEGALCHAR(tc)) {
508                 i++;
509                 *shortName++ = toupper(tc);
510             }
511         }
512     }
513
514     /* Trailing null */
515     *shortName = 0;
516
517     if (shortNameEndp)
518         *shortNameEndp = shortName;
519 }
520
521 void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
522                          clientchar_t *shortName, clientchar_t **shortNameEndp)
523 {
524     clientchar_t number[12];
525     int i, nsize = 0;
526     int vnode = ntohl(pfid->vnode);
527     clientchar_t *lastDot;
528     int validExtension = 0;
529     clientchar_t tc, *temp;
530     const clientchar_t *name;
531
532     /* Unparse the file's vnode number to get a "uniquifier" */
533     do {
534         number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
535         nsize++;
536         vnode /= cm_8Dot3MapSize;
537     } while (vnode);
538
539     /*
540      * Look for valid extension.  There has to be a dot, and
541      * at least one of the characters following has to be legal.
542      */
543     lastDot = cm_ClientStrRChr(longname, '.');
544     if (lastDot) {
545         temp = lastDot; temp++;
546         while (tc = *temp++)
547             if (ISLEGALCHAR(tc))
548                 break;
549         if (tc)
550             validExtension = 1;
551     }
552
553     /* Copy name characters */
554     for (i = 0, name = longname;
555           i < (7 - nsize) && name != lastDot; ) {
556         tc = *name++;
557
558         if (tc == 0)
559             break;
560         if (!ISLEGALCHAR(tc))
561             continue;
562         i++;
563         *shortName++ = toupper((char) tc);
564     }
565
566     /* tilde */
567     *shortName++ = '~';
568
569     /* Copy uniquifier characters */
570     for (i=0; i < nsize; i++) {
571         *shortName++ = number[i];
572     }
573
574     if (validExtension) {
575         /* Copy extension characters */
576         *shortName++ = *lastDot++;      /* copy dot */
577         for (i = 0, tc = *lastDot++;
578              i < 3 && tc;
579              tc = *lastDot++) {
580             if (ISLEGALCHAR(tc)) {
581                 i++;
582                 *shortName++ = toupper(tc);
583             }
584         }
585     }
586
587     /* Trailing null */
588     *shortName = 0;
589
590     if (shortNameEndp)
591         *shortNameEndp = shortName;
592 }
593
594 /*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
595
596   \note This procedure works recursively calling itself.
597
598   \param[in] pattern string containing metacharacters.
599   \param[in] name File name to be compared with 'pattern'.
600
601   \return BOOL : TRUE/FALSE (match/mistmatch)
602 */
603 static BOOL 
604 szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold) 
605 {
606     clientchar_t upattern[MAX_PATH];
607     clientchar_t uname[MAX_PATH];
608
609     clientchar_t * pename;         // points to the last 'name' character
610     clientchar_t * p;
611     clientchar_t * pattern_next;
612
613     if (casefold) {
614         cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
615         cm_ClientStrUpr(upattern);
616         pattern = upattern;
617
618         cm_ClientStrCpy(uname, lengthof(uname), name);
619         cm_ClientStrUpr(uname);
620         name = uname;
621
622         /* The following translations all work on single byte
623            characters */
624         for (p=upattern; *p; p++) {
625             if (*p == '"') *p = '.'; continue;
626             if (*p == '<') *p = '*'; continue;
627             if (*p == '>') *p = '?'; continue;
628         }
629
630         for (p=uname; *p; p++) {
631             if (*p == '"') *p = '.'; continue;
632             if (*p == '<') *p = '*'; continue;
633             if (*p == '>') *p = '?'; continue;
634         }
635     }
636
637     pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
638
639     while (*name) {
640         switch (*pattern) {
641         case '?':
642             pattern = cm_ClientCharNext(pattern);
643             if (*name == '.')
644                 continue;
645             name = cm_ClientCharNext(name);
646             break;
647
648          case '*':
649             pattern = cm_ClientCharNext(pattern);
650             if (*pattern == '\0')
651                 return TRUE;
652
653             pattern_next = cm_ClientCharNext(pattern);
654
655             for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
656                 if (*p == *pattern &&
657                     szWildCardMatchFileName(pattern_next,
658                                             cm_ClientCharNext(p), FALSE))
659                     return TRUE;
660             } /* endfor */
661             if (*pattern == '.' && *pattern_next == '\0') {
662                 for (p = name; p && *p; p = cm_ClientCharNext(p))
663                     if (*p == '.')
664                         break;
665                 if (p && *p)
666                     return FALSE;
667                 return TRUE;
668             }
669             return FALSE;
670
671         default:
672             if (*name != *pattern)
673                 return FALSE;
674             pattern = cm_ClientCharNext(pattern);
675             name = cm_ClientCharNext(name);
676             break;
677         } /* endswitch */
678     } /* endwhile */
679
680     /* if all we have left are wildcards, then we match */
681     for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
682         if (*pattern != '*' && *pattern != '?')
683             return FALSE;
684     }
685     return TRUE;
686 }
687
688 /* do a case-folding search of the star name mask with the name in namep.
689  * Return 1 if we match, otherwise 0.
690  */
691 int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
692 {
693     clientchar_t *newmask, lastchar = _C('\0');
694     int    i, j, casefold, retval;
695     int  star = 0, qmark = 0, dot = 0;
696
697     /* make sure we only match 8.3 names, if requested */
698     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
699         return 0;
700
701     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
702
703     /* optimize the pattern:
704      * if there is a mixture of '?' and '*',
705      * for example  the sequence "*?*?*?*"
706      * must be turned into the form "*"
707      */
708     newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+2)*sizeof(clientchar_t));
709     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
710         lastchar = maskp[i];
711         switch ( maskp[i] ) {
712         case '?':
713         case '>':
714             qmark++;
715             break;
716         case '<':
717         case '*':
718             star++;
719             break;
720         case '.':
721             dot++;
722             /* fallthrough */
723         default:
724             if ( star ) {
725                 newmask[j++] = '*';
726             } else if ( qmark ) {
727                 while ( qmark-- )
728                     newmask[j++] = '?';
729             }
730             newmask[j++] = maskp[i];
731             star = 0;
732             qmark = 0;
733         }
734     }
735     if ( star ) {
736         newmask[j++] = '*';
737     } else if ( qmark ) {
738         while ( qmark-- )
739             newmask[j++] = '?';
740     }
741     if (dot == 0 && lastchar == '<')
742         newmask[j++] = '.';
743     newmask[j++] = '\0';
744
745     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
746
747     free(newmask);
748     return retval;
749 }
750
751 BOOL
752 cm_TargetPerceivedAsDirectory(const fschar_t *target)
753 {
754     char        * ext;
755
756     ext = PathFindExtension(target);
757     if (!ext[0])
758         return TRUE;
759
760     return FALSE;
761 }